Enhance WorkflowToolbar and localStorage management for workflows

- Added success feedback in WorkflowToolbar upon saving a workflow, including visual changes to the save button.
- Implemented localStorage operations for saving, loading, and clearing workflows in workflowStore.
- Updated workflow management functions to persist changes to localStorage, ensuring data consistency across sessions.
This commit is contained in:
Nikhil-Doye
2025-10-14 22:37:29 -04:00
parent d9e7f9416a
commit 9c1a0d8661
3 changed files with 188 additions and 18 deletions
+16 -4
View File
@@ -1,4 +1,4 @@
import React, { useRef, useState } from "react";
import React, { useRef, useState, useEffect } from "react";
import { useWorkflowStore } from "../store/workflowStore";
import {
Download,
@@ -8,6 +8,7 @@ import {
Square,
RotateCcw,
Settings,
Check,
} from "lucide-react";
import {
downloadWorkflow,
@@ -26,10 +27,13 @@ export const WorkflowToolbar: React.FC = () => {
const fileInputRef = useRef<HTMLInputElement>(null);
const [showOpenAIConfig, setShowOpenAIConfig] = useState(false);
const [showSaveSuccess, setShowSaveSuccess] = useState(false);
const handleSave = () => {
if (currentWorkflow) {
saveWorkflow();
setShowSaveSuccess(true);
setTimeout(() => setShowSaveSuccess(false), 2000);
}
};
@@ -86,11 +90,19 @@ export const WorkflowToolbar: React.FC = () => {
<div className="flex items-center space-x-2">
<button
onClick={handleSave}
className="flex items-center space-x-2 px-3 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 transition-colors"
className={`flex items-center space-x-2 px-3 py-2 rounded-md transition-colors ${
showSaveSuccess
? "bg-green-100 text-green-700 hover:bg-green-200"
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
}`}
title="Save workflow"
>
<Save className="w-4 h-4" />
<span>Save</span>
{showSaveSuccess ? (
<Check className="w-4 h-4" />
) : (
<Save className="w-4 h-4" />
)}
<span>{showSaveSuccess ? "Saved!" : "Save"}</span>
</button>
<button
+91 -14
View File
@@ -9,6 +9,53 @@ import {
import { v4 as uuidv4 } from "uuid";
import { callOpenAI, OpenAIConfig } from "../services/openaiService";
// localStorage key for workflows
const WORKFLOWS_STORAGE_KEY = "agent-workflow-builder-workflows";
// Helper functions for localStorage operations
const saveWorkflowsToStorage = (workflows: Workflow[]): boolean => {
try {
localStorage.setItem(WORKFLOWS_STORAGE_KEY, JSON.stringify(workflows));
return true;
} catch (error) {
console.error("Failed to save workflows to localStorage:", error);
// Show user-friendly error message
alert(
"Failed to save workflows. Your browser's storage might be full or disabled."
);
return false;
}
};
const loadWorkflowsFromStorage = (): Workflow[] => {
try {
const stored = localStorage.getItem(WORKFLOWS_STORAGE_KEY);
if (stored) {
const workflows = JSON.parse(stored);
// Convert date strings back to Date objects
return workflows.map((workflow: any) => ({
...workflow,
createdAt: new Date(workflow.createdAt),
updatedAt: new Date(workflow.updatedAt),
}));
}
} catch (error) {
console.error("Failed to load workflows from localStorage:", error);
alert("Failed to load saved workflows. Some data might be corrupted.");
}
return [];
};
const clearWorkflowsFromStorage = (): boolean => {
try {
localStorage.removeItem(WORKFLOWS_STORAGE_KEY);
return true;
} catch (error) {
console.error("Failed to clear workflows from localStorage:", error);
return false;
}
};
interface WorkflowStore {
workflows: Workflow[];
currentWorkflow: Workflow | null;
@@ -21,6 +68,7 @@ interface WorkflowStore {
loadWorkflow: (workflowId: string) => void;
saveWorkflow: () => void;
deleteWorkflow: (workflowId: string) => void;
clearAllWorkflows: () => void;
// Node management
addNode: (type: string, position: { x: number; y: number }) => void;
@@ -58,7 +106,7 @@ const createEmptyWorkflow = (name: string): Workflow => ({
});
export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
workflows: [],
workflows: loadWorkflowsFromStorage(),
currentWorkflow: null,
selectedNodeId: null,
isExecuting: false,
@@ -66,10 +114,15 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
createWorkflow: (name: string) => {
const newWorkflow = createEmptyWorkflow(name);
set((state) => ({
workflows: [...state.workflows, newWorkflow],
const newWorkflows = [...get().workflows, newWorkflow];
set({
workflows: newWorkflows,
currentWorkflow: newWorkflow,
}));
});
// Persist to localStorage
saveWorkflowsToStorage(newWorkflows);
},
loadWorkflow: (workflowId: string) => {
@@ -87,21 +140,45 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
updatedAt: new Date(),
};
set((state) => ({
workflows: state.workflows.map((w) =>
w.id === updatedWorkflow.id ? updatedWorkflow : w
),
const newWorkflows = get().workflows.map((w) =>
w.id === updatedWorkflow.id ? updatedWorkflow : w
);
set({
workflows: newWorkflows,
currentWorkflow: updatedWorkflow,
}));
});
// Persist to localStorage
const success = saveWorkflowsToStorage(newWorkflows);
if (success) {
console.log(`Workflow "${currentWorkflow.name}" saved successfully`);
}
}
},
deleteWorkflow: (workflowId: string) => {
set((state) => ({
workflows: state.workflows.filter((w) => w.id !== workflowId),
currentWorkflow:
state.currentWorkflow?.id === workflowId ? null : state.currentWorkflow,
}));
const newWorkflows = get().workflows.filter((w) => w.id !== workflowId);
const currentWorkflow =
get().currentWorkflow?.id === workflowId ? null : get().currentWorkflow;
set({
workflows: newWorkflows,
currentWorkflow,
});
// Persist to localStorage
saveWorkflowsToStorage(newWorkflows);
},
clearAllWorkflows: () => {
set({
workflows: [],
currentWorkflow: null,
});
// Clear from localStorage
clearWorkflowsFromStorage();
},
addNode: (type: string, position: { x: number; y: number }) => {
+81
View File
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html>
<head>
<title>Test localStorage Persistence</title>
</head>
<body>
<h1>Test localStorage Persistence</h1>
<div id="status"></div>
<button onclick="testSave()">Test Save</button>
<button onclick="testLoad()">Test Load</button>
<button onclick="testClear()">Test Clear</button>
<pre id="output"></pre>
<script>
const WORKFLOWS_STORAGE_KEY = "agent-workflow-builder-workflows";
function testSave() {
const testWorkflow = {
id: "test-123",
name: "Test Workflow",
nodes: [],
edges: [],
createdAt: new Date(),
updatedAt: new Date(),
};
try {
localStorage.setItem(
WORKFLOWS_STORAGE_KEY,
JSON.stringify([testWorkflow])
);
document.getElementById("status").innerHTML =
'<span style="color: green;">✓ Saved successfully</span>';
} catch (error) {
document.getElementById("status").innerHTML =
'<span style="color: red;">✗ Save failed: ' +
error.message +
"</span>";
}
}
function testLoad() {
try {
const stored = localStorage.getItem(WORKFLOWS_STORAGE_KEY);
if (stored) {
const workflows = JSON.parse(stored);
document.getElementById("output").textContent = JSON.stringify(
workflows,
null,
2
);
document.getElementById("status").innerHTML =
'<span style="color: green;">✓ Loaded successfully</span>';
} else {
document.getElementById("status").innerHTML =
'<span style="color: orange;">⚠ No data found</span>';
}
} catch (error) {
document.getElementById("status").innerHTML =
'<span style="color: red;">✗ Load failed: ' +
error.message +
"</span>";
}
}
function testClear() {
try {
localStorage.removeItem(WORKFLOWS_STORAGE_KEY);
document.getElementById("status").innerHTML =
'<span style="color: green;">✓ Cleared successfully</span>';
document.getElementById("output").textContent = "";
} catch (error) {
document.getElementById("status").innerHTML =
'<span style="color: red;">✗ Clear failed: ' +
error.message +
"</span>";
}
}
</script>
</body>
</html>