mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix(import): dedup workflow name (#3813)
This commit is contained in:
committed by
GitHub
parent
b90bb75cda
commit
2dd6d3d1e6
@@ -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,
|
||||
|
||||
@@ -54,6 +54,7 @@ export function Home({ chatId }: HomeProps = {}) {
|
||||
description,
|
||||
color,
|
||||
workspaceId,
|
||||
deduplicate: true,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ export function useImportWorkflow({ workspaceId }: UseImportWorkflowProps) {
|
||||
workspaceId,
|
||||
folderId,
|
||||
sortOrder,
|
||||
deduplicate: true,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ export function useImportWorkspace({ onSuccess }: UseImportWorkspaceProps = {})
|
||||
color: workflowColor,
|
||||
workspaceId: newWorkspace.id,
|
||||
folderId: targetFolderId,
|
||||
deduplicate: true,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user