From 7b52f12065730e9dd7808d76d955144fb66bf9e3 Mon Sep 17 00:00:00 2001 From: Daniel-Warner-X Date: Fri, 7 Nov 2025 20:16:27 -0600 Subject: [PATCH 01/34] layout for the session details page --- .../src/app/projects/[name]/rfe/[id]/page.tsx | 193 ++-- .../[name]/sessions/[sessionName]/page.tsx | 881 +++++++++++++----- 2 files changed, 772 insertions(+), 302 deletions(-) diff --git a/components/frontend/src/app/projects/[name]/rfe/[id]/page.tsx b/components/frontend/src/app/projects/[name]/rfe/[id]/page.tsx index ea97d2107..a8f39a8e2 100644 --- a/components/frontend/src/app/projects/[name]/rfe/[id]/page.tsx +++ b/components/frontend/src/app/projects/[name]/rfe/[id]/page.tsx @@ -6,8 +6,11 @@ import { useParams, useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; import { WorkflowPhase } from "@/types/agentic-session"; -import { ArrowLeft, Loader2 } from "lucide-react"; +import { ArrowLeft, Loader2, Bot } from "lucide-react"; +import { Badge } from "@/components/ui/badge"; +import { Checkbox } from "@/components/ui/checkbox"; import RepoBrowser from "@/components/RepoBrowser"; import type { GitHubFork } from "@/types"; import { Breadcrumbs } from "@/components/breadcrumbs"; @@ -16,7 +19,8 @@ import { RfePhaseCards } from "./rfe-phase-cards"; import { RfeWorkspaceCard } from "./rfe-workspace-card"; import { RfeHeader } from "./rfe-header"; import { RfeAgentsCard } from "./rfe-agents-card"; -import { useRfeWorkflow, useRfeWorkflowSessions, useDeleteRfeWorkflow, useRfeWorkflowSeeding, useSeedRfeWorkflow, useUpdateRfeWorkflow, useRepoBlob, useRepoTree, useOpenJiraIssue } from "@/services/queries"; +import { AVAILABLE_AGENTS } from "@/lib/agents"; +import { useRfeWorkflow, useRfeWorkflowSessions, useDeleteRfeWorkflow, useRfeWorkflowSeeding, useSeedRfeWorkflow, useUpdateRfeWorkflow, useRepoBlob, useRepoTree, useOpenJiraIssue, useRfeWorkflowAgents } from "@/services/queries"; export default function ProjectRFEDetailPage() { const params = useParams(); @@ -32,6 +36,7 @@ export default function ProjectRFEDetailPage() { const seedWorkflowMutation = useSeedRfeWorkflow(); const updateWorkflowMutation = useUpdateRfeWorkflow(); const { openJiraForPath } = useOpenJiraIssue(project, id); + const { data: repoAgents = AVAILABLE_AGENTS, isLoading: loadingAgents } = useRfeWorkflowAgents(project, id); // Extract repo info from workflow const repo = workflow?.umbrellaRepo?.url.replace(/^https?:\/\/(?:www\.)?github.com\//i, '').replace(/\.git$/i, '') || ''; @@ -255,8 +260,6 @@ export default function ProjectRFEDetailPage() { onDelete={deleteWorkflow} /> - - - + {/* Two Column Layout */} +
+ {/* Left Column - Tabs */} +
+ + + Overview + Sessions + {upstreamRepo ? Repository : null} + - - - Overview - Sessions - {upstreamRepo ? Repository : null} - + + { await load(); }} + onLoadSessions={async () => { await loadSessions(); }} + onError={setError} + onOpenJira={openJiraForPath} + /> + - - { await load(); }} - onLoadSessions={async () => { await loadSessions(); }} - onError={setError} - onOpenJira={openJiraForPath} - /> - + + + - - - + + + + +
- - - - - + {/* Right Column - Agents Accordion */} +
+ + + + + +
+ + Agents +
+
+ + {loadingAgents ? ( +
+ +
+ ) : repoAgents.length === 0 ? ( +
+ +

No agents found in repository .claude/agents directory

+

Seed the repository to add agent definitions

+
+ ) : ( + <> +
+ {repoAgents.map((agent) => { + const isSelected = selectedAgents.includes(agent.persona); + return ( +
+ +
+ ); + })} +
+ {selectedAgents.length > 0 && ( +
+
Selected Agents ({selectedAgents.length})
+
+ {selectedAgents.map(persona => { + const agent = repoAgents.find(a => a.persona === persona); + return agent ? ( + + {agent.name} + + ) : null; + })} +
+
+ )} + + )} +
+
+
+
+
+
+
diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 3d8eb8162..45af002b1 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -3,7 +3,7 @@ import { useState, useEffect, useMemo, useCallback } from "react"; import Link from "next/link"; import { formatDistanceToNow } from "date-fns"; -import { ArrowLeft, Square, Trash2, Copy, Play, MoreVertical } from "lucide-react"; +import { ArrowLeft, Square, Trash2, Copy, Play, MoreVertical, Bot, Loader2, FolderTree, AlertCircle, Sprout, CheckCircle2, GitBranch, Edit, Info } from "lucide-react"; import { useRouter } from "next/navigation"; // Custom components @@ -11,13 +11,18 @@ import OverviewTab from "@/components/session/OverviewTab"; import MessagesTab from "@/components/session/MessagesTab"; import WorkspaceTab from "@/components/session/WorkspaceTab"; import ResultsTab from "@/components/session/ResultsTab"; +import { EditRepositoriesDialog } from "../../rfe/[id]/edit-repositories-dialog"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { CloneSessionDialog } from "@/components/clone-session-dialog"; import { Breadcrumbs } from "@/components/breadcrumbs"; +import { PageHeader } from "@/components/page-header"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"; import type { FileTreeNode } from "@/components/file-tree"; @@ -40,6 +45,11 @@ import { useAllSessionGitHubDiffs, useSessionK8sResources, useContinueSession, + useRfeWorkflow, + useRfeWorkflowAgents, + useRfeWorkflowSeeding, + useSeedRfeWorkflow, + useUpdateRfeWorkflow, workspaceKeys, } from "@/services/queries"; import { successToast, errorToast } from "@/hooks/use-toast"; @@ -55,7 +65,6 @@ export default function ProjectSessionDetailPage({ const queryClient = useQueryClient(); const [projectName, setProjectName] = useState(""); const [sessionName, setSessionName] = useState(""); - const [activeTab, setActiveTab] = useState("overview"); const [promptExpanded, setPromptExpanded] = useState(false); const [chatInput, setChatInput] = useState(""); const [backHref, setBackHref] = useState(null); @@ -63,6 +72,9 @@ export default function ProjectSessionDetailPage({ const [contentPodSpawning, setContentPodSpawning] = useState(false); const [contentPodReady, setContentPodReady] = useState(false); const [contentPodError, setContentPodError] = useState(null); + const [selectedAgents, setSelectedAgents] = useState([]); + const [editRepoDialogOpen, setEditRepoDialogOpen] = useState(false); + const [selectedWorkflow, setSelectedWorkflow] = useState("none"); // Extract params useEffect(() => { @@ -89,6 +101,22 @@ export default function ProjectSessionDetailPage({ const pushToGitHubMutation = usePushSessionToGitHub(); const abandonChangesMutation = useAbandonSessionChanges(); const writeWorkspaceFileMutation = useWriteWorkspaceFile(); + + // Get RFE workflow ID from session if this is an RFE session + const rfeWorkflowId = session?.metadata?.labels?.['rfe-workflow-id']; + const { data: rfeWorkflow, refetch: refetchWorkflow } = useRfeWorkflow(projectName, rfeWorkflowId || '', { enabled: !!rfeWorkflowId }); + const { data: repoAgents = [], isLoading: loadingAgents } = useRfeWorkflowAgents( + projectName, + rfeWorkflowId || '', + { enabled: !!rfeWorkflowId } + ); + const { data: seedingData, isLoading: checkingSeeding, error: seedingQueryError, refetch: refetchSeeding } = useRfeWorkflowSeeding( + projectName, + rfeWorkflowId || '', + { enabled: !!rfeWorkflowId } + ); + const seedWorkflowMutation = useSeedRfeWorkflow(); + const updateWorkflowMutation = useUpdateRfeWorkflow(); // Workspace state const [wsSelectedPath, setWsSelectedPath] = useState(); @@ -111,7 +139,7 @@ export default function ProjectSessionDetailPage({ projectName, sessionName, undefined, - { enabled: activeTab === 'workspace' } + { enabled: true } ); // Update tree when workspace items change @@ -450,7 +478,6 @@ export default function ProjectSessionDetailPage({ { onSuccess: () => { setChatInput(""); - setActiveTab('messages'); }, onError: (err) => errorToast(err instanceof Error ? err.message : "Failed to send message"), } @@ -477,6 +504,67 @@ export default function ProjectSessionDetailPage({ ); }; + const handleSeedWorkflow = useCallback(async () => { + if (!rfeWorkflowId) return; + return new Promise((resolve, reject) => { + seedWorkflowMutation.mutate( + { projectName, workflowId: rfeWorkflowId }, + { + onSuccess: () => { + successToast("Repository seeded successfully"); + refetchSeeding(); + resolve(); + }, + onError: (err) => { + errorToast(err instanceof Error ? err.message : "Failed to seed repository"); + reject(err); + }, + } + ); + }); + }, [projectName, rfeWorkflowId, seedWorkflowMutation, refetchSeeding]); + + const handleUpdateRepositories = useCallback(async (data: { umbrellaRepo: { url: string; branch?: string }; supportingRepos: { url: string; branch?: string }[] }) => { + if (!rfeWorkflowId) return; + return new Promise((resolve, reject) => { + updateWorkflowMutation.mutate( + { + projectName, + workflowId: rfeWorkflowId, + data: { + umbrellaRepo: data.umbrellaRepo, + supportingRepos: data.supportingRepos, + }, + }, + { + onSuccess: () => { + successToast("Repositories updated successfully"); + refetchWorkflow(); + refetchSeeding(); + seedWorkflowMutation.reset(); + resolve(); + }, + onError: (err) => { + errorToast(err instanceof Error ? err.message : "Failed to update repositories"); + reject(err); + }, + } + ); + }); + }, [projectName, rfeWorkflowId, updateWorkflowMutation, refetchWorkflow, refetchSeeding, seedWorkflowMutation]); + + // Seeding status from React Query + const isSeeded = seedingData?.isSeeded || false; + const seedingError = seedWorkflowMutation.error?.message || seedingQueryError?.message; + const hasCheckedSeeding = seedingData !== undefined || !!seedingQueryError; + const seedingStatus = { + checking: checkingSeeding, + isSeeded, + error: seedingError, + hasChecked: hasCheckedSeeding, + }; + const workflowWorkspace = rfeWorkflow?.workspacePath || (rfeWorkflowId ? `/rfe-workflows/${rfeWorkflowId}/workspace` : ''); + // Check if session is completed const sessionCompleted = ( session?.status?.phase === 'Completed' || @@ -484,14 +572,14 @@ export default function ProjectSessionDetailPage({ session?.status?.phase === 'Stopped' ); - // Auto-spawn content pod when workspace tab clicked on completed session + // Auto-spawn content pod on completed session // Don't auto-retry if we already encountered an error - user must explicitly retry useEffect(() => { - if (activeTab === 'workspace' && sessionCompleted && !contentPodReady && !contentPodSpawning && !contentPodError) { + if (sessionCompleted && !contentPodReady && !contentPodSpawning && !contentPodError) { spawnContentPodAsync(); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeTab, sessionCompleted, contentPodReady, contentPodSpawning, contentPodError]); + }, [sessionCompleted, contentPodReady, contentPodSpawning, contentPodError]); const spawnContentPodAsync = async () => { if (!projectName || !sessionName) return; @@ -691,10 +779,12 @@ export default function ProjectSessionDetailPage({ // Loading state - also check if params are loaded if (isLoading || !projectName || !sessionName) { return ( -
-
-
- Loading session... +
+
+
+
+ Loading session... +
); @@ -703,258 +793,557 @@ export default function ProjectSessionDetailPage({ // Error state if (error || !session) { return ( -
-
- - - +
+
+
+ + +
+
+
+
+ + +

Error: {error instanceof Error ? error.message : "Session not found"}

+
+
+
- - -

Error: {error instanceof Error ? error.message : "Session not found"}

-
-
); } return ( -
- - -
- {/* Header */} -
-
-

- {session.spec.displayName || session.metadata.name} - - {session.status?.phase || "Pending"} - -

- {session.spec.displayName && ( -
{session.metadata.name}
- )} -
- Created {formatDistanceToNow(new Date(session.metadata.creationTimestamp), { addSuffix: true })} -
-
-
- {/* Continue button for completed sessions (converts headless to interactive) */} - {(session.status?.phase === "Completed" || session.status?.phase === "Failed" || session.status?.phase === "Stopped") && ( - - )} - - {/* Stop button for active sessions */} - {(session.status?.phase === "Pending" || session.status?.phase === "Creating" || session.status?.phase === "Running") && ( - - )} - - {/* Actions dropdown menu */} - - - - - - refetchSession()} - trigger={ - e.preventDefault()}> - - Clone + <> + {rfeWorkflow && ( + { + await handleUpdateRepositories(data); + setEditRepoDialogOpen(false); + }} + isSaving={updateWorkflowMutation.isPending} + /> + )} +
+ {/* Sticky header */} +
+
+ + + {session.spec.displayName || session.metadata.name} + + {session.status?.phase || "Pending"} + +
+ } + description={ +
+ {session.spec.displayName && ( +
{session.metadata.name}
+ )} +
+ Created {formatDistanceToNow(new Date(session.metadata.creationTimestamp), { addSuffix: true })} +
+
+ } + actions={ + <> + {/* Continue button for completed sessions */} + {(session.status?.phase === "Completed" || session.status?.phase === "Failed" || session.status?.phase === "Stopped") && ( + + )} + + {/* Stop button for active sessions */} + {(session.status?.phase === "Pending" || session.status?.phase === "Creating" || session.status?.phase === "Running") && ( + + )} + + {/* Actions dropdown menu */} + + + + + + refetchSession()} + trigger={ + e.preventDefault()}> + + Clone + + } + /> + + + + {deleteMutation.isPending ? "Deleting..." : "Delete"} - } - /> - - - - {deleteMutation.isPending ? "Deleting..." : "Delete"} - - - -
+ + + + } + />
+
- {/* Stats */} -
- - -
Duration
-
{typeof durationMs === "number" ? `${durationMs} ms` : "-"}
-
-
- - -
Messages
-
{messages.length}
-
-
- - -
Agents
-
{subagentStats.uniqueCount > 0 ? subagentStats.uniqueCount : "-"}
-
-
-
+
+
+ {/* Two Column Layout */} +
+ {/* Left Column - Accordions */} +
+ + + + Workflows + + +
+
+ + +
+

+ Workflows provide a structured processes for Ambient Code Platform agents to follow and achieve complex goals. +

+
+
+
- {/* Tabs */} - - - Overview - Messages - Workspace - Results - - - - { - const repo = session.spec.repos?.[idx]; - if (!repo) return; - - setBusyRepo((b) => ({ ...b, [idx]: 'push' })); - const folder = deriveRepoFolderFromUrl(repo.input.url); - const repoPath = `/sessions/${sessionName}/workspace/${folder}`; - - pushToGitHubMutation.mutate( - { projectName, sessionName, repoIndex: idx, repoPath }, - { - onSuccess: () => { - refetchDiffs(); - successToast('Changes pushed to GitHub'); - }, - onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to push changes'), - onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), - } - ); - }} - onAbandon={async (idx) => { - const repo = session.spec.repos?.[idx]; - if (!repo) return; - - setBusyRepo((b) => ({ ...b, [idx]: 'abandon' })); - const folder = deriveRepoFolderFromUrl(repo.input.url); - const repoPath = `/sessions/${sessionName}/workspace/${folder}`; - - abandonChangesMutation.mutate( - { projectName, sessionName, repoIndex: idx, repoPath }, - { - onSuccess: () => { - refetchDiffs(); - successToast('Changes abandoned'); - }, - onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to abandon changes'), - onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), - } - ); - }} - busyRepo={busyRepo} - buildGithubCompareUrl={buildGithubCompareUrl} - onRefreshDiff={handleRefreshDiff} - /> - - - - Promise.resolve(sendChat())} - onInterrupt={() => Promise.resolve(handleInterrupt())} - onEndSession={() => Promise.resolve(handleEndSession())} - onGoToResults={() => setActiveTab('results')} - onContinue={handleContinue} - /> - + + + Overview + + + { + const repo = session.spec.repos?.[idx]; + if (!repo) return; + + setBusyRepo((b) => ({ ...b, [idx]: 'push' })); + const folder = deriveRepoFolderFromUrl(repo.input.url); + const repoPath = `/sessions/${sessionName}/workspace/${folder}`; + + pushToGitHubMutation.mutate( + { projectName, sessionName, repoIndex: idx, repoPath }, + { + onSuccess: () => { + refetchDiffs(); + successToast('Changes pushed to GitHub'); + }, + onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to push changes'), + onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), + } + ); + }} + onAbandon={async (idx) => { + const repo = session.spec.repos?.[idx]; + if (!repo) return; + + setBusyRepo((b) => ({ ...b, [idx]: 'abandon' })); + const folder = deriveRepoFolderFromUrl(repo.input.url); + const repoPath = `/sessions/${sessionName}/workspace/${folder}`; + + abandonChangesMutation.mutate( + { projectName, sessionName, repoIndex: idx, repoPath }, + { + onSuccess: () => { + refetchDiffs(); + successToast('Changes abandoned'); + }, + onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to abandon changes'), + onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), + } + ); + }} + busyRepo={busyRepo} + buildGithubCompareUrl={buildGithubCompareUrl} + onRefreshDiff={handleRefreshDiff} + /> + + - - {sessionCompleted && !contentPodReady ? ( - -
- {contentPodSpawning ? ( - <> -
-
+ + + Workspace + + + {sessionCompleted && !contentPodReady ? ( + +
+ {contentPodSpawning ? ( + <> +
+
+
+

Starting workspace viewer...

+

This may take up to 30 seconds

+ + ) : ( + <> +

+ Session has completed. To view and edit your workspace files, please start a workspace viewer. +

+ + + )}
-

Starting workspace viewer...

-

This may take up to 30 seconds

- + + ) : ( + + )} + + + + + + Spec Repository + + + {!rfeWorkflowId ? ( +
+ +

This session is not associated with an RFE workflow

+

Spec repository is only available for RFE sessions

+
+ ) : ( +
+
Workspace: {workflowWorkspace}
+ + {rfeWorkflow?.branchName && ( + + + Feature Branch + + All modifications will occur on feature branch{' '} + + {rfeWorkflow.branchName} + + {' '}for all supplied repositories. + + + )} + + {(rfeWorkflow?.umbrellaRepo || (rfeWorkflow?.supportingRepos || []).length > 0) && ( +
+ {rfeWorkflow.umbrellaRepo && ( +
+
+ Spec Repo: {rfeWorkflow.umbrellaRepo.url} +
+ {rfeWorkflow.umbrellaRepo.branch && ( +
+ Base branch: {rfeWorkflow.umbrellaRepo.branch} + {rfeWorkflow.branchName && ( + → Feature branch {rfeWorkflow.branchName} {isSeeded ? 'set up' : 'will be set up'} + )} +
+ )} +
+ )} + {(rfeWorkflow.supportingRepos || []).map( + (r: { url: string; branch?: string }, i: number) => ( +
+
+ Supporting: {r.url} +
+ {r.branch && ( +
+ Base branch: {r.branch} + {rfeWorkflow.branchName && ( + → Feature branch {rfeWorkflow.branchName} {isSeeded ? 'set up' : 'will be set up'} + )} +
+ )} +
+ ) + )} +
+ )} + + {!isSeeded && !seedingStatus.checking && seedingStatus.hasChecked && rfeWorkflow?.umbrellaRepo && ( + + + Spec Repository Not Seeded + +

+ Before you can start working on phases, the spec repository needs to be seeded. + This will: +

+
    +
  • Set up the feature branch{rfeWorkflow.branchName && ` (${rfeWorkflow.branchName})`} from the base branch
  • +
  • Add Spec-Kit template files for spec-driven development
  • +
  • Add agent definition files in the .claude directory
  • +
+ {seedingError && ( +
+ Seeding Failed: {seedingError} +
+ )} +
+ + +
+
+
+ )} + + {seedingStatus.checking && rfeWorkflow?.umbrellaRepo && ( +
+ + Checking repository seeding status... +
+ )} + + {isSeeded && ( +
+
+ + Repository seeded and ready +
+ +
+ )} +
+ )} +
+
+ + + + Agents + + + {loadingAgents ? ( +
+ +
+ ) : !rfeWorkflowId || repoAgents.length === 0 ? ( +
+ +

No agents found in repository .claude/agents directory

+

Seed the repository to add agent definitions

+
) : ( <> -

- Session has completed. To view and edit your workspace files, please start a workspace viewer. -

- +
+ {repoAgents.map((agent) => { + const isSelected = selectedAgents.includes(agent.persona); + return ( +
+ +
+ ); + })} +
+ {selectedAgents.length > 0 && ( +
+
Selected Agents ({selectedAgents.length})
+
+ {selectedAgents.map(persona => { + const agent = repoAgents.find(a => a.persona === persona); + return agent ? ( + + {agent.name} + + ) : null; + })} +
+
+ )} )} -
-
- ) : ( - - )} - - - - - - +
+
+ + + + Results + + + + + + + + + Session Details + + +
+ + +
Duration
+
{typeof durationMs === "number" ? `${durationMs} ms` : "-"}
+
+
+ + +
Messages
+
{messages.length}
+
+
+ + +
Agents
+
{subagentStats.uniqueCount > 0 ? subagentStats.uniqueCount : "-"}
+
+
+
+
+
+ +
+ + {/* Right Column - Messages (Always Visible) */} +
+ + + Promise.resolve(sendChat())} + onInterrupt={() => Promise.resolve(handleInterrupt())} + onEndSession={() => Promise.resolve(handleEndSession())} + onGoToResults={() => {}} + onContinue={handleContinue} + /> + + +
+
+
+ ); } From 4b8cca78bfb06f57e0ce55332a5312b47ecc0fb3 Mon Sep 17 00:00:00 2001 From: Andy Braren Date: Fri, 7 Nov 2025 20:16:30 -0600 Subject: [PATCH 02/34] Move static prototype Update primary button colors to blue Improve workspace modal spacing Adjust display name and workspace name logic Adjust workspace modal text Move "Create Workspace" to modal --- components/frontend/src/app/globals.css | 8 +- .../frontend/src/app/projects/new/page.tsx | 221 -- components/frontend/src/app/projects/page.tsx | 71 +- .../components/create-workspace-dialog.tsx | 278 ++ .../frontend/static-prototype/README.md | 95 + ... 2025_10_30 15_56 EDT - Notes by Gemini.md | 55 + ... 2025_10_31 14_29 EDT - Notes by Gemini.md | 74 + ...n 2 - 2025_10_31 14_29 EDT - transcript.md | 856 ++++++ .../curated_feedback.md | 499 +++ .../prototype_version_1_feedback/my_notes.txt | 18 + .../prototype_version_1_feedback/plan.md | 766 +++++ .../slack_feedback.txt | 30 + .../frontend/static-prototype/index.html | 420 +++ .../static-prototype/integrations/page.html | 130 + .../static-prototype/projects/new/page.html | 136 + .../create-api-tests/page.html | 274 ++ .../implement-login-flow/page.html | 310 ++ .../projects/sample-workspace/info/page.html | 228 ++ .../projects/sample-workspace/keys/page.html | 295 ++ .../optimize-queries/headless.html | 303 ++ .../projects/sample-workspace/page.html | 1059 +++++++ .../sample-workspace/permissions/page.html | 318 ++ .../projects/sample-workspace/rfe/page.html | 262 ++ .../sample-workspace/session-1/headless.html | 385 +++ .../sample-workspace/session-1/page.html | 2692 +++++++++++++++++ .../sample-workspace/sessions/page.html | 273 ++ .../sample-workspace/settings/page.html | 340 +++ .../setup-database/headless.html | 307 ++ components/frontend/static-prototype/rfe.md | 1092 +++++++ .../frontend/static-prototype/styles.css | 527 ++++ 30 files changed, 12055 insertions(+), 267 deletions(-) delete mode 100644 components/frontend/src/app/projects/new/page.tsx create mode 100644 components/frontend/src/components/create-workspace-dialog.tsx create mode 100644 components/frontend/static-prototype/README.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/Chat UI Feedback - 2025_10_30 15_56 EDT - Notes by Gemini.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/Chat UI feedback session 2 - 2025_10_31 14_29 EDT - Notes by Gemini.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/Chat UI feedback session 2 - 2025_10_31 14_29 EDT - transcript.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/curated_feedback.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/my_notes.txt create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/plan.md create mode 100644 components/frontend/static-prototype/design_path/prototype_version_1_feedback/slack_feedback.txt create mode 100644 components/frontend/static-prototype/index.html create mode 100644 components/frontend/static-prototype/integrations/page.html create mode 100644 components/frontend/static-prototype/projects/new/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/info/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/keys/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/permissions/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/rfe/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/session-1/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/sessions/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/settings/page.html create mode 100644 components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html create mode 100644 components/frontend/static-prototype/rfe.md create mode 100644 components/frontend/static-prototype/styles.css diff --git a/components/frontend/src/app/globals.css b/components/frontend/src/app/globals.css index b77c4d606..2080a0957 100644 --- a/components/frontend/src/app/globals.css +++ b/components/frontend/src/app/globals.css @@ -52,7 +52,7 @@ --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); + --primary: oklch(0.5 0.22 264); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); @@ -71,7 +71,7 @@ --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary: oklch(0.5 0.22 264); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); @@ -86,8 +86,8 @@ --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); + --primary: oklch(0.6 0.2 264); + --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); diff --git a/components/frontend/src/app/projects/new/page.tsx b/components/frontend/src/app/projects/new/page.tsx deleted file mode 100644 index fa8837957..000000000 --- a/components/frontend/src/app/projects/new/page.tsx +++ /dev/null @@ -1,221 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; -import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { CreateProjectRequest } from "@/types/project"; -import { ArrowLeft, Save, Loader2, Info } from "lucide-react"; -import { successToast, errorToast } from "@/hooks/use-toast"; -import { Breadcrumbs } from "@/components/breadcrumbs"; -import { useCreateProject } from "@/services/queries"; -import { useClusterInfo } from "@/hooks/use-cluster-info"; -import { Alert, AlertDescription } from "@/components/ui/alert"; - -export default function NewProjectPage() { - const router = useRouter(); - const createProjectMutation = useCreateProject(); - const { isOpenShift, isLoading: clusterLoading } = useClusterInfo(); - const [error, setError] = useState(null); - const [formData, setFormData] = useState({ - name: "", - displayName: "", - description: "", - }); - - const [nameError, setNameError] = useState(null); - - const validateProjectName = (name: string) => { - // Validate name pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - const namePattern = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/; - - if (!name) { - return "Project name is required"; - } - - if (name.length > 63) { - return "Project name must be 63 characters or less"; - } - - if (!namePattern.test(name)) { - return "Project name must be lowercase alphanumeric with hyphens (cannot start or end with hyphen)"; - } - - return null; - }; - - const handleNameChange = (name: string) => { - setFormData(prev => ({ ...prev, name })); - setNameError(validateProjectName(name)); - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - // Validate required fields - const nameValidationError = validateProjectName(formData.name); - if (nameValidationError) { - setNameError(nameValidationError); - return; - } - - setError(null); - - // Prepare the request payload - const payload: CreateProjectRequest = { - name: formData.name, - // Only include displayName and description on OpenShift - ...(isOpenShift && formData.displayName?.trim() && { displayName: formData.displayName.trim() }), - ...(isOpenShift && formData.description?.trim() && { description: formData.description.trim() }), - }; - - createProjectMutation.mutate(payload, { - onSuccess: (project) => { - successToast(`Project "${formData.displayName || formData.name}" created successfully`); - router.push(`/projects/${encodeURIComponent(project.name)}`); - }, - onError: (err) => { - const message = err instanceof Error ? err.message : "Failed to create project"; - setError(message); - errorToast(message); - }, - }); - }; - - return ( -
- -
- - - -
- - - - Create New Project - - Create a new Ambient AI project with custom settings and resource configurations - - - -
- {/* Cluster info banner */} - {!clusterLoading && !isOpenShift && ( - - - - Running on vanilla Kubernetes. Display name and description fields are not available. - - - )} - - {/* Basic Information */} -
-

Basic Information

- -
- - handleNameChange(e.target.value)} - placeholder="my-research-project" - className={nameError ? "border-red-500" : ""} - /> - {nameError && ( -

{nameError}

- )} -

- Lowercase alphanumeric with hyphens. Will be used as the Kubernetes namespace. -

-
- - {/* OpenShift-only fields */} - {isOpenShift && ( - <> -
- - setFormData(prev => ({ ...prev, displayName: e.target.value }))} - placeholder="My Research Project" - maxLength={100} - /> -

- Human-readable name for the project (max 100 characters). Defaults to project name if empty. -

-
- -
- - +
+ +
+ + +
+ +
+
+
+ + + + + + + diff --git a/components/frontend/static-prototype/integrations/page.html b/components/frontend/static-prototype/integrations/page.html new file mode 100644 index 000000000..b7ab3a411 --- /dev/null +++ b/components/frontend/static-prototype/integrations/page.html @@ -0,0 +1,130 @@ + + + + + + Integrations - Ambient Code Platform + + + +
+
+
+ +
+
+ + +
+
+
+
+
+ + + +
+
+
+
+
+
+ + + +
+
+

GitHub

+

Connect to GitHub repositories

+
+
+
+
+
+
+
+ Not Connected +
+
+ Connect to GitHub to manage repositories and create pull requests +
+
+ +
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/new/page.html b/components/frontend/static-prototype/projects/new/page.html new file mode 100644 index 000000000..df43d831c --- /dev/null +++ b/components/frontend/static-prototype/projects/new/page.html @@ -0,0 +1,136 @@ + + + + + + Create New Workspace - Ambient Code Platform + + + +
+
+
+ +
+
+ + +
+
+
+
+
+ + + +
+
+
+

Workspace Details

+

Provide basic information about your workspace

+
+
+
+
+ + + Must be lowercase, alphanumeric with hyphens +
+ +
+ + +
+ +
+ + +
+ +
+ + Cancel +
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html b/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html new file mode 100644 index 000000000..973d0d583 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html @@ -0,0 +1,274 @@ + + + + + + create-api-tests - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+ +
+
+
+
DU
+
+
You
+
Write comprehensive API tests for the authentication endpoints we created
+
+
+ +
+
AI
+
+
Claude
+
I'll create comprehensive API tests for your authentication endpoints. Let me start with testing the registration, login, and token validation endpoints...
+
+
+ +
+
DU
+
+
You
+
Make sure to test edge cases like invalid emails and weak passwords
+
+
+ +
+
AI
+
+
Claude
+
Excellent point! I'll include comprehensive edge case testing including invalid email formats, weak passwords, duplicate registrations, and malformed requests. Here are the test suites...
+
+
+ +
+
DU
+
+
You
+
Perfect! Also add tests for JWT token expiration and refresh
+
+
+ +
+
AI
+
+
Claude
+
Done! I've added comprehensive JWT testing including token expiration, refresh token flow, and invalid token handling. All tests are now complete and passing. ✅
+
+
+
+ +
+ + +
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html b/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html new file mode 100644 index 000000000..03c6369da --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html @@ -0,0 +1,310 @@ + + + + + + implement-login-flow - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+ +
+
+
+
DU
+
+
You
+
Create user login and registration endpoints with proper validation and security
+
+
+ +
+
AI
+
+
Claude
+
I'll help you create secure login and registration endpoints. Let me start by setting up the user model with proper password hashing and validation...
+
+
+ +
+
DU
+
+
You
+
Make sure to include JWT token generation and email validation
+
+
+ +
+
AI
+
+
Claude
+
Absolutely! I'll implement JWT token generation for authentication and comprehensive email validation. Here's the updated user model with bcrypt password hashing and JWT integration...
+
+
+
+ +
+ + +
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/info/page.html b/components/frontend/static-prototype/projects/sample-workspace/info/page.html new file mode 100644 index 000000000..5e339fcfd --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/info/page.html @@ -0,0 +1,228 @@ + + + + + + Project Information - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+
+

Project Information

+
+
+
+ Created: 2 days ago +
+
+ Status: + Active +
+
+
+ +
+
+

Quick Stats

+
+
+
+ RFE Workspaces: 3 +
+
+ Active Sessions: 2 +
+
+ API Keys: 1 +
+
+ Team Members: 5 +
+
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/keys/page.html b/components/frontend/static-prototype/projects/sample-workspace/keys/page.html new file mode 100644 index 000000000..4d7f33097 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/keys/page.html @@ -0,0 +1,295 @@ + + + + + + API Keys - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+
+
+

API Keys

+

API keys provide secure access to external services and integrations

+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCreatedLast UsedRoleActions
+
Production API Key
+
For production deployments and CI/CD
+
1 week ago2 hours agoAdmin + +
+
Development Key
+
For local development and testing
+
2 weeks ago1 day agoAdmin + +
+
Monitoring Key
+
Read-only access for monitoring tools
+
3 days agoNeverAdmin + +
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html b/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html new file mode 100644 index 000000000..f1b9dbd34 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html @@ -0,0 +1,303 @@ + + + + + + optimize-queries - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+ +
+
+
+

Session Configuration

+
+
+
+ Task: Optimize database queries for better performance +
+
+ Model: claude-3.5-sonnet +
+
+ Mode: Headless +
+
+ Duration: 18 minutes +
+
+ Status: + + + + + Completed + +
+
+
+ +
+
+

Performance Results

+
+
+
+
+ Query Optimization + 100% +
+
+
+
+
+
+
✓ Analyzed slow queries
+
✓ Added database indexes
+
✓ Optimized JOIN operations
+
✓ Reduced query time by 75%
+
✓ Updated documentation
+
+
+
+
+ +
+
+
+

Execution Log

+ +
+
+
+
+
+ 14:15:30 + [INFO] Session started: Optimize database queries for better performance +
+
+ 14:15:32 + [INFO] Analyzing database query performance +
+
+ 14:16:15 + [WARNING] Found 5 slow queries without proper indexing +
+
+ 14:16:45 + [INFO] Creating optimized database indexes +
+
+ 14:18:22 + [SUCCESS] Database indexes created successfully +
+
+ 14:19:10 + [INFO] Optimizing JOIN operations and subqueries +
+
+ 14:21:35 + [SUCCESS] Query performance improved by 75% +
+
+ 14:22:15 + [INFO] Updating query documentation +
+
+ 14:23:48 + [SUCCESS] Database optimization completed successfully +
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/page.html b/components/frontend/static-prototype/projects/sample-workspace/page.html new file mode 100644 index 000000000..af7c4813f --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/page.html @@ -0,0 +1,1059 @@ + + + + + + sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+
+ + +
+
+
+
+
+ + + +
+
+ + +
+ + +
+
+
+
+

Agentic Sessions

+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Session NameStatusModeModelCreated
+
+
implement-login-flow
+
Create user login and registration endpoints
+
+
Runninginteractiveclaude-3.5-sonnet4 hours ago
+
+
setup-database
+
Initialize PostgreSQL database with user tables
+
+
Completedheadlessclaude-3.5-sonnet1 day ago
+
+
create-api-tests
+
Write comprehensive API tests for authentication endpoints
+
+
Completedinteractiveclaude-3.5-sonnet30 minutes ago
+
+
optimize-queries
+
Optimize database queries for better performance
+
+
Completedheadlessclaude-3.5-sonnet2 hours ago
+
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html b/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html new file mode 100644 index 000000000..b6c91c929 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html @@ -0,0 +1,318 @@ + + + + + + Permissions - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+
+
+

Sharing

+

Users and groups with access to this project and their roles

+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Users/GroupsTypeRoleActions
+
+
john.doe@company.com
+
Project Owner
+
+
UserAdmin + +
+
+
development-team
+
5 members
+
+
GroupView + +
+
+
sarah.admin@company.com
+
Senior Developer
+
+
UserAdmin + +
+
+
qa-team
+
3 members
+
+
GroupView + +
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html b/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html new file mode 100644 index 000000000..81987f1d4 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html @@ -0,0 +1,262 @@ + + + + + + RFE Workspaces - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+
+

User Authentication System

+ Planning +
+
+

Implement secure user authentication with JWT tokens and role-based access control.

+
+ Repository: github.com/company/auth-service +
+
+ Branch: feature/user-auth +
+
+ Created: 2 hours ago +
+
+ + +
+
+
+ +
+
+

API Gateway

+ In Progress +
+
+

Central API gateway for microservices with rate limiting and request routing.

+
+ Repository: github.com/company/api-gateway +
+
+ Branch: feature/gateway-v2 +
+
+ Created: 1 day ago +
+
+ + +
+
+
+ +
+
+

Database Migration Tool

+ Completed +
+
+

Automated database migration and versioning system for production deployments.

+
+ Repository: github.com/company/db-migrator +
+
+ Branch: main +
+
+ Created: 3 days ago +
+
+ + +
+
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html b/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html new file mode 100644 index 000000000..9edf4e635 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html @@ -0,0 +1,385 @@ + + + + + + session-1 (Headless) - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+ +
+
+
+

Session Configuration

+
+
+
+ Task: Create user authentication system +
+
+ Model: claude-3.5-sonnet +
+
+ Mode: Headless +
+
+ Timeout: 30 minutes +
+
+ Status: + + + + + Running + +
+
+
+ +
+
+

Progress

+
+
+
+
+ Overall Progress + 65% +
+
+
+
+
+
+
✓ Repository cloned
+
✓ Dependencies installed
+
⏳ Creating authentication models
+
⏸️ Writing tests
+
⏸️ Documentation update
+
+
+
+
+ +
+
+
+

Execution Log

+ +
+
+
+
+
+ 13:45:23 + [INFO] Session started with task: Create user authentication system +
+
+ 13:45:24 + [INFO] Cloning repository from https://github.com/company/auth-service.git +
+
+ 13:45:28 + [SUCCESS] Repository cloned successfully +
+
+ 13:45:29 + [INFO] Installing dependencies... +
+
+ 13:46:15 + [SUCCESS] Dependencies installed successfully +
+
+ 13:46:16 + [INFO] Analyzing existing codebase structure +
+
+ 13:46:22 + [INFO] Creating User model with authentication fields +
+
+ 13:46:35 + [WORKING] Implementing password hashing and validation... +
+
+ 13:46:42 + [INFO] Adding JWT token generation methods +
+
+ 13:47:01 + [INFO] Creating authentication middleware +
+
+
+
+ +
+
+

Session Actions

+
+
+
+ + + +
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html b/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html new file mode 100644 index 000000000..53100742f --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html @@ -0,0 +1,2692 @@ + + + + + + session-1 - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ +
+ +
+ +
+
+
+ + +
+ + +
+
Workflows provide a structured processes for Ambient Code Platform agents to follow and achieve complex goals.
+
+ + + + + + +
+
+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ + +
+
+
+
ACP
+
+
ACP
+
+
+
+
+ +
+ + + + + + + + +
+
+
+
+ + + + + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html b/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html new file mode 100644 index 000000000..cf2dc0034 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html @@ -0,0 +1,273 @@ + + + + + + Sessions - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+

Agentic Sessions

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Session NameStatusModelStartedDurationActions
+
+
implement-login-flow
+
Create user login and registration endpoints
+
+
Completedclaude-3.5-sonnet4 hours ago23 minutes + +
+
+
setup-database
+
Initialize PostgreSQL database with user tables
+
+
Failedclaude-3.5-sonnet1 day ago12 minutes + +
+
+
create-api-tests
+
Write comprehensive API tests for authentication endpoints
+
+
Runningclaude-3.5-sonnet30 minutes ago30 minutes + +
+
+
optimize-queries
+
Optimize database queries for better performance
+
+
Pendingclaude-3.5-sonnet-- + +
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/settings/page.html b/components/frontend/static-prototype/projects/sample-workspace/settings/page.html new file mode 100644 index 000000000..5f2af9c13 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/settings/page.html @@ -0,0 +1,340 @@ + + + + + + Settings - sample-workspace - Ambient Code Platform + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+
+ + +
+
+
+

General Settings

+

Basic project configuration

+
+
+
+
+ + + Project name cannot be changed after creation +
+
+ + +
+
+ + +
+ +
+
+
+ +
+
+

Runner Secrets

+

Configure the Secret and manage key/value pairs used by project runners.

+
+
+
+
+ + +
+ +
+ + + Required for running agentic sessions +
+ +
+
+

Additional Secrets

+ +
+ +
+
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+ +
+
+
+ + +
+
+
+ +
+
+

Resource Limits

+

Configure resource limits for sessions and workspaces

+
+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ +
+
+

Danger Zone

+

Irreversible and destructive actions

+
+
+
+
+
Archive Project
+
Archive this project to make it read-only
+
+ +
+
+
+
Delete Project
+
Permanently delete this project and all its data
+
+ +
+
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html b/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html new file mode 100644 index 000000000..25f775a06 --- /dev/null +++ b/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html @@ -0,0 +1,307 @@ + + + + + + setup-database - sample-workspace - Ambient Code Platform + + + + +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + +
+ +
+
+
+

Session Configuration

+
+
+
+ Task: Initialize PostgreSQL database with user tables +
+
+ Model: claude-3.5-sonnet +
+
+ Mode: Headless +
+
+ Duration: 12 minutes +
+
+ Status: + + + + + Completed + +
+
+
+ +
+
+

Results Summary

+
+
+
+
+ Overall Progress + 100% +
+
+
+
+
+
+
✓ Database schema created
+
✓ User table with constraints
+
✓ Password hashing implemented
+
✓ Migration scripts generated
+
✓ Initial data seeded
+
+
+
+
+ +
+
+
+

Execution Log

+ +
+
+
+
+
+ 12:30:15 + [INFO] Session started: Initialize PostgreSQL database with user tables +
+
+ 12:30:16 + [INFO] Analyzing existing database structure +
+
+ 12:30:22 + [INFO] Creating users table schema +
+
+ 12:31:05 + [SUCCESS] Users table created with proper constraints +
+
+ 12:31:08 + [INFO] Adding password hashing utilities +
+
+ 12:31:45 + [SUCCESS] Password hashing implemented with bcrypt +
+
+ 12:32:12 + [INFO] Creating database migration scripts +
+
+ 12:33:01 + [SUCCESS] Migration scripts generated +
+
+ 12:33:15 + [INFO] Seeding initial user data +
+
+ 12:33:28 + [SUCCESS] Database initialization completed successfully +
+
+
+
+
+ + + + diff --git a/components/frontend/static-prototype/rfe.md b/components/frontend/static-prototype/rfe.md new file mode 100644 index 000000000..387d4720f --- /dev/null +++ b/components/frontend/static-prototype/rfe.md @@ -0,0 +1,1092 @@ +# RFE: Visual Redesign of Red Hat OpenShift AI (RHOAI) 3.0 Dashboard + +## Executive Summary + +This Request for Enhancement (RFE) proposes three distinct visual redesign directions for the Red Hat OpenShift AI (RHOAI) 3.0 dashboard to address the core challenge faced by AI Platform Engineers like Paula: **efficiently finding and evaluating production-ready AI models among thousands of options**. + +The current dashboard, while functional, presents a traditional enterprise interface that doesn't leverage modern AI-centric design patterns or optimize for the unique workflows of AI practitioners. This redesign focuses on transforming the user experience from a data-heavy administrative interface to an intelligent, task-oriented platform that accelerates model discovery and deployment decisions. + +## Current State Analysis + +### Existing Architecture +- **Framework**: React with TypeScript, PatternFly React components +- **Navigation**: Traditional sidebar navigation with hierarchical structure +- **Layout**: Standard enterprise dashboard with card-based model catalog +- **Feature Management**: Comprehensive feature flag system supporting MVP mode vs full feature set +- **Components**: Heavy use of PatternFly components (Cards, Tables, Forms, Modals, Dropdowns) + +### Current User Journey Pain Points +1. **Cognitive Overload**: Thousands of models presented in basic card/table format +2. **Inefficient Filtering**: Multiple separate filter interfaces without visual feedback +3. **Limited Comparison**: No side-by-side model comparison capabilities +4. **Static Information**: Performance metrics buried in text rather than visual indicators +5. **Context Switching**: Frequent navigation between catalog, registry, and deployment sections + +### Technical Foundation +- **PatternFly Integration**: Extensive use of existing components provides solid accessibility foundation +- **Feature Flags**: Robust system for MVP/full feature mode switching +- **State Management**: Context API for global state, component-level state for UI interactions +- **Routing**: React Router with dynamic route generation based on feature flags + +## User Persona: Paula - AI Platform Engineer + +**Primary Goal**: Find production-ready AI models that balance performance, cost, and specific use case requirements + +**Key Workflows**: +1. **Model Discovery**: Search through thousands of models using multiple criteria +2. **Performance Evaluation**: Compare latency, throughput, accuracy, and resource requirements +3. **Compatibility Assessment**: Verify model compatibility with existing infrastructure +4. **Deployment Planning**: Understand deployment requirements and costs +5. **Monitoring Setup**: Configure monitoring and alerting for deployed models + +**Success Metrics**: +- Time to find relevant models reduced by 60% +- Improved task completion rates for model selection workflows +- Reduced cognitive load when comparing multiple models +- Increased user satisfaction with filtering and search capabilities + +--- + +# Design Direction 1: "AI-First Visual Intelligence" + +## Philosophy +Treat AI models as visual, interactive objects rather than data rows. Transform the dashboard into an intelligent visual workspace where data visualization, interactive filtering, and AI-powered recommendations create an intuitive model discovery experience. + +## User Journey: Paula's Model Discovery Workflow + +### 1. Landing Experience +Paula arrives at a **Visual Model Universe** - a dynamic, interactive visualization showing all available models as nodes in a network graph, clustered by use case, provider, and performance characteristics. + +### 2. Intelligent Filtering +She uses **Visual Filter Sliders** to narrow down options: +- Latency requirement: Drag slider to <100ms +- Cost threshold: Visual budget indicator shows real-time cost implications +- Hardware compatibility: Interactive hardware requirement visualization + +### 3. AI-Powered Recommendations +The **Recommendation Engine** surfaces relevant models based on her query: "Customer service chatbot, production-ready, <100ms latency" with confidence scores and reasoning. + +### 4. Visual Comparison +Paula selects 3-4 models for **Side-by-Side Visual Comparison** with interactive performance charts, compatibility matrices, and deployment requirement visualizations. + +### 5. Workflow Integration +She connects her selected model to MCP servers and agents using the **Visual Workflow Builder** - a drag-and-drop interface showing data flow and dependencies. + +## Key UI Components + +### 1. Visual Model Universe +``` +┌─────────────────────────────────────────────────────────┐ +│ ○ Interactive Network Graph │ +│ ├── Nodes: Models (size = popularity, color = type) │ +│ ├── Clusters: Auto-grouped by ML similarity │ +│ ├── Zoom/Pan: Smooth navigation with mini-map │ +│ └── Search Overlay: Highlights matching nodes │ +└─────────────────────────────────────────────────────────┘ +``` + +### 2. Smart Filter Panel +``` +┌─────────────────────────────────────────────────────────┐ +│ 🎛️ Visual Performance Sliders │ +│ ├── Latency: [====●----] <100ms (23 models) │ +│ ├── Accuracy: [======●--] >95% (45 models) │ +│ ├── Cost/Hour: [$●--------] <$2.50 (67 models) │ +│ └── Hardware: [GPU Memory Visualization] │ +│ │ +│ 🎯 Use Case Tags (Visual Bubbles) │ +│ ├── [NLP] [Computer Vision] [Code Generation] │ +│ └── [Multimodal] [Reasoning] [Translation] │ +│ │ +│ 🤖 AI Recommendations │ +│ ├── "Based on your criteria, try granite-7b-code" │ +│ └── Confidence: ████████░░ 85% │ +└─────────────────────────────────────────────────────────┘ +``` + +### 3. Enhanced Model Cards +``` +┌─────────────────────────────────────────────────────────┐ +│ 📊 granite-7b-code:1.1 [⭐ 4.8/5] │ +│ ├── Performance Radar Chart │ +│ │ ├── Speed: ████████░░ │ +│ │ ├── Accuracy: ██████░░░░ │ +│ │ └── Efficiency: ████████░░ │ +│ ├── Compatibility Badges │ +│ │ ├── ✅ CUDA 12.0 ✅ 16GB RAM ⚠️ Requires A100 │ +│ ├── Live Deployment Status │ +│ │ └── 🟢 23 active deployments, avg 45ms latency │ +│ └── Quick Actions: [Compare] [Deploy] [Details] │ +└─────────────────────────────────────────────────────────┘ +``` + +### 4. Multi-Model Comparison View +``` +┌─────────────────────────────────────────────────────────┐ +│ 📈 Performance Comparison (3 models selected) │ +│ ├── Overlay Chart: Latency vs Accuracy │ +│ │ ├── Model A: ● (45ms, 94%) │ +│ │ ├── Model B: ● (78ms, 97%) │ +│ │ └── Model C: ● (23ms, 89%) │ +│ ├── Specification Matrix │ +│ │ ├──────────────┬─────────┬─────────┬─────────┐ │ +│ │ │ Metric │ Model A │ Model B │ Model C │ │ +│ │ ├──────────────┼─────────┼─────────┼─────────┤ │ +│ │ │ Parameters │ 7B │ 13B │ 3B │ │ +│ │ │ Memory │ 16GB │ 32GB │ 8GB │ │ +│ │ │ Cost/Hour │ $2.40 │ $4.80 │ $1.20 │ │ +│ │ └──────────────┴─────────┴─────────┴─────────┘ │ +│ └── Recommendation: Model C best for your use case │ +└─────────────────────────────────────────────────────────┘ +``` + +### 5. Visual Workflow Builder +``` +┌─────────────────────────────────────────────────────────┐ +│ 🔄 AI Workflow Designer │ +│ ├── [Model] ──→ [MCP Server] ──→ [Agent] ──→ [Output] │ +│ │ │ │ │ │ │ +│ │ granite-7b GitHub MCP Customer Response │ +│ │ Service │ +│ ├── Drag & Drop Components │ +│ ├── Real-time Validation │ +│ └── Performance Prediction: ~67ms end-to-end │ +└─────────────────────────────────────────────────────────┘ +``` + +## Information Architecture + +``` +RHOAI Dashboard (AI-First Visual Intelligence) +├── Visual Model Universe (landing page) +│ ├── Interactive Network Graph (main visualization) +│ ├── Smart Filter Panel (left sidebar) +│ │ ├── Visual Performance Sliders +│ │ ├── Use Case Tag Cloud +│ │ └── AI Recommendation Engine +│ ├── Model Detail Overlay (contextual) +│ └── Quick Action Toolbar (bottom) +├── Comparison Workspace +│ ├── Multi-Model Performance Charts +│ ├── Specification Matrix +│ └── Deployment Cost Calculator +├── Workflow Builder +│ ├── Visual Pipeline Designer +│ ├── Component Library +│ └── Performance Simulator +└── Deployment Dashboard + ├── Live Status Visualization + ├── Performance Monitoring Charts + └── Alert Management +``` + +## Visual Design Language + +### Color Palette +- **Primary**: Deep Blue (#0066CC) - Trust, intelligence +- **Secondary**: Vibrant Teal (#17A2B8) - Innovation, technology +- **Accent**: Warm Orange (#FF6B35) - Energy, action +- **Success**: Green (#28A745) - Deployed, healthy +- **Warning**: Amber (#FFC107) - Attention needed +- **Error**: Red (#DC3545) - Critical issues +- **Neutral**: Grays (#F8F9FA to #343A40) - Background, text + +### Typography +- **Headers**: Red Hat Display (Bold, 24-32px) +- **Body**: Red Hat Text (Regular, 14-16px) +- **Code/Metrics**: Red Hat Mono (Regular, 12-14px) +- **Emphasis**: Red Hat Text (Medium, 16-18px) + +### Spacing & Layout +- **Grid**: 8px base unit, 24px component spacing +- **Cards**: 16px padding, 8px border radius, subtle shadows +- **Interactive Elements**: 44px minimum touch target +- **Whitespace**: Generous spacing for visual breathing room + +### Animation & Interaction +- **Micro-interactions**: 200ms ease-in-out transitions +- **Loading States**: Skeleton screens with shimmer effects +- **Hover States**: Subtle elevation and color changes +- **Focus States**: High-contrast outlines for accessibility + +## Technical Considerations + +### PatternFly Integration (80% Reuse Target) +- **Reuse**: Card, Button, Form, Select, Modal, Tooltip, Progress, Label +- **Extend**: Custom chart components using Recharts with PatternFly theming +- **New Components**: + - `ModelUniverseGraph` (D3.js-based network visualization) + - `VisualFilterPanel` (Custom sliders with real-time feedback) + - `ModelComparisonMatrix` (Interactive specification table) + - `WorkflowBuilder` (Drag-and-drop pipeline designer) + - `PerformanceRadarChart` (Model capability visualization) + +### React Architecture +``` +src/ +├── components/ +│ ├── ai-hub/ +│ │ ├── ModelUniverse/ +│ │ │ ├── NetworkGraph.tsx +│ │ │ ├── FilterPanel.tsx +│ │ │ └── ModelCard.tsx +│ │ ├── Comparison/ +│ │ │ ├── ComparisonView.tsx +│ │ │ └── PerformanceChart.tsx +│ │ └── Workflow/ +│ │ ├── WorkflowBuilder.tsx +│ │ └── ComponentLibrary.tsx +│ └── shared/ +│ ├── Charts/ +│ └── Visualizations/ +├── hooks/ +│ ├── useModelRecommendations.ts +│ ├── useVisualFilters.ts +│ └── useWorkflowValidation.ts +└── utils/ + ├── chartHelpers.ts + └── performanceCalculations.ts +``` + +### Performance Optimizations +- **Virtual Scrolling**: React-window for large model lists (5,000+ items) +- **Lazy Loading**: Code splitting for heavy visualization components +- **Memoization**: React.memo for expensive chart re-renders +- **Debouncing**: 300ms debounce for filter inputs +- **Caching**: React Query with 5-minute cache for model data + +### Data Management +- **GraphQL API**: Flexible queries for model metadata and performance metrics +- **Real-time Updates**: WebSocket connections for live deployment status +- **Optimistic Updates**: Immediate UI feedback for user actions +- **Progressive Loading**: Initial 50 models, infinite scroll for more + +## Accessibility Features + +### Keyboard Navigation +- **Tab Order**: Filter panel → Model cards → Action buttons → Comparison view +- **Shortcuts**: + - `/` to focus search + - `Cmd+K` for command palette + - `Escape` to close modals/overlays + - Arrow keys for graph navigation + +### Screen Reader Support +- **ARIA Labels**: Comprehensive labeling for all interactive elements +- **Live Regions**: Announce filter results and recommendations +- **Alternative Text**: Detailed descriptions for all charts and visualizations +- **Data Tables**: Accessible alternatives for all visual comparisons + +### Visual Accessibility +- **High Contrast**: WCAG AA compliant color ratios (4.5:1 minimum) +- **Focus Indicators**: 2px high-contrast outlines +- **Text Scaling**: Support up to 200% zoom without horizontal scrolling +- **Motion Reduction**: Respect `prefers-reduced-motion` settings + +## Mobile/Responsive Design + +### Breakpoints +- **Mobile**: 320px - 767px (Stacked layout, touch-optimized) +- **Tablet**: 768px - 1023px (Hybrid layout, collapsible panels) +- **Desktop**: 1024px+ (Full layout, multi-panel views) + +### Mobile Adaptations +- **Navigation**: Collapsible hamburger menu +- **Filters**: Bottom sheet modal for filter panel +- **Cards**: Full-width stacked layout +- **Comparison**: Swipeable carousel for model comparison +- **Touch Targets**: Minimum 44px for all interactive elements + +## Performance Impact Assessment + +### Rendering Optimizations +- **Canvas Rendering**: Use HTML5 Canvas for network graphs with >1000 nodes +- **WebGL**: Hardware acceleration for complex visualizations +- **Virtual DOM**: Minimize re-renders with React.memo and useMemo +- **Intersection Observer**: Lazy load off-screen model cards + +### Bundle Size Impact +- **Estimated Addition**: +150KB gzipped for visualization libraries +- **Code Splitting**: Lazy load heavy components (WorkflowBuilder, NetworkGraph) +- **Tree Shaking**: Import only used chart components +- **CDN Assets**: Serve large datasets from CDN with compression + +### Memory Management +- **Cleanup**: Proper cleanup of D3.js event listeners and timers +- **Garbage Collection**: Avoid memory leaks in long-running visualizations +- **Data Pagination**: Limit in-memory model data to 500 items max + +--- + +# Design Direction 2: "Enterprise Command Center" + +## Philosophy +Transform the dashboard into a mission-critical control center optimized for power users who need dense information display, advanced filtering capabilities, and efficient bulk operations. Emphasize data density, customization, and keyboard-driven workflows. + +## User Journey: Paula's Power User Workflow + +### 1. Customizable Dashboard Landing +Paula arrives at her **Personalized Command Center** with customizable widgets showing her most relevant data: recent deployments, model performance alerts, and saved filter sets. + +### 2. Advanced Search & Filtering +She uses the **Command Palette** (Cmd+K) to quickly execute complex queries: "Show GPU models under $3/hour with >95% accuracy deployed in last 30 days" + +### 3. Bulk Operations +Paula selects multiple models using **Batch Selection** and performs bulk actions: compare specifications, export data, or queue for deployment testing. + +### 4. Real-time Monitoring +The **Live Monitoring Dashboard** shows real-time metrics for all deployed models with customizable alerts and drill-down capabilities. + +### 5. Efficient Navigation +She navigates using **Keyboard Shortcuts** and **Breadcrumb Navigation** without touching the mouse, maintaining focus on critical tasks. + +## Key UI Components + +### 1. Customizable Dashboard Widgets +``` +┌─────────────────────────────────────────────────────────┐ +│ 📊 Command Center Dashboard (Drag & Drop Layout) │ +│ ├─────────────────┬─────────────────┬─────────────────┤ │ +│ │ 🎯 Quick Filters │ 📈 Performance │ 🚨 Alerts │ │ +│ │ ├─ Production │ │ ┌─ Latency ──┐ │ │ ⚠️ Model A │ │ +│ │ ├─ <100ms │ │ │ ████████░░ │ │ │ High CPU │ │ +│ │ ├─ GPU Ready │ │ └─ Accuracy ─┘ │ │ 🔴 Model B │ │ +│ │ └─ [23 models] │ │ │ │ Offline │ │ +│ ├─────────────────┼─────────────────┼─────────────────┤ │ +│ │ 📋 Recent Models│ 💰 Cost Monitor │ 🔧 Quick Actions│ │ +│ │ ├─ granite-7b │ │ This Month: │ │ ├─ Deploy │ │ +│ │ ├─ llama-3.1 │ │ $2,847 / $5K │ │ ├─ Compare │ │ +│ │ └─ mistral-7b │ │ ████████░░░░░ │ │ └─ Export │ │ +│ └─────────────────┴─────────────────┴─────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +### 2. Advanced Command Palette +``` +┌─────────────────────────────────────────────────────────┐ +│ 🔍 Command Palette (Cmd+K) │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ > deploy granite-7b to production │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ 📋 Suggestions: │ +│ ├── 🚀 Deploy model to production Cmd+D │ +│ ├── 📊 Compare selected models Cmd+C │ +│ ├── 📁 Export model specifications Cmd+E │ +│ ├── 🔍 Filter by latency <100ms /lat<100 │ +│ ├── 📈 Show performance dashboard Cmd+P │ +│ └── ⚙️ Open model settings Cmd+, │ +│ │ +│ 🕐 Recent Actions: │ +│ ├── Deployed llama-3.1-8b (2 min ago) │ +│ └── Compared 3 models (5 min ago) │ +└─────────────────────────────────────────────────────────┘ +``` + +### 3. Dense Information Table +``` +┌─────────────────────────────────────────────────────────┐ +│ 📋 Model Registry (Advanced Table View) │ +│ ├── 🔍 [Search] 🎛️ [Filters] 📊 [Columns] 💾 [Save] │ +│ ├─────┬──────────────┬─────────┬─────────┬─────────────┤ +│ │ ☐ │ Model Name │ Latency │ Accuracy│ Status │ +│ ├─────┼──────────────┼─────────┼─────────┼─────────────┤ +│ │ ☑ │ granite-7b │ 45ms ⚡ │ 94% ✅ │ 🟢 Active │ +│ │ ☑ │ llama-3.1-8b │ 67ms │ 96% ✅ │ 🟡 Warning │ +│ │ ☐ │ mistral-7b │ 23ms ⚡ │ 89% │ 🟢 Active │ +│ │ ☐ │ gpt-oss-120b │ 156ms │ 97% ✅ │ 🔴 Error │ +│ ├─────┴──────────────┴─────────┴─────────┴─────────────┤ +│ │ 📊 Bulk Actions: [Compare] [Deploy] [Export] [Delete]│ +│ │ 📈 Selected: 2 models | Total: 1,247 models │ +│ └─────────────────────────────────────────────────────┘ +└─────────────────────────────────────────────────────────┘ +``` + +### 4. Multi-Panel Comparison View +``` +┌─────────────────────────────────────────────────────────┐ +│ 📊 Split-Screen Comparison (2/3/4 panel layout) │ +│ ├─────────────────────┬─────────────────────────────────┤ +│ │ 🏷️ granite-7b-code │ 🏷️ llama-3.1-8b-instruct │ +│ │ ├─ Latency: 45ms │ ├─ Latency: 67ms │ +│ │ ├─ Accuracy: 94% │ ├─ Accuracy: 96% │ +│ │ ├─ Memory: 16GB │ ├─ Memory: 24GB │ +│ │ ├─ Cost: $2.40/hr │ ├─ Cost: $3.60/hr │ +│ │ └─ GPU: A100 │ └─ GPU: A100/H100 │ +│ ├─────────────────────┼─────────────────────────────────┤ +│ │ 📈 Performance Chart│ 📈 Performance Chart │ +│ │ ┌─ Latency Trend ─┐ │ ┌─ Latency Trend ─────────────┐│ +│ │ │ ████████████░░░ │ │ │ ████████░░░░░░░░░░░░░░░░░░░ ││ +│ │ └─ Last 24h ──────┘ │ └─ Last 24h ──────────────────┘│ +│ └─────────────────────┴─────────────────────────────────┤ +│ 🔄 Sync Scroll: ☑ | Export: [PDF] [CSV] | Add Panel: +│ +└─────────────────────────────────────────────────────────┘ +``` + +### 5. Real-Time Monitoring Dashboard +``` +┌─────────────────────────────────────────────────────────┐ +│ 🖥️ Live Deployment Monitor │ +│ ├─────────────────────┬─────────────────────────────────┤ +│ │ 🎯 Status Overview │ 📊 Performance Metrics │ +│ │ ├─ 🟢 Healthy: 23 │ ├─ Avg Latency: 67ms │ +│ │ ├─ 🟡 Warning: 3 │ ├─ Throughput: 1.2K req/s │ +│ │ ├─ 🔴 Critical: 1 │ ├─ Error Rate: 0.02% │ +│ │ └─ 🔵 Total: 27 │ └─ SLA Compliance: 99.8% │ +│ ├─────────────────────┴─────────────────────────────────┤ +│ │ 🚨 Active Alerts │ +│ │ ├─ ⚠️ granite-7b: High CPU usage (85%) │ +│ │ ├─ 🔴 llama-3.1: Connection timeout (3 failures) │ +│ │ └─ 🟡 mistral-7b: Memory usage above threshold │ +│ ├─────────────────────────────────────────────────────┤ +│ │ 📈 Historical Performance (Zoomable Timeline) │ +│ │ ┌─ Response Time ─────────────────────────────────────┐│ +│ │ │ ╭─╮ ││ +│ │ │ ╭───╯ ╰─╮ ╭─╮ ││ +│ │ │ ╯ ╰─────╯ ╰─╮ ││ +│ │ │ ╰──────────────────────────────││ +│ │ └─ 1h 6h 12h 24h 7d ──────────────────────┘│ +└─────────────────────────────────────────────────────────┘ +``` + +## Information Architecture + +``` +RHOAI Dashboard (Enterprise Command Center) +├── Customizable Dashboard (landing page) +│ ├── Widget Grid (main content - drag-and-drop) +│ │ ├── Model List Widget (configured queries) +│ │ ├── Performance Charts Widget (selected models) +│ │ ├── Deployment Status Widget (live monitoring) +│ │ ├── Cost Monitor Widget (budget tracking) +│ │ └── Quick Filters Widget (saved filter sets) +│ ├── Top Toolbar +│ │ ├── Command Palette (Cmd+K) +│ │ ├── Search Bar (/ to focus) +│ │ ├── Layout Selector (saved layouts dropdown) +│ │ └── Settings (dashboard configuration) +│ └── Status Bar (bottom) +│ ├── System Status +│ ├── Active Filters Count +│ └── Keyboard Shortcuts Help +├── Advanced Model Catalog +│ ├── Dense Table View (default) +│ │ ├── Sortable/Filterable Columns +│ │ ├── Bulk Selection & Actions +│ │ └── Inline Quick Actions +│ ├── Saved Queries Sidebar +│ │ ├── Predefined Filters +│ │ ├── Custom Query Builder +│ │ └── Recent Searches +│ └── Export & Reporting +│ ├── CSV/Excel Export +│ ├── PDF Reports +│ └── Scheduled Reports +├── Multi-Panel Comparison +│ ├── Split-Screen Layout (2/3/4 panels) +│ ├── Synchronized Navigation +│ ├── Diff Highlighting +│ └── Export Comparison Reports +└── Live Monitoring Center + ├── Real-time Metrics Dashboard + ├── Alert Management System + ├── Historical Performance Analytics + └── SLA Monitoring & Reporting +``` + +## Visual Design Language + +### Color Palette (Professional/High-Contrast) +- **Primary**: Navy Blue (#1F2937) - Authority, reliability +- **Secondary**: Steel Blue (#374151) - Professional, technical +- **Accent**: Electric Blue (#3B82F6) - Action, focus +- **Success**: Forest Green (#059669) - Healthy, operational +- **Warning**: Amber (#D97706) - Attention, caution +- **Error**: Crimson (#DC2626) - Critical, urgent +- **Neutral**: Cool Grays (#F9FAFB to #111827) - Background hierarchy + +### Typography (Information Dense) +- **Headers**: Red Hat Display (Bold, 18-24px) - Compact hierarchy +- **Body**: Red Hat Text (Regular, 13-14px) - Dense readability +- **Code/Data**: Red Hat Mono (Regular, 11-12px) - Technical precision +- **Labels**: Red Hat Text (Medium, 12-13px) - Clear identification + +### Layout Principles +- **Information Density**: Maximize data per screen real estate +- **Scannable Hierarchy**: Clear visual hierarchy for rapid scanning +- **Consistent Spacing**: 4px/8px grid for tight, organized layout +- **Functional Grouping**: Related data clustered with subtle borders + +### Interaction Patterns +- **Keyboard-First**: All actions accessible via keyboard shortcuts +- **Hover Details**: Rich tooltips with additional context +- **Contextual Menus**: Right-click menus for power user actions +- **Bulk Operations**: Multi-select with batch action capabilities + +## Technical Considerations + +### PatternFly Integration (85% Reuse Target) +- **Heavy Reuse**: Table, Toolbar, Dropdown, Modal, Form, Button, Card +- **Enhanced Components**: + - `AdvancedTable` (sortable, filterable, bulk selection) + - `CommandPalette` (fuzzy search, keyboard navigation) + - `DashboardWidget` (drag-and-drop, resizable) + - `MultiPanelLayout` (split-screen comparison) + - `MonitoringChart` (real-time data visualization) + +### React Architecture +``` +src/ +├── components/ +│ ├── command-center/ +│ │ ├── Dashboard/ +│ │ │ ├── DashboardGrid.tsx +│ │ │ ├── Widget.tsx +│ │ │ └── WidgetLibrary.tsx +│ │ ├── CommandPalette/ +│ │ │ ├── CommandPalette.tsx +│ │ │ └── CommandRegistry.ts +│ │ ├── AdvancedTable/ +│ │ │ ├── DataTable.tsx +│ │ │ ├── BulkActions.tsx +│ │ │ └── ColumnManager.tsx +│ │ └── Monitoring/ +│ │ ├── MetricsDashboard.tsx +│ │ ├── AlertManager.tsx +│ │ └── PerformanceChart.tsx +│ └── shared/ +│ ├── KeyboardShortcuts/ +│ └── ExportManager/ +├── hooks/ +│ ├── useKeyboardShortcuts.ts +│ ├── useBulkOperations.ts +│ ├── useRealTimeMetrics.ts +│ └── useDashboardLayout.ts +└── utils/ + ├── commandRegistry.ts + ├── exportHelpers.ts + └── keyboardNavigation.ts +``` + +### Performance Optimizations +- **Virtual Scrolling**: Handle tables with 10,000+ rows efficiently +- **Memoized Calculations**: Cache expensive sorting/filtering operations +- **Debounced Updates**: 150ms debounce for real-time search +- **Lazy Widget Loading**: Load dashboard widgets on demand +- **Efficient Re-renders**: Minimize table re-renders with React.memo + +### Data Management +- **Real-time WebSockets**: Live metrics and alert updates +- **Optimistic UI**: Immediate feedback for bulk operations +- **Background Sync**: Periodic data refresh without UI interruption +- **Offline Capability**: Cache critical data for offline viewing + +## Accessibility Features + +### Keyboard Navigation Excellence +- **Tab Order**: Logical flow through dense interface elements +- **Shortcuts**: Comprehensive keyboard shortcuts for all actions + - `Cmd+K`: Command palette + - `Cmd+F`: Advanced search + - `Cmd+A`: Select all in current view + - `Space`: Toggle selection + - `Enter`: Execute primary action + - `Escape`: Cancel/close current operation + +### Screen Reader Optimization +- **Table Navigation**: Proper table headers and navigation +- **Live Regions**: Announce real-time updates and alerts +- **Descriptive Labels**: Detailed ARIA labels for complex widgets +- **Status Announcements**: Clear feedback for bulk operations + +### Visual Accessibility +- **High Contrast Mode**: Enhanced contrast ratios (7:1 for text) +- **Focus Management**: Clear focus indicators throughout interface +- **Text Scaling**: Support 200% zoom with horizontal scrolling +- **Color Independence**: Information conveyed beyond color alone + +## Mobile/Responsive Design + +### Responsive Strategy +- **Desktop-First**: Optimized for desktop power users +- **Tablet Adaptation**: Collapsible panels, touch-friendly controls +- **Mobile Fallback**: Essential functions only, simplified interface + +### Mobile Adaptations +- **Navigation**: Collapsible command center with essential widgets +- **Tables**: Horizontal scroll with sticky columns +- **Comparison**: Stacked layout with swipe navigation +- **Monitoring**: Simplified metric cards with drill-down + +## Performance Impact Assessment + +### Rendering Performance +- **Table Virtualization**: Handle large datasets without performance degradation +- **Chart Optimization**: Canvas rendering for real-time metrics +- **Memory Management**: Efficient cleanup of real-time subscriptions +- **Bundle Splitting**: Lazy load monitoring and comparison components + +### Data Processing +- **Client-side Filtering**: Fast filtering for large datasets +- **Incremental Updates**: Efficient real-time data updates +- **Background Processing**: Web Workers for heavy calculations +- **Caching Strategy**: Intelligent caching for frequently accessed data + +--- + +# Design Direction 3: "Conversational AI Assistant" + +## Philosophy +Transform the primary interface into a natural language conversation where an AI assistant helps users discover, evaluate, and deploy models through intelligent dialogue. Minimize traditional UI elements in favor of contextual, conversation-driven interactions. + +## User Journey: Paula's Conversational Workflow + +### 1. Natural Language Query +Paula starts with a conversational query: "I need a production-ready model for customer service chatbots that responds in under 100ms and costs less than $3 per hour" + +### 2. Intelligent Clarification +The AI assistant asks clarifying questions: "What type of customer inquiries will this handle? Do you need multilingual support? Any specific compliance requirements?" + +### 3. Smart Recommendations +Based on the conversation, the assistant presents 3-4 tailored recommendations with explanations: "Based on your requirements, I recommend granite-7b-code because it excels at structured responses with 45ms average latency..." + +### 4. Guided Comparison +Paula asks: "How does granite-7b compare to llama-3.1 for my use case?" The assistant provides a contextual comparison with visual aids. + +### 5. Deployment Assistance +The assistant guides through deployment: "I can help you deploy granite-7b. Would you like me to configure it for your customer service environment?" + +## Key UI Components + +### 1. Conversational Interface +``` +┌─────────────────────────────────────────────────────────┐ +│ 🤖 RHOAI Assistant 🎤 🔊 ⚙️ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 👤 I need a production model for customer service │ │ +│ │ chatbots under 100ms latency │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 🤖 I can help you find the perfect model! Let me │ │ +│ │ ask a few questions to narrow down the options: │ │ +│ │ │ │ +│ │ • What type of customer inquiries? (FAQ, tech │ │ +│ │ support, sales, etc.) │ │ +│ │ • Do you need multilingual support? │ │ +│ │ • Any specific compliance requirements? │ │ +│ │ │ │ +│ │ 💡 Quick suggestions: │ │ +│ │ [FAQ Support] [Tech Support] [Sales Inquiries] │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ Type your message... 🎤 │ │ +│ └─────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +### 2. Contextual Model Cards +``` +┌─────────────────────────────────────────────────────────┐ +│ 🤖 Based on your needs, here are my top 3 recommendations:│ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 🥇 granite-7b-code:1.1 [Deploy] │ │ +│ │ ├── ⚡ 45ms avg latency (✅ meets your <100ms req) │ │ +│ │ ├── 💰 $2.40/hour (✅ under your $3 budget) │ │ +│ │ ├── 🎯 94% accuracy on customer service tasks │ │ +│ │ ├── 🏆 Why I recommend this: Excellent balance of │ │ +│ │ │ speed and accuracy, proven in production │ │ +│ │ └── [Tell me more] [Compare with others] [Deploy] │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 🥈 llama-3.1-8b-instruct [Deploy] │ │ +│ │ ├── ⚡ 67ms avg latency (✅ meets requirement) │ │ +│ │ ├── 💰 $3.60/hour (⚠️ slightly over budget) │ │ +│ │ ├── 🎯 96% accuracy (higher than granite-7b) │ │ +│ │ └── 🏆 Why consider: Better accuracy, multilingual │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ 💬 Would you like me to explain why I ranked these │ +│ models this way, or shall we dive deeper into one? │ +└─────────────────────────────────────────────────────────┘ +``` + +### 3. Smart Comparison View +``` +┌─────────────────────────────────────────────────────────┐ +│ 👤 "How does granite-7b compare to llama-3.1?" │ +│ │ +│ 🤖 Great question! Here's how they stack up for your │ +│ customer service use case: │ +│ │ +│ ┌─────────────────────┬─────────────────────────────────┤ +│ │ 🏷️ granite-7b-code │ 🏷️ llama-3.1-8b-instruct │ +│ ├─────────────────────┼─────────────────────────────────┤ +│ │ ⚡ Speed: 45ms │ ⚡ Speed: 67ms │ +│ │ 🎯 Accuracy: 94% │ 🎯 Accuracy: 96% │ +│ │ 💰 Cost: $2.40/hr │ 💰 Cost: $3.60/hr │ +│ │ 🌍 Languages: EN │ 🌍 Languages: 50+ │ +│ │ 📊 Production: ✅ │ 📊 Production: ✅ │ +│ └─────────────────────┴─────────────────────────────────┘ +│ │ +│ 💡 My recommendation: If you only need English and want │ +│ to stay under budget, go with granite-7b. If you │ +│ might expand internationally or need the highest │ +│ accuracy, llama-3.1 is worth the extra cost. │ +│ │ +│ 🎯 Quick actions: │ +│ [Deploy granite-7b] [Deploy llama-3.1] [See more options]│ +└─────────────────────────────────────────────────────────┘ +``` + +### 4. Guided Deployment Wizard +``` +┌─────────────────────────────────────────────────────────┐ +│ 👤 "Let's deploy granite-7b for my customer service" │ +│ │ +│ 🤖 Perfect choice! I'll guide you through the setup. │ +│ I've pre-configured everything based on our │ +│ conversation: │ +│ │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 🚀 Deployment Configuration │ │ +│ │ ├── Model: granite-7b-code:1.1 │ │ +│ │ ├── Environment: Production │ │ +│ │ ├── Instance: A100 GPU (recommended for <100ms) │ │ +│ │ ├── Scaling: Auto-scale 1-5 instances │ │ +│ │ ├── Monitoring: Customer service metrics enabled │ │ +│ │ └── Budget Alert: $3/hour threshold │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ 💬 Everything look good? I can also: │ +│ • Set up A/B testing with llama-3.1 │ +│ • Configure custom monitoring for your KPIs │ +│ • Create alerts for latency spikes │ +│ │ +│ [Deploy Now] [Customize Settings] [Schedule Deployment] │ +└─────────────────────────────────────────────────────────┘ +``` + +### 5. Voice Interface Integration +``` +┌─────────────────────────────────────────────────────────┐ +│ 🎤 Voice Assistant Active 🔊 Speaking │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ 🌊 ████████████████████████████████████████████████ │ │ +│ │ "Show me models with latency under fifty │ │ +│ │ milliseconds for text generation" │ │ +│ └─────────────────────────────────────────────────────┘ │ +│ │ +│ 🤖 I found 12 models matching your criteria. The top │ +│ performers are granite-7b at 45ms, mistral-7b at │ +│ 23ms, and claude-3-haiku at 38ms. Would you like │ +│ me to show you the details or compare them? │ +│ │ +│ 🎯 Voice Commands: │ +│ • "Show details" - Display model specifications │ +│ • "Compare all three" - Side-by-side comparison │ +│ • "Deploy granite" - Start deployment process │ +│ • "Filter by cost" - Add cost filtering │ +│ │ +│ [🎤 Hold to Speak] [⌨️ Switch to Text] [🔇 Mute Voice] │ +└─────────────────────────────────────────────────────────┘ +``` + +### 6. Contextual Help & Learning +``` +┌─────────────────────────────────────────────────────────┐ +│ 🤖 I notice you often look for models under 100ms │ +│ latency. Here are some tips to help you find them │ +│ faster: │ +│ │ +│ 💡 Pro Tips: │ +│ • Use "fast models" as a shortcut for <100ms filter │ +│ • Try "production ready + fast" for pre-vetted options│ +│ • Ask "what's the fastest model for [use case]" │ +│ │ +│ 📚 Would you like me to: │ +│ • Create a saved search for your common criteria? │ +│ • Set up alerts for new fast models? │ +│ • Show you advanced filtering techniques? │ +│ │ +│ 🎯 Quick Actions: │ +│ [Create Saved Search] [Set Up Alerts] [Learn More] │ +│ │ +│ 💬 You can also say things like: │ +│ • "Find me something like granite-7b but faster" │ +│ • "What's new in the model catalog this week?" │ +│ • "Help me optimize costs for my current deployments" │ +└─────────────────────────────────────────────────────────┘ +``` + +## Information Architecture + +``` +RHOAI Dashboard (Conversational AI Assistant) +├── Main Conversation Interface +│ ├── Chat History (persistent, searchable) +│ ├── Message Input (text + voice) +│ ├── Quick Action Buttons (contextual) +│ └── Voice Controls (always available) +├── Contextual Overlays (triggered by conversation) +│ ├── Model Detail Cards +│ ├── Comparison Views +│ ├── Deployment Wizards +│ └── Performance Charts +├── Smart Suggestions Panel (adaptive) +│ ├── Conversation Starters +│ ├── Follow-up Questions +│ ├── Related Actions +│ └── Learning Resources +├── Traditional Fallback Navigation (collapsible) +│ ├── Model Catalog (simplified) +│ ├── Deployments (status only) +│ └── Settings (voice preferences) +└── Assistant Personality & Learning + ├── User Preference Learning + ├── Context Memory (session + long-term) + ├── Expertise Areas (model types, use cases) + └── Conversation History Analysis +``` + +## Visual Design Language + +### Color Palette (Conversational/Friendly) +- **Primary**: Warm Blue (#2563EB) - Trustworthy, intelligent +- **Secondary**: Soft Purple (#7C3AED) - Creative, innovative +- **Accent**: Vibrant Green (#10B981) - Positive, helpful +- **Assistant**: Cool Gray (#6B7280) - Neutral, professional +- **User**: Warm Gray (#374151) - Personal, human +- **Success**: Emerald (#059669) - Achievement, completion +- **Warning**: Amber (#F59E0B) - Caution, attention +- **Error**: Rose (#F43F5E) - Issues, problems + +### Typography (Conversational) +- **Headers**: Red Hat Display (Medium, 20-28px) - Friendly authority +- **Body/Chat**: Red Hat Text (Regular, 15-16px) - Readable conversation +- **Assistant**: Red Hat Text (Regular, 15px) - Consistent, clear +- **User**: Red Hat Text (Medium, 15px) - Slightly emphasized +- **Code/Data**: Red Hat Mono (Regular, 13-14px) - Technical precision + +### Layout Principles +- **Conversation Flow**: Chronological, chat-like interface +- **Contextual Density**: Information appears when relevant +- **Breathing Room**: Generous spacing for comfortable reading +- **Focus Management**: Single conversation thread with contextual overlays + +### Interaction Patterns +- **Natural Language**: Primary interaction through conversation +- **Voice Integration**: Seamless voice input and output +- **Contextual Actions**: Buttons appear based on conversation context +- **Progressive Disclosure**: Information revealed as needed + +## Technical Considerations + +### PatternFly Integration (60% Reuse Target) +- **Selective Reuse**: Card, Modal, Button, Form components for overlays +- **Custom Components**: + - `ConversationInterface` (chat-like message flow) + - `VoiceInput` (speech recognition integration) + - `ContextualOverlay` (smart information display) + - `SmartSuggestions` (AI-powered recommendations) + - `ConversationMemory` (context persistence) + +### React Architecture +``` +src/ +├── components/ +│ ├── conversation/ +│ │ ├── ChatInterface/ +│ │ │ ├── MessageThread.tsx +│ │ │ ├── MessageInput.tsx +│ │ │ └── VoiceControls.tsx +│ │ ├── Assistant/ +│ │ │ ├── AIResponse.tsx +│ │ │ ├── SmartSuggestions.tsx +│ │ │ └── ContextualCards.tsx +│ │ ├── Voice/ +│ │ │ ├── SpeechRecognition.tsx +│ │ │ ├── TextToSpeech.tsx +│ │ │ └── VoiceCommands.tsx +│ │ └── Overlays/ +│ │ ├── ModelDetails.tsx +│ │ ├── ComparisonView.tsx +│ │ └── DeploymentWizard.tsx +│ └── shared/ +│ ├── NaturalLanguage/ +│ └── ContextManager/ +├── hooks/ +│ ├── useConversation.ts +│ ├── useVoiceInterface.ts +│ ├── useAIAssistant.ts +│ └── useContextMemory.ts +├── services/ +│ ├── nlpService.ts +│ ├── voiceService.ts +│ ├── aiAssistant.ts +│ └── conversationMemory.ts +└── utils/ + ├── speechProcessing.ts + ├── contextAnalysis.ts + └── intentRecognition.ts +``` + +### AI/ML Integration +- **Natural Language Processing**: Intent recognition and entity extraction +- **Conversation Management**: Context tracking and memory +- **Voice Processing**: Speech-to-text and text-to-speech +- **Recommendation Engine**: ML-powered model suggestions +- **Learning System**: User preference adaptation + +### Performance Optimizations +- **Streaming Responses**: Real-time AI response generation +- **Voice Processing**: Local speech recognition when possible +- **Context Caching**: Efficient conversation memory management +- **Lazy Loading**: Load overlays and detailed views on demand +- **Offline Capability**: Basic conversation when network limited + +## Accessibility Features + +### Voice Interface Accessibility +- **Multiple Input Methods**: Voice, text, and traditional navigation +- **Voice Feedback**: Audio confirmation of actions +- **Speech Rate Control**: Adjustable speaking speed +- **Voice Commands**: Comprehensive voice control vocabulary + +### Screen Reader Excellence +- **Conversation Flow**: Proper reading order for chat interface +- **Live Regions**: Announce new messages and responses +- **Rich Descriptions**: Detailed descriptions of visual elements +- **Alternative Navigation**: Traditional navigation always available + +### Motor Accessibility +- **Voice Primary**: Reduce need for precise mouse/touch input +- **Large Touch Targets**: 44px minimum for all interactive elements +- **Keyboard Alternatives**: Full keyboard navigation support +- **Dwell Clicking**: Support for eye-tracking and dwell interfaces + +## Mobile/Responsive Design + +### Mobile-First Approach +- **Touch Optimized**: Large touch targets, swipe gestures +- **Voice Primary**: Emphasize voice input on mobile devices +- **Simplified UI**: Minimal chrome, focus on conversation +- **Offline Capability**: Basic functionality without network + +### Responsive Adaptations +- **Mobile**: Full-screen conversation interface +- **Tablet**: Split view with conversation + contextual panels +- **Desktop**: Multi-panel layout with traditional fallback options + +### Cross-Platform Voice +- **Native Integration**: Use platform voice APIs when available +- **Consistent Experience**: Same conversation across all devices +- **Sync Capability**: Conversation history syncs across devices + +## Performance Impact Assessment + +### AI/ML Processing +- **Edge Computing**: Local processing for basic NLP when possible +- **Cloud Integration**: Advanced AI features through API calls +- **Caching Strategy**: Cache common responses and user preferences +- **Progressive Enhancement**: Graceful degradation when AI unavailable + +### Voice Processing +- **Browser APIs**: Use native Web Speech API when supported +- **Fallback Options**: Text input always available +- **Bandwidth Optimization**: Compress voice data for transmission +- **Local Processing**: Client-side voice recognition when possible + +### Memory Management +- **Conversation Pruning**: Limit conversation history length +- **Context Compression**: Efficient storage of conversation context +- **Cleanup**: Proper cleanup of voice processing resources +- **Background Processing**: Handle AI responses without blocking UI + +--- + +# Implementation Recommendations + +## Phased Rollout Strategy + +### Phase 1: Foundation (Months 1-3) +- **Direction 2 (Command Center)**: Implement as primary interface + - Lowest risk, builds on existing patterns + - Immediate productivity gains for power users + - Establishes advanced filtering and bulk operations + +### Phase 2: Visual Enhancement (Months 4-6) +- **Direction 1 (Visual Intelligence)**: Add visual components + - Implement model visualization and comparison tools + - Add performance charts and recommendation engine + - Enhance with interactive filtering + +### Phase 3: AI Integration (Months 7-9) +- **Direction 3 (Conversational)**: Introduce AI assistant + - Start with basic natural language queries + - Add voice interface capabilities + - Implement learning and personalization + +## Technical Implementation Priority + +### High Priority (Must Have) +1. **Advanced Filtering System** (All Directions) +2. **Model Comparison Interface** (Directions 1 & 2) +3. **Real-time Performance Monitoring** (Direction 2) +4. **Responsive Design Foundation** (All Directions) + +### Medium Priority (Should Have) +1. **Visual Model Cards** (Direction 1) +2. **Command Palette** (Direction 2) +3. **Basic AI Recommendations** (Direction 3) +4. **Customizable Dashboards** (Direction 2) + +### Low Priority (Nice to Have) +1. **Network Graph Visualization** (Direction 1) +2. **Voice Interface** (Direction 3) +3. **Workflow Builder** (Direction 1) +4. **Advanced AI Learning** (Direction 3) + +## Success Metrics & KPIs + +### User Experience Metrics +- **Task Completion Time**: 60% reduction in model discovery time +- **User Satisfaction**: >4.5/5 rating for new interface +- **Feature Adoption**: >80% usage of new filtering capabilities +- **Error Reduction**: 50% fewer user errors in model selection + +### Technical Performance Metrics +- **Page Load Time**: <2 seconds for initial dashboard load +- **Filter Response Time**: <300ms for filter operations +- **Accessibility Score**: WCAG 2.1 AA compliance (100%) +- **Mobile Performance**: <3 seconds load time on 3G networks + +### Business Impact Metrics +- **Model Deployment Efficiency**: 40% faster deployment workflows +- **User Retention**: Increased daily active users +- **Support Ticket Reduction**: 30% fewer UI-related support requests +- **Training Time**: 50% reduction in new user onboarding time + +## Risk Mitigation + +### Technical Risks +- **Performance Impact**: Implement progressive loading and virtualization +- **Browser Compatibility**: Provide fallbacks for advanced features +- **Accessibility Regression**: Comprehensive testing throughout development +- **Data Security**: Ensure all new features maintain security standards + +### User Adoption Risks +- **Change Management**: Provide optional traditional interface during transition +- **Training Requirements**: Create comprehensive documentation and tutorials +- **Feature Complexity**: Implement progressive disclosure of advanced features +- **Feedback Integration**: Establish user feedback loops for continuous improvement + +## Conclusion + +These three design directions offer distinct approaches to solving Paula's core challenge of efficiently finding and evaluating AI models. Each direction can be implemented independently or combined to create a comprehensive solution that serves different user preferences and workflows. + +The **Enterprise Command Center** approach provides immediate value with minimal risk, while the **AI-First Visual Intelligence** direction offers innovative visualization capabilities. The **Conversational AI Assistant** represents the future of human-computer interaction for complex technical tasks. + +By implementing these designs with a focus on accessibility, performance, and user experience, RHOAI 3.0 can transform from a traditional enterprise dashboard into a modern, intelligent platform that accelerates AI adoption and deployment across organizations. \ No newline at end of file diff --git a/components/frontend/static-prototype/styles.css b/components/frontend/static-prototype/styles.css new file mode 100644 index 000000000..d73bfb2ad --- /dev/null +++ b/components/frontend/static-prototype/styles.css @@ -0,0 +1,527 @@ +/* vTeam Static Prototype Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + line-height: 1.6; + color: #333; + background-color: #f8fafc; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; +} + +/* Header */ +.header { + background: white; + border-bottom: 1px solid #e2e8f0; + padding: 1rem 0; + position: sticky; + top: 0; + z-index: 100; +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.logo { + font-size: 1.5rem; + font-weight: bold; + color: #000000; + text-decoration: none; +} + +.nav { + display: flex; + gap: 2rem; +} + +.nav a { + text-decoration: none; + color: #64748b; + font-weight: 500; + transition: color 0.2s; +} + +.nav a:hover, .nav a.active { + color: #1e40af; +} + +/* Page Header */ +.page-header { + background: white; + border-bottom: 1px solid #e2e8f0; + padding: 2rem 0; +} + +.page-header-content { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 2rem; +} + +.page-header-left { + flex: 1; +} + +.page-title { + font-size: 2rem; + font-weight: bold; + margin-bottom: 0.5rem; +} + +.page-description { + color: #64748b; + font-size: 1rem; +} + +.page-actions { + display: flex; + gap: 1rem; + align-items: center; + flex-shrink: 0; +} + +.page-actions .btn { + min-width: 140px; + height: 40px; + justify-content: center; + align-items: center; + padding: 0 1rem; +} + +/* Buttons */ +.btn { + padding: 0.5rem 1rem; + border: none; + border-radius: 0.375rem; + font-weight: 500; + cursor: pointer; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.5rem; + transition: all 0.2s; +} + +.btn-primary { + background: #1e40af; + color: white; +} + +.btn-primary:hover { + background: #1d4ed8; +} + +.btn-secondary { + background: white; + color: #374151; + border: 1px solid #d1d5db; +} + +.btn-secondary:hover { + background: #f9fafb; +} + +/* Cards */ +.card { + background: white; + border-radius: 0.5rem; + border: 1px solid #e2e8f0; + overflow: hidden; +} + +.card-header { + padding: 1.5rem; + border-bottom: 1px solid #e2e8f0; +} + +.card-title { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.card-description { + color: #64748b; +} + +.card-content { + padding: 1.5rem; +} + +/* Tables */ +.table { + width: 100%; + border-collapse: collapse; +} + +.table th, +.table td { + text-align: left; + padding: 0.75rem; + border-bottom: 1px solid #e2e8f0; +} + +.table th { + font-weight: 600; + color: #374151; + background: #f8fafc; +} + +.table tr:hover { + background: #f8fafc; +} + +/* Status badges */ +.badge { + padding: 0.25rem 0.75rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 500; +} + +.badge-success { + background: #dcfce7; + color: #166534; +} + +.badge-warning { + background: #fef3c7; + color: #92400e; +} + +.badge-error { + background: #fee2e2; + color: #991b1b; +} + +.badge-info { + background: #dbeafe; + color: #1e40af; +} + +/* Tabs */ +.tabs { + margin-top: 2rem; +} + +.tab-list { + display: flex; + border-bottom: 1px solid #e2e8f0; + margin-bottom: 1.5rem; +} + +.tab-button { + padding: 0.75rem 1rem; + border: none; + background: none; + cursor: pointer; + color: #64748b; + font-weight: 500; + border-bottom: 2px solid transparent; +} + +.tab-button.active { + color: #1e40af; + border-bottom-color: #1e40af; +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; +} + +/* Grid layouts */ +.grid { + display: grid; + gap: 1.5rem; +} + +.grid-2 { + grid-template-columns: repeat(2, 1fr); +} + +.grid-3 { + grid-template-columns: repeat(3, 1fr); +} + +@media (max-width: 768px) { + .grid-2, + .grid-3 { + grid-template-columns: 1fr; + } + + .page-header-content { + flex-direction: column; + align-items: stretch; + gap: 1rem; + } + + .page-actions { + justify-content: flex-start; + } + + .nav { + display: none; + } +} + +/* Breadcrumbs */ +.breadcrumbs { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 1rem; + color: #64748b; + font-size: 0.875rem; +} + +.breadcrumbs a { + color: #1e40af; + text-decoration: none; +} + +.breadcrumbs a:hover { + text-decoration: underline; +} + +/* Project sidebar */ +.project-layout { + display: grid; + grid-template-columns: 250px 1fr; + gap: 2rem; + margin-top: 2rem; +} + +.project-sidebar { + background: white; + border-radius: 0.5rem; + border: 1px solid #e2e8f0; + padding: 1rem; + height: fit-content; +} + +.project-sidebar ul { + list-style: none; +} + +.project-sidebar li { + margin-bottom: 0.5rem; +} + +.project-sidebar a { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem; + color: #64748b; + text-decoration: none; + border-radius: 0.375rem; + transition: all 0.2s; +} + +.project-sidebar a:hover, +.project-sidebar a.active { + background: #f1f5f9; + color: #1e40af; +} + +@media (max-width: 768px) { + .project-layout { + grid-template-columns: 1fr; + } + + .project-sidebar { + order: 2; + } +} + +/* Empty states */ +.empty-state { + text-align: center; + padding: 3rem 1rem; + color: #64748b; +} + +.empty-state h3 { + margin-bottom: 0.5rem; + color: #374151; +} + +/* Animations */ +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +/* Form styles */ +.form-group { + margin-bottom: 1rem; +} + +.form-label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: #374151; +} + +.form-input { + width: 100%; + padding: 0.5rem; + border: 1px solid #d1d5db; + border-radius: 0.375rem; + font-size: 1rem; +} + +select.form-input, +.form-input select { + padding-right: 2.5rem !important; +} + +select { + padding-right: 2.5rem; +} + +.form-input:focus { + outline: none; + border-color: #1e40af; + box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.1); +} + +.form-textarea { + resize: vertical; + min-height: 100px; +} + +/* Modal styles */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal-content { + background: white; + border-radius: 0.5rem; + width: 90%; + max-width: 500px; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5rem; + border-bottom: 1px solid #e2e8f0; +} + +.modal-header h2 { + margin: 0; + font-size: 1.25rem; + font-weight: 600; +} + +.modal-close { + background: none; + border: none; + font-size: 1.5rem; + cursor: pointer; + color: #64748b; + padding: 0; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-close:hover { + color: #374151; +} + +.modal-body { + padding: 1.5rem; +} + +/* User dropdown styles */ +.user-dropdown-trigger:hover { + background-color: #f1f5f9 !important; +} + +.user-dropdown-menu button:hover { + background-color: #f1f5f9 !important; +} + +/* Session dropdown styles */ +#sessionDropdownMenu button:hover { + background-color: #f1f5f9 !important; +} + +/* Accordion styles */ +.accordion-item { + background: white; + border: 1px solid #e2e8f0; + border-radius: 0.375rem; + overflow: hidden; +} + +.accordion-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + background: white; + border: none; + cursor: pointer; + font-weight: 500; + font-size: 0.875rem; + color: #374151; + transition: background-color 0.2s; + text-align: left; +} + +.accordion-header:hover { + background: #f8fafc; +} + +.accordion-header svg { + transition: transform 0.2s; + flex-shrink: 0; +} + +.accordion-content { + background: #f8fafc; + border-top: 1px solid #e2e8f0; + overflow: hidden; +} From ffb7de307fd6e5a3487ca1d3801f8efaca8c1333 Mon Sep 17 00:00:00 2001 From: Andy Braren Date: Fri, 7 Nov 2025 20:16:33 -0600 Subject: [PATCH 03/34] UI revamp: Workspace and session management improvements --- components/frontend/.gitignore | 5 +- components/frontend/README.md | 4 + .../rfe-workflows/[id]/sessions/link/route.ts | 19 + .../app/integrations/IntegrationsClient.tsx | 81 +-- components/frontend/src/app/layout.tsx | 7 +- components/frontend/src/app/page.tsx | 2 +- .../frontend/src/app/projects/[name]/page.tsx | 170 +++-- .../app/projects/[name]/permissions/error.tsx | 37 -- .../projects/[name]/permissions/loading.tsx | 5 - .../app/projects/[name]/permissions/page.tsx | 403 +----------- .../[name]/sessions/[sessionName]/page.tsx | 608 ++++++++++++++---- .../app/projects/[name]/sessions/error.tsx | 37 -- .../app/projects/[name]/sessions/loading.tsx | 5 - .../sessions/new/model-configuration.tsx | 2 +- .../app/projects/[name]/sessions/new/page.tsx | 2 +- .../src/app/projects/[name]/sessions/page.tsx | 321 +-------- .../app/projects/[name]/settings/error.tsx | 37 -- .../app/projects/[name]/settings/loading.tsx | 5 - .../src/app/projects/[name]/settings/page.tsx | 484 +------------- components/frontend/src/app/projects/page.tsx | 31 +- .../frontend/src/components/breadcrumbs.tsx | 16 +- .../src/components/create-session-dialog.tsx | 322 ++++++++++ .../components/create-workspace-dialog.tsx | 10 +- .../src/components/github-connection-card.tsx | 110 ++++ .../frontend/src/components/navigation.tsx | 16 +- .../src/components/session/ResultsTab.tsx | 4 +- .../src/components/session/WorkspaceTab.tsx | 4 +- .../frontend/src/components/ui/card.tsx | 2 +- .../frontend/src/components/ui/separator.tsx | 29 + .../components/workspace-sections/index.ts | 4 + .../workspace-sections/sessions-section.tsx | 284 ++++++++ .../workspace-sections/settings-section.tsx | 523 +++++++++++++++ .../workspace-sections/sharing-section.tsx | 359 +++++++++++ components/frontend/src/lib/config.ts | 3 +- components/frontend/src/lib/env.ts | 5 + components/frontend/src/services/api/rfe.ts | 51 +- components/frontend/src/types/api/rfe.ts | 1 + .../sample-workspace/settings/page.html | 2 +- 38 files changed, 2382 insertions(+), 1628 deletions(-) create mode 100644 components/frontend/src/app/api/projects/[name]/rfe-workflows/[id]/sessions/link/route.ts delete mode 100644 components/frontend/src/app/projects/[name]/permissions/error.tsx delete mode 100644 components/frontend/src/app/projects/[name]/permissions/loading.tsx delete mode 100644 components/frontend/src/app/projects/[name]/sessions/error.tsx delete mode 100644 components/frontend/src/app/projects/[name]/sessions/loading.tsx delete mode 100644 components/frontend/src/app/projects/[name]/settings/error.tsx delete mode 100644 components/frontend/src/app/projects/[name]/settings/loading.tsx create mode 100644 components/frontend/src/components/create-session-dialog.tsx create mode 100644 components/frontend/src/components/github-connection-card.tsx create mode 100644 components/frontend/src/components/ui/separator.tsx create mode 100644 components/frontend/src/components/workspace-sections/index.ts create mode 100644 components/frontend/src/components/workspace-sections/sessions-section.tsx create mode 100644 components/frontend/src/components/workspace-sections/settings-section.tsx create mode 100644 components/frontend/src/components/workspace-sections/sharing-section.tsx diff --git a/components/frontend/.gitignore b/components/frontend/.gitignore index 3eb22dfc0..c9d206bd2 100644 --- a/components/frontend/.gitignore +++ b/components/frontend/.gitignore @@ -60,4 +60,7 @@ jspm_packages/ # TypeScript *.tsbuildinfo -next-env.d.ts \ No newline at end of file +next-env.d.ts + +# Previous frontend +previous-frontend/ \ No newline at end of file diff --git a/components/frontend/README.md b/components/frontend/README.md index c92748388..a5988e42e 100644 --- a/components/frontend/README.md +++ b/components/frontend/README.md @@ -92,11 +92,15 @@ In production, put an OAuth/ingress proxy in front of the app to set these heade ### Environment variables - `BACKEND_URL` (default: `http://localhost:8080/api`) - Used by server-side API routes to reach the backend. +- `FEEDBACK_URL` (optional) + - URL for the feedback link in the masthead. If not set, the link will not appear. - Optional dev helpers: `OC_USER`, `OC_EMAIL`, `OC_TOKEN`, `ENABLE_OC_WHOAMI=1` You can also put these in a `.env.local` file in this folder: ``` BACKEND_URL=http://localhost:8080/api +# Optional: URL for feedback link in masthead +# FEEDBACK_URL=https://forms.example.com/feedback # Optional dev helpers # OC_USER=your.name # OC_EMAIL=your.name@example.com diff --git a/components/frontend/src/app/api/projects/[name]/rfe-workflows/[id]/sessions/link/route.ts b/components/frontend/src/app/api/projects/[name]/rfe-workflows/[id]/sessions/link/route.ts new file mode 100644 index 000000000..5de001521 --- /dev/null +++ b/components/frontend/src/app/api/projects/[name]/rfe-workflows/[id]/sessions/link/route.ts @@ -0,0 +1,19 @@ +import { BACKEND_URL } from '@/lib/config' +import { buildForwardHeadersAsync } from '@/lib/auth' + +export async function POST( + request: Request, + { params }: { params: Promise<{ name: string; id: string }> }, +) { + const { name, id } = await params + const headers = await buildForwardHeadersAsync(request) + const body = await request.text() + const resp = await fetch(`${BACKEND_URL}/projects/${encodeURIComponent(name)}/rfe-workflows/${encodeURIComponent(id)}/sessions/link`, { + method: 'POST', + headers, + body, + }) + const data = await resp.text() + return new Response(data, { status: resp.status, headers: { 'Content-Type': 'application/json' } }) +} + diff --git a/components/frontend/src/app/integrations/IntegrationsClient.tsx b/components/frontend/src/app/integrations/IntegrationsClient.tsx index 657447dcd..4d81fea81 100644 --- a/components/frontend/src/app/integrations/IntegrationsClient.tsx +++ b/components/frontend/src/app/integrations/IntegrationsClient.tsx @@ -1,73 +1,32 @@ 'use client' import React from 'react' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' -import { useGitHubStatus, useDisconnectGitHub } from '@/services/queries' -import { successToast, errorToast } from '@/hooks/use-toast' +import { GitHubConnectionCard } from '@/components/github-connection-card' +import { PageHeader } from '@/components/page-header' type Props = { appSlug?: string } export default function IntegrationsClient({ appSlug }: Props) { - const { data: status, isLoading, refetch } = useGitHubStatus() - const disconnectMutation = useDisconnectGitHub() - - const handleConnect = () => { - if (!appSlug) return - const setupUrl = new URL('/integrations/github/setup', window.location.origin) - const redirectUri = encodeURIComponent(setupUrl.toString()) - const url = `https://github.com/apps/${appSlug}/installations/new?redirect_uri=${redirectUri}` - window.location.href = url - } - - const handleDisconnect = async () => { - disconnectMutation.mutate(undefined, { - onSuccess: () => { - successToast('GitHub disconnected successfully') - refetch() - }, - onError: (error) => { - errorToast(error instanceof Error ? error.message : 'Failed to disconnect GitHub') - }, - }) - } - - const handleManage = () => { - window.open('https://github.com/settings/installations', '_blank') - } - return ( -
-

Integrations

- - - - GitHub - Connect GitHub to enable forks, PRs, and repo browsing - - -
- {status?.installed ? ( -
- Connected{status.githubUserId ? ` as ${status.githubUserId}` : ''} - {status.updatedAt ? ( - · updated {new Date(status.updatedAt).toLocaleString()} - ) : null} -
- ) : ( -
Not connected
- )} -
-
- - {status?.installed ? ( - - ) : ( - - )} +
+ {/* Sticky header */} +
+
+ +
+
+ +
+ {/* Content */} +
+
+
- - +
+
) } diff --git a/components/frontend/src/app/layout.tsx b/components/frontend/src/app/layout.tsx index 7da9cd6ae..d8ff51f21 100644 --- a/components/frontend/src/app/layout.tsx +++ b/components/frontend/src/app/layout.tsx @@ -21,14 +21,15 @@ export default function RootLayout({ children: React.ReactNode; }) { const wsBase = env.BACKEND_URL.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:') + const feedbackUrl = env.FEEDBACK_URL return ( - + - + - +
{children}
diff --git a/components/frontend/src/app/page.tsx b/components/frontend/src/app/page.tsx index 8e1efe49c..ff947ecfc 100644 --- a/components/frontend/src/app/page.tsx +++ b/components/frontend/src/app/page.tsx @@ -16,7 +16,7 @@ export default function HomeRedirect() {
-

Redirecting to RFE Wokspaces...

+

Redirecting to Workspaces...

diff --git a/components/frontend/src/app/projects/[name]/page.tsx b/components/frontend/src/app/projects/[name]/page.tsx index 10ad504c7..7a1d327d3 100644 --- a/components/frontend/src/app/projects/[name]/page.tsx +++ b/components/frontend/src/app/projects/[name]/page.tsx @@ -1,116 +1,114 @@ 'use client'; -import { useCallback } from 'react'; -import { useParams, useRouter } from 'next/navigation'; -import { formatDistanceToNow } from 'date-fns'; -import { RefreshCw } from 'lucide-react'; +import { useState, useEffect } from 'react'; +import { useParams, useSearchParams } from 'next/navigation'; +import { Star, Settings, Users, RefreshCw } from 'lucide-react'; +import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Label } from '@/components/ui/label'; -import { ProjectSubpageHeader } from '@/components/project-subpage-header'; -import { ErrorMessage } from '@/components/error-message'; +import { PageHeader } from '@/components/page-header'; import { Breadcrumbs } from '@/components/breadcrumbs'; -import { useProject } from '@/services/queries'; +import { SessionsSection } from '@/components/workspace-sections/sessions-section'; +import { SharingSection } from '@/components/workspace-sections/sharing-section'; +import { SettingsSection } from '@/components/workspace-sections/settings-section'; +import { useProject } from '@/services/queries/use-projects'; + +type Section = 'sessions' | 'sharing' | 'settings'; export default function ProjectDetailsPage() { const params = useParams(); - const router = useRouter(); + const searchParams = useSearchParams(); const projectName = params?.name as string; + + // Fetch project data for display name and description + const { data: project, isLoading: projectLoading } = useProject(projectName); + + // Initialize active section from query parameter or default to 'sessions' + const initialSection = (searchParams.get('section') as Section) || 'sessions'; + const [activeSection, setActiveSection] = useState
(initialSection); - // React Query hook replaces all manual state management - const { data: project, isLoading, error, refetch } = useProject(projectName); + // Update active section when query parameter changes + useEffect(() => { + const sectionParam = searchParams.get('section') as Section; + if (sectionParam && ['sessions', 'sharing', 'settings'].includes(sectionParam)) { + setActiveSection(sectionParam); + } + }, [searchParams]); - const handleRefresh = useCallback(() => { - refetch(); - }, [refetch]); + const navItems = [ + { id: 'sessions' as Section, label: 'Sessions', icon: Star }, + { id: 'sharing' as Section, label: 'Sharing', icon: Users }, + { id: 'settings' as Section, label: 'Workspace Settings', icon: Settings }, + ]; // Loading state - if (!projectName || (isLoading && !project)) { + if (!projectName || projectLoading) { return (
- Loading project... + Loading workspace...
); } - // Error state (no project loaded) - if (error && !project) { - return ( -
- - -

{error instanceof Error ? error.message : 'Failed to load project'}

-
- - -
-
-
-
- ); - } - - if (!project) return null; - return ( -
- - {project.displayName || project.name}} - description={<>{projectName}} - actions={ - - } - /> - - {/* Error state (with project loaded) */} - {error && project && ( -
- +
+ {/* Sticky header */} +
+
+ +
- )} +
+ +
+ {/* Content */} +
+ {/* Sidebar Navigation */} + -
-
- {/* Project Info */} - - - Project Information - - -
- -

- {project.description || 'No description provided'} -

-
-
- -

- {project.creationTimestamp && - formatDistanceToNow(new Date(project.creationTimestamp), { - addSuffix: true, - })} -

-
-
-
+ {/* Main Content */} + {activeSection === 'sessions' && } + {activeSection === 'sharing' && } + {activeSection === 'settings' && }
diff --git a/components/frontend/src/app/projects/[name]/permissions/error.tsx b/components/frontend/src/app/projects/[name]/permissions/error.tsx deleted file mode 100644 index 9ad3cc608..000000000 --- a/components/frontend/src/app/projects/[name]/permissions/error.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client'; - -import { useEffect } from 'react'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { AlertCircle } from 'lucide-react'; - -export default function PermissionsError({ - error, - reset, -}: { - error: Error & { digest?: string }; - reset: () => void; -}) { - useEffect(() => { - console.error('Permissions page error:', error); - }, [error]); - - return ( -
- - -
- - Failed to load permissions -
- - {error.message || 'An unexpected error occurred while loading permissions.'} - -
- - - -
-
- ); -} diff --git a/components/frontend/src/app/projects/[name]/permissions/loading.tsx b/components/frontend/src/app/projects/[name]/permissions/loading.tsx deleted file mode 100644 index 843fdcf6a..000000000 --- a/components/frontend/src/app/projects/[name]/permissions/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TableSkeleton } from '@/components/skeletons'; - -export default function PermissionsLoading() { - return ; -} diff --git a/components/frontend/src/app/projects/[name]/permissions/page.tsx b/components/frontend/src/app/projects/[name]/permissions/page.tsx index 08bc483c3..a07590d5f 100644 --- a/components/frontend/src/app/projects/[name]/permissions/page.tsx +++ b/components/frontend/src/app/projects/[name]/permissions/page.tsx @@ -1,404 +1,19 @@ 'use client'; -import { useCallback, useMemo, useState } from 'react'; -import { useParams } from 'next/navigation'; -import { Eye, Edit, Shield, Users, User as UserIcon, Plus, RefreshCw, Loader2, Trash2, Info } from 'lucide-react'; - -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Badge } from '@/components/ui/badge'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; -import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { ProjectSubpageHeader } from '@/components/project-subpage-header'; -import { ErrorMessage } from '@/components/error-message'; -import { DestructiveConfirmationDialog } from '@/components/confirmation-dialog'; -import { Breadcrumbs } from '@/components/breadcrumbs'; - -import { useProject, useProjectPermissions, useAddProjectPermission, useRemoveProjectPermission } from '@/services/queries'; -import { successToast, errorToast } from '@/hooks/use-toast'; -import type { PermissionRole, SubjectType } from '@/types/project'; - -const ROLE_DEFINITIONS = { - view: { - label: 'View', - description: 'Can see sessions and duplicate to their own project', - permissions: ['sessions:read', 'sessions:duplicate'] as const, - color: 'bg-blue-100 text-blue-800', - icon: Eye, - }, - edit: { - label: 'Edit', - description: 'Can create sessions in the project', - permissions: ['sessions:read', 'sessions:create', 'sessions:duplicate'] as const, - color: 'bg-green-100 text-green-800', - icon: Edit, - }, - admin: { - label: 'Admin', - description: 'Full project management access', - permissions: ['*'] as const, - color: 'bg-purple-100 text-purple-800', - icon: Shield, - }, -} as const; - -type GrantPermissionForm = { - subjectType: SubjectType; - subjectName: string; - role: PermissionRole; -}; +import { useEffect } from 'react'; +import { useParams, useRouter } from 'next/navigation'; export default function PermissionsPage() { const params = useParams(); + const router = useRouter(); const projectName = params?.name as string; - // React Query hooks replace all manual state management - const { data: project } = useProject(projectName); - const { data: permissions = [], isLoading, error, refetch } = useProjectPermissions(projectName); - const addPermissionMutation = useAddProjectPermission(); - const removePermissionMutation = useRemoveProjectPermission(); - - // Local UI state - const [showGrantDialog, setShowGrantDialog] = useState(false); - const [grantForm, setGrantForm] = useState({ - subjectType: 'group', - subjectName: '', - role: 'view', - }); - const [grantError, setGrantError] = useState(null); - const userRole: PermissionRole | undefined = undefined; // TODO: Fetch from /projects/:name/access - - const [showRevokeDialog, setShowRevokeDialog] = useState(false); - const [toRevoke, setToRevoke] = useState<{ subjectType: SubjectType; subjectName: string; role: PermissionRole } | null>(null); - - // Check if user is admin - for now assume admin, or fetch from a separate endpoint - // TODO: Implement proper user role fetching from /projects/:name/access - const isAdmin = userRole === 'admin' || userRole === undefined; // Default to admin for now - - const handleGrant = useCallback(() => { - if (!grantForm.subjectName.trim()) { - setGrantError(`${grantForm.subjectType === 'group' ? 'Group' : 'User'} name is required`); - return; - } - - const key = `${grantForm.subjectType}:${grantForm.subjectName}`.toLowerCase(); - if (permissions.some((i) => `${i.subjectType}:${i.subjectName}`.toLowerCase() === key)) { - setGrantError('This subject already has access to the project'); - return; + // Redirect to main workspace page + useEffect(() => { + if (projectName) { + router.replace(`/projects/${projectName}?section=sharing`); } + }, [projectName, router]); - setGrantError(null); - addPermissionMutation.mutate( - { - projectName, - permission: { - subjectType: grantForm.subjectType, - subjectName: grantForm.subjectName, - role: grantForm.role, - }, - }, - { - onSuccess: () => { - successToast(`Permission granted to ${grantForm.subjectName} successfully`); - setShowGrantDialog(false); - setGrantForm({ subjectType: 'group', subjectName: '', role: 'view' }); - }, - onError: (error) => { - const message = error instanceof Error ? error.message : 'Failed to grant permission'; - setGrantError(message); - errorToast(message); - }, - } - ); - }, [grantForm, permissions, projectName, addPermissionMutation]); - - const handleRevoke = useCallback(() => { - if (!toRevoke) return; - - removePermissionMutation.mutate( - { - projectName, - subjectType: toRevoke.subjectType, - subjectName: toRevoke.subjectName, - }, - { - onSuccess: () => { - successToast(`Permission revoked from ${toRevoke.subjectName} successfully`); - setShowRevokeDialog(false); - setToRevoke(null); - }, - onError: (error) => { - errorToast(error instanceof Error ? error.message : 'Failed to revoke permission'); - }, - } - ); - }, [toRevoke, projectName, removePermissionMutation]); - - const emptyState = useMemo( - () => ( -
- -

No users or groups have access yet

- {isAdmin && ( - - )} -
- ), - [isAdmin] - ); - - if (!projectName || (isLoading && permissions.length === 0)) { - return ( -
-
- - Loading permissions... -
-
- ); - } - - return ( -
- - Permissions} - description={<>Manage user and group access for {project?.displayName || projectName}} - actions={ - <> - - {isAdmin && ( - - )} - - } - /> - - {/* Error state */} - {error && refetch()} />} - - {/* Mutation errors */} - {addPermissionMutation.isError && ( -
- -
- )} - {removePermissionMutation.isError && ( -
- -
- )} - - {!isAdmin && ( - - - -

- You have {userRole || 'view'} access. Only admins can grant or revoke permissions. -

-
-
- )} - - - - - - Permissions - - Users and groups with access to this project and their roles - - - {permissions.length > 0 ? ( - - - - Subject - Type - Role - {isAdmin && Actions} - - - - {permissions.map((p) => { - const roleConfig = ROLE_DEFINITIONS[p.role]; - const RoleIcon = roleConfig.icon; - const isRevokingThis = - removePermissionMutation.isPending && - removePermissionMutation.variables?.subjectName === p.subjectName && - removePermissionMutation.variables?.subjectType === p.subjectType; - - return ( - - {p.subjectName} - -
- {p.subjectType === 'group' ? ( - - ) : ( - - )} - {p.subjectType === 'group' ? 'Group' : 'User'} -
-
- - - - {roleConfig.label} - - - - {isAdmin && ( - - - - )} -
- ); - })} -
-
- ) : ( - emptyState - )} -
-
- - {/* Grant Permission Dialog */} - - - - Grant Permission - Add a user or group to this project with a role - -
-
- - { - if (addPermissionMutation.isPending) return; - setGrantForm((prev) => ({ ...prev, subjectType: value as SubjectType })); - }} - > - - Group - User - - -
-
- - setGrantForm((prev) => ({ ...prev, subjectName: e.target.value }))} - disabled={addPermissionMutation.isPending} - /> -
-
- -
- {Object.entries(ROLE_DEFINITIONS).map(([roleKey, roleConfig]) => { - const RoleIcon = roleConfig.icon; - const id = `role-${roleKey}`; - return ( -
- setGrantForm((prev) => ({ ...prev, role: roleKey as PermissionRole }))} - disabled={addPermissionMutation.isPending} - /> - -
- ); - })} -
-
- {grantError &&
{grantError}
} -
- - - - -
-
- - {/* Revoke Permission Dialog */} - -
- ); + return null; } diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 45af002b1..a688e7dd9 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -2,8 +2,8 @@ import { useState, useEffect, useMemo, useCallback } from "react"; import Link from "next/link"; -import { formatDistanceToNow } from "date-fns"; -import { ArrowLeft, Square, Trash2, Copy, Play, MoreVertical, Bot, Loader2, FolderTree, AlertCircle, Sprout, CheckCircle2, GitBranch, Edit, Info } from "lucide-react"; +import { formatDistanceToNow, format } from "date-fns"; +import { ArrowLeft, Square, Trash2, Copy, Play, MoreVertical, Bot, Loader2, FolderTree, AlertCircle, Sprout, CheckCircle2, GitBranch, Edit, Info, RefreshCw, Folder, FileText } from "lucide-react"; import { useRouter } from "next/navigation"; // Custom components @@ -20,10 +20,14 @@ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/ import { Checkbox } from "@/components/ui/checkbox"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; import { CloneSessionDialog } from "@/components/clone-session-dialog"; import { Breadcrumbs } from "@/components/breadcrumbs"; import { PageHeader } from "@/components/page-header"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"; +import { GitHubConnectionCard } from "@/components/github-connection-card"; import type { FileTreeNode } from "@/components/file-tree"; import type { SessionMessage } from "@/types"; @@ -50,8 +54,13 @@ import { useRfeWorkflowSeeding, useSeedRfeWorkflow, useUpdateRfeWorkflow, + useCreateRfeWorkflow, + useGitHubStatus, + useWorkflowArtifacts, workspaceKeys, + rfeKeys, } from "@/services/queries"; +import { useSecretsValues } from "@/services/queries/use-secrets"; import { successToast, errorToast } from "@/hooks/use-toast"; import { workspaceApi } from "@/services/api"; import { useQueryClient } from "@tanstack/react-query"; @@ -75,6 +84,13 @@ export default function ProjectSessionDetailPage({ const [selectedAgents, setSelectedAgents] = useState([]); const [editRepoDialogOpen, setEditRepoDialogOpen] = useState(false); const [selectedWorkflow, setSelectedWorkflow] = useState("none"); + const [githubModalOpen, setGithubModalOpen] = useState(false); + const [specRepoUrl, setSpecRepoUrl] = useState("https://github.com/org/repo.git"); + const [baseBranch, setBaseBranch] = useState("main"); + const [openAccordionItems, setOpenAccordionItems] = useState(["workflows"]); + const [contextModalOpen, setContextModalOpen] = useState(false); + const [contextUrl, setContextUrl] = useState(""); + const [contextBranch, setContextBranch] = useState("main"); // Extract params useEffect(() => { @@ -89,10 +105,24 @@ export default function ProjectSessionDetailPage({ }); }, [params]); + // Open spec-repository accordion when plan-feature or develop-feature is selected + useEffect(() => { + if (selectedWorkflow === "plan-feature" || selectedWorkflow === "develop-feature") { + setOpenAccordionItems(prev => { + if (!prev.includes("spec-repository")) { + return [...prev, "spec-repository"]; + } + return prev; + }); + } + }, [selectedWorkflow]); + // React Query hooks const { data: session, isLoading, error, refetch: refetchSession } = useSession(projectName, sessionName); const { data: messages = [] } = useSessionMessages(projectName, sessionName, session?.status?.phase); const { data: k8sResources } = useSessionK8sResources(projectName, sessionName); + const { data: githubStatus } = useGitHubStatus(); + const { data: secretsValues } = useSecretsValues(projectName); const stopMutation = useStopSession(); const deleteMutation = useDeleteSession(); const continueMutation = useContinueSession(); @@ -103,20 +133,25 @@ export default function ProjectSessionDetailPage({ const writeWorkspaceFileMutation = useWriteWorkspaceFile(); // Get RFE workflow ID from session if this is an RFE session - const rfeWorkflowId = session?.metadata?.labels?.['rfe-workflow-id']; - const { data: rfeWorkflow, refetch: refetchWorkflow } = useRfeWorkflow(projectName, rfeWorkflowId || '', { enabled: !!rfeWorkflowId }); + const rfeWorkflowId = session?.metadata?.labels?.['rfe-workflow']; + const { data: rfeWorkflow, refetch: refetchWorkflow } = useRfeWorkflow(projectName, rfeWorkflowId || ''); const { data: repoAgents = [], isLoading: loadingAgents } = useRfeWorkflowAgents( projectName, - rfeWorkflowId || '', - { enabled: !!rfeWorkflowId } + rfeWorkflowId || '' ); const { data: seedingData, isLoading: checkingSeeding, error: seedingQueryError, refetch: refetchSeeding } = useRfeWorkflowSeeding( projectName, - rfeWorkflowId || '', - { enabled: !!rfeWorkflowId } + rfeWorkflowId || '' ); const seedWorkflowMutation = useSeedRfeWorkflow(); const updateWorkflowMutation = useUpdateRfeWorkflow(); + const createWorkflowMutation = useCreateRfeWorkflow(); + + // Fetch artifacts for the spec repository + const { data: workflowArtifacts = [], isLoading: artifactsLoading, refetch: refetchArtifacts } = useWorkflowArtifacts( + projectName, + rfeWorkflowId || '' + ); // Workspace state const [wsSelectedPath, setWsSelectedPath] = useState(); @@ -169,6 +204,16 @@ export default function ProjectSessionDetailPage({ }); }, [queryClient]); + // Handler to refresh spec repository artifacts + const handleRefreshArtifacts = useCallback(async () => { + if (!rfeWorkflowId) return; + // Invalidate artifacts query to force fresh fetch + await queryClient.invalidateQueries({ + queryKey: rfeKeys.artifacts(projectName, rfeWorkflowId), + }); + await refetchArtifacts(); + }, [queryClient, projectName, rfeWorkflowId, refetchArtifacts]); + // GitHub diff state const [busyRepo, setBusyRepo] = useState>({}); @@ -936,7 +981,7 @@ export default function ProjectSessionDetailPage({
{/* Left Column - Accordions */}
- + Workflows @@ -958,130 +1003,28 @@ export default function ProjectSessionDetailPage({

- Workflows provide a structured processes for Ambient Code Platform agents to follow and achieve complex goals. + Workflows provide Ambient agents with structured steps to follow toward more complex goals.

- - - Overview - - - { - const repo = session.spec.repos?.[idx]; - if (!repo) return; - - setBusyRepo((b) => ({ ...b, [idx]: 'push' })); - const folder = deriveRepoFolderFromUrl(repo.input.url); - const repoPath = `/sessions/${sessionName}/workspace/${folder}`; - - pushToGitHubMutation.mutate( - { projectName, sessionName, repoIndex: idx, repoPath }, - { - onSuccess: () => { - refetchDiffs(); - successToast('Changes pushed to GitHub'); - }, - onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to push changes'), - onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), - } - ); - }} - onAbandon={async (idx) => { - const repo = session.spec.repos?.[idx]; - if (!repo) return; - - setBusyRepo((b) => ({ ...b, [idx]: 'abandon' })); - const folder = deriveRepoFolderFromUrl(repo.input.url); - const repoPath = `/sessions/${sessionName}/workspace/${folder}`; - - abandonChangesMutation.mutate( - { projectName, sessionName, repoIndex: idx, repoPath }, - { - onSuccess: () => { - refetchDiffs(); - successToast('Changes abandoned'); - }, - onError: (err) => errorToast(err instanceof Error ? err.message : 'Failed to abandon changes'), - onSettled: () => setBusyRepo((b) => ({ ...b, [idx]: null })), - } - ); - }} - busyRepo={busyRepo} - buildGithubCompareUrl={buildGithubCompareUrl} - onRefreshDiff={handleRefreshDiff} - /> - - - - - - Workspace - - - {sessionCompleted && !contentPodReady ? ( - -
- {contentPodSpawning ? ( - <> -
-
-
-

Starting workspace viewer...

-

This may take up to 30 seconds

- - ) : ( - <> -

- Session has completed. To view and edit your workspace files, please start a workspace viewer. -

- - - )} -
- - ) : ( - - )} - - - + {/* Only show Spec Repository for plan-feature and develop-feature workflows */} + {(selectedWorkflow === "plan-feature" || selectedWorkflow === "develop-feature") && ( Spec Repository {!rfeWorkflowId ? ( -
- -

This session is not associated with an RFE workflow

-

Spec repository is only available for RFE sessions

+
+ +

+ A spec repository is required to store agent config and workflow artifacts. +

+
) : (
@@ -1211,8 +1154,78 @@ export default function ProjectSessionDetailPage({ )}
)} + + {/* Spec Repository Files - Only show after spec repository is seeded */} + {rfeWorkflowId && isSeeded && ( +
+
+
+
+ + Files + {!artifactsLoading && ( + + ({workflowArtifacts.length} {workflowArtifacts.length === 1 ? 'file' : 'files'}) + + )} +
+ +
+
+ {artifactsLoading ? ( +
+ Loading files... +
+ ) : workflowArtifacts.length === 0 ? ( +
+ +

No files yet

+

Files will appear here as agents create artifacts

+
+ ) : ( +
+ {workflowArtifacts.map((artifact) => { + const isDirectory = artifact.type === 'tree'; + const Icon = isDirectory ? Folder : FileText; + const iconColor = isDirectory ? 'text-yellow-600' : 'text-blue-500'; + + return ( +
+ +
+
{artifact.name}
+ {artifact.path !== artifact.name && ( +
{artifact.path}
+ )} +
+ {!isDirectory && artifact.size > 0 && ( +
+ {(artifact.size / 1024).toFixed(1)} KB +
+ )} +
+ ); + })} +
+ )} +
+
+
+ )} + )} @@ -1282,9 +1295,53 @@ export default function ProjectSessionDetailPage({ - + - Results + Context + + + {!rfeWorkflowId || !rfeWorkflow?.supportingRepos || rfeWorkflow.supportingRepos.length === 0 ? ( +
+
+ +
+

No associated repositories configured

+

Add context from external sources

+ + {!rfeWorkflowId && ( +

Configure a spec repository first

+ )} +
+ ) : ( +
+
+ {rfeWorkflow.supportingRepos.map((repo, index) => ( +
+ +
+
{repo.url}
+ {repo.branch && ( +
+ Branch: {repo.branch} +
+ )} +
+
+ ))} +
+ +
+ )} +
+
+ + + + Artifacts @@ -1296,25 +1353,73 @@ export default function ProjectSessionDetailPage({ Session Details -
- - -
Duration
-
{typeof durationMs === "number" ? `${durationMs} ms` : "-"}
-
-
- - -
Messages
-
{messages.length}
-
-
- - -
Agents
-
{subagentStats.uniqueCount > 0 ? subagentStats.uniqueCount : "-"}
-
-
+
+
+
+ Status: + + {session.status?.phase || "Pending"} + +
+
+ Model: + {session.spec.llmSettings.model} +
+
+ Temperature: + {session.spec.llmSettings.temperature} +
+
+ Mode: + {session.spec?.interactive ? "Interactive" : "Headless"} +
+ {session.status?.startTime && ( +
+ Started: + {format(new Date(session.status.startTime), "PPp")} +
+ )} +
+ Duration: + {typeof durationMs === "number" ? `${durationMs}ms` : "-"} +
+ {k8sResources?.pvcName && ( +
+ PVC: + {k8sResources.pvcName} +
+ )} + {k8sResources?.pvcSize && ( +
+ PVC Size: + {k8sResources.pvcSize} +
+ )} + {session.status?.jobName && ( +
+ K8s Job: + {session.status.jobName} +
+ )} +
+ Messages: + {messages.length} +
+
+ Session prompt: + +
+ {promptExpanded && session.spec.prompt && ( +
+

{session.spec.prompt}

+
+ )} +
@@ -1343,6 +1448,223 @@ export default function ProjectSessionDetailPage({
+ + {/* Add Spec Repository Modal */} + + + + Add spec repository + + Set the spec repo and optional supporting repos. Base branch is the branch from which the feature branch will be set up. All modifications will be made to the feature branch. + + + + {!githubStatus?.installed && !secretsValues?.some(secret => secret.key === 'GIT_TOKEN' && secret.value) && ( +
+ +
+ )} + +
+
+ + setSpecRepoUrl(e.target.value)} + /> +

+ The spec repository contains your feature specifications, planning documents, and agent configurations for this RFE workspace +

+
+ +
+ + setBaseBranch(e.target.value)} + /> +
+ +
+ + +
+
+ + + + + +
+
+ + {/* Add Context Modal */} + + + + Add Context + + Add external context sources to enhance agent understanding + + + +
+
+ + setContextUrl(e.target.value)} + /> +

+ Currently supports GitHub repositories for code context +

+
+ +
+ + setContextBranch(e.target.value)} + /> +

+ Leave empty to use the default branch +

+
+ + + + + Google Drive and Jira support coming soon + + +
+ + + + + +
+
); } diff --git a/components/frontend/src/app/projects/[name]/sessions/error.tsx b/components/frontend/src/app/projects/[name]/sessions/error.tsx deleted file mode 100644 index 29ce50d08..000000000 --- a/components/frontend/src/app/projects/[name]/sessions/error.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client'; - -import { useEffect } from 'react'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { AlertCircle } from 'lucide-react'; - -export default function SessionsError({ - error, - reset, -}: { - error: Error & { digest?: string }; - reset: () => void; -}) { - useEffect(() => { - console.error('Sessions page error:', error); - }, [error]); - - return ( -
- - -
- - Failed to load sessions -
- - {error.message || 'An unexpected error occurred while loading sessions.'} - -
- - - -
-
- ); -} diff --git a/components/frontend/src/app/projects/[name]/sessions/loading.tsx b/components/frontend/src/app/projects/[name]/sessions/loading.tsx deleted file mode 100644 index edec2cda6..000000000 --- a/components/frontend/src/app/projects/[name]/sessions/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TableSkeleton } from '@/components/skeletons'; - -export default function SessionsLoading() { - return ; -} diff --git a/components/frontend/src/app/projects/[name]/sessions/new/model-configuration.tsx b/components/frontend/src/app/projects/[name]/sessions/new/model-configuration.tsx index b5b7fe945..0914ebbb6 100644 --- a/components/frontend/src/app/projects/[name]/sessions/new/model-configuration.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/new/model-configuration.tsx @@ -6,8 +6,8 @@ import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; const models = [ - { value: "claude-opus-4-1", label: "Claude Opus 4.1" }, { value: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" }, + { value: "claude-opus-4-1", label: "Claude Opus 4.1" }, { value: "claude-haiku-4-5", label: "Claude Haiku 4.5" }, ]; diff --git a/components/frontend/src/app/projects/[name]/sessions/new/page.tsx b/components/frontend/src/app/projects/[name]/sessions/new/page.tsx index d84d5c4da..6c1d3096a 100644 --- a/components/frontend/src/app/projects/[name]/sessions/new/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/new/page.tsx @@ -87,7 +87,7 @@ export default function NewProjectSessionPage({ params }: { params: Promise<{ na resolver: zodResolver(formSchema), defaultValues: { prompt: "", - model: "claude-3-7-sonnet-latest", + model: "claude-sonnet-4-5", temperature: 0.7, maxTokens: 4000, timeout: 300, diff --git a/components/frontend/src/app/projects/[name]/sessions/page.tsx b/components/frontend/src/app/projects/[name]/sessions/page.tsx index 5cbec04bf..e0cfa4892 100644 --- a/components/frontend/src/app/projects/[name]/sessions/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/page.tsx @@ -1,320 +1,19 @@ 'use client'; -import Link from 'next/link'; -import { useParams } from 'next/navigation'; -import { formatDistanceToNow } from 'date-fns'; -import { Plus, RefreshCw, MoreVertical, Square, Trash2, ArrowRight, Brain } from 'lucide-react'; - -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; -import { ProjectSubpageHeader } from '@/components/project-subpage-header'; -import { EmptyState } from '@/components/empty-state'; -import { ErrorMessage } from '@/components/error-message'; -import { SessionPhaseBadge } from '@/components/status-badge'; -import { Breadcrumbs } from '@/components/breadcrumbs'; - -import { useSessions, useStopSession, useDeleteSession, useContinueSession } from '@/services/queries'; -import { successToast, errorToast } from '@/hooks/use-toast'; +import { useEffect } from 'react'; +import { useParams, useRouter } from 'next/navigation'; export default function ProjectSessionsListPage() { const params = useParams(); + const router = useRouter(); const projectName = params?.name as string; - // React Query hooks replace all manual state management - const { data: sessions = [], isLoading, error, refetch } = useSessions(projectName); - const stopSessionMutation = useStopSession(); - const deleteSessionMutation = useDeleteSession(); - const continueSessionMutation = useContinueSession(); - - const handleStop = async (sessionName: string) => { - stopSessionMutation.mutate( - { projectName, sessionName }, - { - onSuccess: () => { - successToast(`Session "${sessionName}" stopped successfully`); - }, - onError: (error) => { - errorToast(error instanceof Error ? error.message : 'Failed to stop session'); - }, - } - ); - }; - - - const handleDelete = async (sessionName: string) => { - if (!confirm(`Delete agentic session "${sessionName}"? This action cannot be undone.`)) return; - deleteSessionMutation.mutate( - { projectName, sessionName }, - { - onSuccess: () => { - successToast(`Session "${sessionName}" deleted successfully`); - }, - onError: (error) => { - errorToast(error instanceof Error ? error.message : 'Failed to delete session'); - }, - } - ); - }; - - const handleContinue = async (sessionName: string) => { - continueSessionMutation.mutate( - { projectName, parentSessionName: sessionName }, - { - onSuccess: () => { - successToast(`Session "${sessionName}" restarted successfully`); - }, - onError: (error) => { - errorToast(error instanceof Error ? error.message : 'Failed to restart session'); - }, - } - ); - }; - - // Loading state - if (!projectName || (isLoading && sessions.length === 0)) { - return ( -
-
- - Loading sessions... -
-
- ); - } - - // Sort sessions by creation time (newest first) - const sortedSessions = [...sessions].sort((a, b) => { - const aTime = a?.metadata?.creationTimestamp ? new Date(a.metadata.creationTimestamp).getTime() : 0; - const bTime = b?.metadata?.creationTimestamp ? new Date(b.metadata.creationTimestamp).getTime() : 0; - return bTime - aTime; - }); - - return ( -
- - Agentic Sessions} - description={<>Sessions scoped to this project} - actions={ - <> - - - - - - } - /> - - {/* Error state */} - {error && refetch()} />} - - - - Agentic Sessions ({sessions?.length || 0}) - Sessions scoped to this project - - - {sessions.length === 0 ? ( - (window.location.href = `/projects/${encodeURIComponent(projectName)}/sessions/new`), - }} - /> - ) : ( -
- - - - Name - Status - Mode - Model - Created - Cost - Actions - - - - {sortedSessions.map((session) => { - const sessionName = session.metadata.name; - const phase = session.status?.phase || 'Pending'; - const isActionPending = - (stopSessionMutation.isPending && stopSessionMutation.variables?.sessionName === sessionName) || - (deleteSessionMutation.isPending && deleteSessionMutation.variables?.sessionName === sessionName); - - return ( - - - -
-
{session.spec.displayName || session.metadata.name}
- {session.spec.displayName && ( -
{session.metadata.name}
- )} -
- -
- - - - - - {session.spec?.interactive ? 'Interactive' : 'Headless'} - - - - - {session.spec.llmSettings.model} - - - - {session.metadata?.creationTimestamp && - formatDistanceToNow(new Date(session.metadata.creationTimestamp), { addSuffix: true })} - - - {session.status?.total_cost_usd ? ( - ${session.status.total_cost_usd.toFixed(4)} - ) : ( - - )} - - - {isActionPending ? ( - - ) : ( - - )} - -
- ); - })} -
-
-
- )} -
-
-
- ); -} - -// Session actions component extracted for clarity -type SessionActionsProps = { - sessionName: string; - phase: string; - onStop: (sessionName: string) => void; - onContinue: (sessionName: string) => void; - onDelete: (sessionName: string) => void; -}; - -function SessionActions({ sessionName, phase, onStop, onContinue, onDelete }: SessionActionsProps) { - type RowAction = { - key: string; - label: string; - onClick: () => void; - icon: React.ReactNode; - className?: string; - }; - - const actions: RowAction[] = []; - - if (phase === 'Pending' || phase === 'Creating' || phase === 'Running') { - actions.push({ - key: 'stop', - label: 'Stop', - onClick: () => onStop(sessionName), - icon: , - className: 'text-orange-600', - }); - } - - // Allow continue for all completed sessions (converts headless to interactive) - if (phase === 'Completed' || phase === 'Failed' || phase === 'Stopped' || phase === 'Error') { - actions.push({ - key: 'continue', - label: 'Continue', - onClick: () => onContinue(sessionName), - icon: , - className: 'text-green-600', - }); - } - - // Delete is always available except when Creating - if (phase !== 'Creating') { - actions.push({ - key: 'delete', - label: 'Delete', - onClick: () => onDelete(sessionName), - icon: , - className: 'text-red-600', - }); - } - - // Single action: show as button - if (actions.length === 1) { - const action = actions[0]; - return ( - - ); - } - - // No actions: show disabled button - if (actions.length === 0) { - return ( - - ); - } + // Redirect to main workspace page (sessions is the default view) + useEffect(() => { + if (projectName) { + router.replace(`/projects/${projectName}`); + } + }, [projectName, router]); - // Multiple actions: show dropdown - return ( - - - - - - {actions.map((action) => ( - - {action.label} - - ))} - - - ); + return null; } diff --git a/components/frontend/src/app/projects/[name]/settings/error.tsx b/components/frontend/src/app/projects/[name]/settings/error.tsx deleted file mode 100644 index 84ba3e418..000000000 --- a/components/frontend/src/app/projects/[name]/settings/error.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client'; - -import { useEffect } from 'react'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { AlertCircle } from 'lucide-react'; - -export default function SettingsError({ - error, - reset, -}: { - error: Error & { digest?: string }; - reset: () => void; -}) { - useEffect(() => { - console.error('Settings page error:', error); - }, [error]); - - return ( -
- - -
- - Failed to load settings -
- - {error.message || 'An unexpected error occurred while loading settings.'} - -
- - - -
-
- ); -} diff --git a/components/frontend/src/app/projects/[name]/settings/loading.tsx b/components/frontend/src/app/projects/[name]/settings/loading.tsx deleted file mode 100644 index 775621468..000000000 --- a/components/frontend/src/app/projects/[name]/settings/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { FormSkeleton } from '@/components/skeletons'; - -export default function SettingsLoading() { - return ; -} diff --git a/components/frontend/src/app/projects/[name]/settings/page.tsx b/components/frontend/src/app/projects/[name]/settings/page.tsx index bd29a87b5..f9c1f1f2c 100644 --- a/components/frontend/src/app/projects/[name]/settings/page.tsx +++ b/components/frontend/src/app/projects/[name]/settings/page.tsx @@ -1,479 +1,19 @@ -"use client"; +'use client'; -import { useEffect, useState } from "react"; -import { ProjectSubpageHeader } from "@/components/project-subpage-header"; -import { Breadcrumbs } from "@/components/breadcrumbs"; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Button } from "@/components/ui/button"; -import { RefreshCw, Save, Loader2, Info } from "lucide-react"; -import { Plus, Trash2, Eye, EyeOff } from "lucide-react"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { successToast, errorToast } from "@/hooks/use-toast"; -import { useProject, useUpdateProject } from "@/services/queries/use-projects"; -import { useSecretsList, useSecretsConfig, useSecretsValues, useUpdateSecretsConfig, useUpdateSecrets } from "@/services/queries/use-secrets"; -import { useMemo } from "react"; +import { useEffect } from 'react'; +import { useParams, useRouter } from 'next/navigation'; -export default function ProjectSettingsPage({ params }: { params: Promise<{ name: string }> }) { - const [projectName, setProjectName] = useState(""); - const [formData, setFormData] = useState({ displayName: "", description: "" }); - const [secretName, setSecretName] = useState(""); - const [secrets, setSecrets] = useState>([]); - const [mode, setMode] = useState<"existing" | "new">("existing"); - const [showValues, setShowValues] = useState>({}); - const [anthropicApiKey, setAnthropicApiKey] = useState(""); - const [showAnthropicKey, setShowAnthropicKey] = useState(false); - const [gitUserName, setGitUserName] = useState(""); - const [gitUserEmail, setGitUserEmail] = useState(""); - const [gitToken, setGitToken] = useState(""); - const [showGitToken, setShowGitToken] = useState(false); - const [jiraUrl, setJiraUrl] = useState(""); - const [jiraProject, setJiraProject] = useState(""); - const [jiraEmail, setJiraEmail] = useState(""); - const [jiraToken, setJiraToken] = useState(""); - const [showJiraToken, setShowJiraToken] = useState(false); - const FIXED_KEYS = useMemo(() => ["ANTHROPIC_API_KEY","GIT_USER_NAME","GIT_USER_EMAIL","GIT_TOKEN","JIRA_URL","JIRA_PROJECT","JIRA_EMAIL","JIRA_API_TOKEN"] as const, []); +export default function ProjectSettingsPage() { + const params = useParams(); + const router = useRouter(); + const projectName = params?.name as string; - // React Query hooks - const { data: project, isLoading: projectLoading, refetch: refetchProject } = useProject(projectName); - const { data: secretsList } = useSecretsList(projectName); - const { data: secretsConfig } = useSecretsConfig(projectName); - const { data: secretsValues } = useSecretsValues(projectName); - const updateProjectMutation = useUpdateProject(); - const updateSecretsConfigMutation = useUpdateSecretsConfig(); - const updateSecretsMutation = useUpdateSecrets(); - - // Extract projectName from params - useEffect(() => { - params.then(({ name }) => setProjectName(name)); - }, [params]); - - // Sync project data to form - useEffect(() => { - if (project) { - setFormData({ displayName: project.displayName || "", description: project.description || "" }); - } - }, [project]); - - // Sync secrets config to state + // Redirect to main workspace page useEffect(() => { - if (secretsConfig) { - if (secretsConfig.secretName) { - setSecretName(secretsConfig.secretName); - setMode("existing"); - } else { - setSecretName("ambient-runner-secrets"); - setMode("new"); - } + if (projectName) { + router.replace(`/projects/${projectName}?section=settings`); } - }, [secretsConfig]); - - // Sync secrets values to state - useEffect(() => { - if (secretsValues) { - const byKey: Record = Object.fromEntries(secretsValues.map(s => [s.key, s.value])); - setAnthropicApiKey(byKey["ANTHROPIC_API_KEY"] || ""); - setGitUserName(byKey["GIT_USER_NAME"] || ""); - setGitUserEmail(byKey["GIT_USER_EMAIL"] || ""); - setGitToken(byKey["GIT_TOKEN"] || ""); - setJiraUrl(byKey["JIRA_URL"] || ""); - setJiraProject(byKey["JIRA_PROJECT"] || ""); - setJiraEmail(byKey["JIRA_EMAIL"] || ""); - setJiraToken(byKey["JIRA_API_TOKEN"] || ""); - setSecrets(secretsValues.filter(s => !FIXED_KEYS.includes(s.key as typeof FIXED_KEYS[number]))); - } - }, [secretsValues, FIXED_KEYS]); - - const handleRefresh = () => { - void refetchProject(); - }; - - const handleSave = () => { - if (!project) return; - updateProjectMutation.mutate( - { - name: projectName, - data: { - displayName: formData.displayName.trim(), - description: formData.description.trim() || undefined, - annotations: project.annotations || {}, - }, - }, - { - onSuccess: () => { - successToast("Project settings updated successfully!"); - }, - onError: (error) => { - const message = error instanceof Error ? error.message : "Failed to update project"; - errorToast(message); - }, - } - ); - }; - - const handleSaveSecrets = () => { - if (!projectName) return; - - const name = secretName.trim() || "ambient-runner-secrets"; - - // First update config - updateSecretsConfigMutation.mutate( - { projectName, secretName: name }, - { - onSuccess: () => { - // Then update secrets values - const data: Record = {}; - if (anthropicApiKey) data["ANTHROPIC_API_KEY"] = anthropicApiKey; - if (gitUserName) data["GIT_USER_NAME"] = gitUserName; - if (gitUserEmail) data["GIT_USER_EMAIL"] = gitUserEmail; - if (gitToken) data["GIT_TOKEN"] = gitToken; - if (jiraUrl) data["JIRA_URL"] = jiraUrl; - if (jiraProject) data["JIRA_PROJECT"] = jiraProject; - if (jiraEmail) data["JIRA_EMAIL"] = jiraEmail; - if (jiraToken) data["JIRA_API_TOKEN"] = jiraToken; - for (const { key, value } of secrets) { - if (!key) continue; - if (FIXED_KEYS.includes(key as typeof FIXED_KEYS[number])) continue; - data[key] = value ?? ""; - } - - updateSecretsMutation.mutate( - { - projectName, - secrets: Object.entries(data).map(([key, value]) => ({ key, value })), - }, - { - onSuccess: () => { - successToast("Secrets saved successfully!"); - }, - onError: (error) => { - const message = error instanceof Error ? error.message : "Failed to save secrets"; - errorToast(message); - }, - } - ); - }, - onError: (error) => { - const message = error instanceof Error ? error.message : "Failed to save secret config"; - errorToast(message); - }, - } - ); - }; - - const addSecretRow = () => { - setSecrets((prev) => [...prev, { key: "", value: "" }]); - }; - - const removeSecretRow = (idx: number) => { - setSecrets((prev) => prev.filter((_, i) => i !== idx)); - }; - - return ( -
- - Project Settings} - description={<>{projectName}} - actions={ - - } - /> - - {/* Only show project metadata editor on OpenShift */} - {project?.isOpenShift ? ( - - - Edit Project - Rename display name or update description - - -
- - setFormData((prev) => ({ ...prev, displayName: e.target.value }))} - placeholder="My Awesome Project" - maxLength={100} - /> -
-
- - -
- -
- - -
- -
-
-
- - - - - - - diff --git a/components/frontend/static-prototype/integrations/page.html b/components/frontend/static-prototype/integrations/page.html deleted file mode 100644 index b7ab3a411..000000000 --- a/components/frontend/static-prototype/integrations/page.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - Integrations - Ambient Code Platform - - - -
-
-
- -
-
- - -
-
-
-
-
- - - -
-
-
-
-
-
- - - -
-
-

GitHub

-

Connect to GitHub repositories

-
-
-
-
-
-
-
- Not Connected -
-
- Connect to GitHub to manage repositories and create pull requests -
-
- -
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/new/page.html b/components/frontend/static-prototype/projects/new/page.html deleted file mode 100644 index df43d831c..000000000 --- a/components/frontend/static-prototype/projects/new/page.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - Create New Workspace - Ambient Code Platform - - - -
-
-
- -
-
- - -
-
-
-
-
- - - -
-
-
-

Workspace Details

-

Provide basic information about your workspace

-
-
-
-
- - - Must be lowercase, alphanumeric with hyphens -
- -
- - -
- -
- - -
- -
- - Cancel -
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html b/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html deleted file mode 100644 index 973d0d583..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/create-api-tests/page.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - create-api-tests - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
- -
-
-
-
DU
-
-
You
-
Write comprehensive API tests for the authentication endpoints we created
-
-
- -
-
AI
-
-
Claude
-
I'll create comprehensive API tests for your authentication endpoints. Let me start with testing the registration, login, and token validation endpoints...
-
-
- -
-
DU
-
-
You
-
Make sure to test edge cases like invalid emails and weak passwords
-
-
- -
-
AI
-
-
Claude
-
Excellent point! I'll include comprehensive edge case testing including invalid email formats, weak passwords, duplicate registrations, and malformed requests. Here are the test suites...
-
-
- -
-
DU
-
-
You
-
Perfect! Also add tests for JWT token expiration and refresh
-
-
- -
-
AI
-
-
Claude
-
Done! I've added comprehensive JWT testing including token expiration, refresh token flow, and invalid token handling. All tests are now complete and passing. ✅
-
-
-
- -
- - -
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html b/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html deleted file mode 100644 index 03c6369da..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/implement-login-flow/page.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - implement-login-flow - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
- -
-
-
-
DU
-
-
You
-
Create user login and registration endpoints with proper validation and security
-
-
- -
-
AI
-
-
Claude
-
I'll help you create secure login and registration endpoints. Let me start by setting up the user model with proper password hashing and validation...
-
-
- -
-
DU
-
-
You
-
Make sure to include JWT token generation and email validation
-
-
- -
-
AI
-
-
Claude
-
Absolutely! I'll implement JWT token generation for authentication and comprehensive email validation. Here's the updated user model with bcrypt password hashing and JWT integration...
-
-
-
- -
- - -
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/info/page.html b/components/frontend/static-prototype/projects/sample-workspace/info/page.html deleted file mode 100644 index 5e339fcfd..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/info/page.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - Project Information - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-
-

Project Information

-
-
-
- Created: 2 days ago -
-
- Status: - Active -
-
-
- -
-
-

Quick Stats

-
-
-
- RFE Workspaces: 3 -
-
- Active Sessions: 2 -
-
- API Keys: 1 -
-
- Team Members: 5 -
-
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/keys/page.html b/components/frontend/static-prototype/projects/sample-workspace/keys/page.html deleted file mode 100644 index 4d7f33097..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/keys/page.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - - API Keys - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-
-
-

API Keys

-

API keys provide secure access to external services and integrations

-
-
- - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameCreatedLast UsedRoleActions
-
Production API Key
-
For production deployments and CI/CD
-
1 week ago2 hours agoAdmin - -
-
Development Key
-
For local development and testing
-
2 weeks ago1 day agoAdmin - -
-
Monitoring Key
-
Read-only access for monitoring tools
-
3 days agoNeverAdmin - -
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html b/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html deleted file mode 100644 index f1b9dbd34..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/optimize-queries/headless.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - - optimize-queries - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
- -
-
-
-

Session Configuration

-
-
-
- Task: Optimize database queries for better performance -
-
- Model: claude-3.5-sonnet -
-
- Mode: Headless -
-
- Duration: 18 minutes -
-
- Status: - - - - - Completed - -
-
-
- -
-
-

Performance Results

-
-
-
-
- Query Optimization - 100% -
-
-
-
-
-
-
✓ Analyzed slow queries
-
✓ Added database indexes
-
✓ Optimized JOIN operations
-
✓ Reduced query time by 75%
-
✓ Updated documentation
-
-
-
-
- -
-
-
-

Execution Log

- -
-
-
-
-
- 14:15:30 - [INFO] Session started: Optimize database queries for better performance -
-
- 14:15:32 - [INFO] Analyzing database query performance -
-
- 14:16:15 - [WARNING] Found 5 slow queries without proper indexing -
-
- 14:16:45 - [INFO] Creating optimized database indexes -
-
- 14:18:22 - [SUCCESS] Database indexes created successfully -
-
- 14:19:10 - [INFO] Optimizing JOIN operations and subqueries -
-
- 14:21:35 - [SUCCESS] Query performance improved by 75% -
-
- 14:22:15 - [INFO] Updating query documentation -
-
- 14:23:48 - [SUCCESS] Database optimization completed successfully -
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/page.html b/components/frontend/static-prototype/projects/sample-workspace/page.html deleted file mode 100644 index af7c4813f..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/page.html +++ /dev/null @@ -1,1059 +0,0 @@ - - - - - - sample-workspace - Ambient Code Platform - - - -
-
-
- -
-
- - -
-
-
-
-
- - - -
-
- - -
- - -
-
-
-
-

Agentic Sessions

-
- - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Session NameStatusModeModelCreated
-
-
implement-login-flow
-
Create user login and registration endpoints
-
-
Runninginteractiveclaude-3.5-sonnet4 hours ago
-
-
setup-database
-
Initialize PostgreSQL database with user tables
-
-
Completedheadlessclaude-3.5-sonnet1 day ago
-
-
create-api-tests
-
Write comprehensive API tests for authentication endpoints
-
-
Completedinteractiveclaude-3.5-sonnet30 minutes ago
-
-
optimize-queries
-
Optimize database queries for better performance
-
-
Completedheadlessclaude-3.5-sonnet2 hours ago
-
-
-
- - - - - - - - - - - - -
-
-
- - - - - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html b/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html deleted file mode 100644 index b6c91c929..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/permissions/page.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - Permissions - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-
-
-

Sharing

-

Users and groups with access to this project and their roles

-
-
- - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Users/GroupsTypeRoleActions
-
-
john.doe@company.com
-
Project Owner
-
-
UserAdmin - -
-
-
development-team
-
5 members
-
-
GroupView - -
-
-
sarah.admin@company.com
-
Senior Developer
-
-
UserAdmin - -
-
-
qa-team
-
3 members
-
-
GroupView - -
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html b/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html deleted file mode 100644 index 81987f1d4..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/rfe/page.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - RFE Workspaces - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-
-

User Authentication System

- Planning -
-
-

Implement secure user authentication with JWT tokens and role-based access control.

-
- Repository: github.com/company/auth-service -
-
- Branch: feature/user-auth -
-
- Created: 2 hours ago -
-
- - -
-
-
- -
-
-

API Gateway

- In Progress -
-
-

Central API gateway for microservices with rate limiting and request routing.

-
- Repository: github.com/company/api-gateway -
-
- Branch: feature/gateway-v2 -
-
- Created: 1 day ago -
-
- - -
-
-
- -
-
-

Database Migration Tool

- Completed -
-
-

Automated database migration and versioning system for production deployments.

-
- Repository: github.com/company/db-migrator -
-
- Branch: main -
-
- Created: 3 days ago -
-
- - -
-
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html b/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html deleted file mode 100644 index 9edf4e635..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/session-1/headless.html +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - session-1 (Headless) - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
- -
-
-
-

Session Configuration

-
-
-
- Task: Create user authentication system -
-
- Model: claude-3.5-sonnet -
-
- Mode: Headless -
-
- Timeout: 30 minutes -
-
- Status: - - - - - Running - -
-
-
- -
-
-

Progress

-
-
-
-
- Overall Progress - 65% -
-
-
-
-
-
-
✓ Repository cloned
-
✓ Dependencies installed
-
⏳ Creating authentication models
-
⏸️ Writing tests
-
⏸️ Documentation update
-
-
-
-
- -
-
-
-

Execution Log

- -
-
-
-
-
- 13:45:23 - [INFO] Session started with task: Create user authentication system -
-
- 13:45:24 - [INFO] Cloning repository from https://github.com/company/auth-service.git -
-
- 13:45:28 - [SUCCESS] Repository cloned successfully -
-
- 13:45:29 - [INFO] Installing dependencies... -
-
- 13:46:15 - [SUCCESS] Dependencies installed successfully -
-
- 13:46:16 - [INFO] Analyzing existing codebase structure -
-
- 13:46:22 - [INFO] Creating User model with authentication fields -
-
- 13:46:35 - [WORKING] Implementing password hashing and validation... -
-
- 13:46:42 - [INFO] Adding JWT token generation methods -
-
- 13:47:01 - [INFO] Creating authentication middleware -
-
-
-
- -
-
-

Session Actions

-
-
-
- - - -
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html b/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html deleted file mode 100644 index 53100742f..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/session-1/page.html +++ /dev/null @@ -1,2692 +0,0 @@ - - - - - - session-1 - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- -
- -
- -
-
-
- - -
- - -
-
Workflows provide a structured processes for Ambient Code Platform agents to follow and achieve complex goals.
-
- - - - - - -
-
-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
- - -
-
-
-
ACP
-
-
ACP
-
-
-
-
- -
- - - - - - - - -
-
-
-
- - - - - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html b/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html deleted file mode 100644 index cf2dc0034..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/sessions/page.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - Sessions - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-

Agentic Sessions

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Session NameStatusModelStartedDurationActions
-
-
implement-login-flow
-
Create user login and registration endpoints
-
-
Completedclaude-3.5-sonnet4 hours ago23 minutes - -
-
-
setup-database
-
Initialize PostgreSQL database with user tables
-
-
Failedclaude-3.5-sonnet1 day ago12 minutes - -
-
-
create-api-tests
-
Write comprehensive API tests for authentication endpoints
-
-
Runningclaude-3.5-sonnet30 minutes ago30 minutes - -
-
-
optimize-queries
-
Optimize database queries for better performance
-
-
Pendingclaude-3.5-sonnet-- - -
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/settings/page.html b/components/frontend/static-prototype/projects/sample-workspace/settings/page.html deleted file mode 100644 index 46fad4db0..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/settings/page.html +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - Settings - sample-workspace - Ambient Code Platform - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
-
- - -
-
-
-

General Settings

-

Basic project configuration

-
-
-
-
- - - Project name cannot be changed after creation -
-
- - -
-
- - -
- -
-
-
- -
-
-

Runner Secrets

-

Configure the Secret and manage key/value pairs used by workspace runners.

-
-
-
-
- - -
- -
- - - Required for running agentic sessions -
- -
-
-

Additional Secrets

- -
- -
-
-
- -
-
- -
- -
- -
-
- -
-
- -
- -
-
-
- - -
-
-
- -
-
-

Resource Limits

-

Configure resource limits for sessions and workspaces

-
-
-
-
- - -
-
- - -
-
- - -
- -
-
-
- -
-
-

Danger Zone

-

Irreversible and destructive actions

-
-
-
-
-
Archive Project
-
Archive this project to make it read-only
-
- -
-
-
-
Delete Project
-
Permanently delete this project and all its data
-
- -
-
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html b/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html deleted file mode 100644 index 25f775a06..000000000 --- a/components/frontend/static-prototype/projects/sample-workspace/setup-database/headless.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - - - setup-database - sample-workspace - Ambient Code Platform - - - - -
-
-
- -
- -
- - -
-
-
-
-
- - - -
- -
-
-
-

Session Configuration

-
-
-
- Task: Initialize PostgreSQL database with user tables -
-
- Model: claude-3.5-sonnet -
-
- Mode: Headless -
-
- Duration: 12 minutes -
-
- Status: - - - - - Completed - -
-
-
- -
-
-

Results Summary

-
-
-
-
- Overall Progress - 100% -
-
-
-
-
-
-
✓ Database schema created
-
✓ User table with constraints
-
✓ Password hashing implemented
-
✓ Migration scripts generated
-
✓ Initial data seeded
-
-
-
-
- -
-
-
-

Execution Log

- -
-
-
-
-
- 12:30:15 - [INFO] Session started: Initialize PostgreSQL database with user tables -
-
- 12:30:16 - [INFO] Analyzing existing database structure -
-
- 12:30:22 - [INFO] Creating users table schema -
-
- 12:31:05 - [SUCCESS] Users table created with proper constraints -
-
- 12:31:08 - [INFO] Adding password hashing utilities -
-
- 12:31:45 - [SUCCESS] Password hashing implemented with bcrypt -
-
- 12:32:12 - [INFO] Creating database migration scripts -
-
- 12:33:01 - [SUCCESS] Migration scripts generated -
-
- 12:33:15 - [INFO] Seeding initial user data -
-
- 12:33:28 - [SUCCESS] Database initialization completed successfully -
-
-
-
-
- - - - diff --git a/components/frontend/static-prototype/rfe.md b/components/frontend/static-prototype/rfe.md deleted file mode 100644 index 387d4720f..000000000 --- a/components/frontend/static-prototype/rfe.md +++ /dev/null @@ -1,1092 +0,0 @@ -# RFE: Visual Redesign of Red Hat OpenShift AI (RHOAI) 3.0 Dashboard - -## Executive Summary - -This Request for Enhancement (RFE) proposes three distinct visual redesign directions for the Red Hat OpenShift AI (RHOAI) 3.0 dashboard to address the core challenge faced by AI Platform Engineers like Paula: **efficiently finding and evaluating production-ready AI models among thousands of options**. - -The current dashboard, while functional, presents a traditional enterprise interface that doesn't leverage modern AI-centric design patterns or optimize for the unique workflows of AI practitioners. This redesign focuses on transforming the user experience from a data-heavy administrative interface to an intelligent, task-oriented platform that accelerates model discovery and deployment decisions. - -## Current State Analysis - -### Existing Architecture -- **Framework**: React with TypeScript, PatternFly React components -- **Navigation**: Traditional sidebar navigation with hierarchical structure -- **Layout**: Standard enterprise dashboard with card-based model catalog -- **Feature Management**: Comprehensive feature flag system supporting MVP mode vs full feature set -- **Components**: Heavy use of PatternFly components (Cards, Tables, Forms, Modals, Dropdowns) - -### Current User Journey Pain Points -1. **Cognitive Overload**: Thousands of models presented in basic card/table format -2. **Inefficient Filtering**: Multiple separate filter interfaces without visual feedback -3. **Limited Comparison**: No side-by-side model comparison capabilities -4. **Static Information**: Performance metrics buried in text rather than visual indicators -5. **Context Switching**: Frequent navigation between catalog, registry, and deployment sections - -### Technical Foundation -- **PatternFly Integration**: Extensive use of existing components provides solid accessibility foundation -- **Feature Flags**: Robust system for MVP/full feature mode switching -- **State Management**: Context API for global state, component-level state for UI interactions -- **Routing**: React Router with dynamic route generation based on feature flags - -## User Persona: Paula - AI Platform Engineer - -**Primary Goal**: Find production-ready AI models that balance performance, cost, and specific use case requirements - -**Key Workflows**: -1. **Model Discovery**: Search through thousands of models using multiple criteria -2. **Performance Evaluation**: Compare latency, throughput, accuracy, and resource requirements -3. **Compatibility Assessment**: Verify model compatibility with existing infrastructure -4. **Deployment Planning**: Understand deployment requirements and costs -5. **Monitoring Setup**: Configure monitoring and alerting for deployed models - -**Success Metrics**: -- Time to find relevant models reduced by 60% -- Improved task completion rates for model selection workflows -- Reduced cognitive load when comparing multiple models -- Increased user satisfaction with filtering and search capabilities - ---- - -# Design Direction 1: "AI-First Visual Intelligence" - -## Philosophy -Treat AI models as visual, interactive objects rather than data rows. Transform the dashboard into an intelligent visual workspace where data visualization, interactive filtering, and AI-powered recommendations create an intuitive model discovery experience. - -## User Journey: Paula's Model Discovery Workflow - -### 1. Landing Experience -Paula arrives at a **Visual Model Universe** - a dynamic, interactive visualization showing all available models as nodes in a network graph, clustered by use case, provider, and performance characteristics. - -### 2. Intelligent Filtering -She uses **Visual Filter Sliders** to narrow down options: -- Latency requirement: Drag slider to <100ms -- Cost threshold: Visual budget indicator shows real-time cost implications -- Hardware compatibility: Interactive hardware requirement visualization - -### 3. AI-Powered Recommendations -The **Recommendation Engine** surfaces relevant models based on her query: "Customer service chatbot, production-ready, <100ms latency" with confidence scores and reasoning. - -### 4. Visual Comparison -Paula selects 3-4 models for **Side-by-Side Visual Comparison** with interactive performance charts, compatibility matrices, and deployment requirement visualizations. - -### 5. Workflow Integration -She connects her selected model to MCP servers and agents using the **Visual Workflow Builder** - a drag-and-drop interface showing data flow and dependencies. - -## Key UI Components - -### 1. Visual Model Universe -``` -┌─────────────────────────────────────────────────────────┐ -│ ○ Interactive Network Graph │ -│ ├── Nodes: Models (size = popularity, color = type) │ -│ ├── Clusters: Auto-grouped by ML similarity │ -│ ├── Zoom/Pan: Smooth navigation with mini-map │ -│ └── Search Overlay: Highlights matching nodes │ -└─────────────────────────────────────────────────────────┘ -``` - -### 2. Smart Filter Panel -``` -┌─────────────────────────────────────────────────────────┐ -│ 🎛️ Visual Performance Sliders │ -│ ├── Latency: [====●----] <100ms (23 models) │ -│ ├── Accuracy: [======●--] >95% (45 models) │ -│ ├── Cost/Hour: [$●--------] <$2.50 (67 models) │ -│ └── Hardware: [GPU Memory Visualization] │ -│ │ -│ 🎯 Use Case Tags (Visual Bubbles) │ -│ ├── [NLP] [Computer Vision] [Code Generation] │ -│ └── [Multimodal] [Reasoning] [Translation] │ -│ │ -│ 🤖 AI Recommendations │ -│ ├── "Based on your criteria, try granite-7b-code" │ -│ └── Confidence: ████████░░ 85% │ -└─────────────────────────────────────────────────────────┘ -``` - -### 3. Enhanced Model Cards -``` -┌─────────────────────────────────────────────────────────┐ -│ 📊 granite-7b-code:1.1 [⭐ 4.8/5] │ -│ ├── Performance Radar Chart │ -│ │ ├── Speed: ████████░░ │ -│ │ ├── Accuracy: ██████░░░░ │ -│ │ └── Efficiency: ████████░░ │ -│ ├── Compatibility Badges │ -│ │ ├── ✅ CUDA 12.0 ✅ 16GB RAM ⚠️ Requires A100 │ -│ ├── Live Deployment Status │ -│ │ └── 🟢 23 active deployments, avg 45ms latency │ -│ └── Quick Actions: [Compare] [Deploy] [Details] │ -└─────────────────────────────────────────────────────────┘ -``` - -### 4. Multi-Model Comparison View -``` -┌─────────────────────────────────────────────────────────┐ -│ 📈 Performance Comparison (3 models selected) │ -│ ├── Overlay Chart: Latency vs Accuracy │ -│ │ ├── Model A: ● (45ms, 94%) │ -│ │ ├── Model B: ● (78ms, 97%) │ -│ │ └── Model C: ● (23ms, 89%) │ -│ ├── Specification Matrix │ -│ │ ├──────────────┬─────────┬─────────┬─────────┐ │ -│ │ │ Metric │ Model A │ Model B │ Model C │ │ -│ │ ├──────────────┼─────────┼─────────┼─────────┤ │ -│ │ │ Parameters │ 7B │ 13B │ 3B │ │ -│ │ │ Memory │ 16GB │ 32GB │ 8GB │ │ -│ │ │ Cost/Hour │ $2.40 │ $4.80 │ $1.20 │ │ -│ │ └──────────────┴─────────┴─────────┴─────────┘ │ -│ └── Recommendation: Model C best for your use case │ -└─────────────────────────────────────────────────────────┘ -``` - -### 5. Visual Workflow Builder -``` -┌─────────────────────────────────────────────────────────┐ -│ 🔄 AI Workflow Designer │ -│ ├── [Model] ──→ [MCP Server] ──→ [Agent] ──→ [Output] │ -│ │ │ │ │ │ │ -│ │ granite-7b GitHub MCP Customer Response │ -│ │ Service │ -│ ├── Drag & Drop Components │ -│ ├── Real-time Validation │ -│ └── Performance Prediction: ~67ms end-to-end │ -└─────────────────────────────────────────────────────────┘ -``` - -## Information Architecture - -``` -RHOAI Dashboard (AI-First Visual Intelligence) -├── Visual Model Universe (landing page) -│ ├── Interactive Network Graph (main visualization) -│ ├── Smart Filter Panel (left sidebar) -│ │ ├── Visual Performance Sliders -│ │ ├── Use Case Tag Cloud -│ │ └── AI Recommendation Engine -│ ├── Model Detail Overlay (contextual) -│ └── Quick Action Toolbar (bottom) -├── Comparison Workspace -│ ├── Multi-Model Performance Charts -│ ├── Specification Matrix -│ └── Deployment Cost Calculator -├── Workflow Builder -│ ├── Visual Pipeline Designer -│ ├── Component Library -│ └── Performance Simulator -└── Deployment Dashboard - ├── Live Status Visualization - ├── Performance Monitoring Charts - └── Alert Management -``` - -## Visual Design Language - -### Color Palette -- **Primary**: Deep Blue (#0066CC) - Trust, intelligence -- **Secondary**: Vibrant Teal (#17A2B8) - Innovation, technology -- **Accent**: Warm Orange (#FF6B35) - Energy, action -- **Success**: Green (#28A745) - Deployed, healthy -- **Warning**: Amber (#FFC107) - Attention needed -- **Error**: Red (#DC3545) - Critical issues -- **Neutral**: Grays (#F8F9FA to #343A40) - Background, text - -### Typography -- **Headers**: Red Hat Display (Bold, 24-32px) -- **Body**: Red Hat Text (Regular, 14-16px) -- **Code/Metrics**: Red Hat Mono (Regular, 12-14px) -- **Emphasis**: Red Hat Text (Medium, 16-18px) - -### Spacing & Layout -- **Grid**: 8px base unit, 24px component spacing -- **Cards**: 16px padding, 8px border radius, subtle shadows -- **Interactive Elements**: 44px minimum touch target -- **Whitespace**: Generous spacing for visual breathing room - -### Animation & Interaction -- **Micro-interactions**: 200ms ease-in-out transitions -- **Loading States**: Skeleton screens with shimmer effects -- **Hover States**: Subtle elevation and color changes -- **Focus States**: High-contrast outlines for accessibility - -## Technical Considerations - -### PatternFly Integration (80% Reuse Target) -- **Reuse**: Card, Button, Form, Select, Modal, Tooltip, Progress, Label -- **Extend**: Custom chart components using Recharts with PatternFly theming -- **New Components**: - - `ModelUniverseGraph` (D3.js-based network visualization) - - `VisualFilterPanel` (Custom sliders with real-time feedback) - - `ModelComparisonMatrix` (Interactive specification table) - - `WorkflowBuilder` (Drag-and-drop pipeline designer) - - `PerformanceRadarChart` (Model capability visualization) - -### React Architecture -``` -src/ -├── components/ -│ ├── ai-hub/ -│ │ ├── ModelUniverse/ -│ │ │ ├── NetworkGraph.tsx -│ │ │ ├── FilterPanel.tsx -│ │ │ └── ModelCard.tsx -│ │ ├── Comparison/ -│ │ │ ├── ComparisonView.tsx -│ │ │ └── PerformanceChart.tsx -│ │ └── Workflow/ -│ │ ├── WorkflowBuilder.tsx -│ │ └── ComponentLibrary.tsx -│ └── shared/ -│ ├── Charts/ -│ └── Visualizations/ -├── hooks/ -│ ├── useModelRecommendations.ts -│ ├── useVisualFilters.ts -│ └── useWorkflowValidation.ts -└── utils/ - ├── chartHelpers.ts - └── performanceCalculations.ts -``` - -### Performance Optimizations -- **Virtual Scrolling**: React-window for large model lists (5,000+ items) -- **Lazy Loading**: Code splitting for heavy visualization components -- **Memoization**: React.memo for expensive chart re-renders -- **Debouncing**: 300ms debounce for filter inputs -- **Caching**: React Query with 5-minute cache for model data - -### Data Management -- **GraphQL API**: Flexible queries for model metadata and performance metrics -- **Real-time Updates**: WebSocket connections for live deployment status -- **Optimistic Updates**: Immediate UI feedback for user actions -- **Progressive Loading**: Initial 50 models, infinite scroll for more - -## Accessibility Features - -### Keyboard Navigation -- **Tab Order**: Filter panel → Model cards → Action buttons → Comparison view -- **Shortcuts**: - - `/` to focus search - - `Cmd+K` for command palette - - `Escape` to close modals/overlays - - Arrow keys for graph navigation - -### Screen Reader Support -- **ARIA Labels**: Comprehensive labeling for all interactive elements -- **Live Regions**: Announce filter results and recommendations -- **Alternative Text**: Detailed descriptions for all charts and visualizations -- **Data Tables**: Accessible alternatives for all visual comparisons - -### Visual Accessibility -- **High Contrast**: WCAG AA compliant color ratios (4.5:1 minimum) -- **Focus Indicators**: 2px high-contrast outlines -- **Text Scaling**: Support up to 200% zoom without horizontal scrolling -- **Motion Reduction**: Respect `prefers-reduced-motion` settings - -## Mobile/Responsive Design - -### Breakpoints -- **Mobile**: 320px - 767px (Stacked layout, touch-optimized) -- **Tablet**: 768px - 1023px (Hybrid layout, collapsible panels) -- **Desktop**: 1024px+ (Full layout, multi-panel views) - -### Mobile Adaptations -- **Navigation**: Collapsible hamburger menu -- **Filters**: Bottom sheet modal for filter panel -- **Cards**: Full-width stacked layout -- **Comparison**: Swipeable carousel for model comparison -- **Touch Targets**: Minimum 44px for all interactive elements - -## Performance Impact Assessment - -### Rendering Optimizations -- **Canvas Rendering**: Use HTML5 Canvas for network graphs with >1000 nodes -- **WebGL**: Hardware acceleration for complex visualizations -- **Virtual DOM**: Minimize re-renders with React.memo and useMemo -- **Intersection Observer**: Lazy load off-screen model cards - -### Bundle Size Impact -- **Estimated Addition**: +150KB gzipped for visualization libraries -- **Code Splitting**: Lazy load heavy components (WorkflowBuilder, NetworkGraph) -- **Tree Shaking**: Import only used chart components -- **CDN Assets**: Serve large datasets from CDN with compression - -### Memory Management -- **Cleanup**: Proper cleanup of D3.js event listeners and timers -- **Garbage Collection**: Avoid memory leaks in long-running visualizations -- **Data Pagination**: Limit in-memory model data to 500 items max - ---- - -# Design Direction 2: "Enterprise Command Center" - -## Philosophy -Transform the dashboard into a mission-critical control center optimized for power users who need dense information display, advanced filtering capabilities, and efficient bulk operations. Emphasize data density, customization, and keyboard-driven workflows. - -## User Journey: Paula's Power User Workflow - -### 1. Customizable Dashboard Landing -Paula arrives at her **Personalized Command Center** with customizable widgets showing her most relevant data: recent deployments, model performance alerts, and saved filter sets. - -### 2. Advanced Search & Filtering -She uses the **Command Palette** (Cmd+K) to quickly execute complex queries: "Show GPU models under $3/hour with >95% accuracy deployed in last 30 days" - -### 3. Bulk Operations -Paula selects multiple models using **Batch Selection** and performs bulk actions: compare specifications, export data, or queue for deployment testing. - -### 4. Real-time Monitoring -The **Live Monitoring Dashboard** shows real-time metrics for all deployed models with customizable alerts and drill-down capabilities. - -### 5. Efficient Navigation -She navigates using **Keyboard Shortcuts** and **Breadcrumb Navigation** without touching the mouse, maintaining focus on critical tasks. - -## Key UI Components - -### 1. Customizable Dashboard Widgets -``` -┌─────────────────────────────────────────────────────────┐ -│ 📊 Command Center Dashboard (Drag & Drop Layout) │ -│ ├─────────────────┬─────────────────┬─────────────────┤ │ -│ │ 🎯 Quick Filters │ 📈 Performance │ 🚨 Alerts │ │ -│ │ ├─ Production │ │ ┌─ Latency ──┐ │ │ ⚠️ Model A │ │ -│ │ ├─ <100ms │ │ │ ████████░░ │ │ │ High CPU │ │ -│ │ ├─ GPU Ready │ │ └─ Accuracy ─┘ │ │ 🔴 Model B │ │ -│ │ └─ [23 models] │ │ │ │ Offline │ │ -│ ├─────────────────┼─────────────────┼─────────────────┤ │ -│ │ 📋 Recent Models│ 💰 Cost Monitor │ 🔧 Quick Actions│ │ -│ │ ├─ granite-7b │ │ This Month: │ │ ├─ Deploy │ │ -│ │ ├─ llama-3.1 │ │ $2,847 / $5K │ │ ├─ Compare │ │ -│ │ └─ mistral-7b │ │ ████████░░░░░ │ │ └─ Export │ │ -│ └─────────────────┴─────────────────┴─────────────────┘ │ -└─────────────────────────────────────────────────────────┘ -``` - -### 2. Advanced Command Palette -``` -┌─────────────────────────────────────────────────────────┐ -│ 🔍 Command Palette (Cmd+K) │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ > deploy granite-7b to production │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ 📋 Suggestions: │ -│ ├── 🚀 Deploy model to production Cmd+D │ -│ ├── 📊 Compare selected models Cmd+C │ -│ ├── 📁 Export model specifications Cmd+E │ -│ ├── 🔍 Filter by latency <100ms /lat<100 │ -│ ├── 📈 Show performance dashboard Cmd+P │ -│ └── ⚙️ Open model settings Cmd+, │ -│ │ -│ 🕐 Recent Actions: │ -│ ├── Deployed llama-3.1-8b (2 min ago) │ -│ └── Compared 3 models (5 min ago) │ -└─────────────────────────────────────────────────────────┘ -``` - -### 3. Dense Information Table -``` -┌─────────────────────────────────────────────────────────┐ -│ 📋 Model Registry (Advanced Table View) │ -│ ├── 🔍 [Search] 🎛️ [Filters] 📊 [Columns] 💾 [Save] │ -│ ├─────┬──────────────┬─────────┬─────────┬─────────────┤ -│ │ ☐ │ Model Name │ Latency │ Accuracy│ Status │ -│ ├─────┼──────────────┼─────────┼─────────┼─────────────┤ -│ │ ☑ │ granite-7b │ 45ms ⚡ │ 94% ✅ │ 🟢 Active │ -│ │ ☑ │ llama-3.1-8b │ 67ms │ 96% ✅ │ 🟡 Warning │ -│ │ ☐ │ mistral-7b │ 23ms ⚡ │ 89% │ 🟢 Active │ -│ │ ☐ │ gpt-oss-120b │ 156ms │ 97% ✅ │ 🔴 Error │ -│ ├─────┴──────────────┴─────────┴─────────┴─────────────┤ -│ │ 📊 Bulk Actions: [Compare] [Deploy] [Export] [Delete]│ -│ │ 📈 Selected: 2 models | Total: 1,247 models │ -│ └─────────────────────────────────────────────────────┘ -└─────────────────────────────────────────────────────────┘ -``` - -### 4. Multi-Panel Comparison View -``` -┌─────────────────────────────────────────────────────────┐ -│ 📊 Split-Screen Comparison (2/3/4 panel layout) │ -│ ├─────────────────────┬─────────────────────────────────┤ -│ │ 🏷️ granite-7b-code │ 🏷️ llama-3.1-8b-instruct │ -│ │ ├─ Latency: 45ms │ ├─ Latency: 67ms │ -│ │ ├─ Accuracy: 94% │ ├─ Accuracy: 96% │ -│ │ ├─ Memory: 16GB │ ├─ Memory: 24GB │ -│ │ ├─ Cost: $2.40/hr │ ├─ Cost: $3.60/hr │ -│ │ └─ GPU: A100 │ └─ GPU: A100/H100 │ -│ ├─────────────────────┼─────────────────────────────────┤ -│ │ 📈 Performance Chart│ 📈 Performance Chart │ -│ │ ┌─ Latency Trend ─┐ │ ┌─ Latency Trend ─────────────┐│ -│ │ │ ████████████░░░ │ │ │ ████████░░░░░░░░░░░░░░░░░░░ ││ -│ │ └─ Last 24h ──────┘ │ └─ Last 24h ──────────────────┘│ -│ └─────────────────────┴─────────────────────────────────┤ -│ 🔄 Sync Scroll: ☑ | Export: [PDF] [CSV] | Add Panel: +│ -└─────────────────────────────────────────────────────────┘ -``` - -### 5. Real-Time Monitoring Dashboard -``` -┌─────────────────────────────────────────────────────────┐ -│ 🖥️ Live Deployment Monitor │ -│ ├─────────────────────┬─────────────────────────────────┤ -│ │ 🎯 Status Overview │ 📊 Performance Metrics │ -│ │ ├─ 🟢 Healthy: 23 │ ├─ Avg Latency: 67ms │ -│ │ ├─ 🟡 Warning: 3 │ ├─ Throughput: 1.2K req/s │ -│ │ ├─ 🔴 Critical: 1 │ ├─ Error Rate: 0.02% │ -│ │ └─ 🔵 Total: 27 │ └─ SLA Compliance: 99.8% │ -│ ├─────────────────────┴─────────────────────────────────┤ -│ │ 🚨 Active Alerts │ -│ │ ├─ ⚠️ granite-7b: High CPU usage (85%) │ -│ │ ├─ 🔴 llama-3.1: Connection timeout (3 failures) │ -│ │ └─ 🟡 mistral-7b: Memory usage above threshold │ -│ ├─────────────────────────────────────────────────────┤ -│ │ 📈 Historical Performance (Zoomable Timeline) │ -│ │ ┌─ Response Time ─────────────────────────────────────┐│ -│ │ │ ╭─╮ ││ -│ │ │ ╭───╯ ╰─╮ ╭─╮ ││ -│ │ │ ╯ ╰─────╯ ╰─╮ ││ -│ │ │ ╰──────────────────────────────││ -│ │ └─ 1h 6h 12h 24h 7d ──────────────────────┘│ -└─────────────────────────────────────────────────────────┘ -``` - -## Information Architecture - -``` -RHOAI Dashboard (Enterprise Command Center) -├── Customizable Dashboard (landing page) -│ ├── Widget Grid (main content - drag-and-drop) -│ │ ├── Model List Widget (configured queries) -│ │ ├── Performance Charts Widget (selected models) -│ │ ├── Deployment Status Widget (live monitoring) -│ │ ├── Cost Monitor Widget (budget tracking) -│ │ └── Quick Filters Widget (saved filter sets) -│ ├── Top Toolbar -│ │ ├── Command Palette (Cmd+K) -│ │ ├── Search Bar (/ to focus) -│ │ ├── Layout Selector (saved layouts dropdown) -│ │ └── Settings (dashboard configuration) -│ └── Status Bar (bottom) -│ ├── System Status -│ ├── Active Filters Count -│ └── Keyboard Shortcuts Help -├── Advanced Model Catalog -│ ├── Dense Table View (default) -│ │ ├── Sortable/Filterable Columns -│ │ ├── Bulk Selection & Actions -│ │ └── Inline Quick Actions -│ ├── Saved Queries Sidebar -│ │ ├── Predefined Filters -│ │ ├── Custom Query Builder -│ │ └── Recent Searches -│ └── Export & Reporting -│ ├── CSV/Excel Export -│ ├── PDF Reports -│ └── Scheduled Reports -├── Multi-Panel Comparison -│ ├── Split-Screen Layout (2/3/4 panels) -│ ├── Synchronized Navigation -│ ├── Diff Highlighting -│ └── Export Comparison Reports -└── Live Monitoring Center - ├── Real-time Metrics Dashboard - ├── Alert Management System - ├── Historical Performance Analytics - └── SLA Monitoring & Reporting -``` - -## Visual Design Language - -### Color Palette (Professional/High-Contrast) -- **Primary**: Navy Blue (#1F2937) - Authority, reliability -- **Secondary**: Steel Blue (#374151) - Professional, technical -- **Accent**: Electric Blue (#3B82F6) - Action, focus -- **Success**: Forest Green (#059669) - Healthy, operational -- **Warning**: Amber (#D97706) - Attention, caution -- **Error**: Crimson (#DC2626) - Critical, urgent -- **Neutral**: Cool Grays (#F9FAFB to #111827) - Background hierarchy - -### Typography (Information Dense) -- **Headers**: Red Hat Display (Bold, 18-24px) - Compact hierarchy -- **Body**: Red Hat Text (Regular, 13-14px) - Dense readability -- **Code/Data**: Red Hat Mono (Regular, 11-12px) - Technical precision -- **Labels**: Red Hat Text (Medium, 12-13px) - Clear identification - -### Layout Principles -- **Information Density**: Maximize data per screen real estate -- **Scannable Hierarchy**: Clear visual hierarchy for rapid scanning -- **Consistent Spacing**: 4px/8px grid for tight, organized layout -- **Functional Grouping**: Related data clustered with subtle borders - -### Interaction Patterns -- **Keyboard-First**: All actions accessible via keyboard shortcuts -- **Hover Details**: Rich tooltips with additional context -- **Contextual Menus**: Right-click menus for power user actions -- **Bulk Operations**: Multi-select with batch action capabilities - -## Technical Considerations - -### PatternFly Integration (85% Reuse Target) -- **Heavy Reuse**: Table, Toolbar, Dropdown, Modal, Form, Button, Card -- **Enhanced Components**: - - `AdvancedTable` (sortable, filterable, bulk selection) - - `CommandPalette` (fuzzy search, keyboard navigation) - - `DashboardWidget` (drag-and-drop, resizable) - - `MultiPanelLayout` (split-screen comparison) - - `MonitoringChart` (real-time data visualization) - -### React Architecture -``` -src/ -├── components/ -│ ├── command-center/ -│ │ ├── Dashboard/ -│ │ │ ├── DashboardGrid.tsx -│ │ │ ├── Widget.tsx -│ │ │ └── WidgetLibrary.tsx -│ │ ├── CommandPalette/ -│ │ │ ├── CommandPalette.tsx -│ │ │ └── CommandRegistry.ts -│ │ ├── AdvancedTable/ -│ │ │ ├── DataTable.tsx -│ │ │ ├── BulkActions.tsx -│ │ │ └── ColumnManager.tsx -│ │ └── Monitoring/ -│ │ ├── MetricsDashboard.tsx -│ │ ├── AlertManager.tsx -│ │ └── PerformanceChart.tsx -│ └── shared/ -│ ├── KeyboardShortcuts/ -│ └── ExportManager/ -├── hooks/ -│ ├── useKeyboardShortcuts.ts -│ ├── useBulkOperations.ts -│ ├── useRealTimeMetrics.ts -│ └── useDashboardLayout.ts -└── utils/ - ├── commandRegistry.ts - ├── exportHelpers.ts - └── keyboardNavigation.ts -``` - -### Performance Optimizations -- **Virtual Scrolling**: Handle tables with 10,000+ rows efficiently -- **Memoized Calculations**: Cache expensive sorting/filtering operations -- **Debounced Updates**: 150ms debounce for real-time search -- **Lazy Widget Loading**: Load dashboard widgets on demand -- **Efficient Re-renders**: Minimize table re-renders with React.memo - -### Data Management -- **Real-time WebSockets**: Live metrics and alert updates -- **Optimistic UI**: Immediate feedback for bulk operations -- **Background Sync**: Periodic data refresh without UI interruption -- **Offline Capability**: Cache critical data for offline viewing - -## Accessibility Features - -### Keyboard Navigation Excellence -- **Tab Order**: Logical flow through dense interface elements -- **Shortcuts**: Comprehensive keyboard shortcuts for all actions - - `Cmd+K`: Command palette - - `Cmd+F`: Advanced search - - `Cmd+A`: Select all in current view - - `Space`: Toggle selection - - `Enter`: Execute primary action - - `Escape`: Cancel/close current operation - -### Screen Reader Optimization -- **Table Navigation**: Proper table headers and navigation -- **Live Regions**: Announce real-time updates and alerts -- **Descriptive Labels**: Detailed ARIA labels for complex widgets -- **Status Announcements**: Clear feedback for bulk operations - -### Visual Accessibility -- **High Contrast Mode**: Enhanced contrast ratios (7:1 for text) -- **Focus Management**: Clear focus indicators throughout interface -- **Text Scaling**: Support 200% zoom with horizontal scrolling -- **Color Independence**: Information conveyed beyond color alone - -## Mobile/Responsive Design - -### Responsive Strategy -- **Desktop-First**: Optimized for desktop power users -- **Tablet Adaptation**: Collapsible panels, touch-friendly controls -- **Mobile Fallback**: Essential functions only, simplified interface - -### Mobile Adaptations -- **Navigation**: Collapsible command center with essential widgets -- **Tables**: Horizontal scroll with sticky columns -- **Comparison**: Stacked layout with swipe navigation -- **Monitoring**: Simplified metric cards with drill-down - -## Performance Impact Assessment - -### Rendering Performance -- **Table Virtualization**: Handle large datasets without performance degradation -- **Chart Optimization**: Canvas rendering for real-time metrics -- **Memory Management**: Efficient cleanup of real-time subscriptions -- **Bundle Splitting**: Lazy load monitoring and comparison components - -### Data Processing -- **Client-side Filtering**: Fast filtering for large datasets -- **Incremental Updates**: Efficient real-time data updates -- **Background Processing**: Web Workers for heavy calculations -- **Caching Strategy**: Intelligent caching for frequently accessed data - ---- - -# Design Direction 3: "Conversational AI Assistant" - -## Philosophy -Transform the primary interface into a natural language conversation where an AI assistant helps users discover, evaluate, and deploy models through intelligent dialogue. Minimize traditional UI elements in favor of contextual, conversation-driven interactions. - -## User Journey: Paula's Conversational Workflow - -### 1. Natural Language Query -Paula starts with a conversational query: "I need a production-ready model for customer service chatbots that responds in under 100ms and costs less than $3 per hour" - -### 2. Intelligent Clarification -The AI assistant asks clarifying questions: "What type of customer inquiries will this handle? Do you need multilingual support? Any specific compliance requirements?" - -### 3. Smart Recommendations -Based on the conversation, the assistant presents 3-4 tailored recommendations with explanations: "Based on your requirements, I recommend granite-7b-code because it excels at structured responses with 45ms average latency..." - -### 4. Guided Comparison -Paula asks: "How does granite-7b compare to llama-3.1 for my use case?" The assistant provides a contextual comparison with visual aids. - -### 5. Deployment Assistance -The assistant guides through deployment: "I can help you deploy granite-7b. Would you like me to configure it for your customer service environment?" - -## Key UI Components - -### 1. Conversational Interface -``` -┌─────────────────────────────────────────────────────────┐ -│ 🤖 RHOAI Assistant 🎤 🔊 ⚙️ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 👤 I need a production model for customer service │ │ -│ │ chatbots under 100ms latency │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 🤖 I can help you find the perfect model! Let me │ │ -│ │ ask a few questions to narrow down the options: │ │ -│ │ │ │ -│ │ • What type of customer inquiries? (FAQ, tech │ │ -│ │ support, sales, etc.) │ │ -│ │ • Do you need multilingual support? │ │ -│ │ • Any specific compliance requirements? │ │ -│ │ │ │ -│ │ 💡 Quick suggestions: │ │ -│ │ [FAQ Support] [Tech Support] [Sales Inquiries] │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ Type your message... 🎤 │ │ -│ └─────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────┘ -``` - -### 2. Contextual Model Cards -``` -┌─────────────────────────────────────────────────────────┐ -│ 🤖 Based on your needs, here are my top 3 recommendations:│ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 🥇 granite-7b-code:1.1 [Deploy] │ │ -│ │ ├── ⚡ 45ms avg latency (✅ meets your <100ms req) │ │ -│ │ ├── 💰 $2.40/hour (✅ under your $3 budget) │ │ -│ │ ├── 🎯 94% accuracy on customer service tasks │ │ -│ │ ├── 🏆 Why I recommend this: Excellent balance of │ │ -│ │ │ speed and accuracy, proven in production │ │ -│ │ └── [Tell me more] [Compare with others] [Deploy] │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 🥈 llama-3.1-8b-instruct [Deploy] │ │ -│ │ ├── ⚡ 67ms avg latency (✅ meets requirement) │ │ -│ │ ├── 💰 $3.60/hour (⚠️ slightly over budget) │ │ -│ │ ├── 🎯 96% accuracy (higher than granite-7b) │ │ -│ │ └── 🏆 Why consider: Better accuracy, multilingual │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ 💬 Would you like me to explain why I ranked these │ -│ models this way, or shall we dive deeper into one? │ -└─────────────────────────────────────────────────────────┘ -``` - -### 3. Smart Comparison View -``` -┌─────────────────────────────────────────────────────────┐ -│ 👤 "How does granite-7b compare to llama-3.1?" │ -│ │ -│ 🤖 Great question! Here's how they stack up for your │ -│ customer service use case: │ -│ │ -│ ┌─────────────────────┬─────────────────────────────────┤ -│ │ 🏷️ granite-7b-code │ 🏷️ llama-3.1-8b-instruct │ -│ ├─────────────────────┼─────────────────────────────────┤ -│ │ ⚡ Speed: 45ms │ ⚡ Speed: 67ms │ -│ │ 🎯 Accuracy: 94% │ 🎯 Accuracy: 96% │ -│ │ 💰 Cost: $2.40/hr │ 💰 Cost: $3.60/hr │ -│ │ 🌍 Languages: EN │ 🌍 Languages: 50+ │ -│ │ 📊 Production: ✅ │ 📊 Production: ✅ │ -│ └─────────────────────┴─────────────────────────────────┘ -│ │ -│ 💡 My recommendation: If you only need English and want │ -│ to stay under budget, go with granite-7b. If you │ -│ might expand internationally or need the highest │ -│ accuracy, llama-3.1 is worth the extra cost. │ -│ │ -│ 🎯 Quick actions: │ -│ [Deploy granite-7b] [Deploy llama-3.1] [See more options]│ -└─────────────────────────────────────────────────────────┘ -``` - -### 4. Guided Deployment Wizard -``` -┌─────────────────────────────────────────────────────────┐ -│ 👤 "Let's deploy granite-7b for my customer service" │ -│ │ -│ 🤖 Perfect choice! I'll guide you through the setup. │ -│ I've pre-configured everything based on our │ -│ conversation: │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 🚀 Deployment Configuration │ │ -│ │ ├── Model: granite-7b-code:1.1 │ │ -│ │ ├── Environment: Production │ │ -│ │ ├── Instance: A100 GPU (recommended for <100ms) │ │ -│ │ ├── Scaling: Auto-scale 1-5 instances │ │ -│ │ ├── Monitoring: Customer service metrics enabled │ │ -│ │ └── Budget Alert: $3/hour threshold │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ 💬 Everything look good? I can also: │ -│ • Set up A/B testing with llama-3.1 │ -│ • Configure custom monitoring for your KPIs │ -│ • Create alerts for latency spikes │ -│ │ -│ [Deploy Now] [Customize Settings] [Schedule Deployment] │ -└─────────────────────────────────────────────────────────┘ -``` - -### 5. Voice Interface Integration -``` -┌─────────────────────────────────────────────────────────┐ -│ 🎤 Voice Assistant Active 🔊 Speaking │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ 🌊 ████████████████████████████████████████████████ │ │ -│ │ "Show me models with latency under fifty │ │ -│ │ milliseconds for text generation" │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ 🤖 I found 12 models matching your criteria. The top │ -│ performers are granite-7b at 45ms, mistral-7b at │ -│ 23ms, and claude-3-haiku at 38ms. Would you like │ -│ me to show you the details or compare them? │ -│ │ -│ 🎯 Voice Commands: │ -│ • "Show details" - Display model specifications │ -│ • "Compare all three" - Side-by-side comparison │ -│ • "Deploy granite" - Start deployment process │ -│ • "Filter by cost" - Add cost filtering │ -│ │ -│ [🎤 Hold to Speak] [⌨️ Switch to Text] [🔇 Mute Voice] │ -└─────────────────────────────────────────────────────────┘ -``` - -### 6. Contextual Help & Learning -``` -┌─────────────────────────────────────────────────────────┐ -│ 🤖 I notice you often look for models under 100ms │ -│ latency. Here are some tips to help you find them │ -│ faster: │ -│ │ -│ 💡 Pro Tips: │ -│ • Use "fast models" as a shortcut for <100ms filter │ -│ • Try "production ready + fast" for pre-vetted options│ -│ • Ask "what's the fastest model for [use case]" │ -│ │ -│ 📚 Would you like me to: │ -│ • Create a saved search for your common criteria? │ -│ • Set up alerts for new fast models? │ -│ • Show you advanced filtering techniques? │ -│ │ -│ 🎯 Quick Actions: │ -│ [Create Saved Search] [Set Up Alerts] [Learn More] │ -│ │ -│ 💬 You can also say things like: │ -│ • "Find me something like granite-7b but faster" │ -│ • "What's new in the model catalog this week?" │ -│ • "Help me optimize costs for my current deployments" │ -└─────────────────────────────────────────────────────────┘ -``` - -## Information Architecture - -``` -RHOAI Dashboard (Conversational AI Assistant) -├── Main Conversation Interface -│ ├── Chat History (persistent, searchable) -│ ├── Message Input (text + voice) -│ ├── Quick Action Buttons (contextual) -│ └── Voice Controls (always available) -├── Contextual Overlays (triggered by conversation) -│ ├── Model Detail Cards -│ ├── Comparison Views -│ ├── Deployment Wizards -│ └── Performance Charts -├── Smart Suggestions Panel (adaptive) -│ ├── Conversation Starters -│ ├── Follow-up Questions -│ ├── Related Actions -│ └── Learning Resources -├── Traditional Fallback Navigation (collapsible) -│ ├── Model Catalog (simplified) -│ ├── Deployments (status only) -│ └── Settings (voice preferences) -└── Assistant Personality & Learning - ├── User Preference Learning - ├── Context Memory (session + long-term) - ├── Expertise Areas (model types, use cases) - └── Conversation History Analysis -``` - -## Visual Design Language - -### Color Palette (Conversational/Friendly) -- **Primary**: Warm Blue (#2563EB) - Trustworthy, intelligent -- **Secondary**: Soft Purple (#7C3AED) - Creative, innovative -- **Accent**: Vibrant Green (#10B981) - Positive, helpful -- **Assistant**: Cool Gray (#6B7280) - Neutral, professional -- **User**: Warm Gray (#374151) - Personal, human -- **Success**: Emerald (#059669) - Achievement, completion -- **Warning**: Amber (#F59E0B) - Caution, attention -- **Error**: Rose (#F43F5E) - Issues, problems - -### Typography (Conversational) -- **Headers**: Red Hat Display (Medium, 20-28px) - Friendly authority -- **Body/Chat**: Red Hat Text (Regular, 15-16px) - Readable conversation -- **Assistant**: Red Hat Text (Regular, 15px) - Consistent, clear -- **User**: Red Hat Text (Medium, 15px) - Slightly emphasized -- **Code/Data**: Red Hat Mono (Regular, 13-14px) - Technical precision - -### Layout Principles -- **Conversation Flow**: Chronological, chat-like interface -- **Contextual Density**: Information appears when relevant -- **Breathing Room**: Generous spacing for comfortable reading -- **Focus Management**: Single conversation thread with contextual overlays - -### Interaction Patterns -- **Natural Language**: Primary interaction through conversation -- **Voice Integration**: Seamless voice input and output -- **Contextual Actions**: Buttons appear based on conversation context -- **Progressive Disclosure**: Information revealed as needed - -## Technical Considerations - -### PatternFly Integration (60% Reuse Target) -- **Selective Reuse**: Card, Modal, Button, Form components for overlays -- **Custom Components**: - - `ConversationInterface` (chat-like message flow) - - `VoiceInput` (speech recognition integration) - - `ContextualOverlay` (smart information display) - - `SmartSuggestions` (AI-powered recommendations) - - `ConversationMemory` (context persistence) - -### React Architecture -``` -src/ -├── components/ -│ ├── conversation/ -│ │ ├── ChatInterface/ -│ │ │ ├── MessageThread.tsx -│ │ │ ├── MessageInput.tsx -│ │ │ └── VoiceControls.tsx -│ │ ├── Assistant/ -│ │ │ ├── AIResponse.tsx -│ │ │ ├── SmartSuggestions.tsx -│ │ │ └── ContextualCards.tsx -│ │ ├── Voice/ -│ │ │ ├── SpeechRecognition.tsx -│ │ │ ├── TextToSpeech.tsx -│ │ │ └── VoiceCommands.tsx -│ │ └── Overlays/ -│ │ ├── ModelDetails.tsx -│ │ ├── ComparisonView.tsx -│ │ └── DeploymentWizard.tsx -│ └── shared/ -│ ├── NaturalLanguage/ -│ └── ContextManager/ -├── hooks/ -│ ├── useConversation.ts -│ ├── useVoiceInterface.ts -│ ├── useAIAssistant.ts -│ └── useContextMemory.ts -├── services/ -│ ├── nlpService.ts -│ ├── voiceService.ts -│ ├── aiAssistant.ts -│ └── conversationMemory.ts -└── utils/ - ├── speechProcessing.ts - ├── contextAnalysis.ts - └── intentRecognition.ts -``` - -### AI/ML Integration -- **Natural Language Processing**: Intent recognition and entity extraction -- **Conversation Management**: Context tracking and memory -- **Voice Processing**: Speech-to-text and text-to-speech -- **Recommendation Engine**: ML-powered model suggestions -- **Learning System**: User preference adaptation - -### Performance Optimizations -- **Streaming Responses**: Real-time AI response generation -- **Voice Processing**: Local speech recognition when possible -- **Context Caching**: Efficient conversation memory management -- **Lazy Loading**: Load overlays and detailed views on demand -- **Offline Capability**: Basic conversation when network limited - -## Accessibility Features - -### Voice Interface Accessibility -- **Multiple Input Methods**: Voice, text, and traditional navigation -- **Voice Feedback**: Audio confirmation of actions -- **Speech Rate Control**: Adjustable speaking speed -- **Voice Commands**: Comprehensive voice control vocabulary - -### Screen Reader Excellence -- **Conversation Flow**: Proper reading order for chat interface -- **Live Regions**: Announce new messages and responses -- **Rich Descriptions**: Detailed descriptions of visual elements -- **Alternative Navigation**: Traditional navigation always available - -### Motor Accessibility -- **Voice Primary**: Reduce need for precise mouse/touch input -- **Large Touch Targets**: 44px minimum for all interactive elements -- **Keyboard Alternatives**: Full keyboard navigation support -- **Dwell Clicking**: Support for eye-tracking and dwell interfaces - -## Mobile/Responsive Design - -### Mobile-First Approach -- **Touch Optimized**: Large touch targets, swipe gestures -- **Voice Primary**: Emphasize voice input on mobile devices -- **Simplified UI**: Minimal chrome, focus on conversation -- **Offline Capability**: Basic functionality without network - -### Responsive Adaptations -- **Mobile**: Full-screen conversation interface -- **Tablet**: Split view with conversation + contextual panels -- **Desktop**: Multi-panel layout with traditional fallback options - -### Cross-Platform Voice -- **Native Integration**: Use platform voice APIs when available -- **Consistent Experience**: Same conversation across all devices -- **Sync Capability**: Conversation history syncs across devices - -## Performance Impact Assessment - -### AI/ML Processing -- **Edge Computing**: Local processing for basic NLP when possible -- **Cloud Integration**: Advanced AI features through API calls -- **Caching Strategy**: Cache common responses and user preferences -- **Progressive Enhancement**: Graceful degradation when AI unavailable - -### Voice Processing -- **Browser APIs**: Use native Web Speech API when supported -- **Fallback Options**: Text input always available -- **Bandwidth Optimization**: Compress voice data for transmission -- **Local Processing**: Client-side voice recognition when possible - -### Memory Management -- **Conversation Pruning**: Limit conversation history length -- **Context Compression**: Efficient storage of conversation context -- **Cleanup**: Proper cleanup of voice processing resources -- **Background Processing**: Handle AI responses without blocking UI - ---- - -# Implementation Recommendations - -## Phased Rollout Strategy - -### Phase 1: Foundation (Months 1-3) -- **Direction 2 (Command Center)**: Implement as primary interface - - Lowest risk, builds on existing patterns - - Immediate productivity gains for power users - - Establishes advanced filtering and bulk operations - -### Phase 2: Visual Enhancement (Months 4-6) -- **Direction 1 (Visual Intelligence)**: Add visual components - - Implement model visualization and comparison tools - - Add performance charts and recommendation engine - - Enhance with interactive filtering - -### Phase 3: AI Integration (Months 7-9) -- **Direction 3 (Conversational)**: Introduce AI assistant - - Start with basic natural language queries - - Add voice interface capabilities - - Implement learning and personalization - -## Technical Implementation Priority - -### High Priority (Must Have) -1. **Advanced Filtering System** (All Directions) -2. **Model Comparison Interface** (Directions 1 & 2) -3. **Real-time Performance Monitoring** (Direction 2) -4. **Responsive Design Foundation** (All Directions) - -### Medium Priority (Should Have) -1. **Visual Model Cards** (Direction 1) -2. **Command Palette** (Direction 2) -3. **Basic AI Recommendations** (Direction 3) -4. **Customizable Dashboards** (Direction 2) - -### Low Priority (Nice to Have) -1. **Network Graph Visualization** (Direction 1) -2. **Voice Interface** (Direction 3) -3. **Workflow Builder** (Direction 1) -4. **Advanced AI Learning** (Direction 3) - -## Success Metrics & KPIs - -### User Experience Metrics -- **Task Completion Time**: 60% reduction in model discovery time -- **User Satisfaction**: >4.5/5 rating for new interface -- **Feature Adoption**: >80% usage of new filtering capabilities -- **Error Reduction**: 50% fewer user errors in model selection - -### Technical Performance Metrics -- **Page Load Time**: <2 seconds for initial dashboard load -- **Filter Response Time**: <300ms for filter operations -- **Accessibility Score**: WCAG 2.1 AA compliance (100%) -- **Mobile Performance**: <3 seconds load time on 3G networks - -### Business Impact Metrics -- **Model Deployment Efficiency**: 40% faster deployment workflows -- **User Retention**: Increased daily active users -- **Support Ticket Reduction**: 30% fewer UI-related support requests -- **Training Time**: 50% reduction in new user onboarding time - -## Risk Mitigation - -### Technical Risks -- **Performance Impact**: Implement progressive loading and virtualization -- **Browser Compatibility**: Provide fallbacks for advanced features -- **Accessibility Regression**: Comprehensive testing throughout development -- **Data Security**: Ensure all new features maintain security standards - -### User Adoption Risks -- **Change Management**: Provide optional traditional interface during transition -- **Training Requirements**: Create comprehensive documentation and tutorials -- **Feature Complexity**: Implement progressive disclosure of advanced features -- **Feedback Integration**: Establish user feedback loops for continuous improvement - -## Conclusion - -These three design directions offer distinct approaches to solving Paula's core challenge of efficiently finding and evaluating AI models. Each direction can be implemented independently or combined to create a comprehensive solution that serves different user preferences and workflows. - -The **Enterprise Command Center** approach provides immediate value with minimal risk, while the **AI-First Visual Intelligence** direction offers innovative visualization capabilities. The **Conversational AI Assistant** represents the future of human-computer interaction for complex technical tasks. - -By implementing these designs with a focus on accessibility, performance, and user experience, RHOAI 3.0 can transform from a traditional enterprise dashboard into a modern, intelligent platform that accelerates AI adoption and deployment across organizations. \ No newline at end of file diff --git a/components/frontend/static-prototype/styles.css b/components/frontend/static-prototype/styles.css deleted file mode 100644 index d73bfb2ad..000000000 --- a/components/frontend/static-prototype/styles.css +++ /dev/null @@ -1,527 +0,0 @@ -/* vTeam Static Prototype Styles */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - line-height: 1.6; - color: #333; - background-color: #f8fafc; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 0 20px; -} - -/* Header */ -.header { - background: white; - border-bottom: 1px solid #e2e8f0; - padding: 1rem 0; - position: sticky; - top: 0; - z-index: 100; -} - -.header-content { - display: flex; - justify-content: space-between; - align-items: center; -} - -.logo { - font-size: 1.5rem; - font-weight: bold; - color: #000000; - text-decoration: none; -} - -.nav { - display: flex; - gap: 2rem; -} - -.nav a { - text-decoration: none; - color: #64748b; - font-weight: 500; - transition: color 0.2s; -} - -.nav a:hover, .nav a.active { - color: #1e40af; -} - -/* Page Header */ -.page-header { - background: white; - border-bottom: 1px solid #e2e8f0; - padding: 2rem 0; -} - -.page-header-content { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 2rem; -} - -.page-header-left { - flex: 1; -} - -.page-title { - font-size: 2rem; - font-weight: bold; - margin-bottom: 0.5rem; -} - -.page-description { - color: #64748b; - font-size: 1rem; -} - -.page-actions { - display: flex; - gap: 1rem; - align-items: center; - flex-shrink: 0; -} - -.page-actions .btn { - min-width: 140px; - height: 40px; - justify-content: center; - align-items: center; - padding: 0 1rem; -} - -/* Buttons */ -.btn { - padding: 0.5rem 1rem; - border: none; - border-radius: 0.375rem; - font-weight: 500; - cursor: pointer; - text-decoration: none; - display: inline-flex; - align-items: center; - gap: 0.5rem; - transition: all 0.2s; -} - -.btn-primary { - background: #1e40af; - color: white; -} - -.btn-primary:hover { - background: #1d4ed8; -} - -.btn-secondary { - background: white; - color: #374151; - border: 1px solid #d1d5db; -} - -.btn-secondary:hover { - background: #f9fafb; -} - -/* Cards */ -.card { - background: white; - border-radius: 0.5rem; - border: 1px solid #e2e8f0; - overflow: hidden; -} - -.card-header { - padding: 1.5rem; - border-bottom: 1px solid #e2e8f0; -} - -.card-title { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 0.5rem; -} - -.card-description { - color: #64748b; -} - -.card-content { - padding: 1.5rem; -} - -/* Tables */ -.table { - width: 100%; - border-collapse: collapse; -} - -.table th, -.table td { - text-align: left; - padding: 0.75rem; - border-bottom: 1px solid #e2e8f0; -} - -.table th { - font-weight: 600; - color: #374151; - background: #f8fafc; -} - -.table tr:hover { - background: #f8fafc; -} - -/* Status badges */ -.badge { - padding: 0.25rem 0.75rem; - border-radius: 9999px; - font-size: 0.75rem; - font-weight: 500; -} - -.badge-success { - background: #dcfce7; - color: #166534; -} - -.badge-warning { - background: #fef3c7; - color: #92400e; -} - -.badge-error { - background: #fee2e2; - color: #991b1b; -} - -.badge-info { - background: #dbeafe; - color: #1e40af; -} - -/* Tabs */ -.tabs { - margin-top: 2rem; -} - -.tab-list { - display: flex; - border-bottom: 1px solid #e2e8f0; - margin-bottom: 1.5rem; -} - -.tab-button { - padding: 0.75rem 1rem; - border: none; - background: none; - cursor: pointer; - color: #64748b; - font-weight: 500; - border-bottom: 2px solid transparent; -} - -.tab-button.active { - color: #1e40af; - border-bottom-color: #1e40af; -} - -.tab-content { - display: none; -} - -.tab-content.active { - display: block; -} - -/* Grid layouts */ -.grid { - display: grid; - gap: 1.5rem; -} - -.grid-2 { - grid-template-columns: repeat(2, 1fr); -} - -.grid-3 { - grid-template-columns: repeat(3, 1fr); -} - -@media (max-width: 768px) { - .grid-2, - .grid-3 { - grid-template-columns: 1fr; - } - - .page-header-content { - flex-direction: column; - align-items: stretch; - gap: 1rem; - } - - .page-actions { - justify-content: flex-start; - } - - .nav { - display: none; - } -} - -/* Breadcrumbs */ -.breadcrumbs { - display: flex; - align-items: center; - gap: 0.5rem; - margin-bottom: 1rem; - color: #64748b; - font-size: 0.875rem; -} - -.breadcrumbs a { - color: #1e40af; - text-decoration: none; -} - -.breadcrumbs a:hover { - text-decoration: underline; -} - -/* Project sidebar */ -.project-layout { - display: grid; - grid-template-columns: 250px 1fr; - gap: 2rem; - margin-top: 2rem; -} - -.project-sidebar { - background: white; - border-radius: 0.5rem; - border: 1px solid #e2e8f0; - padding: 1rem; - height: fit-content; -} - -.project-sidebar ul { - list-style: none; -} - -.project-sidebar li { - margin-bottom: 0.5rem; -} - -.project-sidebar a { - display: flex; - align-items: center; - gap: 0.75rem; - padding: 0.5rem; - color: #64748b; - text-decoration: none; - border-radius: 0.375rem; - transition: all 0.2s; -} - -.project-sidebar a:hover, -.project-sidebar a.active { - background: #f1f5f9; - color: #1e40af; -} - -@media (max-width: 768px) { - .project-layout { - grid-template-columns: 1fr; - } - - .project-sidebar { - order: 2; - } -} - -/* Empty states */ -.empty-state { - text-align: center; - padding: 3rem 1rem; - color: #64748b; -} - -.empty-state h3 { - margin-bottom: 0.5rem; - color: #374151; -} - -/* Animations */ -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -/* Form styles */ -.form-group { - margin-bottom: 1rem; -} - -.form-label { - display: block; - margin-bottom: 0.5rem; - font-weight: 500; - color: #374151; -} - -.form-input { - width: 100%; - padding: 0.5rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; - font-size: 1rem; -} - -select.form-input, -.form-input select { - padding-right: 2.5rem !important; -} - -select { - padding-right: 2.5rem; -} - -.form-input:focus { - outline: none; - border-color: #1e40af; - box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.1); -} - -.form-textarea { - resize: vertical; - min-height: 100px; -} - -/* Modal styles */ -.modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - justify-content: center; - align-items: center; - z-index: 1000; -} - -.modal-content { - background: white; - border-radius: 0.5rem; - width: 90%; - max-width: 500px; - max-height: 90vh; - overflow-y: auto; - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); -} - -.modal-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1.5rem; - border-bottom: 1px solid #e2e8f0; -} - -.modal-header h2 { - margin: 0; - font-size: 1.25rem; - font-weight: 600; -} - -.modal-close { - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: #64748b; - padding: 0; - width: 24px; - height: 24px; - display: flex; - align-items: center; - justify-content: center; -} - -.modal-close:hover { - color: #374151; -} - -.modal-body { - padding: 1.5rem; -} - -/* User dropdown styles */ -.user-dropdown-trigger:hover { - background-color: #f1f5f9 !important; -} - -.user-dropdown-menu button:hover { - background-color: #f1f5f9 !important; -} - -/* Session dropdown styles */ -#sessionDropdownMenu button:hover { - background-color: #f1f5f9 !important; -} - -/* Accordion styles */ -.accordion-item { - background: white; - border: 1px solid #e2e8f0; - border-radius: 0.375rem; - overflow: hidden; -} - -.accordion-header { - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem 1rem; - background: white; - border: none; - cursor: pointer; - font-weight: 500; - font-size: 0.875rem; - color: #374151; - transition: background-color 0.2s; - text-align: left; -} - -.accordion-header:hover { - background: #f8fafc; -} - -.accordion-header svg { - transition: transform 0.2s; - flex-shrink: 0; -} - -.accordion-content { - background: #f8fafc; - border-top: 1px solid #e2e8f0; - overflow: hidden; -} From 171a8f5507031b192a47f251f8ec08153b5a6e72 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Fri, 7 Nov 2025 21:42:29 -0600 Subject: [PATCH 10/34] Refactor OOTB workflows endpoint response handling - Replaced `NextResponse` with the standard `Response` object for consistency in the OOTB workflows GET endpoint. - Updated error handling to return a JSON response with appropriate headers, improving API response format. - This change enhances the clarity and standardization of the API responses for better integration with frontend components. --- .../[sessionName]/workflow/route.ts | 27 +++++++++++++++++++ .../src/app/api/workflows/ootb/route.ts | 12 +++++---- 2 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/route.ts diff --git a/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/route.ts b/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/route.ts new file mode 100644 index 000000000..257eb76ae --- /dev/null +++ b/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/route.ts @@ -0,0 +1,27 @@ +import { BACKEND_URL } from '@/lib/config'; +import { buildForwardHeadersAsync } from '@/lib/auth'; + +export async function POST( + request: Request, + { params }: { params: Promise<{ name: string; sessionName: string }> }, +) { + const { name, sessionName } = await params; + const headers = await buildForwardHeadersAsync(request); + const body = await request.text(); + + const resp = await fetch( + `${BACKEND_URL}/projects/${encodeURIComponent(name)}/agentic-sessions/${encodeURIComponent(sessionName)}/workflow`, + { + method: 'POST', + headers, + body, + } + ); + + const data = await resp.text(); + return new Response(data, { + status: resp.status, + headers: { 'Content-Type': 'application/json' } + }); +} + diff --git a/components/frontend/src/app/api/workflows/ootb/route.ts b/components/frontend/src/app/api/workflows/ootb/route.ts index cd991acb5..41c463a95 100644 --- a/components/frontend/src/app/api/workflows/ootb/route.ts +++ b/components/frontend/src/app/api/workflows/ootb/route.ts @@ -1,4 +1,3 @@ -import { NextResponse } from "next/server"; import { BACKEND_URL } from "@/lib/config"; export async function GET() { @@ -14,7 +13,7 @@ export async function GET() { // Forward the response from backend const data = await response.text(); - return new NextResponse(data, { + return new Response(data, { status: response.status, headers: { "Content-Type": "application/json", @@ -22,9 +21,12 @@ export async function GET() { }); } catch (error) { console.error("Failed to fetch OOTB workflows:", error); - return NextResponse.json( - { error: "Failed to fetch OOTB workflows" }, - { status: 500 } + return new Response( + JSON.stringify({ error: "Failed to fetch OOTB workflows" }), + { + status: 500, + headers: { "Content-Type": "application/json" } + } ); } } From 7bc113f5f436bed50bbe213cfc775f4c76c1d9d8 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Fri, 7 Nov 2025 22:15:21 -0600 Subject: [PATCH 11/34] Enhance working directory handling in ClaudeCodeAdapter - Added logic to ensure the working directory exists before passing it to the SDK, creating the directory if it does not. - Implemented error handling for directory creation failures, falling back to the workspace root if necessary. - Improved logging for better debugging of working directory and additional directories. --- components/runners/claude-code-runner/wrapper.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/runners/claude-code-runner/wrapper.py b/components/runners/claude-code-runner/wrapper.py index d898f560c..a7aabe94c 100644 --- a/components/runners/claude-code-runner/wrapper.py +++ b/components/runners/claude-code-runner/wrapper.py @@ -271,6 +271,19 @@ async def _run_claude_agent_sdk(self, prompt: str): if artifacts_path not in add_dirs and artifacts_path != cwd_path: add_dirs.append(artifacts_path) + # Ensure the working directory exists before passing to SDK + cwd_path_obj = Path(cwd_path) + if not cwd_path_obj.exists(): + logging.warning(f"Working directory does not exist, creating: {cwd_path}") + try: + cwd_path_obj.mkdir(parents=True, exist_ok=True) + logging.info(f"Created working directory: {cwd_path}") + except Exception as e: + logging.error(f"Failed to create working directory: {e}") + # Fall back to workspace root + cwd_path = self.context.workspace_path + logging.info(f"Falling back to workspace root: {cwd_path}") + # Log working directory and additional directories for debugging logging.info(f"Claude SDK CWD: {cwd_path}") logging.info(f"Claude SDK additional directories: {add_dirs}") From d52fbceae095c744d1bff379ac2a33703032ccb9 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 07:14:51 -0600 Subject: [PATCH 12/34] Implement dynamic workflow activation in ProjectSessionDetailPage - Introduced state management for pending and active workflows, allowing users to select and activate workflows dynamically. - Enhanced the UI to display active workflow status and provide feedback during activation. - Updated the backend to support active workflow retrieval and session updates, including error handling and logging improvements. - Refactored workflow selection logic to accommodate custom workflows and improved user experience with alerts and loading states. --- .../[name]/sessions/[sessionName]/page.tsx | 315 +++++++++++------- .../frontend/src/types/agentic-session.ts | 6 + components/frontend/src/types/api/sessions.ts | 5 + .../operator/internal/handlers/sessions.go | 1 + .../runners/claude-code-runner/wrapper.py | 106 ++++-- 5 files changed, 287 insertions(+), 146 deletions(-) diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 21710e9f5..c289c3879 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -85,7 +85,9 @@ export default function ProjectSessionDetailPage({ const [customWorkflowUrl, setCustomWorkflowUrl] = useState(""); const [customWorkflowBranch, setCustomWorkflowBranch] = useState("main"); const [customWorkflowPath, setCustomWorkflowPath] = useState(""); - const [workflowLoading, setWorkflowLoading] = useState(false); + const [pendingWorkflow, setPendingWorkflow] = useState<{ id: string; name: string; description: string; gitUrl: string; branch: string; path?: string; enabled: boolean } | null>(null); + const [activeWorkflow, setActiveWorkflow] = useState(null); + const [workflowActivating, setWorkflowActivating] = useState(false); // Extract params useEffect(() => { @@ -146,6 +148,20 @@ export default function ProjectSessionDetailPage({ // Fetch OOTB workflows from backend const { data: ootbWorkflows = [] } = useOOTBWorkflows(); + + // Load active workflow from session spec if present + useEffect(() => { + if (session?.spec?.activeWorkflow) { + // Derive workflow ID from gitUrl if possible + const gitUrl = session.spec.activeWorkflow.gitUrl; + const matchingWorkflow = ootbWorkflows.find(w => w.gitUrl === gitUrl); + if (matchingWorkflow) { + setActiveWorkflow(matchingWorkflow.id); + } else { + setActiveWorkflow("custom"); + } + } + }, [session, ootbWorkflows]); // Workspace state - removed unused tree/file management code @@ -159,18 +175,17 @@ export default function ProjectSessionDetailPage({ await refetchArtifacts(); }, [queryClient, projectName, rfeWorkflowId, refetchArtifacts]); - // Handler for workflow selection - const handleWorkflowChange = async (value: string) => { + // Handler for workflow selection (just sets pending, doesn't activate) + const handleWorkflowChange = (value: string) => { setSelectedWorkflow(value); - if (value === "custom") { - // Open custom workflow dialog - setCustomWorkflowDialogOpen(true); + if (value === "none") { + setPendingWorkflow(null); return; } - if (value === "none") { - // No workflow selected, nothing to do + if (value === "custom") { + setCustomWorkflowDialogOpen(true); return; } @@ -186,22 +201,25 @@ export default function ProjectSessionDetailPage({ return; } - const workflowConfig = { - gitUrl: workflow.gitUrl, - branch: workflow.branch, - path: workflow.path || "", - }; + // Set as pending (user must click Activate) + setPendingWorkflow(workflow); + }; + + // Handler to activate the pending workflow + const handleActivateWorkflow = async () => { + if (!pendingWorkflow) return; + + setWorkflowActivating(true); - // Call API to set workflow - setWorkflowLoading(true); try { + // 1. Update CR with workflow configuration const response = await fetch(`/api/projects/${projectName}/agentic-sessions/${sessionName}/workflow`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - gitUrl: workflowConfig.gitUrl, - branch: workflowConfig.branch, - path: workflowConfig.path || "", + gitUrl: pendingWorkflow.gitUrl, + branch: pendingWorkflow.branch, + path: pendingWorkflow.path || "", }), }); @@ -210,89 +228,56 @@ export default function ProjectSessionDetailPage({ throw new Error(errorData.error || "Failed to update workflow"); } - successToast(`Workflow "${value}" activated`); + // 2. Send WebSocket message to trigger workflow clone and restart + await fetch(`/api/projects/${projectName}/agentic-sessions/${sessionName}/messages`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + type: "workflow_change", + gitUrl: pendingWorkflow.gitUrl, + branch: pendingWorkflow.branch, + path: pendingWorkflow.path || "", + }), + }); + + successToast(`Activating workflow: ${pendingWorkflow.name}`); + setActiveWorkflow(pendingWorkflow.id); + setPendingWorkflow(null); - // Send WebSocket message to notify runner immediately - try { - await fetch(`/api/projects/${projectName}/agentic-sessions/${sessionName}/messages`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - type: "workflow_change", - gitUrl: workflowConfig.gitUrl, - branch: workflowConfig.branch, - path: workflowConfig.path || "", - }), - }); - } catch (err) { - console.warn("Failed to notify runner via WebSocket:", err); - } + // Wait for restart to complete (give runner time to clone and restart) + await new Promise(resolve => setTimeout(resolve, 3000)); - // Refresh session to see updated workflow await refetchSession(); + successToast("Workflow activated successfully"); + } catch (error) { - console.error("Failed to update workflow:", error); - errorToast(error instanceof Error ? error.message : "Failed to update workflow"); + console.error("Failed to activate workflow:", error); + errorToast(error instanceof Error ? error.message : "Failed to activate workflow"); } finally { - setWorkflowLoading(false); + setWorkflowActivating(false); } }; // Handler for custom workflow submission - const handleCustomWorkflowSubmit = async () => { + const handleCustomWorkflowSubmit = () => { if (!customWorkflowUrl.trim()) { errorToast("Git URL is required"); return; } - setWorkflowLoading(true); - try { - const response = await fetch(`/api/projects/${projectName}/agentic-sessions/${sessionName}/workflow`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - gitUrl: customWorkflowUrl.trim(), - branch: customWorkflowBranch.trim() || "main", - path: customWorkflowPath.trim() || "", - }), - }); - - if (!response.ok) { - const errorData = await response.json(); - throw new Error(errorData.error || "Failed to update workflow"); - } - - successToast("Custom workflow activated"); - - // Send WebSocket message to notify runner immediately - try { - await fetch(`/api/projects/${projectName}/agentic-sessions/${sessionName}/messages`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - type: "workflow_change", - gitUrl: customWorkflowUrl.trim(), - branch: customWorkflowBranch.trim() || "main", - path: customWorkflowPath.trim() || "", - }), - }); - } catch (err) { - console.warn("Failed to notify runner via WebSocket:", err); - } - - setCustomWorkflowDialogOpen(false); - // Reset form - setCustomWorkflowUrl(""); - setCustomWorkflowBranch("main"); - setCustomWorkflowPath(""); - // Refresh session - await refetchSession(); - } catch (error) { - console.error("Failed to update workflow:", error); - errorToast(error instanceof Error ? error.message : "Failed to update workflow"); - } finally { - setWorkflowLoading(false); - } + // Set as pending custom workflow + setPendingWorkflow({ + id: "custom", + name: "Custom Workflow", + description: `Custom workflow from ${customWorkflowUrl.trim()}`, + gitUrl: customWorkflowUrl.trim(), + branch: customWorkflowBranch.trim() || "main", + path: customWorkflowPath.trim() || "", + enabled: true, + }); + + setCustomWorkflowDialogOpen(false); + setSelectedWorkflow("custom"); }; // Helper to derive repo folder from URL @@ -914,34 +899,113 @@ export default function ProjectSessionDetailPage({ - Workflows +
+ Workflows + {activeWorkflow && ( + + Active + + )} +
-
- - -
-

- Workflows provide Ambient agents with structured steps to follow toward more complex goals. -

+ + {/* Show active workflow info */} + {activeWorkflow && !workflowActivating && ( + + + Workflow Active + +

+ {ootbWorkflows.find(w => w.id === activeWorkflow)?.name || "Custom Workflow"} +

+

+ Claude is working with this workflow. Slash commands and templates are available. +

+
+
+ )} + + {/* Show selector only if no active workflow and not activating */} + {!activeWorkflow && !workflowActivating && ( + <> +
+ + +
+ + {!pendingWorkflow && ( +

+ Workflows provide Ambient agents with structured steps to follow toward more complex goals. +

+ )} + + {/* Show workflow preview and activate button */} + {pendingWorkflow && ( + + + Ready to Activate + +
+

{pendingWorkflow.name}

+

{pendingWorkflow.description}

+

+ Claude will pause briefly to load the workflow. Your chat history will be preserved. +

+ +
+
+
+ )} + + )} + + {/* Show activating state */} + {workflowActivating && ( + + + Activating Workflow... + +
+

Claude is restarting with the new workflow.

+
    +
  • Cloning workflow repository
  • +
  • Setting up workspace structure
  • +
  • Restarting Claude Code
  • +
+

+ This may take 10-30 seconds... +

+
+
+
+ )} +
@@ -1365,8 +1429,21 @@ export default function ProjectSessionDetailPage({ {/* Right Column - Messages (Always Visible) */}
- + + {/* Workflow activation overlay */} + {workflowActivating && ( +
+ + + Activating Workflow... + +

Claude is restarting with the new workflow. Please wait...

+
+
+
+ )} + setCustomWorkflowUrl(e.target.value)} - disabled={workflowLoading} + disabled={workflowActivating} />
@@ -1632,7 +1709,7 @@ export default function ProjectSessionDetailPage({ placeholder="main" value={customWorkflowBranch} onChange={(e) => setCustomWorkflowBranch(e.target.value)} - disabled={workflowLoading} + disabled={workflowActivating} />
@@ -1643,7 +1720,7 @@ export default function ProjectSessionDetailPage({ placeholder="workflows/my-workflow" value={customWorkflowPath} onChange={(e) => setCustomWorkflowPath(e.target.value)} - disabled={workflowLoading} + disabled={workflowActivating} />

Optional subdirectory within the repository containing the workflow @@ -1655,15 +1732,15 @@ export default function ProjectSessionDetailPage({ + + + ) : ( +

+
+
+ Remote: {artifactsRemote.url} +
+ +
+
+ Branch: {artifactsRemote.branch} +
+
+ )} + + {/* Git Status Display */} + {gitStatus?.hasChanges && ( +
+
Uncommitted Changes:
+
+ {gitStatus.filesAdded > 0 && ( +
+{gitStatus.filesAdded} files added
+ )} + {gitStatus.filesRemoved > 0 && ( +
-{gitStatus.filesRemoved} files removed
+ )} +
+ {gitStatus.totalAdded} additions, {gitStatus.totalRemoved} deletions +
+
+
+ )} + + {/* Synchronize Button */} + {artifactsRemote && gitStatus?.initialized && ( + + )} + +
+ + + {/* Only show Spec Repository for plan-feature and develop-feature workflows */} {(selectedWorkflow === "plan-feature" || selectedWorkflow === "develop-feature") && ( @@ -1752,6 +1976,61 @@ export default function ProjectSessionDetailPage({ + + {/* Configure Artifacts Remote Dialog */} + + + + Configure Artifacts Repository + + Set up a Git repository to save and synchronize your workflow outputs. + + + +
+
+ + setArtifactsRepoUrl(e.target.value)} + /> +

+ The repository where your workflow outputs will be saved +

+
+ +
+ + setArtifactsBranch(e.target.value)} + /> +

+ Branch to push artifacts to (will be created if it doesn't exist) +

+
+
+ + + + + +
+
); } From 1fec89ba138c9d175457bbb371b8adcb38a44918 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 08:22:38 -0600 Subject: [PATCH 14/34] Fix typo in artifact branch description on ProjectSessionDetailPage --- .../src/app/projects/[name]/sessions/[sessionName]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 6f4c59491..6775b4cc6 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -2010,7 +2010,7 @@ export default function ProjectSessionDetailPage({ onChange={(e) => setArtifactsBranch(e.target.value)} />

- Branch to push artifacts to (will be created if it doesn't exist) + Branch to push artifacts to (will be created if it doesn't exist)

From cb9638974b24d26fad28fd1bea8b0d5514a6ff11 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 08:36:38 -0600 Subject: [PATCH 15/34] Remove Artifacts section from ProjectSessionDetailPage and add break statement in ClaudeCodeAdapter to trigger restart in interactive loop --- .../app/projects/[name]/sessions/[sessionName]/page.tsx | 9 --------- components/runners/claude-code-runner/wrapper.py | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 6775b4cc6..b6c235b6f 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -1564,15 +1564,6 @@ export default function ProjectSessionDetailPage({ - - - Artifacts - - - - - - Session Details diff --git a/components/runners/claude-code-runner/wrapper.py b/components/runners/claude-code-runner/wrapper.py index d4e256366..dffaa8c08 100644 --- a/components/runners/claude-code-runner/wrapper.py +++ b/components/runners/claude-code-runner/wrapper.py @@ -520,6 +520,8 @@ async def process_one_prompt(text: str): path = str(payload.get('path') or '').strip() if git_url: await self._handle_workflow_selection(git_url, branch, path) + # Break out of interactive loop to trigger restart + break else: await self._send_log("⚠️ Workflow change request missing gitUrl") elif mtype == 'interrupt': From 6521f8493de4ba3a81589254deb78c9e36833cbe Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 08:41:35 -0600 Subject: [PATCH 16/34] Remove unused ResultsTab import from ProjectSessionDetailPage to streamline code and improve maintainability. --- .../src/app/projects/[name]/sessions/[sessionName]/page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index b6c235b6f..df1892802 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -7,7 +7,6 @@ import { useRouter } from "next/navigation"; // Custom components import MessagesTab from "@/components/session/MessagesTab"; -import ResultsTab from "@/components/session/ResultsTab"; import { EditRepositoriesDialog } from "../../rfe/[id]/edit-repositories-dialog"; import { Button } from "@/components/ui/button"; From 3f9cf8009c6963df6cf75137a3d7db1238ba8bc1 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 09:09:50 -0600 Subject: [PATCH 17/34] Enhance Git remote configuration in ProjectSessionDetailPage - Updated ConfigureGitRemote handler to use sessionName consistently for service naming and path construction. - Added logic to persist Git remote configuration in session annotations for artifacts, improving session management. - Enhanced ProjectSessionDetailPage to load artifacts remote from session annotations, providing a seamless user experience. - Introduced UI components for displaying artifacts directory and configuring Git remotes, streamlining the workflow for users. --- components/backend/handlers/sessions.go | 54 +++++++++++++------ .../[name]/sessions/[sessionName]/page.tsx | 33 ++++++++++-- .../runners/claude-code-runner/wrapper.py | 6 +-- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/components/backend/handlers/sessions.go b/components/backend/handlers/sessions.go index 4bedadd83..2d6025727 100644 --- a/components/backend/handlers/sessions.go +++ b/components/backend/handlers/sessions.go @@ -2771,58 +2771,82 @@ func GetGitStatus(c *gin.Context) { // Body: { path: string, remoteUrl: string, branch: string } func ConfigureGitRemote(c *gin.Context) { project := c.Param("projectName") - session := c.Param("sessionName") - + sessionName := c.Param("sessionName") + _, reqDyn := GetK8sClientsForRequest(c) + var body struct { Path string `json:"path" binding:"required"` RemoteUrl string `json:"remoteUrl" binding:"required"` Branch string `json:"branch"` } - + if err := c.BindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) return } - + if body.Branch == "" { body.Branch = "main" } - + // Build absolute path - absPath := fmt.Sprintf("/sessions/%s/workspace/%s", session, body.Path) - + absPath := fmt.Sprintf("/sessions/%s/workspace/%s", sessionName, body.Path) + // Get content service endpoint - serviceName := fmt.Sprintf("temp-content-%s", session) + serviceName := fmt.Sprintf("temp-content-%s", sessionName) reqK8s, _ := GetK8sClientsForRequest(c) if reqK8s != nil { if _, err := reqK8s.CoreV1().Services(project).Get(c.Request.Context(), serviceName, v1.GetOptions{}); err != nil { - serviceName = fmt.Sprintf("ambient-content-%s", session) + serviceName = fmt.Sprintf("ambient-content-%s", sessionName) } } else { - serviceName = fmt.Sprintf("ambient-content-%s", session) + serviceName = fmt.Sprintf("ambient-content-%s", sessionName) } - + endpoint := fmt.Sprintf("http://%s.%s.svc:8080/content/git-configure-remote", serviceName, project) - + reqBody, _ := json.Marshal(map[string]interface{}{ "path": absPath, "remoteUrl": body.RemoteUrl, "branch": body.Branch, }) - + req, _ := http.NewRequestWithContext(c.Request.Context(), http.MethodPost, endpoint, strings.NewReader(string(reqBody))) req.Header.Set("Content-Type", "application/json") if v := c.GetHeader("Authorization"); v != "" { req.Header.Set("Authorization", v) } - + resp, err := http.DefaultClient.Do(req) if err != nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "content service unavailable"}) return } defer resp.Body.Close() - + + // If successful, persist remote config to session annotations for persistence + if resp.StatusCode == http.StatusOK && body.Path == "artifacts" { + // Persist artifacts remote config in annotations + gvr := GetAgenticSessionV1Alpha1Resource() + item, err := reqDyn.Resource(gvr).Namespace(project).Get(c.Request.Context(), sessionName, v1.GetOptions{}) + if err == nil { + metadata := item.Object["metadata"].(map[string]interface{}) + if metadata["annotations"] == nil { + metadata["annotations"] = make(map[string]interface{}) + } + anns := metadata["annotations"].(map[string]interface{}) + anns["ambient-code.io/artifacts-remote-url"] = body.RemoteUrl + anns["ambient-code.io/artifacts-remote-branch"] = body.Branch + + _, err = reqDyn.Resource(gvr).Namespace(project).Update(c.Request.Context(), item, v1.UpdateOptions{}) + if err != nil { + log.Printf("Warning: Failed to persist artifacts remote to annotations: %v", err) + } else { + log.Printf("Persisted artifacts remote to session annotations: %s@%s", body.RemoteUrl, body.Branch) + } + } + } + bodyBytes, _ := io.ReadAll(resp.Body) c.Data(resp.StatusCode, resp.Header.Get("Content-Type"), bodyBytes) } diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index df1892802..9ac36d038 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -176,6 +176,16 @@ export default function ProjectSessionDetailPage({ setActiveWorkflow("custom"); } } + + // Load artifacts remote from session annotations if present + const artifactsUrl = session?.metadata?.annotations?.['ambient-code.io/artifacts-remote-url']; + const artifactsBranch = session?.metadata?.annotations?.['ambient-code.io/artifacts-remote-branch']; + if (artifactsUrl) { + setArtifactsRemote({ + url: artifactsUrl, + branch: artifactsBranch || "main", + }); + } }, [session, ootbWorkflows]); // Workspace state - removed unused tree/file management code @@ -1155,13 +1165,30 @@ export default function ProjectSessionDetailPage({
+ {/* File Browser for Artifacts */} +
+
+ Files & Directories + +
+
+ Path: artifacts/ +
+

+ All workflow outputs are stored here. Configure a Git remote below to save and sync your work. +

+
+ {/* Remote Configuration Status */} {!artifactsRemote ? ( - No Remote Configured + Configure Git Remote -

Configure a Git repository to save and sync your work.

+

Set up a Git repository to version control and sync your outputs.

+

This will initialize git in the artifacts directory and configure the remote.

diff --git a/components/runners/claude-code-runner/wrapper.py b/components/runners/claude-code-runner/wrapper.py index dffaa8c08..951d7e89f 100644 --- a/components/runners/claude-code-runner/wrapper.py +++ b/components/runners/claude-code-runner/wrapper.py @@ -237,10 +237,8 @@ async def _run_claude_agent_sdk(self, prompt: str): if derived_name: workflow_path = str(Path(self.context.workspace_path) / "workflows" / derived_name) - # Check if path is specified within the workflow - workflow_subpath = (os.getenv('ACTIVE_WORKFLOW_PATH') or '').strip() - if workflow_subpath: - workflow_path = str(Path(workflow_path) / workflow_subpath) + # NOTE: Don't append ACTIVE_WORKFLOW_PATH here - we already extracted + # the subdirectory during clone, so workflow_path is the final location if Path(workflow_path).exists(): cwd_path = workflow_path From 3dda46178b7786829ca147c85dece3b606f65cb5 Mon Sep 17 00:00:00 2001 From: Gage Krumbach Date: Sat, 8 Nov 2025 10:41:52 -0600 Subject: [PATCH 18/34] Implement workflow metadata retrieval and enhance ProjectSessionDetailPage - Added new endpoint to retrieve commands and agents metadata for active workflows. - Integrated workflow metadata fetching into ProjectSessionDetailPage, allowing users to view available commands and agents. - Enhanced UI to display commands and agents, including auto-selection options for agents during chat interactions. - Updated MessagesTab to show selected agents and their descriptions, improving user guidance during sessions. - Introduced new API types and query hooks for better type safety and data management. --- components/backend/handlers/content.go | 141 +++++++++++ components/backend/handlers/sessions.go | 12 + components/backend/routes.go | 3 +- components/frontend/package-lock.json | 35 +++ components/frontend/package.json | 1 + .../[sessionName]/workflow/metadata/route.ts | 17 ++ .../[name]/sessions/[sessionName]/page.tsx | 224 ++++++++++++++++-- .../src/components/session/MessagesTab.tsx | 26 +- .../frontend/src/components/ui/tooltip.tsx | 31 +++ .../frontend/src/services/api/workflows.ts | 29 +++ .../src/services/queries/use-workflows.ts | 15 ++ 11 files changed, 510 insertions(+), 24 deletions(-) create mode 100644 components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/metadata/route.ts create mode 100644 components/frontend/src/components/ui/tooltip.tsx diff --git a/components/backend/handlers/content.go b/components/backend/handlers/content.go index 9a823675e..d672a9360 100644 --- a/components/backend/handlers/content.go +++ b/components/backend/handlers/content.go @@ -428,3 +428,144 @@ func ContentList(c *gin.Context) { log.Printf("ContentList: returning %d items for path=%q", len(items), path) c.JSON(http.StatusOK, gin.H{"items": items}) } + +// ContentWorkflowMetadata handles GET /content/workflow-metadata?session= +// Parses .claude/commands/*.md and .claude/agents/*.md files from active workflow +func ContentWorkflowMetadata(c *gin.Context) { + sessionName := c.Query("session") + if sessionName == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "missing session parameter"}) + return + } + + log.Printf("ContentWorkflowMetadata: session=%q", sessionName) + + // Find active workflow directory + workflowDir := findActiveWorkflowDir(sessionName) + if workflowDir == "" { + log.Printf("ContentWorkflowMetadata: no active workflow found for session=%q", sessionName) + c.JSON(http.StatusOK, gin.H{"commands": []interface{}{}, "agents": []interface{}{}}) + return + } + + log.Printf("ContentWorkflowMetadata: found workflow at %q", workflowDir) + + // Parse commands from .claude/commands/*.md + commandsDir := filepath.Join(workflowDir, ".claude", "commands") + commands := []map[string]interface{}{} + + if files, err := os.ReadDir(commandsDir); err == nil { + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), ".md") { + filePath := filepath.Join(commandsDir, file.Name()) + metadata := parseFrontmatter(filePath) + commandName := strings.TrimSuffix(file.Name(), ".md") + + displayName := metadata["displayName"] + if displayName == "" { + displayName = commandName + } + + commands = append(commands, map[string]interface{}{ + "id": commandName, + "name": displayName, + "description": metadata["description"], + "slashCommand": "/" + commandName, + }) + } + } + log.Printf("ContentWorkflowMetadata: found %d commands", len(commands)) + } else { + log.Printf("ContentWorkflowMetadata: commands directory not found or unreadable: %v", err) + } + + // Parse agents from .claude/agents/*.md + agentsDir := filepath.Join(workflowDir, ".claude", "agents") + agents := []map[string]interface{}{} + + if files, err := os.ReadDir(agentsDir); err == nil { + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), ".md") { + filePath := filepath.Join(agentsDir, file.Name()) + metadata := parseFrontmatter(filePath) + agentID := strings.TrimSuffix(file.Name(), ".md") + + agents = append(agents, map[string]interface{}{ + "id": agentID, + "name": metadata["name"], + "description": metadata["description"], + "tools": metadata["tools"], + }) + } + } + log.Printf("ContentWorkflowMetadata: found %d agents", len(agents)) + } else { + log.Printf("ContentWorkflowMetadata: agents directory not found or unreadable: %v", err) + } + + c.JSON(http.StatusOK, gin.H{ + "commands": commands, + "agents": agents, + }) +} + +// parseFrontmatter extracts YAML frontmatter from a markdown file +func parseFrontmatter(filePath string) map[string]string { + content, err := os.ReadFile(filePath) + if err != nil { + log.Printf("parseFrontmatter: failed to read %q: %v", filePath, err) + return map[string]string{} + } + + str := string(content) + if !strings.HasPrefix(str, "---\n") { + return map[string]string{} + } + + // Find end of frontmatter + endIdx := strings.Index(str[4:], "\n---") + if endIdx == -1 { + return map[string]string{} + } + + frontmatter := str[4 : 4+endIdx] + result := map[string]string{} + + // Simple key: value parsing + for _, line := range strings.Split(frontmatter, "\n") { + if strings.TrimSpace(line) == "" { + continue + } + parts := strings.SplitN(line, ":", 2) + if len(parts) == 2 { + key := strings.TrimSpace(parts[0]) + value := strings.Trim(strings.TrimSpace(parts[1]), "\"'") + result[key] = value + } + } + + return result +} + +// findActiveWorkflowDir finds the active workflow directory for a session +func findActiveWorkflowDir(sessionName string) string { + workflowsBase := filepath.Join(StateBaseDir, "sessions", sessionName, "workspace", "workflows") + + entries, err := os.ReadDir(workflowsBase) + if err != nil { + log.Printf("findActiveWorkflowDir: failed to read workflows directory %q: %v", workflowsBase, err) + return "" + } + + // Find first directory that has .claude subdirectory + for _, entry := range entries { + if entry.IsDir() && entry.Name() != "default" { + claudeDir := filepath.Join(workflowsBase, entry.Name(), ".claude") + if stat, err := os.Stat(claudeDir); err == nil && stat.IsDir() { + return filepath.Join(workflowsBase, entry.Name()) + } + } + } + + return "" +} diff --git a/components/backend/handlers/sessions.go b/components/backend/handlers/sessions.go index 2d6025727..a7c07e16a 100644 --- a/components/backend/handlers/sessions.go +++ b/components/backend/handlers/sessions.go @@ -1159,6 +1159,18 @@ func SelectWorkflow(c *gin.Context) { }) } +// GetWorkflowMetadata retrieves commands and agents metadata from the active workflow +// GET /api/projects/:projectName/agentic-sessions/:sessionName/workflow/metadata +func GetWorkflowMetadata(c *gin.Context) { + sessionName := c.Param("sessionName") + + // Use the internal ContentWorkflowMetadata function + // Pass session name as query parameter + c.Request.URL.RawQuery = "session=" + sessionName + + ContentWorkflowMetadata(c) +} + // GET /api/workflows/ootb // ListOOTBWorkflows returns the list of out-of-the-box workflows func ListOOTBWorkflows(c *gin.Context) { diff --git a/components/backend/routes.go b/components/backend/routes.go index 262c0ab19..87e2b793f 100644 --- a/components/backend/routes.go +++ b/components/backend/routes.go @@ -26,7 +26,7 @@ func registerRoutes(r *gin.Engine, jiraHandler *jira.Handler) { { // Public endpoints (no auth required) api.GET("/workflows/ootb", handlers.ListOOTBWorkflows) - + api.POST("/projects/:projectName/agentic-sessions/:sessionName/github/token", handlers.MintSessionGitHubToken) projectGroup := api.Group("/projects/:projectName", handlers.ValidateProjectContext()) @@ -63,6 +63,7 @@ func registerRoutes(r *gin.Engine, jiraHandler *jira.Handler) { projectGroup.GET("/agentic-sessions/:sessionName/content-pod-status", handlers.GetContentPodStatus) projectGroup.DELETE("/agentic-sessions/:sessionName/content-pod", handlers.DeleteContentPod) projectGroup.POST("/agentic-sessions/:sessionName/workflow", handlers.SelectWorkflow) + projectGroup.GET("/agentic-sessions/:sessionName/workflow/metadata", handlers.GetWorkflowMetadata) projectGroup.GET("/rfe-workflows", handlers.ListProjectRFEWorkflows) projectGroup.POST("/rfe-workflows", handlers.CreateProjectRFEWorkflow) diff --git a/components/frontend/package-lock.json b/components/frontend/package-lock.json index fdf77f9bc..12708c5e6 100644 --- a/components/frontend/package-lock.json +++ b/components/frontend/package-lock.json @@ -19,6 +19,7 @@ "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-toast": "^1.2.15", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.90.2", "@tanstack/react-query-devtools": "^5.90.2", "class-variance-authority": "^0.7.1", @@ -1719,6 +1720,40 @@ } } }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", diff --git a/components/frontend/package.json b/components/frontend/package.json index 68ff0792e..f5931698c 100644 --- a/components/frontend/package.json +++ b/components/frontend/package.json @@ -20,6 +20,7 @@ "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-toast": "^1.2.15", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.90.2", "@tanstack/react-query-devtools": "^5.90.2", "class-variance-authority": "^0.7.1", diff --git a/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/metadata/route.ts b/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/metadata/route.ts new file mode 100644 index 000000000..a7596cd7d --- /dev/null +++ b/components/frontend/src/app/api/projects/[name]/agentic-sessions/[sessionName]/workflow/metadata/route.ts @@ -0,0 +1,17 @@ +import { BACKEND_URL } from '@/lib/config'; +import { buildForwardHeadersAsync } from '@/lib/auth'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ name: string; sessionName: string }> }, +) { + const { name, sessionName } = await params; + const headers = await buildForwardHeadersAsync(request); + const resp = await fetch( + `${BACKEND_URL}/projects/${encodeURIComponent(name)}/agentic-sessions/${encodeURIComponent(sessionName)}/workflow/metadata`, + { headers } + ); + const data = await resp.text(); + return new Response(data, { status: resp.status, headers: { 'Content-Type': 'application/json' } }); +} + diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx index 9ac36d038..c06255a6e 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx @@ -8,6 +8,7 @@ import { useRouter } from "next/navigation"; // Custom components import MessagesTab from "@/components/session/MessagesTab"; import { EditRepositoriesDialog } from "../../rfe/[id]/edit-repositories-dialog"; +import { FileTree, type FileTreeNode } from "@/components/file-tree"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; @@ -50,10 +51,12 @@ import { useWorkflowArtifacts, rfeKeys, } from "@/services/queries"; +import { useWorkspaceList } from "@/services/queries/use-workspace"; import { useSecretsValues } from "@/services/queries/use-secrets"; import { successToast, errorToast } from "@/hooks/use-toast"; -import { useOOTBWorkflows } from "@/services/queries/use-workflows"; +import { useOOTBWorkflows, useWorkflowMetadata } from "@/services/queries/use-workflows"; import { useQueryClient } from "@tanstack/react-query"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; export default function ProjectSessionDetailPage({ params, @@ -87,6 +90,7 @@ export default function ProjectSessionDetailPage({ const [pendingWorkflow, setPendingWorkflow] = useState<{ id: string; name: string; description: string; gitUrl: string; branch: string; path?: string; enabled: boolean } | null>(null); const [activeWorkflow, setActiveWorkflow] = useState(null); const [workflowActivating, setWorkflowActivating] = useState(false); + const [autoSelectAgents, setAutoSelectAgents] = useState(false); // Artifacts git management state const [artifactsRemote, setArtifactsRemote] = useState<{url: string; branch: string} | null>(null); @@ -164,6 +168,21 @@ export default function ProjectSessionDetailPage({ // Fetch OOTB workflows from backend const { data: ootbWorkflows = [] } = useOOTBWorkflows(); + // Fetch workflow metadata (commands and agents) when workflow is active + const { data: workflowMetadata } = useWorkflowMetadata( + projectName, + sessionName, + !!activeWorkflow && !workflowActivating + ); + + // Fetch artifacts directory listing + const { data: artifactsFiles = [], refetch: refetchArtifactsFiles } = useWorkspaceList( + projectName, + sessionName, + "artifacts", + { enabled: openAccordionItems.includes("artifacts") } + ); + // Load active workflow from session spec if present useEffect(() => { if (session?.spec?.activeWorkflow) { @@ -708,19 +727,50 @@ export default function ProjectSessionDetailPage({ }; const sendChat = () => { - if (!chatInput.trim()) return; + if (!chatInput.trim() && !selectedAgents.length && !autoSelectAgents) return; + + // Build message with agent prepend if needed + let finalMessage = chatInput.trim(); + + if (autoSelectAgents) { + finalMessage = "You MUST use relevant sub-agents when needed based on the task at hand. " + finalMessage; + } else if (selectedAgents.length > 0) { + const agentNames = selectedAgents + .map(id => workflowMetadata?.agents?.find(a => a.id === id)) + .filter(Boolean) + .map(agent => agent!.name) + .join(', '); + + finalMessage = `You MUST collaborate with these agents: ${agentNames}. ` + finalMessage; + } sendChatMutation.mutate( - { projectName, sessionName, content: chatInput.trim() }, + { projectName, sessionName, content: finalMessage }, { onSuccess: () => { setChatInput(""); + // Clear agent selection after sending + setSelectedAgents([]); + setAutoSelectAgents(false); }, onError: (err) => errorToast(err instanceof Error ? err.message : "Failed to send message"), } ); }; + const handleCommandClick = (slashCommand: string) => { + // Auto-send the command + sendChatMutation.mutate( + { projectName, sessionName, content: slashCommand }, + { + onSuccess: () => { + successToast(`Command ${slashCommand} sent`); + }, + onError: (err) => errorToast(err instanceof Error ? err.message : "Failed to send command"), + } + ); + }; + const handleInterrupt = () => { sendControlMutation.mutate( { projectName, sessionName, type: 'interrupt' }, @@ -1052,18 +1102,124 @@ export default function ProjectSessionDetailPage({ {/* Show active workflow info */} {activeWorkflow && !workflowActivating && ( - - - Workflow Active - -

- {ootbWorkflows.find(w => w.id === activeWorkflow)?.name || "Custom Workflow"} + <> + + + Workflow Active + +

+ {ootbWorkflows.find(w => w.id === activeWorkflow)?.name || "Custom Workflow"} +

+

+ Claude is working with this workflow. Slash commands and templates are available. +

+
+
+ + {/* Commands Section */} + {workflowMetadata?.commands && workflowMetadata.commands.length > 0 && ( +
+
Slash Commands
+
+ {workflowMetadata.commands.map((cmd) => ( + + ))} +
+
+ )} + + {workflowMetadata?.commands?.length === 0 && ( +

+ No commands found in this workflow

-

- Claude is working with this workflow. Slash commands and templates are available. + )} + + {/* Agents Section */} + {workflowMetadata?.agents && workflowMetadata.agents.length > 0 && ( +

+
Agents
+ +
+ { + setAutoSelectAgents(!!checked); + if (checked) setSelectedAgents([]); + }} + /> + +
+ +
+ {workflowMetadata.agents.map((agent) => ( + + + +
+ { + if (checked) { + setSelectedAgents([...selectedAgents, agent.id]); + } else { + setSelectedAgents(selectedAgents.filter(id => id !== agent.id)); + } + }} + /> + +
+
+ +

{agent.description}

+
+
+
+ ))} +
+ + {(selectedAgents.length > 0 || autoSelectAgents) && ( + + + + Next message will include agent instructions + + + )} +
+ )} + + {workflowMetadata?.agents?.length === 0 && ( +

+ No agents found in this workflow

- - + )} + )} {/* Show selector only if no active workflow and not activating */} @@ -1166,19 +1322,37 @@ export default function ProjectSessionDetailPage({
{/* File Browser for Artifacts */} -
-
- Files & Directories -
-
- Path: artifacts/ +
+ {artifactsFiles.length === 0 ? ( +
+ +

No files yet

+

Workflow outputs will appear here

+
+ ) : ( + ({ + name: item.name, + path: item.path, + type: item.isDir ? 'folder' : 'file', + sizeKb: item.size ? item.size / 1024 : undefined, + }))} + selectedPath={undefined} + onSelect={() => {}} + onToggle={() => {}} + /> + )}
-

- All workflow outputs are stored here. Configure a Git remote below to save and sync your work. -

{/* Remote Configuration Status */} @@ -1695,6 +1869,12 @@ export default function ProjectSessionDetailPage({ onEndSession={() => Promise.resolve(handleEndSession())} onGoToResults={() => {}} onContinue={handleContinue} + selectedAgents={selectedAgents} + autoSelectAgents={autoSelectAgents} + agentNames={selectedAgents + .map(id => workflowMetadata?.agents?.find(a => a.id === id)) + .filter(Boolean) + .map(agent => agent!.name)} /> diff --git a/components/frontend/src/components/session/MessagesTab.tsx b/components/frontend/src/components/session/MessagesTab.tsx index b5ce8ebd4..027579b53 100644 --- a/components/frontend/src/components/session/MessagesTab.tsx +++ b/components/frontend/src/components/session/MessagesTab.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { Brain, Loader2, Settings } from "lucide-react"; import { StreamMessage } from "@/components/ui/stream-message"; import { @@ -22,10 +23,13 @@ export type MessagesTabProps = { onEndSession: () => Promise; onGoToResults?: () => void; onContinue: () => void; + selectedAgents?: string[]; + autoSelectAgents?: boolean; + agentNames?: string[]; }; -const MessagesTab: React.FC = ({ session, streamMessages, chatInput, setChatInput, onSendChat, onInterrupt, onEndSession, onGoToResults, onContinue}) => { +const MessagesTab: React.FC = ({ session, streamMessages, chatInput, setChatInput, onSendChat, onInterrupt, onEndSession, onGoToResults, onContinue, selectedAgents = [], autoSelectAgents = false, agentNames = [] }) => { const [sendingChat, setSendingChat] = useState(false); const [interrupting, setInterrupting] = useState(false); const [ending, setEnding] = useState(false); @@ -135,6 +139,26 @@ const MessagesTab: React.FC = ({ session, streamMessages, chat
+ {/* Agent prepend chips - show when agents selected */} + {(selectedAgents.length > 0 || autoSelectAgents) && ( +
+
Next message will include:
+
+ {autoSelectAgents ? ( + + Auto-select relevant agents + + ) : ( + agentNames.map((name, idx) => ( + + {name.split(' - ')[0]} {/* Just first part of name */} + + )) + )} +
+
+ )} +