fix(import): dedup workflow name (#3813)

This commit is contained in:
Vikhyath Mondreti
2026-03-27 13:09:49 -07:00
committed by GitHub
parent b90bb75cda
commit 2dd6d3d1e6
5 changed files with 50 additions and 36 deletions

View File

@@ -8,7 +8,7 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { listWorkflows, type WorkflowScope } from '@/lib/workflows/utils'
import { deduplicateWorkflowName, listWorkflows, type WorkflowScope } from '@/lib/workflows/utils'
import { getUserEntityPermissions, workspaceExists } from '@/lib/workspaces/permissions/utils'
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
@@ -25,6 +25,7 @@ const CreateWorkflowSchema = z.object({
workspaceId: z.string().optional(),
folderId: z.string().nullable().optional(),
sortOrder: z.number().int().optional(),
deduplicate: z.boolean().optional(),
})
// GET /api/workflows - Get workflows for user (optionally filtered by workspaceId)
@@ -126,12 +127,13 @@ export async function POST(req: NextRequest) {
const body = await req.json()
const {
id: clientId,
name,
name: requestedName,
description,
color,
workspaceId,
folderId,
sortOrder: providedSortOrder,
deduplicate,
} = CreateWorkflowSchema.parse(body)
if (!workspaceId) {
@@ -162,19 +164,6 @@ export async function POST(req: NextRequest) {
logger.info(`[${requestId}] Creating workflow ${workflowId} for user ${userId}`)
import('@/lib/core/telemetry')
.then(({ PlatformEvents }) => {
PlatformEvents.workflowCreated({
workflowId,
name,
workspaceId: workspaceId || undefined,
folderId: folderId || undefined,
})
})
.catch(() => {
// Silently fail
})
let sortOrder: number
if (providedSortOrder !== undefined) {
sortOrder = providedSortOrder
@@ -214,30 +203,49 @@ export async function POST(req: NextRequest) {
sortOrder = minSortOrder != null ? minSortOrder - 1 : 0
}
const duplicateConditions = [
eq(workflow.workspaceId, workspaceId),
isNull(workflow.archivedAt),
eq(workflow.name, name),
]
let name = requestedName
if (folderId) {
duplicateConditions.push(eq(workflow.folderId, folderId))
if (deduplicate) {
name = await deduplicateWorkflowName(requestedName, workspaceId, folderId)
} else {
duplicateConditions.push(isNull(workflow.folderId))
const duplicateConditions = [
eq(workflow.workspaceId, workspaceId),
isNull(workflow.archivedAt),
eq(workflow.name, requestedName),
]
if (folderId) {
duplicateConditions.push(eq(workflow.folderId, folderId))
} else {
duplicateConditions.push(isNull(workflow.folderId))
}
const [duplicateWorkflow] = await db
.select({ id: workflow.id })
.from(workflow)
.where(and(...duplicateConditions))
.limit(1)
if (duplicateWorkflow) {
return NextResponse.json(
{ error: `A workflow named "${requestedName}" already exists in this folder` },
{ status: 409 }
)
}
}
const [duplicateWorkflow] = await db
.select({ id: workflow.id })
.from(workflow)
.where(and(...duplicateConditions))
.limit(1)
if (duplicateWorkflow) {
return NextResponse.json(
{ error: `A workflow named "${name}" already exists in this folder` },
{ status: 409 }
)
}
import('@/lib/core/telemetry')
.then(({ PlatformEvents }) => {
PlatformEvents.workflowCreated({
workflowId,
name,
workspaceId: workspaceId || undefined,
folderId: folderId || undefined,
})
})
.catch(() => {
// Silently fail
})
await db.insert(workflow).values({
id: workflowId,

View File

@@ -54,6 +54,7 @@ export function Home({ chatId }: HomeProps = {}) {
description,
color,
workspaceId,
deduplicate: true,
}),
})

View File

@@ -56,6 +56,7 @@ export function useImportWorkflow({ workspaceId }: UseImportWorkflowProps) {
workspaceId,
folderId,
sortOrder,
deduplicate: true,
}),
})

View File

@@ -176,6 +176,7 @@ export function useImportWorkspace({ onSuccess }: UseImportWorkspaceProps = {})
color: workflowColor,
workspaceId: newWorkspace.id,
folderId: targetFolderId,
deduplicate: true,
}),
})

View File

@@ -164,6 +164,7 @@ interface CreateWorkflowVariables {
folderId?: string | null
sortOrder?: number
id?: string
deduplicate?: boolean
}
interface CreateWorkflowResult {
@@ -300,7 +301,8 @@ export function useCreateWorkflow() {
return useMutation({
mutationFn: async (variables: CreateWorkflowVariables): Promise<CreateWorkflowResult> => {
const { workspaceId, name, description, color, folderId, sortOrder, id } = variables
const { workspaceId, name, description, color, folderId, sortOrder, id, deduplicate } =
variables
logger.info(`Creating new workflow in workspace: ${workspaceId}`)
@@ -315,6 +317,7 @@ export function useCreateWorkflow() {
workspaceId,
folderId: folderId || null,
sortOrder,
deduplicate,
}),
})