Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(webapp): fix agent overview page scroll bug + layout fixes on task and agent pages#4454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { type ReactNode } from "react"; | ||
| import { cn } from "~/utils/cn"; | ||
| import { Header2 } from "./Headers"; | ||
| import { TITLE_BAR_CHROME } from "./Tabs"; | ||
| /** | ||
| * Names the table below it. Bottom rule only — it doubles as the table's top edge, so render the | ||
| * table with `showTopBorder={false}`. Use `TabContainer variant="title"` for the tabbed form. | ||
| */ | ||
| export function TitleBar({ | ||
| title, | ||
| children, | ||
| className, | ||
| }: { | ||
| title: ReactNode; | ||
| /** Right-aligned controls. */ | ||
| children?: ReactNode; | ||
| className?: string; | ||
| }) { | ||
| return ( | ||
| <div className={cn(TITLE_BAR_CHROME, "items-center justify-between pl-2.5 pr-1.5", className)}> | ||
| <Header2>{title}</Header2> | ||
| {children ? <div className="flex items-center gap-1.5">{children}</div> : null} | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -42,7 +42,7 @@ const TooltipContent = React.forwardRef< | ||
| ref={ref} | ||
| sideOffset={sideOffset} | ||
| className={cn( | ||
| "z-50 max-w-[230px] overflow-hidden animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 focus-visible:outline-hidden", | ||
| "z-50 overflow-hidden animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 focus-visible:outline-hidden", | ||
samejr marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| variantClasses[variant], | ||
| className | ||
| )} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -234,28 +234,10 @@ export default function Page() { | ||
| </PageAccessories> | ||
| </NavBar> | ||
| <MetricsLayout.Root> | ||
| {/* Filters — the pinned bar under the NavBar: the TimeFilter and pagination that used to | ||
| be fused with the tabs now live here, above the charts (Queues list pattern). Left and | ||
| right clusters are child divs; the slot's baked justify-between spreads them. */} | ||
| <MetricsLayout.Filters> | ||
| <div className="flex items-center gap-2"> | ||
| <TimeFilter defaultPeriod="7d" labelName={tabLabel} /> | ||
| </div> | ||
| <div className="flex items-center gap-2"> | ||
| {tab === "sessions" ? ( | ||
| <Suspense fallback={null}> | ||
| <TypedAwait resolve={sessionList} errorElement={null}> | ||
| {(list) => (list ? <ListPagination list={list} /> : null)} | ||
| </TypedAwait> | ||
| </Suspense> | ||
| ) : ( | ||
| <Suspense fallback={null}> | ||
| <TypedAwait resolve={runList} errorElement={null}> | ||
| {(list) => (list ? <ListPagination list={list} /> : null)} | ||
| </TypedAwait> | ||
| </Suspense> | ||
| )} | ||
| </div> | ||
| </MetricsLayout.Filters> | ||
| {/* Activity / LLM spend / Token charts as a fixed-height chart row (three-up), synced + | ||
| @@ -315,23 +297,45 @@ export default function Page() { | ||
| {/* Tabs alone on their row (Queue detail pattern), then the table below them. */} | ||
| <MetricsLayout.Content> | ||
| <TabContainer className="px-3"> | ||
| <TabButton | ||
| isActive={tab === "sessions"} | ||
| layoutId="agent-page-tabs" | ||
| onClick={() => setTab("sessions")} | ||
| > | ||
| Sessions | ||
| </TabButton> | ||
| <TabButton | ||
| isActive={tab === "runs"} | ||
| layoutId="agent-page-tabs" | ||
| onClick={() => setTab("runs")} | ||
| > | ||
| Runs | ||
| </TabButton> | ||
| </TabContainer> | ||
| <AgentContentArea tab={tab} sessionList={sessionList} runList={runList} /> | ||
| {/* Single child so Content's gap-2.5 can't separate the bar from the table. */} | ||
| <div className="flex flex-col"> | ||
| <TabContainer variant="title" className="justify-between border-y px-2"> | ||
| <div className="flex items-stretch gap-x-6"> | ||
| <TabButton | ||
| isActive={tab === "sessions"} | ||
| layoutId="agent-page-tabs" | ||
| variant="title" | ||
| onClick={() => setTab("sessions")} | ||
| > | ||
| Sessions | ||
| </TabButton> | ||
| <TabButton | ||
| isActive={tab === "runs"} | ||
| layoutId="agent-page-tabs" | ||
| variant="title" | ||
| onClick={() => setTab("runs")} | ||
| > | ||
| Runs | ||
| </TabButton> | ||
| </div> | ||
| <div className="flex items-center gap-1.5"> | ||
| {tab === "sessions" ? ( | ||
| <Suspense fallback={null}> | ||
| <TypedAwait resolve={sessionList} errorElement={null}> | ||
| {(list) => (list ? <ListPagination list={list} /> : null)} | ||
| </TypedAwait> | ||
| </Suspense> | ||
| ) : ( | ||
| <Suspense fallback={null}> | ||
| <TypedAwait resolve={runList} errorElement={null}> | ||
| {(list) => (list ? <ListPagination list={list} /> : null)} | ||
| </TypedAwait> | ||
| </Suspense> | ||
| )} | ||
| </div> | ||
| </TabContainer> | ||
| <AgentContentArea tab={tab} sessionList={sessionList} runList={runList} /> | ||
| </div> | ||
| </MetricsLayout.Content> | ||
| <MetricsLayout.Sidebar | ||
| @@ -356,8 +360,7 @@ function AgentContentArea({ | ||
| sessionList, | ||
| runList, | ||
| }: { tab: AgentTab } & Pick<LoaderData, "sessionList" | "runList">) { | ||
| // The table flows in the page-level scroll (MetricsLayout.Root scroll="page"); a sticky header | ||
| // keeps the column labels pinned as the whole column scrolls. | ||
| // No `stickyHeader` — it drops the table's own overflow-x-auto and the charts scroll with it. | ||
samejr marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return tab === "sessions" ? ( | ||
| <Suspense fallback={<TableLoading />}> | ||
| <TypedAwait resolve={sessionList} errorElement={<TableLoading />}> | ||
| @@ -367,7 +370,7 @@ function AgentContentArea({ | ||
| sessions={list.sessions} | ||
| filters={list.filters} | ||
| hasFilters={list.hasFilters} | ||
| stickyHeader | ||
| showTopBorder={false} | ||
| /> | ||
| ) : ( | ||
| <TableLoading /> | ||
| @@ -386,7 +389,7 @@ function AgentContentArea({ | ||
| filters={list.filters} | ||
| runs={list.runs} | ||
| variant="dimmed" | ||
| stickyHeader | ||
| showTopBorder={false} | ||
| /> | ||
| ) : ( | ||
| <TableLoading /> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,6 @@ | ||
| import { Outlet } from "@remix-run/react"; | ||
| import { PageContainer } from "~/components/layout/AppLayout"; | ||
| // No PageContainer — the child pages render their own; nesting two collapses the inner one's height. | ||
| export default function Page() { | ||
| return ( | ||
| <PageContainer> | ||
| <Outlet /> | ||
| </PageContainer> | ||
| ); | ||
| return <Outlet />; | ||
samejr marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.