feat(duplicate): duplicate variables when duplicating a workflow (#1254)

* feat(duplicate): duplicate variables when duplicating a workflow

* better typing
This commit is contained in:
Waleed
2025-09-04 21:20:30 -07:00
committed by GitHub
parent 53dd277cfe
commit 8668622d66
4 changed files with 53 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ import { createLogger } from '@/lib/logs/console/logger'
import { getUserEntityPermissions } from '@/lib/permissions/utils'
import { db } from '@/db'
import { workflow, workflowBlocks, workflowEdges, workflowSubflows } from '@/db/schema'
import type { Variable } from '@/stores/panel/variables/types'
import type { LoopConfig, ParallelConfig } from '@/stores/workflows/workflow/types'
const logger = createLogger('WorkflowDuplicateAPI')
@@ -97,7 +98,20 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
isDeployed: false,
collaborators: [],
runCount: 0,
variables: source.variables || {},
// Duplicate variables with new IDs and new workflowId
variables: (() => {
const sourceVars = (source.variables as Record<string, Variable>) || {}
const remapped: Record<string, Variable> = {}
for (const [, variable] of Object.entries(sourceVars) as [string, Variable][]) {
const newVarId = crypto.randomUUID()
remapped[newVarId] = {
...variable,
id: newVarId,
workflowId: newWorkflowId,
}
}
return remapped
})(),
isPublished: false,
marketplaceData: null,
})

View File

@@ -97,6 +97,34 @@ export const useVariablesStore = create<VariablesStore>()(
error: null,
isEditing: null,
async loadForWorkflow(workflowId) {
try {
set({ isLoading: true, error: null })
const res = await fetch(`/api/workflows/${workflowId}/variables`, { method: 'GET' })
if (!res.ok) {
const text = await res.text().catch(() => '')
throw new Error(text || `Failed to load variables: ${res.statusText}`)
}
const data = await res.json()
const variables = (data?.data as Record<string, Variable>) || {}
set((state) => {
const withoutWorkflow = Object.fromEntries(
Object.entries(state.variables).filter(
(entry): entry is [string, Variable] => entry[1].workflowId !== workflowId
)
)
return {
variables: { ...withoutWorkflow, ...variables },
isLoading: false,
error: null,
}
})
} catch (e) {
const message = e instanceof Error ? e.message : 'Unknown error'
set({ isLoading: false, error: message })
}
},
addVariable: (variable, providedId?: string) => {
const id = providedId || crypto.randomUUID()

View File

@@ -23,6 +23,11 @@ export interface VariablesStore {
error: string | null
isEditing: string | null
/**
* Loads variables for a specific workflow from the API and hydrates the store.
*/
loadForWorkflow: (workflowId: string) => Promise<void>
/**
* Adds a new variable with automatic name uniqueness validation
* If a variable with the same name exists, it will be suffixed with a number

View File

@@ -1190,7 +1190,11 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
}))
}
// Workflow has already been persisted to the database via the duplication endpoint
try {
await useVariablesStore.getState().loadForWorkflow(id)
} catch (error) {
logger.warn(`Error hydrating variables for duplicated workflow ${id}:`, error)
}
logger.info(
`Duplicated workflow ${sourceId} to ${id} in workspace ${workspaceId || 'none'}`