Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions react-compiler.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const REACT_COMPILER_ENABLED_DIRS = [
"src/components/shared/TaskDetails/Actions/UnpackSubgraphButton.tsx",
"src/components/shared/ReactFlow/FlowSidebar/components/ComponentHoverPopover.tsx",
"src/components/shared/ReactFlow/FlowControls/StackingControls.tsx",
"src/components/shared/ReactFlow/FlowCanvas/TaskNode/StatusIndicator.tsx",
"src/components/shared/ReactFlow/FlowCanvas/FlexNode",
"src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/ZIndexEditor.tsx",
"src/components/Editor/IOEditor/IOZIndexEditor.tsx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,34 @@ import {
getExecutionStatusLabel,
} from "@/utils/executionStatus";

type StatusTabProps = {
status: string;
label?: string;
className?: string;
};

/** @public consumed by the run comparison graph, landed later in this stack. */
export const StatusTab = ({ status, label, className }: StatusTabProps) => {
const { style, text, icon } = getStatusMetadata(status);

return (
<div
title={label ? `${label} · ${text}` : text}
className={cn(
"h-8.75 overflow-hidden rounded-t-md px-2.5 py-1 text-[10px]",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 This is an AI-generated code review comment.

The extraction changes how the existing indicator renders (Medium)

StatusTab is a clean extraction, but it adds overflow-hidden here plus whitespace-nowrap and truncate on the inner row — none of which the original markup had — and StatusIndicator below now renders through it. So editor and run-graph task nodes start truncating status text instead of wrapping it, which is outside this PR's stated scope.

If the truncation is only needed for the two side-by-side tabs in the compare graph, pass it in via className from MergedTaskNode and leave the shared path rendering as it did.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated reply.

Checked this one and I do not think it changes the existing indicator — leaving the extraction as is.

  • On the StatusIndicator path the new classes are inert: the wrapper is absolute … flex items-start with no width cap, so the tab is shrink-to-fit and there is nothing for min-w-0 / truncate / overflow-hidden to act on.
  • They are load-bearing in MergedTaskNode, which passes min-w-0 flex-1 into a w-64 node — that is what the extraction was for.

One real change I will own: the shared tab adds a native title tooltip, so the editor and run graph now get a hover tooltip on the status label where they previously had none. Happy to gate that behind a prop if it is unwanted.

style,
className,
)}
>
<div className="flex min-w-0 items-center gap-1 font-mono whitespace-nowrap text-white">
{label && <span className="shrink-0 font-semibold">{label}</span>}
<span className="shrink-0">{icon}</span>
<span className="truncate">{text}</span>
</div>
</div>
);
};

type StatusIndicatorProps = {
status: string;
disabledCache?: boolean;
Expand All @@ -23,20 +51,12 @@ export const StatusIndicator = ({
status,
disabledCache = false,
}: StatusIndicatorProps) => {
const { style, text, icon } = getStatusMetadata(status);

return (
<div className="absolute -z-1 -top-5 left-0 flex items-start">
<div
className={cn("h-8.75 rounded-t-md px-2.5 py-1 text-[10px]", style, {
"rounded-tr-none": disabledCache,
})}
>
<div className="flex items-center gap-1 font-mono text-white">
{icon}
{text}
</div>
</div>
<StatusTab
status={status}
className={cn({ "rounded-tr-none": disabledCache })}
/>
{disabledCache && (
<div className="h-5.5 bg-status-cancelling rounded-tr-md flex items-center px-1.5">
<QuickTooltip content="Cache Disabled" className="whitespace-nowrap">
Expand Down
36 changes: 32 additions & 4 deletions src/routes/v2/pages/CompareView/components/DiffStatusBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,56 @@ import { Icon } from "@/components/ui/icon";
import { InlineStack } from "@/components/ui/layout";
import { Text } from "@/components/ui/typography";
import { cn } from "@/lib/utils";
import type { SpotlightMode } from "@/routes/v2/pages/CompareView/utils/buildMergedGraph";
import { DIFF_STATUS_ICON, type DiffStatus } from "@/utils/diffStatus";

export const DIFF_STATUS_LABELS: Record<DiffStatus, string> = {
const DIFF_STATUS_LABELS: Record<DiffStatus, string> = {
unchanged: "Unchanged",
lost: "Removed",
new: "Added",
changed: "Changed",
};

const SPOTLIGHT_STATUS_LABELS: Partial<Record<DiffStatus, string>> = {
lost: "Only in A",
new: "Only in B",
};

/**
* "Added" and "Removed" describe a move from A to B, which only makes sense
* while both runs are on screen. With one run spotlighted the reader is standing
* inside it, so a task being highlighted *and* called removed contradicts
* itself — name the run it belongs to instead.
*/
export function diffStatusLabel(
status: DiffStatus,
spotlight: SpotlightMode = "both",
): string {
const sideLabel =
spotlight === "both" ? undefined : SPOTLIGHT_STATUS_LABELS[status];
return sideLabel ?? DIFF_STATUS_LABELS[status];
}

const DIFF_STATUS_TONE: Record<DiffStatus, string> = {
unchanged: "bg-diff-unchanged text-diff-unchanged-foreground",
lost: "bg-diff-lost text-diff-lost-foreground line-through",
lost: "bg-diff-lost text-diff-lost-foreground",
new: "bg-diff-new text-diff-new-foreground",
changed: "bg-diff-changed text-diff-changed-foreground",
};

interface DiffStatusBadgeProps {
status: DiffStatus;
spotlight?: SpotlightMode;
className?: string;
}

export function DiffStatusBadge({ status, className }: DiffStatusBadgeProps) {
export function DiffStatusBadge({
status,
spotlight = "both",
className,
}: DiffStatusBadgeProps) {
const icon = DIFF_STATUS_ICON[status];
const label = diffStatusLabel(status, spotlight);

return (
<InlineStack
Expand All @@ -35,12 +62,13 @@ export function DiffStatusBadge({ status, className }: DiffStatusBadgeProps) {
className={cn(
"rounded px-1.5 py-0.5",
DIFF_STATUS_TONE[status],
status === "lost" && spotlight === "both" && "line-through",
className,
)}
>
{icon && <Icon name={icon.name} size="xs" />}
<Text as="span" size="xs" weight="semibold" className="text-inherit">
{DIFF_STATUS_LABELS[status]}
{label}
</Text>
</InlineStack>
);
Expand Down
Loading
Loading