diff --git a/chainforge/react-server/package.json b/chainforge/react-server/package.json
index 229a67686..884023508 100644
--- a/chainforge/react-server/package.json
+++ b/chainforge/react-server/package.json
@@ -57,6 +57,7 @@
"dayjs": "^1.11.8",
"emoji-mart": "^5.5.2",
"emoji-picker-react": "^4.4.9",
+ "file-saver": "^2.0.5",
"google-auth-library": "^8.8.0",
"https-browserify": "^1.0.0",
"jstat": "^1.9.6",
@@ -135,6 +136,8 @@
},
"devDependencies": {
"@craco/craco": "^7.1.0",
+ "@types/file-saver": "^2.0.7",
+ "@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.0",
"@types/papaparse": "^5.3.14",
"@types/react-beautiful-dnd": "^13.1.8",
diff --git a/chainforge/react-server/src/App.tsx b/chainforge/react-server/src/App.tsx
index ffb2dbde0..96d2fd7cb 100644
--- a/chainforge/react-server/src/App.tsx
+++ b/chainforge/react-server/src/App.tsx
@@ -117,6 +117,7 @@ import NestedMenu, { NestedMenuItemProps } from "./NestedMenu";
import RequestClarificationModal, {
RequestClarificationModalProps,
} from "./RequestClarificationModal";
+import { jsontoYml } from "./backend/jsonToYml";
const IS_ACCEPTED_BROWSER =
(isChrome ||
@@ -667,6 +668,17 @@ const App = () => {
URL.revokeObjectURL(downloadLink.href);
};
+ const exportYml = useCallback(
+ async (flowData?: unknown) => {
+ if (!rfInstance && !flowData) return;
+ // We first get the data of the flow, if we haven't already
+ const flow = flowData ?? rfInstance?.toObject();
+ if (!flow) return;
+ await jsontoYml(JSON.stringify(flow), flowFileName);
+ },
+ [rfInstance, flowFileName],
+ );
+
// Export flow to JSON
const exportFlow = useCallback(
(
@@ -1573,6 +1585,17 @@ const App = () => {
>
Export
+