diff --git a/app/w/[id]/workflow.tsx b/app/w/[id]/workflow.tsx index 4c9e6c18ec..5288689310 100644 --- a/app/w/[id]/workflow.tsx +++ b/app/w/[id]/workflow.tsx @@ -46,7 +46,7 @@ function WorkflowContent() { // Store access const { addNotification } = useNotificationStore() - const { workflows, setActiveWorkflow, addWorkflow } = useWorkflowRegistry() + const { workflows, setActiveWorkflow, createWorkflow } = useWorkflowRegistry() const { blocks, edges, loops, addBlock, updateBlockPosition, addEdge, removeEdge } = useWorkflowStore() @@ -65,25 +65,13 @@ function WorkflowContent() { useEffect(() => { if (!isInitialized) return - const createInitialWorkflow = () => { - const id = crypto.randomUUID() - const newWorkflow = { - id, - name: 'Workflow 1', - lastModified: new Date(), - description: 'New workflow', - color: '#3972F6', - } - addWorkflow(newWorkflow) - return id - } - const validateAndNavigate = () => { const workflowIds = Object.keys(workflows) const currentId = params.id as string if (workflowIds.length === 0) { - const newId = createInitialWorkflow() + // Create initial workflow using the centralized function + const newId = createWorkflow({ isInitial: true }) router.replace(`/w/${newId}`) return } @@ -97,7 +85,7 @@ function WorkflowContent() { } validateAndNavigate() - }, [params.id, workflows, setActiveWorkflow, addWorkflow, router, isInitialized]) + }, [params.id, workflows, setActiveWorkflow, createWorkflow, router, isInitialized]) // Transform blocks and loops into ReactFlow nodes const nodes = useMemo(() => { diff --git a/app/w/components/sidebar/sidebar.tsx b/app/w/components/sidebar/sidebar.tsx index f08f7ea321..dc43331792 100644 --- a/app/w/components/sidebar/sidebar.tsx +++ b/app/w/components/sidebar/sidebar.tsx @@ -12,31 +12,12 @@ import { NavItem } from './components/nav-item/nav-item' import { SettingsModal } from './components/settings-modal/settings-modal' export function Sidebar() { - const WORKFLOW_COLORS = ['#3972F6', '#F639DD', '#F6B539', '#8139F6', '#F64439'] - const { workflows, addWorkflow } = useWorkflowRegistry() + const { workflows, createWorkflow } = useWorkflowRegistry() const router = useRouter() const [showSettings, setShowSettings] = useState(false) const handleCreateWorkflow = () => { - const id = crypto.randomUUID() - const workflowArray = Object.values(workflows) - const lastWorkflow = workflowArray[workflowArray.length - 1] - - // Find the index of the last used color, defaulting to first color if undefined - const lastColorIndex = lastWorkflow?.color ? WORKFLOW_COLORS.indexOf(lastWorkflow.color) : -1 - - // Get next color index, wrapping around to 0 if we reach the end - const nextColorIndex = (lastColorIndex + 1) % WORKFLOW_COLORS.length - - const newWorkflow = { - id, - name: `Workflow ${workflowArray.length + 1}`, - lastModified: new Date(), - description: 'New workflow', - color: WORKFLOW_COLORS[nextColorIndex], - } - - addWorkflow(newWorkflow) + const id = createWorkflow() router.push(`/w/${id}`) } diff --git a/app/w/components/toolbar/toolbar.tsx b/app/w/components/toolbar/toolbar.tsx index e3ad6fe16a..39d64d36b1 100644 --- a/app/w/components/toolbar/toolbar.tsx +++ b/app/w/components/toolbar/toolbar.tsx @@ -60,7 +60,6 @@ export function Toolbar() { autoCorrect="off" autoCapitalize="off" spellCheck="false" - name={`search-input-${Math.random()}`} /> diff --git a/components/ui/input.tsx b/components/ui/input.tsx index 4d4774126a..6a95e7ce41 100644 --- a/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -2,8 +2,7 @@ import * as React from 'react' import { cn } from '@/lib/utils' const Input = React.forwardRef>( - ({ className, type, autoComplete = 'off', name, ...props }, ref) => { - const randomName = name || `input-${Math.random()}` + ({ className, type, autoComplete = 'off', ...props }, ref) => { return ( >( autoCorrect="off" autoCapitalize="off" spellCheck="false" - name={randomName} {...props} /> ) diff --git a/stores/workflow/registry/store.ts b/stores/workflow/registry/store.ts index 84b6782f19..1ec30c1b23 100644 --- a/stores/workflow/registry/store.ts +++ b/stores/workflow/registry/store.ts @@ -4,7 +4,7 @@ import { addDeletedWorkflow } from '../../sync-manager' import { useWorkflowStore } from '../store' import { useSubBlockStore } from '../subblock/store' import { WorkflowMetadata, WorkflowRegistry } from './types' -import { generateUniqueName } from './utils' +import { generateUniqueName, getNextWorkflowColor } from './utils' export const useWorkflowRegistry = create()( devtools( @@ -81,18 +81,23 @@ export const useWorkflowRegistry = create()( set({ activeWorkflowId: id, error: null }) }, - // Create new workflow with default starter block - addWorkflow: (metadata: WorkflowMetadata) => { - const uniqueName = generateUniqueName(get().workflows) - const updatedMetadata = { ...metadata, name: uniqueName } + /** + * Creates a new workflow with appropriate metadata and initial blocks + * @param options - Optional configuration for workflow creation + * @returns The ID of the newly created workflow + */ + createWorkflow: (options = {}) => { + const { workflows } = get() + const id = crypto.randomUUID() - set((state) => ({ - workflows: { - ...state.workflows, - [metadata.id]: updatedMetadata, - }, - error: null, - })) + // Generate workflow metadata with appropriate name and color + const newWorkflow: WorkflowMetadata = { + id, + name: generateUniqueName(workflows), + lastModified: new Date(), + description: 'New workflow', + color: getNextWorkflowColor(workflows), + } // Create starter block for new workflow const starterId = crypto.randomUUID() @@ -210,18 +215,29 @@ export const useWorkflowRegistry = create()( lastSaved: Date.now(), } + // Add workflow to registry + set((state) => ({ + workflows: { + ...state.workflows, + [id]: newWorkflow, + }, + error: null, + })) + // Save workflow list to localStorage - const workflows = get().workflows - localStorage.setItem('workflow-registry', JSON.stringify(workflows)) + const updatedWorkflows = get().workflows + localStorage.setItem('workflow-registry', JSON.stringify(updatedWorkflows)) // Save initial workflow state to localStorage - localStorage.setItem(`workflow-${metadata.id}`, JSON.stringify(initialState)) + localStorage.setItem(`workflow-${id}`, JSON.stringify(initialState)) - // If this is the first workflow, set it as active and update workflow store - if (Object.keys(workflows).length === 1) { - set({ activeWorkflowId: metadata.id }) + // If this is the first workflow or it's an initial workflow, set it as active + if (options.isInitial || Object.keys(updatedWorkflows).length === 1) { + set({ activeWorkflowId: id }) useWorkflowStore.setState(initialState) } + + return id }, // Delete workflow and clean up associated storage diff --git a/stores/workflow/registry/types.ts b/stores/workflow/registry/types.ts index c4ec8fccf3..e3ebf59a0c 100644 --- a/stores/workflow/registry/types.ts +++ b/stores/workflow/registry/types.ts @@ -15,9 +15,9 @@ export interface WorkflowRegistryState { export interface WorkflowRegistryActions { setActiveWorkflow: (id: string) => Promise - addWorkflow: (metadata: WorkflowMetadata) => void removeWorkflow: (id: string) => void updateWorkflow: (id: string, metadata: Partial) => void + createWorkflow: (options?: { isInitial?: boolean }) => string } export type WorkflowRegistry = WorkflowRegistryState & WorkflowRegistryActions diff --git a/stores/workflow/registry/utils.ts b/stores/workflow/registry/utils.ts index 2b6d5180e1..0896c4c5ae 100644 --- a/stores/workflow/registry/utils.ts +++ b/stores/workflow/registry/utils.ts @@ -1,5 +1,8 @@ import { WorkflowMetadata } from './types' +// Available workflow colors +export const WORKFLOW_COLORS = ['#3972F6', '#F639DD', '#F6B539', '#8139F6', '#F64439'] + export function generateUniqueName(existingWorkflows: Record): string { // Extract numbers from existing workflow names using regex const numbers = Object.values(existingWorkflows) @@ -17,3 +20,26 @@ export function generateUniqueName(existingWorkflows: Record): string { + const workflowArray = Object.values(existingWorkflows) + + if (workflowArray.length === 0) { + return WORKFLOW_COLORS[0] + } + + const lastWorkflow = workflowArray[workflowArray.length - 1] + + // Find the index of the last used color, defaulting to first color if undefined + const lastColorIndex = lastWorkflow?.color ? WORKFLOW_COLORS.indexOf(lastWorkflow.color) : -1 + + // Get next color index, wrapping around to 0 if we reach the end + const nextColorIndex = (lastColorIndex + 1) % WORKFLOW_COLORS.length + + return WORKFLOW_COLORS[nextColorIndex] +}