Skip to content

Commit 2a52141

Browse files
feat(slack): canvas related operations (#4306)
* feat(slack): canvas related operations * extract shared code
1 parent 76ad59f commit 2a52141

11 files changed

Lines changed: 887 additions & 2 deletions

File tree

apps/sim/blocks/blocks/slack.ts

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
4646
{ label: 'Get User Presence', id: 'get_user_presence' },
4747
{ label: 'Edit Canvas', id: 'edit_canvas' },
4848
{ label: 'Create Channel Canvas', id: 'create_channel_canvas' },
49+
{ label: 'Get Canvas Info', id: 'get_canvas' },
50+
{ label: 'List Canvases', id: 'list_canvases' },
51+
{ label: 'Lookup Canvas Sections', id: 'lookup_canvas_sections' },
52+
{ label: 'Delete Canvas', id: 'delete_canvas' },
4953
{ label: 'Create Conversation', id: 'create_conversation' },
5054
{ label: 'Invite to Conversation', id: 'invite_to_conversation' },
5155
{ label: 'Open View', id: 'open_view' },
@@ -146,6 +150,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
146150
'get_user',
147151
'get_user_presence',
148152
'edit_canvas',
153+
'get_canvas',
154+
'list_canvases',
155+
'lookup_canvas_sections',
156+
'delete_canvas',
149157
'create_conversation',
150158
'open_view',
151159
'update_view',
@@ -182,6 +190,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
182190
'get_user',
183191
'get_user_presence',
184192
'edit_canvas',
193+
'get_canvas',
194+
'list_canvases',
195+
'lookup_canvas_sections',
196+
'delete_canvas',
185197
'create_conversation',
186198
'open_view',
187199
'update_view',
@@ -820,6 +832,132 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
820832
value: 'create_channel_canvas',
821833
},
822834
},
835+
// Get Canvas specific fields
836+
{
837+
id: 'getCanvasId',
838+
title: 'Canvas ID',
839+
type: 'short-input',
840+
placeholder: 'Enter canvas ID (e.g., F1234ABCD)',
841+
condition: {
842+
field: 'operation',
843+
value: 'get_canvas',
844+
},
845+
required: true,
846+
},
847+
// List Canvases specific fields
848+
{
849+
id: 'canvasListChannel',
850+
title: 'Channel ID',
851+
type: 'short-input',
852+
placeholder: 'Optional channel filter (e.g., C1234567890)',
853+
condition: {
854+
field: 'operation',
855+
value: 'list_canvases',
856+
},
857+
mode: 'advanced',
858+
},
859+
{
860+
id: 'canvasListCount',
861+
title: 'Canvas Limit',
862+
type: 'short-input',
863+
placeholder: '100',
864+
condition: {
865+
field: 'operation',
866+
value: 'list_canvases',
867+
},
868+
mode: 'advanced',
869+
},
870+
{
871+
id: 'canvasListPage',
872+
title: 'Page',
873+
type: 'short-input',
874+
placeholder: '1',
875+
condition: {
876+
field: 'operation',
877+
value: 'list_canvases',
878+
},
879+
mode: 'advanced',
880+
},
881+
{
882+
id: 'canvasListUser',
883+
title: 'User ID',
884+
type: 'short-input',
885+
placeholder: 'Optional creator filter (e.g., U1234567890)',
886+
condition: {
887+
field: 'operation',
888+
value: 'list_canvases',
889+
},
890+
mode: 'advanced',
891+
},
892+
{
893+
id: 'canvasListTsFrom',
894+
title: 'Created After',
895+
type: 'short-input',
896+
placeholder: 'Unix timestamp (e.g., 123456789)',
897+
condition: {
898+
field: 'operation',
899+
value: 'list_canvases',
900+
},
901+
mode: 'advanced',
902+
},
903+
{
904+
id: 'canvasListTsTo',
905+
title: 'Created Before',
906+
type: 'short-input',
907+
placeholder: 'Unix timestamp (e.g., 123456789)',
908+
condition: {
909+
field: 'operation',
910+
value: 'list_canvases',
911+
},
912+
mode: 'advanced',
913+
},
914+
{
915+
id: 'canvasListTeamId',
916+
title: 'Team ID',
917+
type: 'short-input',
918+
placeholder: 'Encoded team ID (org tokens only)',
919+
condition: {
920+
field: 'operation',
921+
value: 'list_canvases',
922+
},
923+
mode: 'advanced',
924+
},
925+
// Lookup Canvas Sections specific fields
926+
{
927+
id: 'lookupCanvasId',
928+
title: 'Canvas ID',
929+
type: 'short-input',
930+
placeholder: 'Enter canvas ID (e.g., F1234ABCD)',
931+
condition: {
932+
field: 'operation',
933+
value: 'lookup_canvas_sections',
934+
},
935+
required: true,
936+
},
937+
{
938+
id: 'sectionCriteria',
939+
title: 'Section Criteria',
940+
type: 'code',
941+
language: 'json',
942+
placeholder: '{"section_types":["h1"],"contains_text":"Roadmap"}',
943+
condition: {
944+
field: 'operation',
945+
value: 'lookup_canvas_sections',
946+
},
947+
required: true,
948+
},
949+
// Delete Canvas specific fields
950+
{
951+
id: 'deleteCanvasId',
952+
title: 'Canvas ID',
953+
type: 'short-input',
954+
placeholder: 'Enter canvas ID (e.g., F1234ABCD)',
955+
condition: {
956+
field: 'operation',
957+
value: 'delete_canvas',
958+
},
959+
required: true,
960+
},
823961
// Create Conversation specific fields
824962
{
825963
id: 'conversationName',
@@ -1058,6 +1196,10 @@ Do not include any explanations, markdown formatting, or other text outside the
10581196
'slack_get_user_presence',
10591197
'slack_edit_canvas',
10601198
'slack_create_channel_canvas',
1199+
'slack_get_canvas',
1200+
'slack_list_canvases',
1201+
'slack_lookup_canvas_sections',
1202+
'slack_delete_canvas',
10611203
'slack_create_conversation',
10621204
'slack_invite_to_conversation',
10631205
'slack_open_view',
@@ -1106,6 +1248,14 @@ Do not include any explanations, markdown formatting, or other text outside the
11061248
return 'slack_edit_canvas'
11071249
case 'create_channel_canvas':
11081250
return 'slack_create_channel_canvas'
1251+
case 'get_canvas':
1252+
return 'slack_get_canvas'
1253+
case 'list_canvases':
1254+
return 'slack_list_canvases'
1255+
case 'lookup_canvas_sections':
1256+
return 'slack_lookup_canvas_sections'
1257+
case 'delete_canvas':
1258+
return 'slack_delete_canvas'
11091259
case 'create_conversation':
11101260
return 'slack_create_conversation'
11111261
case 'invite_to_conversation':
@@ -1164,6 +1314,17 @@ Do not include any explanations, markdown formatting, or other text outside the
11641314
canvasTitle,
11651315
channelCanvasTitle,
11661316
channelCanvasContent,
1317+
getCanvasId,
1318+
canvasListChannel,
1319+
canvasListCount,
1320+
canvasListPage,
1321+
canvasListUser,
1322+
canvasListTsFrom,
1323+
canvasListTsTo,
1324+
canvasListTeamId,
1325+
lookupCanvasId,
1326+
sectionCriteria,
1327+
deleteCanvasId,
11671328
conversationName,
11681329
isPrivate,
11691330
teamId,
@@ -1343,6 +1504,49 @@ Do not include any explanations, markdown formatting, or other text outside the
13431504
}
13441505
break
13451506

1507+
case 'get_canvas':
1508+
baseParams.canvasId = getCanvasId
1509+
break
1510+
1511+
case 'list_canvases':
1512+
if (canvasListChannel) {
1513+
baseParams.channel = String(canvasListChannel).trim()
1514+
}
1515+
if (canvasListCount) {
1516+
const parsedCount = Number.parseInt(canvasListCount, 10)
1517+
if (!Number.isNaN(parsedCount) && parsedCount > 0) {
1518+
baseParams.count = parsedCount
1519+
}
1520+
}
1521+
if (canvasListPage) {
1522+
const parsedPage = Number.parseInt(canvasListPage, 10)
1523+
if (!Number.isNaN(parsedPage) && parsedPage > 0) {
1524+
baseParams.page = parsedPage
1525+
}
1526+
}
1527+
if (canvasListUser) {
1528+
baseParams.user = String(canvasListUser).trim()
1529+
}
1530+
if (canvasListTsFrom) {
1531+
baseParams.tsFrom = String(canvasListTsFrom).trim()
1532+
}
1533+
if (canvasListTsTo) {
1534+
baseParams.tsTo = String(canvasListTsTo).trim()
1535+
}
1536+
if (canvasListTeamId) {
1537+
baseParams.teamId = String(canvasListTeamId).trim()
1538+
}
1539+
break
1540+
1541+
case 'lookup_canvas_sections':
1542+
baseParams.canvasId = lookupCanvasId
1543+
baseParams.criteria = sectionCriteria
1544+
break
1545+
1546+
case 'delete_canvas':
1547+
baseParams.canvasId = deleteCanvasId
1548+
break
1549+
13461550
case 'create_conversation':
13471551
baseParams.name = conversationName
13481552
baseParams.isPrivate = isPrivate === 'true'
@@ -1461,6 +1665,24 @@ Do not include any explanations, markdown formatting, or other text outside the
14611665
// Create Channel Canvas inputs
14621666
channelCanvasTitle: { type: 'string', description: 'Title for channel canvas' },
14631667
channelCanvasContent: { type: 'string', description: 'Content for channel canvas' },
1668+
// Canvas management inputs
1669+
getCanvasId: { type: 'string', description: 'Canvas ID to retrieve' },
1670+
canvasListChannel: { type: 'string', description: 'Optional channel filter for canvases' },
1671+
canvasListCount: { type: 'string', description: 'Maximum number of canvases to return' },
1672+
canvasListPage: { type: 'string', description: 'Canvas list page number' },
1673+
canvasListUser: { type: 'string', description: 'Optional canvas creator user filter' },
1674+
canvasListTsFrom: {
1675+
type: 'string',
1676+
description: 'Filter canvases created after this timestamp',
1677+
},
1678+
canvasListTsTo: {
1679+
type: 'string',
1680+
description: 'Filter canvases created before this timestamp',
1681+
},
1682+
canvasListTeamId: { type: 'string', description: 'Encoded team ID for org tokens' },
1683+
lookupCanvasId: { type: 'string', description: 'Canvas ID to search for sections' },
1684+
sectionCriteria: { type: 'json', description: 'Canvas section lookup criteria' },
1685+
deleteCanvasId: { type: 'string', description: 'Canvas ID to delete' },
14641686
// Create Conversation inputs
14651687
conversationName: { type: 'string', description: 'Name for the new channel' },
14661688
isPrivate: { type: 'string', description: 'Create as private channel (true/false)' },
@@ -1511,6 +1733,26 @@ Do not include any explanations, markdown formatting, or other text outside the
15111733
// slack_canvas outputs
15121734
canvas_id: { type: 'string', description: 'Canvas identifier for created canvases' },
15131735
title: { type: 'string', description: 'Canvas title' },
1736+
canvas: {
1737+
type: 'json',
1738+
description: 'Canvas file metadata returned by Slack',
1739+
},
1740+
canvases: {
1741+
type: 'json',
1742+
description: 'Array of canvas file objects returned by Slack',
1743+
},
1744+
paging: {
1745+
type: 'json',
1746+
description: 'Pagination information for listed canvases',
1747+
},
1748+
sections: {
1749+
type: 'json',
1750+
description: 'Canvas section IDs returned by Slack section lookup',
1751+
},
1752+
ok: {
1753+
type: 'boolean',
1754+
description: 'Whether Slack completed the canvas operation successfully',
1755+
},
15141756

15151757
// slack_message_reader outputs (read operation)
15161758
messages: {

apps/sim/lib/oauth/oauth.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
704704
services: {
705705
slack: {
706706
name: 'Slack',
707-
description: 'Send messages using a bot for Slack.',
707+
description: 'Use Slack messaging, files, reactions, views, and canvases.',
708708
providerId: 'slack',
709709
icon: SlackIcon,
710710
baseProviderIcon: SlackIcon,
@@ -722,6 +722,7 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
722722
// TODO: Add 'users:read.email' once Slack app review is approved
723723
'files:write',
724724
'files:read',
725+
'canvases:read',
725726
'canvases:write',
726727
'reactions:write',
727728
],

apps/sim/lib/oauth/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ export const SCOPE_DESCRIPTIONS: Record<string, string> = {
278278
'users:read.email': 'View user email addresses',
279279
'files:write': 'Upload files',
280280
'files:read': 'Download and read files',
281-
'canvases:write': 'Create canvas documents',
281+
'canvases:read': 'Read canvas sections',
282+
'canvases:write': 'Create, edit, and delete canvas documents',
282283
'reactions:write': 'Add emoji reactions to messages',
283284

284285
// Webflow scopes

apps/sim/tools/registry.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,19 +2364,23 @@ import {
23642364
slackCanvasTool,
23652365
slackCreateChannelCanvasTool,
23662366
slackCreateConversationTool,
2367+
slackDeleteCanvasTool,
23672368
slackDeleteMessageTool,
23682369
slackDownloadTool,
23692370
slackEditCanvasTool,
23702371
slackEphemeralMessageTool,
2372+
slackGetCanvasTool,
23712373
slackGetChannelInfoTool,
23722374
slackGetMessageTool,
23732375
slackGetThreadTool,
23742376
slackGetUserPresenceTool,
23752377
slackGetUserTool,
23762378
slackInviteToConversationTool,
2379+
slackListCanvasesTool,
23772380
slackListChannelsTool,
23782381
slackListMembersTool,
23792382
slackListUsersTool,
2383+
slackLookupCanvasSectionsTool,
23802384
slackMessageReaderTool,
23812385
slackMessageTool,
23822386
slackOpenViewTool,
@@ -3360,6 +3364,10 @@ export const tools: Record<string, ToolConfig> = {
33603364
slack_publish_view: slackPublishViewTool,
33613365
slack_edit_canvas: slackEditCanvasTool,
33623366
slack_create_channel_canvas: slackCreateChannelCanvasTool,
3367+
slack_get_canvas: slackGetCanvasTool,
3368+
slack_list_canvases: slackListCanvasesTool,
3369+
slack_lookup_canvas_sections: slackLookupCanvasSectionsTool,
3370+
slack_delete_canvas: slackDeleteCanvasTool,
33633371
slack_create_conversation: slackCreateConversationTool,
33643372
slack_invite_to_conversation: slackInviteToConversationTool,
33653373
github_repo_info: githubRepoInfoTool,

0 commit comments

Comments
 (0)