Skip to content

Commit d1c04fd

Browse files
committed
Cleanup TaskDetails
1 parent ef66839 commit d1c04fd

File tree

5 files changed

+245
-358
lines changed

5 files changed

+245
-358
lines changed

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

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { useNavigate } from "@tanstack/react-router";
2-
import { CircleFadingArrowUp, CopyIcon } from "lucide-react";
32
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
43

54
import type { TooltipButtonProps } from "@/components/shared/Buttons/TooltipButton";
@@ -126,38 +125,26 @@ const TaskNodeCard = () => {
126125
const actions: Array<TooltipButtonProps> = [];
127126

128127
if (!readOnly) {
129-
actions.push(
130-
{
131-
children: (
132-
<div className="flex items-center gap-2">
133-
<CopyIcon />
134-
</div>
135-
),
136-
variant: "outline",
137-
tooltip: "Duplicate Task",
138-
onClick: callbacks.onDuplicate,
139-
},
140-
{
141-
children: (
142-
<div className="flex items-center gap-2">
143-
<CircleFadingArrowUp />
144-
</div>
145-
),
146-
variant: "outline",
147-
className: cn(isCustomComponent && "hidden"),
148-
tooltip: "Update Task from Source URL",
149-
onClick: callbacks.onUpgrade,
150-
},
151-
);
128+
actions.push({
129+
children: <Icon name="Copy" size="sm" />,
130+
variant: "outline",
131+
tooltip: "Duplicate Task",
132+
onClick: callbacks.onDuplicate,
133+
});
134+
}
135+
136+
if (!readOnly && !isCustomComponent) {
137+
actions.push({
138+
children: <Icon name="CircleFadingArrowUp" size="sm" />,
139+
variant: "outline",
140+
tooltip: "Update Task from Source URL",
141+
onClick: callbacks.onUpgrade,
142+
});
152143
}
153144

154145
if (isSubgraphNode && taskId && isSubgraphNavigationEnabled) {
155146
actions.push({
156-
children: (
157-
<div className="flex items-center gap-2">
158-
<Icon name="Workflow" size="sm" />
159-
</div>
160-
),
147+
children: <Icon name="Workflow" size="sm" />,
161148
variant: "outline",
162149
tooltip: `Enter Subgraph: ${subgraphDescription}`,
163150
onClick: () => navigateToSubgraph(taskId),
@@ -166,11 +153,7 @@ const TaskNodeCard = () => {
166153

167154
if (isInAppEditorEnabled) {
168155
actions.push({
169-
children: (
170-
<div className="flex items-center gap-2">
171-
<Icon name="FilePenLine" size="sm" />
172-
</div>
173-
),
156+
children: <Icon name="FilePenLine" size="sm" />,
174157
variant: "outline",
175158
tooltip: "Edit Component Definition",
176159
onClick: handleEditComponent,

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ const TaskOverview = ({ taskNode, actions }: TaskOverviewProps) => {
128128
url={taskSpec.componentRef.url}
129129
onDelete={callbacks.onDelete}
130130
status={status}
131-
hasDeletionConfirmation={false}
132131
readOnly={readOnly}
133132
actions={detailActions}
134133
/>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { type ReactNode } from "react";
2+
import { FaPython } from "react-icons/fa";
3+
4+
import useToastNotification from "@/hooks/useToastNotification";
5+
import type { ComponentSpec } from "@/utils/componentSpec";
6+
import { downloadYamlFromComponentText } from "@/utils/URL";
7+
import copyToYaml from "@/utils/yaml";
8+
9+
import {
10+
ActionBlock,
11+
type ActionOrReactNode,
12+
} from "../ContextPanel/Blocks/ActionBlock";
13+
14+
interface TaskActionsProps {
15+
displayName: string;
16+
componentSpec: ComponentSpec;
17+
actions?: ReactNode[];
18+
onDelete?: () => void;
19+
readOnly?: boolean;
20+
className?: string;
21+
}
22+
23+
const TaskActions = ({
24+
displayName,
25+
componentSpec,
26+
actions = [],
27+
onDelete,
28+
readOnly = false,
29+
className,
30+
}: TaskActionsProps) => {
31+
const notify = useToastNotification();
32+
33+
const pythonOriginalCode =
34+
componentSpec?.metadata?.annotations?.original_python_code;
35+
36+
const stringToPythonCodeDownload = () => {
37+
if (!pythonOriginalCode) return;
38+
39+
const blob = new Blob([pythonOriginalCode], { type: "text/x-python" });
40+
const url = URL.createObjectURL(blob);
41+
const a = document.createElement("a");
42+
a.href = url;
43+
a.download = `${componentSpec?.name || displayName}.py`;
44+
document.body.appendChild(a);
45+
a.click();
46+
document.body.removeChild(a);
47+
URL.revokeObjectURL(url);
48+
};
49+
50+
const handleDownloadYaml = () => {
51+
downloadYamlFromComponentText(componentSpec, displayName);
52+
};
53+
54+
const handleCopyYaml = () => {
55+
copyToYaml(
56+
componentSpec,
57+
(message) => notify(message, "success"),
58+
(message) => notify(message, "error"),
59+
);
60+
};
61+
62+
const handleDelete = () => {
63+
try {
64+
onDelete?.();
65+
} catch (error) {
66+
console.error("Error deleting component:", error);
67+
notify(`Error deleting component`, "error");
68+
}
69+
};
70+
71+
const orderedActions: ActionOrReactNode[] = [
72+
{
73+
label: "Download YAML",
74+
icon: "Download",
75+
onClick: handleDownloadYaml,
76+
},
77+
{
78+
label: "Download Python Code",
79+
content: <FaPython />,
80+
hidden: !pythonOriginalCode,
81+
onClick: stringToPythonCodeDownload,
82+
},
83+
{
84+
label: "Copy YAML",
85+
icon: "Clipboard",
86+
onClick: handleCopyYaml,
87+
},
88+
...actions,
89+
{
90+
label: "Delete Component",
91+
icon: "Trash",
92+
destructive: true,
93+
hidden: !onDelete || readOnly,
94+
onClick: handleDelete,
95+
},
96+
];
97+
98+
return <ActionBlock actions={orderedActions} className={className} />;
99+
};
100+
101+
export default TaskActions;

0 commit comments

Comments
 (0)