Skip to content

Commit 950e030

Browse files
committed
Rework CodeViewer Implementation
1 parent c5adfbb commit 950e030

File tree

6 files changed

+123
-105
lines changed

6 files changed

+123
-105
lines changed

src/components/Editor/Context/PipelineDetails.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { useEffect, useState } from "react";
22

33
import { useValidationIssueNavigation } from "@/components/Editor/hooks/useValidationIssueNavigation";
4+
import { ViewYamlButton } from "@/components/shared/Buttons/ViewYamlButton";
45
import { ActionBlock } from "@/components/shared/ContextPanel/Blocks/ActionBlock";
56
import { ContentBlock } from "@/components/shared/ContextPanel/Blocks/ContentBlock";
67
import { ListBlock } from "@/components/shared/ContextPanel/Blocks/ListBlock";
78
import { TextBlock } from "@/components/shared/ContextPanel/Blocks/TextBlock";
89
import { CopyText } from "@/components/shared/CopyText/CopyText";
9-
import { TaskImplementation } from "@/components/shared/TaskDetails";
1010
import { BlockStack } from "@/components/ui/layout";
1111
import useToastNotification from "@/hooks/useToastNotification";
1212
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
@@ -83,12 +83,7 @@ const PipelineDetails = () => {
8383

8484
const actions = [
8585
<RenamePipeline key="rename-pipeline-action" />,
86-
<TaskImplementation
87-
key="pipeline-implementation-action"
88-
displayName={componentSpec.name ?? "Pipeline"}
89-
componentSpec={componentSpec}
90-
showInlineContent={false}
91-
/>,
86+
<ViewYamlButton key="view-pipeline-yaml" componentSpec={componentSpec} />,
9287
];
9388

9489
return (

src/components/PipelineRun/RunDetails.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import {
2-
ActionBlock,
3-
type ActionOrReactNode,
4-
} from "@/components/shared/ContextPanel/Blocks/ActionBlock";
1+
import { ActionBlock } from "@/components/shared/ContextPanel/Blocks/ActionBlock";
52
import { ContentBlock } from "@/components/shared/ContextPanel/Blocks/ContentBlock";
63
import { ListBlock } from "@/components/shared/ContextPanel/Blocks/ListBlock";
74
import { TextBlock } from "@/components/shared/ContextPanel/Blocks/TextBlock";
@@ -10,7 +7,6 @@ import PipelineIO from "@/components/shared/Execution/PipelineIO";
107
import { InfoBox } from "@/components/shared/InfoBox";
118
import { LoadingScreen } from "@/components/shared/LoadingScreen";
129
import { StatusBar } from "@/components/shared/Status";
13-
import { TaskImplementation } from "@/components/shared/TaskDetails";
1410
import { BlockStack, InlineStack } from "@/components/ui/layout";
1511
import { Text } from "@/components/ui/typography";
1612
import { useCheckComponentSpecFromPath } from "@/hooks/useCheckComponentSpecFromPath";
@@ -26,6 +22,7 @@ import {
2622
isExecutionComplete,
2723
} from "@/utils/executionStatus";
2824

25+
import { ViewYamlButton } from "../shared/Buttons/ViewYamlButton";
2926
import { CancelPipelineRunButton } from "./components/CancelPipelineRunButton";
3027
import { ClonePipelineButton } from "./components/ClonePipelineButton";
3128
import { InspectPipelineButton } from "./components/InspectPipelineButton";
@@ -93,14 +90,10 @@ export const RunDetails = () => {
9390

9491
const annotations = componentSpec.metadata?.annotations || {};
9592

96-
const actions: ActionOrReactNode[] = [];
93+
const actions = [];
9794

9895
actions.push(
99-
<TaskImplementation
100-
displayName={componentSpec.name ?? "Pipeline"}
101-
componentSpec={componentSpec}
102-
showInlineContent={false}
103-
/>,
96+
<ViewYamlButton key="view-pipeline-yaml" componentSpec={componentSpec} />,
10497
);
10598

10699
if (canAccessEditorSpec && componentSpec.name) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useState } from "react";
2+
3+
import { Icon } from "@/components/ui/icon";
4+
import type {
5+
ComponentSpec,
6+
HydratedComponentReference,
7+
} from "@/utils/componentSpec";
8+
import { getComponentName } from "@/utils/getComponentName";
9+
10+
import TaskImplementation from "../TaskDetails/Implementation";
11+
import TooltipButton from "./TooltipButton";
12+
13+
type ViewYamlButtonProps =
14+
| { componentRef: HydratedComponentReference; componentSpec?: never }
15+
| { componentSpec: ComponentSpec; componentRef?: never };
16+
17+
export const ViewYamlButton = ({
18+
componentRef,
19+
componentSpec,
20+
}: ViewYamlButtonProps) => {
21+
const [showCodeViewer, setShowCodeViewer] = useState(false);
22+
23+
const name = componentRef
24+
? getComponentName(componentRef)
25+
: componentSpec.name || "Component";
26+
27+
const handleClick = () => {
28+
setShowCodeViewer(true);
29+
};
30+
31+
const handleClose = () => {
32+
setShowCodeViewer(false);
33+
};
34+
35+
return (
36+
<>
37+
<TooltipButton
38+
variant="outline"
39+
tooltip="View YAML"
40+
onClick={handleClick}
41+
>
42+
<Icon name="FileCodeCorner" />
43+
</TooltipButton>
44+
45+
{showCodeViewer && (
46+
<TaskImplementation
47+
componentRef={componentRef}
48+
componentSpec={componentSpec}
49+
displayName={name}
50+
fullscreen
51+
onClose={handleClose}
52+
/>
53+
)}
54+
</>
55+
);
56+
};

src/components/shared/CodeViewer/CodeViewer.tsx

Lines changed: 40 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import { FileCode2, Maximize2, X as XIcon } from "lucide-react";
21
import { useEffect, useState } from "react";
32

43
import { Button } from "@/components/ui/button";
5-
import { cn } from "@/lib/utils";
4+
import { Icon } from "@/components/ui/icon";
65

7-
import TooltipButton from "../Buttons/TooltipButton";
86
import { FullscreenElement } from "../FullscreenElement";
97
import CodeSyntaxHighlighter from "./CodeSyntaxHighlighter";
108

119
interface CodeViewerProps {
1210
code: string;
1311
language?: string;
1412
filename?: string;
15-
showInlineContent?: boolean;
13+
fullscreen?: boolean;
14+
onClose?: () => void;
1615
}
1716

1817
const DEFAULT_CODE_VIEWER_HEIGHT = 128;
@@ -21,28 +20,19 @@ const CodeViewer = ({
2120
code,
2221
language = "yaml",
2322
filename = "",
24-
showInlineContent = true,
23+
fullscreen = false,
24+
onClose,
2525
}: CodeViewerProps) => {
26-
const [isFullscreen, setIsFullscreen] = useState(false);
27-
const shouldRenderInlineCode = showInlineContent || isFullscreen;
26+
const [isFullscreen, setIsFullscreen] = useState(fullscreen);
27+
28+
const handleToggleFullscreen = () => {
29+
if (isFullscreen && onClose) {
30+
onClose();
31+
}
2832

29-
const handleEnterFullscreen = () => {
3033
setIsFullscreen((prev) => !prev);
3134
};
3235

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-
4636
useEffect(() => {
4737
const handleEscapeKey = (e: KeyboardEvent) => {
4838
if (isFullscreen && e.key === "Escape") {
@@ -61,54 +51,37 @@ const CodeViewer = ({
6151

6252
return (
6353
<FullscreenElement fullscreen={isFullscreen}>
64-
<div
65-
className={cn(
66-
"flex flex-col transition-shadow duration-150",
67-
shouldRenderInlineCode
68-
? "bg-slate-900 h-full rounded-md"
69-
: "bg-transparent",
70-
)}
71-
>
72-
{shouldRenderInlineCode ? (
73-
<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">
74-
<div className="flex items-baseline gap-2">
75-
<span className="font-semibold text-base text-secondary">
76-
{filename}
77-
</span>
78-
<span className="text-sm text-secondary">(Read Only)</span>
79-
</div>
80-
<Button
81-
type="button"
82-
variant="ghost"
83-
size="icon"
84-
onClick={handleEnterFullscreen}
85-
className="text-gray-200 hover:text-white"
86-
title={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
87-
aria-label={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
88-
>
89-
{isFullscreen ? (
90-
<XIcon className="size-4" />
91-
) : (
92-
<Maximize2 className="size-4" />
93-
)}
94-
</Button>
54+
<div className="flex flex-col transition-shadow duration-150 bg-slate-900 h-full rounded-md">
55+
<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">
56+
<div className="flex items-baseline gap-2">
57+
<span className="font-semibold text-base text-secondary">
58+
{filename}
59+
</span>
60+
<span className="text-sm text-secondary">(Read Only)</span>
9561
</div>
96-
) : (
97-
<div className="flex">{compactButton}</div>
98-
)}
99-
{shouldRenderInlineCode && (
100-
<div className="flex-1 relative">
101-
<div
102-
className="absolute inset-0 overflow-y-auto bg-slate-900"
103-
style={{
104-
willChange: "transform",
105-
minHeight: DEFAULT_CODE_VIEWER_HEIGHT,
106-
}}
107-
>
108-
<CodeSyntaxHighlighter code={code} language={language} />
109-
</div>
62+
<Button
63+
type="button"
64+
variant="ghost"
65+
size="icon"
66+
onClick={handleToggleFullscreen}
67+
className="text-gray-200 hover:text-black"
68+
title={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
69+
aria-label={isFullscreen ? "Exit fullscreen" : "View fullscreen"}
70+
>
71+
{isFullscreen ? <Icon name="X" /> : <Icon name="Maximize2" />}
72+
</Button>
73+
</div>
74+
<div className="flex-1 relative">
75+
<div
76+
className="absolute inset-0 overflow-y-auto bg-slate-900"
77+
style={{
78+
willChange: "transform",
79+
minHeight: DEFAULT_CODE_VIEWER_HEIGHT,
80+
}}
81+
>
82+
<CodeSyntaxHighlighter code={code} language={language} />
11083
</div>
111-
)}
84+
</div>
11285
</div>
11386
</FullscreenElement>
11487
);

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {
88

99
import type { TooltipButtonProps } from "@/components/shared/Buttons/TooltipButton";
1010
import TooltipButton from "@/components/shared/Buttons/TooltipButton";
11+
import { ViewYamlButton } from "@/components/shared/Buttons/ViewYamlButton";
1112
import { ComponentDetailsDialog } from "@/components/shared/Dialogs";
1213
import { ComponentFavoriteToggle } from "@/components/shared/FavoriteComponentToggle";
1314
import { StatusIcon } from "@/components/shared/Status";
14-
import {
15-
TaskDetails,
16-
TaskImplementation,
17-
} from "@/components/shared/TaskDetails";
15+
import { TaskDetails } from "@/components/shared/TaskDetails";
1816
import { Icon } from "@/components/ui/icon";
1917
import { BlockStack, InlineStack } from "@/components/ui/layout";
2018
import { Separator } from "@/components/ui/separator";
@@ -66,12 +64,7 @@ const TaskOverview = ({ taskNode, actions }: TaskOverviewProps) => {
6664
...(actions?.map((action) => (
6765
<TooltipButton {...action} key={action.tooltip?.toString()} />
6866
)) ?? []),
69-
<TaskImplementation
70-
key="task-implementation-action"
71-
displayName={name}
72-
componentRef={taskSpec.componentRef}
73-
showInlineContent={false}
74-
/>,
67+
<ViewYamlButton key="view-task-yaml" componentSpec={componentSpec} />,
7568
];
7669

7770
return (

src/components/shared/TaskDetails/Implementation.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@ interface TaskImplementationProps {
99
displayName: string;
1010
componentRef?: ComponentReference;
1111
componentSpec?: ComponentSpec;
12-
showInlineContent?: boolean;
12+
fullscreen?: boolean;
13+
onClose?: () => void;
1314
}
1415

1516
const TaskImplementation = withSuspenseWrapper(
1617
({
1718
displayName,
1819
componentRef,
1920
componentSpec,
20-
showInlineContent = true,
21+
fullscreen,
22+
onClose,
2123
}: TaskImplementationProps) => {
2224
if (componentRef) {
2325
return (
2426
<ComponentRefCodeViewer
2527
componentRef={componentRef}
2628
displayName={displayName}
27-
showInlineContent={showInlineContent}
29+
fullscreen={fullscreen}
30+
onClose={onClose}
2831
/>
2932
);
3033
}
@@ -34,7 +37,8 @@ const TaskImplementation = withSuspenseWrapper(
3437
<ComponentSpecCodeViewer
3538
componentSpec={componentSpec}
3639
displayName={displayName}
37-
showInlineContent={showInlineContent}
40+
fullscreen={fullscreen}
41+
onClose={onClose}
3842
/>
3943
);
4044
}
@@ -51,8 +55,9 @@ const ComponentRefCodeViewer = withSuspenseWrapper(
5155
({
5256
componentRef,
5357
displayName,
54-
showInlineContent = true,
55-
}: Pick<TaskImplementationProps, "displayName" | "showInlineContent"> & {
58+
fullscreen,
59+
onClose,
60+
}: Omit<TaskImplementationProps, "componentSpec"> & {
5661
componentRef: ComponentReference;
5762
}) => {
5863
const hydratedComponentRef = useHydrateComponentReference(componentRef);
@@ -66,7 +71,8 @@ const ComponentRefCodeViewer = withSuspenseWrapper(
6671
code={hydratedComponentRef.text}
6772
language="yaml"
6873
filename={displayName}
69-
showInlineContent={showInlineContent}
74+
fullscreen={fullscreen}
75+
onClose={onClose}
7076
/>
7177
);
7278
},
@@ -75,8 +81,9 @@ const ComponentRefCodeViewer = withSuspenseWrapper(
7581
const ComponentSpecCodeViewer = ({
7682
componentSpec,
7783
displayName,
78-
showInlineContent = true,
79-
}: Pick<TaskImplementationProps, "displayName" | "showInlineContent"> & {
84+
fullscreen,
85+
onClose,
86+
}: Omit<TaskImplementationProps, "componentRef"> & {
8087
componentSpec: ComponentSpec;
8188
}) => {
8289
const code = componentSpecToText(componentSpec);
@@ -86,7 +93,8 @@ const ComponentSpecCodeViewer = ({
8693
code={code}
8794
language="yaml"
8895
filename={displayName}
89-
showInlineContent={showInlineContent}
96+
fullscreen={fullscreen}
97+
onClose={onClose}
9098
/>
9199
);
92100
};

0 commit comments

Comments
 (0)