refactor(site): demui AgentRow and AgentStatus (#27789)

Migrate agent row log expand/collapse and agent status troubleshooting
link off MUI onto shared Collapsible and Link primitives.

Replaces `Collapse` in `AgentRow` with `Collapsible` /
`CollapsibleTrigger` / `CollapsibleContent`, and swaps the MUI `Link` in
`AgentStatus` for the shared `Link` component.
This commit is contained in:
Jake Howell
2026-08-05 02:11:55 +10:00
committed by GitHub
parent df1700916e
commit 3640b69533
2 changed files with 235 additions and 214 deletions
+227 -212
View File
@@ -1,4 +1,3 @@
import Collapse from "@mui/material/Collapse";
import {
CopyIcon,
EllipsisIcon,
@@ -31,6 +30,11 @@ import { CheckIcon } from "#/components/AnimatedIcons/Check";
import { ChevronDownIcon } from "#/components/AnimatedIcons/ChevronDown";
import { Badge } from "#/components/Badge/Badge";
import { Button } from "#/components/Button/Button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "#/components/Collapsible/Collapsible";
import {
DropdownMenu,
DropdownMenuContent,
@@ -553,221 +557,232 @@ export const AgentRow: FC<AgentRowProps> = ({
</div>
<section className="border-0 border-t border-solid border-border">
<div className="px-4 py-2 relative">
<Button
variant="subtle"
onClick={() => setShowLogs((v) => !v)}
className="after:content-[''] after:absolute after:inset-0"
>
<ChevronDownIcon open={showLogs} />
<span>Logs</span>
{agent.lifecycle_state === "starting" &&
runningScriptsCount > 0 &&
connectivityIssues.length === 0 && (
<Badge
variant="default"
size="xs"
className="ml-1.5"
svgSize="sm"
>
<Spinner
size="lg"
loading
className="text-content-secondary -ml-1"
/>
<span>{runningScriptsCount}</span>
</Badge>
)}
{hasConnectivityIssues && (
<Badge
variant={hasWarningConnectivityIssues ? "warning" : "info"}
size="xs"
className="ml-1.5"
<Collapsible open={shouldExpandLogs} onOpenChange={setShowLogs}>
<div className="px-4 py-2 relative">
<CollapsibleTrigger asChild>
<Button
variant="subtle"
className="after:content-[''] after:absolute after:inset-0"
>
{hasWarningConnectivityIssues ? (
<TriangleAlertIcon className="-ml-0.5" />
) : (
<InfoIcon className="-ml-0.5" />
)}
<span>{connectivityIssues.length}</span>
</Badge>
)}
</Button>
</div>
<Collapse in={shouldExpandLogs}>
<div className={cn("px-4", hasStartupFeatures ? "pb-4" : "py-4")}>
{/*
Collapse's `in` condition is needed here,
or else the Spinner will also show as Collapse is closing
*/}
{shouldExpandLogs &&
!(hasConnectivityIssues || shouldShowLogsTabs) && (
<Spinner size="lg" loading className="block mx-auto" />
)}
{hasConnectivityIssues && (
<div className="mb-4 flex flex-col gap-3">
{connectivityIssues.map((issue) => (
<AgentAlert
key={`${issue.title}-${issue.detail}`}
{...issue}
troubleshootingURL={agent.troubleshooting_url}
/>
))}
</div>
)}
{shouldShowLogsTabs && (
<div className="border border-solid rounded-md overflow-clip">
<Tabs
className="-mx-px -mt-px"
value={selectedLogTab}
onValueChange={handleSelectedLogTabChange}
>
<div className="flex items-stretch">
<div className="min-w-0 flex-1 overflow-hidden">
<TabsList
variant="outsideBox"
overflowKebabMenu
ref={logTabsListContainerRef}
className="px-4"
>
{visibleLogTabs.map((tab) => (
<TabsTrigger
key={tab.value}
value={tab.value}
{...getTabMeasureProps(tab.value)}
>
{tab.startIcon}
<span className="whitespace-nowrap">
{tab.title}
</span>
{tab.error && (
<Badge
variant="warning"
size="xs"
className="ml-1.5"
>
<TriangleAlertIcon />
</Badge>
)}
</TabsTrigger>
))}
{overflowLogTabs.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
data-slot="tabs-trigger"
data-log-overflow-trigger
data-state={
overflowLogTabValuesSet.has(selectedLogTab)
? "active"
: "inactive"
}
aria-label="More log tabs"
className={cn(
"cursor-pointer -mb-px",
"inline-flex items-center justify-center",
"border-none py-3 bg-transparent text-inherit",
"transition-colors duration-150 ease-linear",
)}
>
<EllipsisIcon className="size-icon-sm" />
<span className="sr-only">More log tabs</span>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuRadioGroup
value={selectedLogTab}
onValueChange={handleSelectedLogTabChange}
>
{overflowLogTabs.map((tab) => (
<DropdownMenuRadioItem
key={tab.value}
value={tab.value}
className="gap-2"
>
{tab.startIcon}
<span className="whitespace-nowrap">
{tab.title}
</span>
{tab.error && (
<Badge
variant="warning"
size="xs"
className="ml-1.5"
>
<TriangleAlertIcon />
</Badge>
)}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)}
</TabsList>
</div>
<div
className={cn(
"h-12.5 shrink-0 flex items-center gap-2 pl-2 pr-3",
"border-solid border-0 border-b border-l",
)}
<ChevronDownIcon open={showLogs} />
<span>Logs</span>
{agent.lifecycle_state === "starting" &&
runningScriptsCount > 0 &&
connectivityIssues.length === 0 && (
<Badge
variant="default"
size="xs"
className="ml-1.5"
svgSize="sm"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="subtle"
size="sm"
className="min-w-0"
disabled={!hasSelectedLogs}
onClick={() => copyToClipboard(selectedLogsText)}
>
{showCopiedSuccess ? <CheckIcon /> : <CopyIcon />}
</Button>
</TooltipTrigger>
<TooltipContent>
{showCopiedSuccess
? "Copied!"
: "Copy selected logs"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<DownloadSelectedAgentLogsButton
agentName={agent.name}
logSets={downloadableLogSets}
allLogsText={allLogsText}
disabled={!hasAnyLogs}
<Spinner
size="lg"
loading
className="text-content-secondary -ml-1"
/>
</div>
</div>
{/*
Using a singular TabsContent is necessary to avoid scrolling
issues when the selected log tab changes.
*/}
<TabsContent value={selectedLogTab}>
<AutoSizer disableHeight>
{({ width }) => (
<AgentLogs
ref={logListRef}
innerRef={logListDivRef}
height={256}
width={width}
onScroll={handleLogScroll}
logs={selectedLogLines}
sources={agent.log_sources}
overflowed={agent.logs_overflowed}
className="bg-transparent"
showSourceIcons={selectedLogTab === "all"}
/>
)}
</AutoSizer>
</TabsContent>
</Tabs>
</div>
)}
<span>{runningScriptsCount}</span>
</Badge>
)}
{hasConnectivityIssues && (
<Badge
variant={hasWarningConnectivityIssues ? "warning" : "info"}
size="xs"
className="ml-1.5"
>
{hasWarningConnectivityIssues ? (
<TriangleAlertIcon className="-ml-0.5" />
) : (
<InfoIcon className="-ml-0.5" />
)}
<span>{connectivityIssues.length}</span>
</Badge>
)}
</Button>
</CollapsibleTrigger>
</div>
</Collapse>
<CollapsibleContent>
<div className={cn("px-4", hasStartupFeatures ? "pb-4" : "py-4")}>
{/*
Gate the spinner on `shouldExpandLogs` so it does not flash while
CollapsibleContent is closing.
*/}
{shouldExpandLogs &&
!(hasConnectivityIssues || shouldShowLogsTabs) && (
<div className="h-[300px] flex items-center justify-center">
<Spinner size="lg" loading className="block mx-auto" />
</div>
)}
{hasConnectivityIssues && (
<div className="mb-4 flex flex-col gap-3">
{connectivityIssues.map((issue) => (
<AgentAlert
key={`${issue.title}-${issue.detail}`}
{...issue}
troubleshootingURL={agent.troubleshooting_url}
/>
))}
</div>
)}
{shouldShowLogsTabs && (
<div className="border border-solid rounded-md overflow-clip">
<Tabs
className="-mx-px -mt-px"
value={selectedLogTab}
onValueChange={handleSelectedLogTabChange}
>
<div className="flex items-stretch">
<div className="min-w-0 flex-1 overflow-hidden">
<TabsList
variant="outsideBox"
overflowKebabMenu
ref={logTabsListContainerRef}
className="px-4"
>
{visibleLogTabs.map((tab) => (
<TabsTrigger
key={tab.value}
value={tab.value}
{...getTabMeasureProps(tab.value)}
>
{tab.startIcon}
<span className="whitespace-nowrap">
{tab.title}
</span>
{tab.error && (
<Badge
variant="warning"
size="xs"
className="ml-1.5"
>
<TriangleAlertIcon />
</Badge>
)}
</TabsTrigger>
))}
{overflowLogTabs.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
data-slot="tabs-trigger"
data-log-overflow-trigger
data-state={
overflowLogTabValuesSet.has(selectedLogTab)
? "active"
: "inactive"
}
aria-label="More log tabs"
className={cn(
"cursor-pointer -mb-px",
"inline-flex items-center justify-center",
"border-none py-3 bg-transparent text-inherit",
"transition-colors duration-150 ease-linear",
)}
>
<EllipsisIcon className="size-icon-sm" />
<span className="sr-only">More log tabs</span>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuRadioGroup
value={selectedLogTab}
onValueChange={handleSelectedLogTabChange}
>
{overflowLogTabs.map((tab) => (
<DropdownMenuRadioItem
key={tab.value}
value={tab.value}
className="gap-2"
>
{tab.startIcon}
<span className="whitespace-nowrap">
{tab.title}
</span>
{tab.error && (
<Badge
variant="warning"
size="xs"
className="ml-1.5"
>
<TriangleAlertIcon />
</Badge>
)}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)}
</TabsList>
</div>
<div
className={cn(
"h-12.5 shrink-0 flex items-center gap-2 pl-2 pr-3",
"border-solid border-0 border-b border-l",
)}
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="subtle"
size="sm"
className="min-w-0"
disabled={!hasSelectedLogs}
onClick={() =>
copyToClipboard(selectedLogsText)
}
>
{showCopiedSuccess ? (
<CheckIcon />
) : (
<CopyIcon />
)}
</Button>
</TooltipTrigger>
<TooltipContent>
{showCopiedSuccess
? "Copied!"
: "Copy selected logs"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<DownloadSelectedAgentLogsButton
agentName={agent.name}
logSets={downloadableLogSets}
allLogsText={allLogsText}
disabled={!hasAnyLogs}
/>
</div>
</div>
{/*
Using a singular TabsContent is necessary to avoid scrolling
issues when the selected log tab changes.
*/}
<TabsContent value={selectedLogTab}>
<AutoSizer disableHeight>
{({ width }) => (
<AgentLogs
ref={logListRef}
innerRef={logListDivRef}
height={256}
width={width}
onScroll={handleLogScroll}
logs={selectedLogLines}
sources={agent.log_sources}
overflowed={agent.logs_overflowed}
className="bg-transparent"
showSourceIcons={selectedLogTab === "all"}
/>
)}
</AutoSizer>
</TabsContent>
</Tabs>
</div>
)}
</div>
</CollapsibleContent>
</Collapsible>
</section>
</div>
);
+8 -2
View File
@@ -1,4 +1,3 @@
import Link from "@mui/material/Link";
import { TriangleAlertIcon } from "lucide-react";
import type { FC } from "react";
import type {
@@ -12,6 +11,7 @@ import {
HelpPopoverTitle,
HelpPopoverTrigger,
} from "#/components/HelpPopover/HelpPopover";
import { Link } from "#/components/Link/Link";
import {
Tooltip,
TooltipContent,
@@ -75,7 +75,13 @@ const AgentWarningTooltip: FC<AgentWarningTooltipProps> = ({
{troubleshootingURL && (
<>
{" "}
<Link target="_blank" rel="noreferrer" href={troubleshootingURL}>
<Link
target="_blank"
rel="noreferrer"
href={troubleshootingURL}
className="p-0 mt-2"
showExternalIcon={false}
>
Troubleshoot
</Link>
</>