Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eb07a08
v0.5.35: helm updates, copilot improvements, 404 for docs, salesforce…
icecrasher321 Dec 19, 2025
4d1a9a3
v0.5.36: hitl improvements, opengraph, slack fixes, one-click unsubsc…
waleedlatif1 Dec 19, 2025
4431a1a
fix(helm): add custom egress rules to realtime network policy (#2481)
Lutherwaves Dec 20, 2025
3e697d9
v0.5.37: redaction utils consolidation, logs updates, autoconnect imp…
waleedlatif1 Dec 20, 2025
4827866
v0.5.38: snap to grid, copilot ux improvements, billing line items
waleedlatif1 Dec 21, 2025
0f4ec96
v0.5.39: notion, workflow variables fixes
waleedlatif1 Dec 21, 2025
3d9d9cb
v0.5.40: supabase ops to allow non-public schemas, jira uuid
icecrasher321 Dec 22, 2025
e12dd20
v0.5.41: memory fixes, copilot improvements, knowledgebase improvemen…
icecrasher321 Dec 23, 2025
57e4b49
v0.5.42: fix memory migration
icecrasher321 Dec 23, 2025
b304233
v0.5.43: export logs, circleback, grain, vertex, code hygiene, schedu…
waleedlatif1 Dec 24, 2025
b6ba3b5
v0.5.44: keyboard shortcuts, autolayout, light mode, byok, testing im…
waleedlatif1 Dec 27, 2025
dd3209a
v0.5.45: light mode fixes, realtime usage indicator, docker build imp…
waleedlatif1 Dec 28, 2025
93b7531
v1 works
Shubhamxshah Dec 30, 2025
239371f
all fields work
Shubhamxshah Dec 30, 2025
b46a1e6
update item
Shubhamxshah Dec 30, 2025
8767661
tested all endpoints
Shubhamxshah Dec 30, 2025
de29d42
added a sub block note for api token
Shubhamxshah Dec 30, 2025
014fcc4
icon correction
Shubhamxshah Dec 30, 2025
17d7c95
Merge branch 'staging' into feat/monday.com
Shubhamxshah Dec 30, 2025
fdd523c
monday trigger
Shubhamxshah Dec 30, 2025
7af2be2
tested trigger
Shubhamxshah Dec 30, 2025
611b28e
fixed greptile issues
Shubhamxshah Dec 30, 2025
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
57 changes: 57 additions & 0 deletions apps/sim/app/api/tools/monday/boards/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { NextResponse } from 'next/server'
import { createLogger } from '@sim/logger'
import { generateRequestId } from '@/lib/core/utils/request'
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'

export const dynamic = 'force-dynamic'

const logger = createLogger('MondayBoardsAPI')

interface MondayBoard {
id: string
name: string
description?: string
board_kind: string
state: string
}

/**
* POST /api/tools/monday/boards
* Fetches active boards from a Monday.com account
*
* @param request - Request containing the Monday.com API key
* @returns JSON response with list of active boards
*/
export async function POST(request: Request) {
try {
const requestId = generateRequestId()
const body = await request.json()
const { apiKey } = body

if (!apiKey) {
logger.error('Missing API key in request')
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
}

logger.info('Fetching Monday.com boards', { requestId })

const data = await executeMondayQuery<{ boards: MondayBoard[] }>(apiKey, {
query: QUERIES.GET_BOARDS,
})

const boards = (data.boards || [])
.filter((board) => board.state === 'active')
.map((board) => ({
id: board.id,
name: board.name,
description: board.description,
kind: board.board_kind,
}))

logger.info(`Successfully fetched ${boards.length} Monday.com boards`, { requestId })
return NextResponse.json({ items: boards })
} catch (error) {
logger.error('Error fetching Monday.com boards:', error)
return NextResponse.json({ error: 'Failed to retrieve Monday.com boards' }, { status: 500 })
}
}
62 changes: 62 additions & 0 deletions apps/sim/app/api/tools/monday/columns/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { NextResponse } from 'next/server'
import { createLogger } from '@sim/logger'
import { generateRequestId } from '@/lib/core/utils/request'
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'

export const dynamic = 'force-dynamic'

const logger = createLogger('MondayColumnsAPI')

interface MondayColumn {
id: string
title: string
type: string
settings_str?: string
}

export async function POST(request: Request) {
try {
const requestId = generateRequestId()
const body = await request.json()
const { apiKey, boardId } = body

if (!apiKey) {
logger.error('Missing API key in request')
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
}

if (!boardId) {
logger.error('Missing board ID in request')
return NextResponse.json({ error: 'Board ID is required' }, { status: 400 })
}

const parsedBoardId = parseInt(boardId, 10)
if (isNaN(parsedBoardId)) {
logger.error('Invalid board ID format', { boardId })
return NextResponse.json({ error: 'Board ID must be a valid number' }, { status: 400 })
}

logger.info('Fetching Monday.com columns', { requestId, boardId: parsedBoardId })

const data = await executeMondayQuery<{ boards: Array<{ columns: MondayColumn[] }> }>(
apiKey,
{
query: QUERIES.GET_BOARD_COLUMNS,
variables: { boardId: [parsedBoardId] },
}
)

const columns = data.boards?.[0]?.columns || []
const formattedColumns = columns.map((col) => ({
id: col.id,
name: col.title,
type: col.type,
}))

logger.info(`Successfully fetched ${formattedColumns.length} columns`, { requestId })
return NextResponse.json({ items: formattedColumns })
} catch (error) {
logger.error('Error fetching Monday.com columns:', error)
return NextResponse.json({ error: 'Failed to retrieve columns' }, { status: 500 })
}
}
55 changes: 55 additions & 0 deletions apps/sim/app/api/tools/monday/groups/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { NextResponse } from 'next/server'
import { createLogger } from '@sim/logger'
import { generateRequestId } from '@/lib/core/utils/request'
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'

export const dynamic = 'force-dynamic'

const logger = createLogger('MondayGroupsAPI')

interface MondayGroup {
id: string
title: string
color: string
}

export async function POST(request: Request) {
try {
const requestId = generateRequestId()
const body = await request.json()
const { apiKey, boardId } = body

if (!apiKey || !boardId) {
return NextResponse.json(
{ error: 'API key and board ID are required' },
{ status: 400 }
)
}

logger.info('Fetching Monday.com groups', { requestId, boardId })

const data = await executeMondayQuery<{ boards: Array<{ groups: MondayGroup[] }> }>(
apiKey,
{
query: QUERIES.GET_BOARD_GROUPS,
variables: { boardId: [parseInt(boardId, 10)] },
}
)

const groups = data.boards?.[0]?.groups || []
const formattedGroups = groups.map((group) => ({
id: group.id,
name: group.title,
color: group.color,
}))

logger.info(`Successfully fetched ${formattedGroups.length} groups`, { requestId })
return NextResponse.json({ items: formattedGroups })
} catch (error) {
logger.error('Error fetching Monday.com groups:', error)
return NextResponse.json(
{ error: 'Failed to retrieve groups', details: (error as Error).message },
{ status: 500 }
)
}
}
85 changes: 85 additions & 0 deletions apps/sim/app/api/tools/monday/items/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { QUERIES } from '@/tools/monday/graphql'

const logger = createLogger('MondayItemsAPI')

interface MondayItem {
id: string
name: string
}

/**
* POST /api/tools/monday/items
* Fetches items from a Monday.com board for selector dropdown
*/
export async function POST(request: Request) {
try {
const body = await request.json()
const { apiKey, boardId } = body

if (!apiKey) {
logger.warn('Missing apiKey in request')
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
}

if (!boardId) {
logger.warn('Missing boardId in request')
return NextResponse.json({ error: 'Board ID is required' }, { status: 400 })
}

logger.info('Fetching Monday.com items', { boardId })

const response = await fetch('https://api.monday.com/v2', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: apiKey,
'API-Version': '2024-01',
},
body: JSON.stringify({
query: QUERIES.GET_BOARD_ITEMS,
variables: {
boardId: [parseInt(boardId, 10)],
limit: 100,
},
}),
})

if (!response.ok) {
const errorText = await response.text()
logger.error('Monday.com API error', {
status: response.status,
error: errorText,
})
return NextResponse.json(
{ error: `Monday.com API error: ${response.status}` },
{ status: response.status }
)
}

const result = await response.json()

if (result.errors) {
logger.error('Monday.com GraphQL errors', { errors: result.errors })
return NextResponse.json(
{ error: 'Failed to fetch items', details: result.errors },
{ status: 400 }
)
}

const items = result.data?.boards?.[0]?.items_page?.items || []

logger.info('Successfully fetched Monday.com items', { count: items.length })

return NextResponse.json({
items: items.map((item: MondayItem) => ({
id: item.id,
name: item.name,
})),
})
} catch (error) {
logger.error('Unexpected error fetching Monday.com items', { error })
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
104 changes: 104 additions & 0 deletions apps/sim/app/api/tools/monday/status-options/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { NextResponse } from 'next/server'
import { createLogger } from '@sim/logger'
import { generateRequestId } from '@/lib/core/utils/request'
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'

export const dynamic = 'force-dynamic'

const logger = createLogger('MondayStatusOptionsAPI')

interface MondayColumn {
id: string
title: string
type: string
settings_str?: string
}

interface StatusLabel {
id: string
label: string
color: string
}

interface StatusLabelSettings {
label: string
color?: string
}

export async function POST(request: Request) {
try {
const requestId = generateRequestId()
const body = await request.json()
const { apiKey, boardId, columnId } = body

if (!apiKey || !boardId || !columnId) {
return NextResponse.json(
{ error: 'API key, board ID, and column ID are required' },
{ status: 400 }
)
}

logger.info('Fetching Monday.com status options', { requestId, boardId, columnId })

const data = await executeMondayQuery<{ boards: Array<{ columns: MondayColumn[] }> }>(
apiKey,
{
query: QUERIES.GET_COLUMN_SETTINGS,
variables: {
boardId: [parseInt(boardId, 10)],
columnId,
},
}
)

const column = data.boards?.[0]?.columns?.[0]

if (!column) {
return NextResponse.json({ error: 'Column not found' }, { status: 404 })
}

if (column.type !== 'status' && column.type !== 'color') {
return NextResponse.json(
{ error: `Column type ${column.type} does not have status options` },
{ status: 400 }
)
}

let statusOptions: StatusLabel[] = []

if (column.settings_str) {
try {
const settings = JSON.parse(column.settings_str)
const labels = settings.labels || {}

statusOptions = Object.entries(labels).map(([id, label]: [string, StatusLabelSettings | string]) => {
if (typeof label === 'string') {
return { id, label, color: '#000000' }
}
return {
id,
label: label.label,
color: label.color || '#000000',
}
})
} catch (parseError) {
logger.error('Failed to parse column settings', {
error: parseError,
settings_str: column.settings_str,
})
}
}

logger.info(`Successfully fetched ${statusOptions.length} status options`, { requestId })
return NextResponse.json({
items: statusOptions.map((option) => ({
id: option.id,
name: option.label,
color: option.color,
})),
})
} catch (error) {
logger.error('Error fetching Monday.com status options:', error)
return NextResponse.json({ error: 'Failed to retrieve status options' }, { status: 500 })
}
}
Loading