Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 56 additions & 10 deletions apps/docs/openapi-v2-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -15997,6 +15997,16 @@
"disableKnowledgeBaseExport": {
"type": "boolean",
"description": "Prevent downloading a whole knowledge base as an archive."
},
"deniedPartialAccessProjectIssues": {
"default": [],
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
}
},
"required": [
Expand Down Expand Up @@ -16041,7 +16051,8 @@
"disableToolAutoApproval",
"hideSandboxesTab",
"disableOAuthAppAccess",
"disableKnowledgeBaseExport"
"disableKnowledgeBaseExport",
"deniedPartialAccessProjectIssues"
],
"additionalProperties": false,
"description": "Resolved restrictions. True disables a boolean capability; null allowlists permit every value and empty allowlists permit none."
Expand Down Expand Up @@ -16171,7 +16182,8 @@
"disableToolAutoApproval": false,
"hideSandboxesTab": false,
"disableOAuthAppAccess": false,
"disableKnowledgeBaseExport": false
"disableKnowledgeBaseExport": false,
"deniedPartialAccessProjectIssues": []
},
"isDefault": false,
"membershipMode": "inherit",
Expand Down Expand Up @@ -16246,7 +16258,8 @@
"disableToolAutoApproval": false,
"hideSandboxesTab": false,
"disableOAuthAppAccess": false,
"disableKnowledgeBaseExport": false
"disableKnowledgeBaseExport": false,
"deniedPartialAccessProjectIssues": []
},
"isDefault": false,
"membershipMode": "inherit",
Expand Down Expand Up @@ -16500,6 +16513,15 @@
"disableKnowledgeBaseExport": {
"type": "boolean",
"description": "Prevent downloading a whole knowledge base as an archive."
},
"deniedPartialAccessProjectIssues": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -16591,7 +16613,8 @@
"disableToolAutoApproval": false,
"hideSandboxesTab": false,
"disableOAuthAppAccess": false,
"disableKnowledgeBaseExport": false
"disableKnowledgeBaseExport": false,
"deniedPartialAccessProjectIssues": []
},
"isDefault": false,
"membershipMode": "inherit",
Expand Down Expand Up @@ -16664,7 +16687,8 @@
"disableToolAutoApproval": false,
"hideSandboxesTab": false,
"disableOAuthAppAccess": false,
"disableKnowledgeBaseExport": false
"disableKnowledgeBaseExport": false,
"deniedPartialAccessProjectIssues": []
},
"isDefault": false,
"membershipMode": "inherit",
Expand Down Expand Up @@ -16925,6 +16949,15 @@
"disableKnowledgeBaseExport": {
"type": "boolean",
"description": "Prevent downloading a whole knowledge base as an archive."
},
"deniedPartialAccessProjectIssues": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -18201,6 +18234,16 @@
"disableKnowledgeBaseExport": {
"type": "boolean",
"description": "Prevent downloading a whole knowledge base as an archive."
},
"deniedPartialAccessProjectIssues": {
"default": [],
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"description": "Issues in the listed Projects are unavailable to teammates without access to every active environment."
}
},
"required": [
Expand Down Expand Up @@ -18245,7 +18288,8 @@
"disableToolAutoApproval",
"hideSandboxesTab",
"disableOAuthAppAccess",
"disableKnowledgeBaseExport"
"disableKnowledgeBaseExport",
"deniedPartialAccessProjectIssues"
],
"additionalProperties": false
},
Expand Down Expand Up @@ -20730,7 +20774,7 @@
"description": "Access request being reviewed."
},
"changes": {
"maxItems": 42,
"maxItems": 43,
"type": "array",
"items": {
"type": "object",
Expand Down Expand Up @@ -20779,7 +20823,8 @@
"disableToolAutoApproval",
"hideSandboxesTab",
"disableOAuthAppAccess",
"disableKnowledgeBaseExport"
"disableKnowledgeBaseExport",
"deniedPartialAccessProjectIssues"
],
"description": "Permission restriction changed by approval."
},
Expand Down Expand Up @@ -21291,7 +21336,7 @@
"description": "Access request being reviewed."
},
"changes": {
"maxItems": 42,
"maxItems": 43,
"type": "array",
"items": {
"type": "object",
Expand Down Expand Up @@ -21340,7 +21385,8 @@
"disableToolAutoApproval",
"hideSandboxesTab",
"disableOAuthAppAccess",
"disableKnowledgeBaseExport"
"disableKnowledgeBaseExport",
"deniedPartialAccessProjectIssues"
],
"description": "Permission restriction changed by approval."
},
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/api/folders/[id]/duplicate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getSession } from '@/lib/auth'
import { asOrchestrationError } from '@/lib/core/orchestration/types'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import type { DbOrTx } from '@/lib/db/types'
import type { DbOrTx, DbTransaction } from '@/lib/db/types'
import { deduplicateFolderName } from '@/lib/folders/naming'
import { nextFolderSortOrder } from '@/lib/folders/orchestration'
import { assertFolderCollectionHasRoom, toFolderApi } from '@/lib/folders/queries'
Expand Down Expand Up @@ -409,7 +409,7 @@ async function duplicateFolderStructure(
}

async function duplicateWorkflowsInFolderTree(
tx: DbOrTx,
tx: DbTransaction,
sourceWorkspaceId: string,
targetWorkspaceId: string,
folderMapping: Map<string, string>,
Expand Down
45 changes: 45 additions & 0 deletions apps/sim/app/api/projects/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
archiveProjectContract,
getProjectContract,
renameProjectContract,
} from '@/lib/api/contracts/projects'
import {
defineInternalJsonRoute,
internalOrchestrationErrorPolicy,
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
import {
archiveProject,
getProject,
projectOperations,
renameProject,
} from '@/lib/projects/application'

export const GET = defineInternalJsonRoute({
contract: getProjectContract,
auth: internalSessionAuth,
operation: projectOperations.get,
rateLimit: internalRateLimits.user({ bucketName: 'projects.read' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ params, query }) => ({ projectId: params.id, ...query }),
useCase: getProject,
})
export const PATCH = defineInternalJsonRoute({
contract: renameProjectContract,
auth: internalSessionAuth,
operation: projectOperations.rename,
rateLimit: internalRateLimits.user({ bucketName: 'projects.write' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ params, body }) => ({ projectId: params.id, name: body.name }),
useCase: renameProject,
})
export const DELETE = defineInternalJsonRoute({
contract: archiveProjectContract,
auth: internalSessionAuth,
operation: projectOperations.archive,
rateLimit: internalRateLimits.user({ bucketName: 'projects.write' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ params }) => ({ projectId: params.id }),
useCase: archiveProject,
})
18 changes: 18 additions & 0 deletions apps/sim/app/api/projects/by-workspace/[workspaceId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getWorkspaceProjectContract } from '@/lib/api/contracts/projects'
import {
defineInternalJsonRoute,
internalOrchestrationErrorPolicy,
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
import { getWorkspaceProject, projectOperations } from '@/lib/projects/application'

export const GET = defineInternalJsonRoute({
contract: getWorkspaceProjectContract,
auth: internalSessionAuth,
operation: projectOperations.get,
rateLimit: internalRateLimits.user({ bucketName: 'projects.read' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ params }) => params,
useCase: getWorkspaceProject,
})
28 changes: 28 additions & 0 deletions apps/sim/app/api/projects/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createProjectContract, listProjectsContract } from '@/lib/api/contracts/projects'
import {
defineInternalJsonRoute,
internalOrchestrationErrorPolicy,
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
import { createProject, listProjects, projectOperations } from '@/lib/projects/application'

export const GET = defineInternalJsonRoute({
contract: listProjectsContract,
auth: internalSessionAuth,
operation: projectOperations.list,
rateLimit: internalRateLimits.user({ bucketName: 'projects.read' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ query }) => query,
useCase: listProjects,
})

export const POST = defineInternalJsonRoute({
contract: createProjectContract,
auth: internalSessionAuth,
operation: projectOperations.create,
rateLimit: internalRateLimits.user({ bucketName: 'projects.write' }),
errorPolicy: internalOrchestrationErrorPolicy,
mapInput: ({ body }) => body,
useCase: createProject,
})
28 changes: 17 additions & 11 deletions apps/sim/app/api/superuser/import-workflow/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { type NextRequest, NextResponse } from 'next/server'
import { importWorkflowAsSuperuserContract } from '@/lib/api/contracts/workflows'
import { parseRequest } from '@/lib/api/server'
import { getSession } from '@/lib/auth'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { loadCopilotChatMessages } from '@/lib/mothership/chat/lifecycle'
import { appendCopilotChatMessages } from '@/lib/mothership/chat/messages-store'
Expand Down Expand Up @@ -136,17 +137,19 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
null
)

await db.insert(workflow).values(
await buildNewWorkflowRow(db, {
id: newWorkflowId,
userId: session.user.id,
workspaceId: targetWorkspaceId,
folderId: null,
name: dedupedName,
description: sourceWorkflow.description,
variables: sourceWorkflow.variables || {},
})
)
await db.transaction(async (tx) => {
await tx.insert(workflow).values(
await buildNewWorkflowRow(tx, {
id: newWorkflowId,
userId: session.user.id,
workspaceId: targetWorkspaceId,
folderId: null,
name: dedupedName,
description: sourceWorkflow.description,
variables: sourceWorkflow.variables || {},
})
)
})

// Save using existing persistence logic
const saveResult = await saveWorkflowToNormalizedTables(newWorkflowId, importedData, {
Expand Down Expand Up @@ -225,6 +228,9 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
copilotChatsImported,
})
} catch (error) {
if (error instanceof OrchestrationError && error.code === 'not_found') {
return NextResponse.json({ error: 'Target workspace not found' }, { status: 404 })
}
logger.error('Error importing workflow', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
Expand Down
26 changes: 16 additions & 10 deletions apps/sim/app/api/v1/admin/workflows/import/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { and, eq, isNull } from 'drizzle-orm'
import { NextResponse } from 'next/server'
import { adminV1ImportWorkflowContract } from '@/lib/api/contracts/v1/admin'
import { parseRequest } from '@/lib/api/server'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { parseWorkflowJson } from '@/lib/workflows/operations/import-export'
import { buildNewWorkflowRow } from '@/lib/workflows/persistence/new-workflow-row'
Expand Down Expand Up @@ -115,16 +116,18 @@ export const POST = withRouteHandler(
const workflowId = generateId()
const dedupedName = await deduplicateWorkflowName(workflowName, workspaceId, folderId || null)

await db.insert(workflow).values(
await buildNewWorkflowRow(db, {
id: workflowId,
userId: workspaceData.ownerId,
workspaceId,
folderId: folderId || null,
name: dedupedName,
description: workflowDescription,
})
)
await db.transaction(async (tx) => {
await tx.insert(workflow).values(
await buildNewWorkflowRow(tx, {
Comment thread
mzxchandra marked this conversation as resolved.
id: workflowId,
userId: workspaceData.ownerId,
workspaceId,
folderId: folderId || null,
name: dedupedName,
description: workflowDescription,
})
)
})

/**
* Same normalization the editor and the v1 import API run, via the one
Expand Down Expand Up @@ -180,6 +183,9 @@ export const POST = withRouteHandler(

return NextResponse.json(response)
} catch (error) {
if (error instanceof OrchestrationError && error.code === 'not_found') {
return notFoundResponse('Workspace')
}
if (error instanceof FolderNotFoundError) {
return badRequestResponse(error.message)
}
Expand Down
Loading
Loading