Skip to content

Commit 93b7531

Browse files
committed
v1 works
1 parent dd3209a commit 93b7531

File tree

30 files changed

+1775
-13
lines changed

30 files changed

+1775
-13
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { NextResponse } from 'next/server'
2+
import { createLogger } from '@sim/logger'
3+
import { generateRequestId } from '@/lib/core/utils/request'
4+
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'
5+
6+
export const dynamic = 'force-dynamic'
7+
8+
const logger = createLogger('MondayBoardsAPI')
9+
10+
interface MondayBoard {
11+
id: string
12+
name: string
13+
description?: string
14+
board_kind: string
15+
state: string
16+
}
17+
18+
export async function POST(request: Request) {
19+
try {
20+
const requestId = generateRequestId()
21+
const body = await request.json()
22+
const { apiKey } = body
23+
24+
if (!apiKey) {
25+
logger.error('Missing API key in request')
26+
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
27+
}
28+
29+
logger.info('Fetching Monday.com boards', { requestId })
30+
31+
const data = await executeMondayQuery<{ boards: MondayBoard[] }>(apiKey, {
32+
query: QUERIES.GET_BOARDS,
33+
})
34+
35+
const boards = (data.boards || [])
36+
.filter((board) => board.state === 'active')
37+
.map((board) => ({
38+
id: board.id,
39+
name: board.name,
40+
description: board.description,
41+
kind: board.board_kind,
42+
}))
43+
44+
logger.info(`Successfully fetched ${boards.length} Monday.com boards`, { requestId })
45+
return NextResponse.json({ items: boards })
46+
} catch (error) {
47+
logger.error('Error fetching Monday.com boards:', error)
48+
return NextResponse.json(
49+
{ error: 'Failed to retrieve Monday.com boards', details: (error as Error).message },
50+
{ status: 500 }
51+
)
52+
}
53+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { NextResponse } from 'next/server'
2+
import { createLogger } from '@sim/logger'
3+
import { generateRequestId } from '@/lib/core/utils/request'
4+
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'
5+
6+
export const dynamic = 'force-dynamic'
7+
8+
const logger = createLogger('MondayColumnsAPI')
9+
10+
interface MondayColumn {
11+
id: string
12+
title: string
13+
type: string
14+
settings_str?: string
15+
}
16+
17+
export async function POST(request: Request) {
18+
try {
19+
const requestId = generateRequestId()
20+
const body = await request.json()
21+
const { apiKey, boardId } = body
22+
23+
if (!apiKey) {
24+
logger.error('Missing API key in request')
25+
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
26+
}
27+
28+
if (!boardId) {
29+
logger.error('Missing board ID in request')
30+
return NextResponse.json({ error: 'Board ID is required' }, { status: 400 })
31+
}
32+
33+
logger.info('Fetching Monday.com columns', { requestId, boardId })
34+
35+
const data = await executeMondayQuery<{ boards: Array<{ columns: MondayColumn[] }> }>(
36+
apiKey,
37+
{
38+
query: QUERIES.GET_BOARD_COLUMNS,
39+
variables: { boardId: [parseInt(boardId, 10)] },
40+
}
41+
)
42+
43+
const columns = data.boards?.[0]?.columns || []
44+
const formattedColumns = columns.map((col) => ({
45+
id: col.id,
46+
name: col.title,
47+
type: col.type,
48+
}))
49+
50+
logger.info(`Successfully fetched ${formattedColumns.length} columns`, { requestId })
51+
return NextResponse.json({ items: formattedColumns })
52+
} catch (error) {
53+
logger.error('Error fetching Monday.com columns:', error)
54+
return NextResponse.json(
55+
{ error: 'Failed to retrieve columns', details: (error as Error).message },
56+
{ status: 500 }
57+
)
58+
}
59+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { NextResponse } from 'next/server'
2+
import { createLogger } from '@sim/logger'
3+
import { generateRequestId } from '@/lib/core/utils/request'
4+
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'
5+
6+
export const dynamic = 'force-dynamic'
7+
8+
const logger = createLogger('MondayGroupsAPI')
9+
10+
interface MondayGroup {
11+
id: string
12+
title: string
13+
color: string
14+
}
15+
16+
export async function POST(request: Request) {
17+
try {
18+
const requestId = generateRequestId()
19+
const body = await request.json()
20+
const { apiKey, boardId } = body
21+
22+
if (!apiKey || !boardId) {
23+
return NextResponse.json(
24+
{ error: 'API key and board ID are required' },
25+
{ status: 400 }
26+
)
27+
}
28+
29+
logger.info('Fetching Monday.com groups', { requestId, boardId })
30+
31+
const data = await executeMondayQuery<{ boards: Array<{ groups: MondayGroup[] }> }>(
32+
apiKey,
33+
{
34+
query: QUERIES.GET_BOARD_GROUPS,
35+
variables: { boardId: [parseInt(boardId, 10)] },
36+
}
37+
)
38+
39+
const groups = data.boards?.[0]?.groups || []
40+
const formattedGroups = groups.map((group) => ({
41+
id: group.id,
42+
name: group.title,
43+
color: group.color,
44+
}))
45+
46+
logger.info(`Successfully fetched ${formattedGroups.length} groups`, { requestId })
47+
return NextResponse.json({ items: formattedGroups })
48+
} catch (error) {
49+
logger.error('Error fetching Monday.com groups:', error)
50+
return NextResponse.json(
51+
{ error: 'Failed to retrieve groups', details: (error as Error).message },
52+
{ status: 500 }
53+
)
54+
}
55+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { NextResponse } from 'next/server'
2+
import { createLogger } from '@sim/logger'
3+
import { generateRequestId } from '@/lib/core/utils/request'
4+
import { executeMondayQuery, QUERIES } from '@/tools/monday/graphql'
5+
6+
export const dynamic = 'force-dynamic'
7+
8+
const logger = createLogger('MondayStatusOptionsAPI')
9+
10+
interface MondayColumn {
11+
id: string
12+
title: string
13+
type: string
14+
settings_str?: string
15+
}
16+
17+
interface StatusLabel {
18+
id: string
19+
label: string
20+
color: string
21+
}
22+
23+
export async function POST(request: Request) {
24+
try {
25+
const requestId = generateRequestId()
26+
const body = await request.json()
27+
const { apiKey, boardId, columnId } = body
28+
29+
if (!apiKey || !boardId || !columnId) {
30+
return NextResponse.json(
31+
{ error: 'API key, board ID, and column ID are required' },
32+
{ status: 400 }
33+
)
34+
}
35+
36+
logger.info('Fetching Monday.com status options', { requestId, boardId, columnId })
37+
38+
const data = await executeMondayQuery<{ boards: Array<{ columns: MondayColumn[] }> }>(
39+
apiKey,
40+
{
41+
query: QUERIES.GET_COLUMN_SETTINGS,
42+
variables: {
43+
boardId: [parseInt(boardId, 10)],
44+
columnId,
45+
},
46+
}
47+
)
48+
49+
const column = data.boards?.[0]?.columns?.[0]
50+
51+
if (!column) {
52+
return NextResponse.json({ error: 'Column not found' }, { status: 404 })
53+
}
54+
55+
if (column.type !== 'status' && column.type !== 'color') {
56+
return NextResponse.json(
57+
{ error: `Column type ${column.type} does not have status options` },
58+
{ status: 400 }
59+
)
60+
}
61+
62+
let statusOptions: StatusLabel[] = []
63+
64+
if (column.settings_str) {
65+
try {
66+
const settings = JSON.parse(column.settings_str)
67+
const labels = settings.labels || {}
68+
69+
statusOptions = Object.entries(labels).map(([id, label]: [string, any]) => ({
70+
id,
71+
label: label.label || label,
72+
color: label.color || '#000000',
73+
}))
74+
} catch (parseError) {
75+
logger.error('Failed to parse column settings', {
76+
error: parseError,
77+
settings_str: column.settings_str,
78+
})
79+
}
80+
}
81+
82+
logger.info(`Successfully fetched ${statusOptions.length} status options`, { requestId })
83+
return NextResponse.json({
84+
items: statusOptions.map((option) => ({
85+
id: option.id,
86+
name: option.label,
87+
color: option.color,
88+
})),
89+
})
90+
} catch (error) {
91+
logger.error('Error fetching Monday.com status options:', error)
92+
return NextResponse.json(
93+
{ error: 'Failed to retrieve status options', details: (error as Error).message },
94+
{ status: 500 }
95+
)
96+
}
97+
}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/selector-combobox/selector-combobox.tsx

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,46 @@ export function SelectorCombobox({
3838
onOptionChange,
3939
allowSearch = true,
4040
}: SelectorComboboxProps) {
41+
// For Monday.com selectors, read apiKey and boardId directly from block state
42+
const [apiKeyFromBlock] = useSubBlockValue<string>(blockId, 'apiKey')
43+
const [boardIdFromBlock] = useSubBlockValue<string>(blockId, 'board_id')
44+
const [boardIdCamelFromBlock] = useSubBlockValue<string>(blockId, 'boardId')
45+
const [columnIdFromBlock] = useSubBlockValue<string>(blockId, 'column_id')
46+
const [columnIdCamelFromBlock] = useSubBlockValue<string>(blockId, 'columnId')
47+
48+
// Merge Monday.com specific values into context if they're missing
49+
const enrichedContext = selectorKey.startsWith('monday.') ? {
50+
...selectorContext,
51+
apiKey: selectorContext.apiKey || apiKeyFromBlock,
52+
boardId: selectorContext.boardId || boardIdFromBlock || boardIdCamelFromBlock,
53+
columnId: selectorContext.columnId || columnIdFromBlock || columnIdCamelFromBlock,
54+
} : selectorContext
55+
56+
// For Monday selectors, override disabled if we have apiKey and required dependencies
57+
let actualDisabled = disabled
58+
if (selectorKey.startsWith('monday.')) {
59+
if (selectorKey === 'monday.boards') {
60+
// boards only needs apiKey
61+
actualDisabled = !enrichedContext.apiKey
62+
} else if (selectorKey === 'monday.columns' || selectorKey === 'monday.groups') {
63+
// columns/groups need apiKey AND boardId
64+
actualDisabled = !enrichedContext.apiKey || !enrichedContext.boardId
65+
} else if (selectorKey === 'monday.status-options') {
66+
// status-options need apiKey, boardId, AND columnId
67+
actualDisabled = !enrichedContext.apiKey || !enrichedContext.boardId || !enrichedContext.columnId
68+
}
69+
}
70+
71+
console.log('[SelectorCombobox RENDER]', {
72+
subBlockId: subBlock.id,
73+
selectorKey,
74+
disabled,
75+
actualDisabled,
76+
hasApiKey: !!enrichedContext.apiKey,
77+
apiKeyFromBlock,
78+
enrichedContext
79+
})
80+
4181
const [storeValueRaw, setStoreValue] = useSubBlockValue<string | null | undefined>(
4282
blockId,
4383
subBlock.id
@@ -52,11 +92,11 @@ export function SelectorCombobox({
5292
isLoading,
5393
error,
5494
} = useSelectorOptions(selectorKey, {
55-
context: selectorContext,
95+
context: enrichedContext,
5696
search: allowSearch ? searchTerm : undefined,
5797
})
5898
const { data: detailOption } = useSelectorOptionDetail(selectorKey, {
59-
context: selectorContext,
99+
context: enrichedContext,
60100
detailId: activeValue,
61101
})
62102
const optionMap = useSelectorOptionMap(options, detailOption ?? undefined)
@@ -89,12 +129,12 @@ export function SelectorCombobox({
89129

90130
const handleSelection = useCallback(
91131
(value: string) => {
92-
if (readOnly || disabled) return
132+
if (readOnly || actualDisabled) return
93133
setStoreValue(value)
94134
setIsEditing(false)
95135
onOptionChange?.(value)
96136
},
97-
[setStoreValue, onOptionChange, readOnly, disabled]
137+
[setStoreValue, onOptionChange, readOnly, actualDisabled]
98138
)
99139

100140
return (
@@ -104,7 +144,7 @@ export function SelectorCombobox({
104144
subBlockId={subBlock.id}
105145
config={subBlock}
106146
value={activeValue ?? ''}
107-
disabled={disabled || readOnly}
147+
disabled={actualDisabled || readOnly}
108148
isPreview={isPreview}
109149
>
110150
{({ ref, onDrop, onDragOver }) => (
@@ -127,7 +167,7 @@ export function SelectorCombobox({
127167
}
128168
}}
129169
placeholder={placeholder || subBlock.placeholder || 'Select an option'}
130-
disabled={disabled || readOnly}
170+
disabled={actualDisabled || readOnly}
131171
editable={allowSearch}
132172
filterOptions={allowSearch}
133173
inputRef={ref as React.RefObject<HTMLInputElement>}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,22 @@ export function useDependsOnGate(
144144

145145
const finalDisabled = disabledProp || isPreview || blocked
146146

147+
// Debug logging for dependency issues
148+
if (typeof window !== 'undefined' && allDependsOnFields.includes('apiKey')) {
149+
console.log('[useDependsOnGate Debug]', {
150+
subBlockId: subBlock.id,
151+
allDependsOnFields,
152+
dependencyValuesMap,
153+
depsSatisfied,
154+
blocked,
155+
finalDisabled,
156+
})
157+
}
158+
147159
return {
148160
dependsOn,
149161
dependencyValues,
162+
dependencyValuesMap,
150163
depsSatisfied,
151164
blocked,
152165
finalDisabled,

0 commit comments

Comments
 (0)