Skip to content

Commit b46a1e6

Browse files
committed
update item
1 parent 239371f commit b46a1e6

File tree

10 files changed

+303
-19
lines changed

10 files changed

+303
-19
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { createLogger } from '@sim/logger'
2+
import { NextResponse } from 'next/server'
3+
import { QUERIES } from '@/tools/monday/graphql'
4+
5+
const logger = createLogger('MondayItemsAPI')
6+
7+
/**
8+
* POST /api/tools/monday/items
9+
* Fetches items from a Monday.com board for selector dropdown
10+
*/
11+
export async function POST(request: Request) {
12+
try {
13+
const body = await request.json()
14+
const { apiKey, boardId } = body
15+
16+
if (!apiKey) {
17+
logger.warn('Missing apiKey in request')
18+
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
19+
}
20+
21+
if (!boardId) {
22+
logger.warn('Missing boardId in request')
23+
return NextResponse.json({ error: 'Board ID is required' }, { status: 400 })
24+
}
25+
26+
logger.info('Fetching Monday.com items', { boardId })
27+
28+
const response = await fetch('https://api.monday.com/v2', {
29+
method: 'POST',
30+
headers: {
31+
'Content-Type': 'application/json',
32+
Authorization: apiKey,
33+
'API-Version': '2024-01',
34+
},
35+
body: JSON.stringify({
36+
query: QUERIES.GET_BOARD_ITEMS,
37+
variables: {
38+
boardId: [parseInt(boardId, 10)],
39+
limit: 100,
40+
},
41+
}),
42+
})
43+
44+
if (!response.ok) {
45+
const errorText = await response.text()
46+
logger.error('Monday.com API error', {
47+
status: response.status,
48+
error: errorText,
49+
})
50+
return NextResponse.json(
51+
{ error: `Monday.com API error: ${response.status}` },
52+
{ status: response.status }
53+
)
54+
}
55+
56+
const result = await response.json()
57+
58+
if (result.errors) {
59+
logger.error('Monday.com GraphQL errors', { errors: result.errors })
60+
return NextResponse.json(
61+
{ error: 'Failed to fetch items', details: result.errors },
62+
{ status: 400 }
63+
)
64+
}
65+
66+
const items = result.data?.boards?.[0]?.items_page?.items || []
67+
68+
logger.info('Successfully fetched Monday.com items', { count: items.length })
69+
70+
return NextResponse.json({
71+
items: items.map((item: any) => ({
72+
id: item.id,
73+
name: item.name,
74+
})),
75+
})
76+
} catch (error) {
77+
logger.error('Unexpected error fetching Monday.com items', { error })
78+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
79+
}
80+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { createLogger } from '@sim/logger'
2+
import { NextResponse } from 'next/server'
3+
import { QUERIES } from '@/tools/monday/graphql'
4+
5+
const logger = createLogger('MondaySubitemsAPI')
6+
7+
/**
8+
* POST /api/tools/monday/subitems
9+
* Fetches subitems from a Monday.com item for selector dropdown
10+
*/
11+
export async function POST(request: Request) {
12+
try {
13+
const body = await request.json()
14+
const { apiKey, itemId } = body
15+
16+
if (!apiKey) {
17+
logger.warn('Missing apiKey in request')
18+
return NextResponse.json({ error: 'API key is required' }, { status: 400 })
19+
}
20+
21+
if (!itemId) {
22+
logger.warn('Missing itemId in request')
23+
return NextResponse.json({ error: 'Item ID is required' }, { status: 400 })
24+
}
25+
26+
logger.info('Fetching Monday.com subitems', { itemId })
27+
28+
const response = await fetch('https://api.monday.com/v2', {
29+
method: 'POST',
30+
headers: {
31+
'Content-Type': 'application/json',
32+
Authorization: apiKey,
33+
'API-Version': '2024-01',
34+
},
35+
body: JSON.stringify({
36+
query: QUERIES.GET_ITEM_SUBITEMS,
37+
variables: {
38+
itemId: [parseInt(itemId, 10)],
39+
},
40+
}),
41+
})
42+
43+
if (!response.ok) {
44+
const errorText = await response.text()
45+
logger.error('Monday.com API error', {
46+
status: response.status,
47+
error: errorText,
48+
})
49+
return NextResponse.json(
50+
{ error: `Monday.com API error: ${response.status}` },
51+
{ status: response.status }
52+
)
53+
}
54+
55+
const result = await response.json()
56+
57+
if (result.errors) {
58+
logger.error('Monday.com GraphQL errors', { errors: result.errors })
59+
return NextResponse.json(
60+
{ error: 'Failed to fetch subitems', details: result.errors },
61+
{ status: 400 }
62+
)
63+
}
64+
65+
const subitems = result.data?.items?.[0]?.subitems || []
66+
67+
logger.info('Successfully fetched Monday.com subitems', { count: subitems.length })
68+
69+
return NextResponse.json({
70+
items: subitems.map((subitem: any) => ({
71+
id: subitem.id,
72+
name: subitem.name,
73+
})),
74+
})
75+
} catch (error) {
76+
logger.error('Unexpected error fetching Monday.com subitems', { error })
77+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
78+
}
79+
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export function FileSelectorInput({
5959
const [groupIdListFromStore] = useSubBlockValue(blockId, 'group_id_list')
6060
const [columnIdValueFromStore] = useSubBlockValue(blockId, 'column_id')
6161
const [columnIdCamelFromStore] = useSubBlockValue(blockId, 'columnId')
62+
const [itemIdValueFromStore] = useSubBlockValue(blockId, 'item_id')
63+
const [itemIdCamelFromStore] = useSubBlockValue(blockId, 'itemId')
6264

6365
const connectedCredential = previewContextValues?.credential ?? connectedCredentialFromStore
6466
const domainValue = previewContextValues?.domain ?? domainValueFromStore
@@ -86,6 +88,11 @@ export function FileSelectorInput({
8688
previewContextValues?.columnId ??
8789
columnIdValueFromStore ??
8890
columnIdCamelFromStore
91+
const itemIdValue =
92+
previewContextValues?.item_id ??
93+
previewContextValues?.itemId ??
94+
itemIdValueFromStore ??
95+
itemIdCamelFromStore
8996

9097
const normalizedCredentialId =
9198
typeof connectedCredential === 'string'
@@ -114,6 +121,7 @@ export function FileSelectorInput({
114121
boardId: (boardIdValue as string) || undefined,
115122
groupId: (groupIdValue as string) || undefined,
116123
columnId: (columnIdValue as string) || undefined,
124+
itemId: (itemIdValue as string) || undefined,
117125
})
118126
}, [
119127
subBlock,
@@ -129,6 +137,7 @@ export function FileSelectorInput({
129137
boardIdValue,
130138
groupIdValue,
131139
columnIdValue,
140+
itemIdValue,
132141
])
133142

134143
const isMondaySelector = selectorResolution?.key?.startsWith('monday.')
@@ -150,12 +159,18 @@ export function FileSelectorInput({
150159
selectorResolution?.key === 'webflow.items' && !selectorResolution.context.collectionId
151160
const missingBoard =
152161
isMondaySelector &&
153-
(selectorResolution?.key === 'monday.groups' || selectorResolution?.key === 'monday.columns') &&
162+
(selectorResolution?.key === 'monday.groups' ||
163+
selectorResolution?.key === 'monday.columns' ||
164+
selectorResolution?.key === 'monday.items') &&
154165
!selectorResolution?.context.boardId
155166
const missingColumn =
156167
isMondaySelector &&
157168
selectorResolution?.key === 'monday.status-options' &&
158169
!selectorResolution?.context.columnId
170+
const missingItem =
171+
isMondaySelector &&
172+
selectorResolution?.key === 'monday.subitems' &&
173+
!selectorResolution?.context.itemId
159174

160175
const disabledReason =
161176
finalDisabled ||
@@ -169,6 +184,7 @@ export function FileSelectorInput({
169184
missingCollection ||
170185
missingBoard ||
171186
missingColumn ||
187+
missingItem ||
172188
!selectorResolution?.key
173189

174190
if (!selectorResolution?.key) {

apps/sim/blocks/blocks/monday.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,6 @@ export const MondayBlock: BlockConfig<MondayResponse> = {
7575
condition: { field: 'operation', value: 'monday_create_item' },
7676
},
7777
// UPDATE ITEM fields
78-
{
79-
id: 'item_id',
80-
title: 'Item ID',
81-
type: 'short-input',
82-
placeholder: 'Enter item ID to update',
83-
required: true,
84-
condition: { field: 'operation', value: 'monday_update_item' },
85-
},
8678
{
8779
id: 'board_id_update',
8880
title: 'Board',
@@ -94,6 +86,26 @@ export const MondayBlock: BlockConfig<MondayResponse> = {
9486
condition: { field: 'operation', value: 'monday_update_item' },
9587
dependsOn: ['apiKey'],
9688
},
89+
{
90+
id: 'item_id',
91+
title: 'Item',
92+
type: 'file-selector',
93+
serviceId: 'monday',
94+
placeholder: 'Select an item to update',
95+
required: true,
96+
condition: { field: 'operation', value: 'monday_update_item' },
97+
dependsOn: ['apiKey', 'board_id_update'],
98+
},
99+
{
100+
id: 'subitem_id',
101+
title: 'Sub-Item (Optional)',
102+
type: 'file-selector',
103+
serviceId: 'monday',
104+
placeholder: 'Select a sub-item to update (optional)',
105+
required: false,
106+
condition: { field: 'operation', value: 'monday_update_item' },
107+
dependsOn: ['apiKey', 'item_id'],
108+
},
97109
{
98110
id: 'column_values_update',
99111
title: 'Column Values (JSON)',
@@ -172,6 +184,7 @@ export const MondayBlock: BlockConfig<MondayResponse> = {
172184
board_id: { type: 'string', description: 'Board ID' },
173185
group_id: { type: 'string', description: 'Group/section ID' },
174186
item_id: { type: 'string', description: 'Item ID' },
187+
subitem_id: { type: 'string', description: 'Sub-item ID' },
175188
item_name: { type: 'string', description: 'Item name' },
176189
column_values: { type: 'json', description: 'Column values as JSON' },
177190
limit: { type: 'number', description: 'Maximum number of items to return' },

apps/sim/hooks/selectors/registry.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,56 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
889889
}))
890890
},
891891
},
892+
'monday.items': {
893+
key: 'monday.items',
894+
staleTime: SELECTOR_STALE,
895+
getQueryKey: ({ context }: SelectorQueryArgs) => [
896+
'selectors',
897+
'monday.items',
898+
context.apiKey ?? 'none',
899+
context.boardId ?? 'none',
900+
],
901+
enabled: ({ context }) => Boolean(context.apiKey && context.boardId),
902+
fetchList: async ({ context }: SelectorQueryArgs) => {
903+
const body = JSON.stringify({
904+
apiKey: context.apiKey,
905+
boardId: context.boardId,
906+
})
907+
const data = await fetchJson<{ items: { id: string; name: string }[] }>(
908+
'/api/tools/monday/items',
909+
{ method: 'POST', body }
910+
)
911+
return (data.items || []).map((item) => ({
912+
id: item.id,
913+
label: item.name,
914+
}))
915+
},
916+
},
917+
'monday.subitems': {
918+
key: 'monday.subitems',
919+
staleTime: SELECTOR_STALE,
920+
getQueryKey: ({ context }: SelectorQueryArgs) => [
921+
'selectors',
922+
'monday.subitems',
923+
context.apiKey ?? 'none',
924+
context.itemId ?? 'none',
925+
],
926+
enabled: ({ context }) => Boolean(context.apiKey && context.itemId),
927+
fetchList: async ({ context }: SelectorQueryArgs) => {
928+
const body = JSON.stringify({
929+
apiKey: context.apiKey,
930+
itemId: context.itemId,
931+
})
932+
const data = await fetchJson<{ items: { id: string; name: string }[] }>(
933+
'/api/tools/monday/subitems',
934+
{ method: 'POST', body }
935+
)
936+
return (data.items || []).map((subitem) => ({
937+
id: subitem.id,
938+
label: subitem.name,
939+
}))
940+
},
941+
},
892942
}
893943

894944
export function getSelectorDefinition(key: SelectorKey): SelectorDefinition {

apps/sim/hooks/selectors/resolution.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface SelectorResolutionArgs {
2020
apiKey?: string
2121
boardId?: string
2222
columnId?: string
23+
itemId?: string
2324
}
2425

2526
const defaultContext: SelectorContext = {}
@@ -64,6 +65,7 @@ function buildBaseContext(
6465
apiKey: args.apiKey,
6566
boardId: args.boardId,
6667
columnId: args.columnId,
68+
itemId: args.itemId,
6769
...extra,
6870
}
6971
}
@@ -148,6 +150,12 @@ function resolveFileSelector(
148150
if (subBlock.id === 'status_column' || subBlock.id === 'statusColumn') {
149151
return { key: 'monday.status-options', context, allowSearch: true }
150152
}
153+
if (subBlock.id === 'item_id' || subBlock.id === 'itemId') {
154+
return { key: 'monday.items', context, allowSearch: true }
155+
}
156+
if (subBlock.id === 'subitem_id' || subBlock.id === 'subitemId') {
157+
return { key: 'monday.subitems', context, allowSearch: true }
158+
}
151159
return { key: null, context, allowSearch: true }
152160
default:
153161
return { key: null, context, allowSearch: true }

apps/sim/hooks/selectors/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export type SelectorKey =
3131
| 'monday.columns'
3232
| 'monday.groups'
3333
| 'monday.status-options'
34+
| 'monday.items'
35+
| 'monday.subitems'
3436

3537

3638
export interface SelectorOption {
@@ -58,6 +60,7 @@ export interface SelectorContext {
5860
boardId?: string
5961
groupId?: string
6062
columnId?: string
63+
itemId?: string
6164
}
6265

6366
export interface SelectorQueryArgs {

0 commit comments

Comments
 (0)