Skip to content

Commit 96dcbf7

Browse files
authored
Updates view yaml button (#1434)
## Description Redesigned the YAML viewer component to improve usability across the application. The CodeViewer component now supports a collapsed state with a "View YAML" button that expands to show the full YAML content. This change applies to Pipeline Details, Run Details, and Task Overview sections. Key improvements: - Added a compact "View YAML" button that replaces the previously expanded YAML sections - Removed the collapsible Pipeline YAML section in favor of the new button approach - Improved styling and consistency of the code viewer component - Added proper fullscreen toggle functionality with keyboard support ## Type of Change - [x] Improvement - [x] Cleanup/Refactor ## Checklist - [x] I have tested this does not break current pipelines / runs functionality - [x] I have tested the changes on staging ## Test Instructions 1. Navigate to Pipeline Details, Run Details, or Task Overview sections 2. Verify the new "View YAML" button appears instead of the expanded YAML section 3. Click the button to view the YAML in fullscreen mode 4. Test that ESC key closes the fullscreen view 5. Verify the YAML content is correctly displayed and formatted 6\. Verify logs and component library implimentation are still functionl as they were before [yaml.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.com/user-attachments/thumbnails/4429657d-b138-4d41-9bff-0558afb322a5.mov" />](https://app.graphite.com/user-attachments/video/4429657d-b138-4d41-9bff-0558afb322a5.mov)
1 parent 184824e commit 96dcbf7

File tree

9 files changed

+98
-121
lines changed

9 files changed

+98
-121
lines changed

src/components/Editor/PipelineDetails.tsx

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ import { Frown, Network } from "lucide-react";
22
import { useEffect, useState } from "react";
33

44
import { Button } from "@/components/ui/button";
5-
import {
6-
Collapsible,
7-
CollapsibleContent,
8-
CollapsibleTrigger,
9-
} from "@/components/ui/collapsible";
105
import { Icon } from "@/components/ui/icon";
116
import { InlineStack } from "@/components/ui/layout";
127
import { ScrollArea } from "@/components/ui/scroll-area";
@@ -34,8 +29,6 @@ const PipelineDetails = () => {
3429

3530
const notify = useToastNotification();
3631

37-
const [isYamlOpen, setIsYamlOpen] = useState(false);
38-
3932
// Utility function to convert TypeSpecType to string
4033
const typeSpecToString = (typeSpec?: TypeSpecType): string => {
4134
if (typeSpec === undefined) {
@@ -134,6 +127,14 @@ const PipelineDetails = () => {
134127
<RenamePipeline />
135128
</div>
136129

130+
<div className="flex gap-2 flex-wrap items-center">
131+
<TaskImplementation
132+
displayName={componentSpec.name ?? "Pipeline"}
133+
componentSpec={componentSpec}
134+
showInlineContent={false}
135+
/>
136+
</div>
137+
137138
{/* General Metadata */}
138139
<div className="flex flex-col gap-2 text-xs text-secondary-foreground mb-2">
139140
<div className="flex flex-wrap gap-6">
@@ -339,30 +340,6 @@ const PipelineDetails = () => {
339340
</InfoBox>
340341
)}
341342
</div>
342-
343-
{/* Pipeline YAML */}
344-
<Collapsible
345-
open={isYamlOpen}
346-
onOpenChange={setIsYamlOpen}
347-
className="h-full"
348-
>
349-
<CollapsibleTrigger asChild>
350-
<InlineStack
351-
gap="1"
352-
blockAlign="center"
353-
className="font-medium text-md cursor-pointer"
354-
>
355-
<Icon name={isYamlOpen ? "ChevronDown" : "ChevronRight"} />
356-
Pipeline YAML
357-
</InlineStack>
358-
</CollapsibleTrigger>
359-
<CollapsibleContent className="mt-1 h-9/10 flex-1 min-h-0">
360-
<TaskImplementation
361-
displayName={componentSpec.name ?? "Pipeline"}
362-
componentSpec={componentSpec}
363-
/>
364-
</CollapsibleContent>
365-
</Collapsible>
366343
</div>
367344
);
368345
};

src/components/PipelineRun/RunDetails.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,12 @@ export const RunDetails = () => {
125125
)}
126126

127127
<div>
128-
<div className="flex gap-2">
128+
<div className="flex gap-2 flex-wrap items-center">
129+
<TaskImplementation
130+
displayName={componentSpec.name ?? "Pipeline"}
131+
componentSpec={componentSpec}
132+
showInlineContent={false}
133+
/>
129134
{canAccessEditorSpec && componentSpec.name && (
130135
<InspectPipelineButton pipelineName={componentSpec.name} />
131136
)}
@@ -229,20 +234,6 @@ export const RunDetails = () => {
229234
</div>
230235
</div>
231236
</div>
232-
233-
{componentSpec && (
234-
<div className="flex flex-col h-full">
235-
<div className="font-medium text-md flex items-center gap-1 cursor-pointer">
236-
Pipeline YAML
237-
</div>
238-
<div className="mt-1 h-full min-h-0 flex-1">
239-
<TaskImplementation
240-
displayName={componentSpec.name ?? "Pipeline"}
241-
componentSpec={componentSpec}
242-
/>
243-
</div>
244-
</div>
245-
)}
246237
</div>
247238
);
248239
};

src/components/shared/CodeViewer/CodeViewer.tsx

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
1-
import { Maximize2, X as XIcon } from "lucide-react";
1+
import { FileCode2, Maximize2, X as XIcon } from "lucide-react";
22
import { useCallback, useEffect, useState } from "react";
33

44
import { Button } from "@/components/ui/button";
5+
import { cn } from "@/lib/utils";
56

7+
import TooltipButton from "../Buttons/TooltipButton";
68
import { FullscreenElement } from "../FullscreenElement";
79
import CodeSyntaxHighlighter from "./CodeSyntaxHighlighter";
810

911
interface CodeViewerProps {
1012
code: string;
1113
language?: string;
12-
title?: string;
1314
filename?: string;
15+
showInlineContent?: boolean;
1416
}
1517

16-
const DEFAULT_HEIGHT = 128;
18+
const DEFAULT_CODE_VIEWER_HEIGHT = 128;
1719

1820
const CodeViewer = ({
1921
code,
2022
language = "yaml",
2123
filename = "",
24+
showInlineContent = true,
2225
}: CodeViewerProps) => {
2326
const [isFullscreen, setIsFullscreen] = useState(false);
27+
const shouldRenderInlineCode = showInlineContent || isFullscreen;
2428

2529
const handleEnterFullscreen = useCallback(() => {
2630
setIsFullscreen((prev) => !prev);
2731
}, []);
2832

33+
const compactButton = (
34+
<TooltipButton
35+
type="button"
36+
variant="outline"
37+
size="icon"
38+
tooltip="View YAML"
39+
onClick={handleEnterFullscreen}
40+
aria-label="View YAML"
41+
>
42+
<FileCode2 className="size-4" />
43+
</TooltipButton>
44+
);
45+
2946
useEffect(() => {
3047
const handleEscapeKey = (e: KeyboardEvent) => {
3148
if (isFullscreen && e.key === "Escape") {
@@ -44,33 +61,46 @@ const CodeViewer = ({
4461

4562
return (
4663
<FullscreenElement fullscreen={isFullscreen}>
47-
<div className="h-full bg-slate-900 flex flex-col">
48-
<div className="flex justify-between items-center p-2 sticky top-0 z-10 bg-slate-800">
49-
<h3 className="text-secondary font-medium ml-2">
50-
{filename} <span className="text-sm">(Read Only)</span>
51-
</h3>
52-
<Button
53-
variant="ghost"
54-
size="icon"
55-
onClick={handleEnterFullscreen}
56-
className="text-gray-300 hover:text-slate-800"
57-
title={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
58-
>
59-
{isFullscreen ? (
60-
<XIcon className="size-4" />
61-
) : (
62-
<Maximize2 className="size-4" />
63-
)}
64-
</Button>
65-
</div>
66-
<div className="flex-1 relative">
67-
<div
68-
className="absolute inset-0 overflow-y-auto bg-slate-900"
69-
style={{ willChange: "transform", minHeight: DEFAULT_HEIGHT }}
70-
>
71-
<CodeSyntaxHighlighter code={code} language={language} />
64+
<div
65+
className={cn(
66+
"flex flex-col transition-shadow duration-150",
67+
shouldRenderInlineCode ? "bg-slate-900 h-full rounded-md" : "bg-transparent",
68+
)}
69+
>
70+
{shouldRenderInlineCode ? (
71+
<div className="flex items-center justify-between gap-2 bg-slate-800 sticky top-0 z-10 rounded-t-md px-3 py-2.5">
72+
<div className="flex items-baseline gap-2">
73+
<span className="font-semibold text-base text-secondary">{filename}</span>
74+
<span className="text-sm text-secondary">(Read Only)</span>
75+
</div>
76+
<Button
77+
type="button"
78+
variant="ghost"
79+
size="icon"
80+
onClick={handleEnterFullscreen}
81+
className="text-gray-200 hover:text-white"
82+
title={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
83+
aria-label={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
84+
>
85+
{isFullscreen ? <XIcon className="size-4" /> : <Maximize2 className="size-4" />}
86+
</Button>
87+
</div>
88+
) : (
89+
<div className="flex">{compactButton}</div>
90+
)}
91+
{shouldRenderInlineCode && (
92+
<div className="flex-1 relative">
93+
<div
94+
className="absolute inset-0 overflow-y-auto bg-slate-900"
95+
style={{
96+
willChange: "transform",
97+
minHeight: DEFAULT_CODE_VIEWER_HEIGHT,
98+
}}
99+
>
100+
<CodeSyntaxHighlighter code={code} language={language} />
101+
</div>
72102
</div>
73-
</div>
103+
)}
74104
</div>
75105
</FullscreenElement>
76106
);

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/TaskNodeCard.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const TaskNodeCard = () => {
135135
<CopyIcon />
136136
</div>
137137
),
138-
variant: "secondary",
138+
variant: "outline",
139139
tooltip: "Duplicate Task",
140140
onClick: callbacks.onDuplicate,
141141
},
@@ -145,7 +145,7 @@ const TaskNodeCard = () => {
145145
<CircleFadingArrowUp />
146146
</div>
147147
),
148-
variant: "secondary",
148+
variant: "outline",
149149
className: cn(isCustomComponent && "hidden"),
150150
tooltip: "Update Task from Source URL",
151151
onClick: callbacks.onUpgrade,
@@ -160,7 +160,7 @@ const TaskNodeCard = () => {
160160
<Icon name="Workflow" size="sm" />
161161
</div>
162162
),
163-
variant: "secondary",
163+
variant: "outline",
164164
tooltip: `Enter Subgraph: ${subgraphDescription}`,
165165
onClick: () => navigateToSubgraph(taskId),
166166
});
@@ -173,7 +173,7 @@ const TaskNodeCard = () => {
173173
<Icon name="FilePenLine" size="sm" />
174174
</div>
175175
),
176-
variant: "secondary",
176+
variant: "outline",
177177
tooltip: "Edit Component Definition",
178178
onClick: handleEditComponent,
179179
});

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/TaskOverview.tsx

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ const TaskOverview = ({ taskNode, actions }: TaskOverviewProps) => {
6161
const executionId = details?.child_task_execution_ids?.[taskId];
6262
const canRename = !readOnly && isSubgraph;
6363

64+
const detailActions = [
65+
...(actions?.map((action) => (
66+
<TooltipButton {...action} key={action.tooltip?.toString()} />
67+
)) ?? []),
68+
<TaskImplementation
69+
key="task-implementation-action"
70+
displayName={name}
71+
componentSpec={componentSpec}
72+
showInlineContent={false}
73+
/>,
74+
];
75+
6476
return (
6577
<BlockStack className="h-full" data-context-panel="task-overview">
6678
<InlineStack gap="2" blockAlign="center" className="px-2 pb-2">
@@ -118,24 +130,7 @@ const TaskOverview = ({ taskNode, actions }: TaskOverviewProps) => {
118130
status={status}
119131
hasDeletionConfirmation={false}
120132
readOnly={readOnly}
121-
additionalSection={[
122-
{
123-
title: "Component YAML",
124-
isCollapsed: true,
125-
component: (
126-
<div className="h-[512px]">
127-
<TaskImplementation
128-
key="task-implementation"
129-
displayName={name}
130-
componentSpec={componentSpec}
131-
/>
132-
</div>
133-
),
134-
},
135-
]}
136-
actions={actions?.map((action) => (
137-
<TooltipButton {...action} key={action.tooltip?.toString()} />
138-
))}
133+
actions={detailActions}
139134
/>
140135
</TabsContent>
141136
<TabsContent value="io">

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/logs.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ const LogDisplay = ({
3535
<CodeViewer
3636
code={logs.log_text || ""}
3737
language="text"
38-
title="Execution Logs"
3938
filename="Execution Logs"
4039
/>
4140
</div>
@@ -45,7 +44,6 @@ const LogDisplay = ({
4544
<CodeViewer
4645
code={logs.system_error_exception_full || ""}
4746
language="text"
48-
title="System Error Logs"
4947
filename="System Error Logs"
5048
/>
5149
</div>

src/components/shared/TaskDetails/Details.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,10 @@ const TaskDetails = ({
265265
</div>
266266
))}
267267

268-
<div className="px-3 py-2 flex flex-row gap-2" key={0}>
268+
<div className="px-3 py-2 flex flex-wrap gap-2" key={0}>
269269
<Tooltip>
270270
<TooltipTrigger asChild>
271-
<Button variant="secondary" onClick={handleDownloadYaml}>
271+
<Button variant="outline" onClick={handleDownloadYaml}>
272272
<DownloadIcon />
273273
</Button>
274274
</TooltipTrigger>
@@ -277,10 +277,7 @@ const TaskDetails = ({
277277
{pythonOriginalCode && (
278278
<Tooltip>
279279
<TooltipTrigger asChild>
280-
<Button
281-
variant="secondary"
282-
onClick={stringToPythonCodeDownload}
283-
>
280+
<Button variant="outline" onClick={stringToPythonCodeDownload}>
284281
<FaPython className="mr-1" />
285282
</Button>
286283
</TooltipTrigger>
@@ -289,7 +286,7 @@ const TaskDetails = ({
289286
)}
290287
<Tooltip>
291288
<TooltipTrigger asChild>
292-
<Button variant="secondary" onClick={handleCopyYaml}>
289+
<Button variant="outline" onClick={handleCopyYaml}>
293290
<ClipboardIcon />
294291
</Button>
295292
</TooltipTrigger>

src/components/shared/TaskDetails/Implementation.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@ import { useMemo } from "react";
33

44
import { CodeViewer } from "@/components/shared/CodeViewer";
55
import type { ComponentSpec } from "@/utils/componentSpec";
6-
import { getComponentFilename } from "@/utils/getComponentFilename";
76

87
interface TaskImplementationProps {
98
displayName: string;
109
componentSpec: ComponentSpec;
10+
showInlineContent?: boolean;
1111
}
1212

1313
const TaskImplementation = ({
1414
displayName,
1515
componentSpec,
16+
showInlineContent = true,
1617
}: TaskImplementationProps) => {
17-
const filename = getComponentFilename(componentSpec);
18-
1918
const code = useMemo(
2019
() =>
2120
yaml.dump(componentSpec, {
@@ -38,8 +37,8 @@ const TaskImplementation = ({
3837
<CodeViewer
3938
code={code}
4039
language="yaml"
41-
title={`${displayName} Implementation (read-only)`}
42-
filename={filename}
40+
filename={displayName}
41+
showInlineContent={showInlineContent}
4342
/>
4443
);
4544
};

0 commit comments

Comments
 (0)