Skip to content

feat(selectors): add dropdown selectors for 14 integrations#3433

Open
waleedlatif1 wants to merge 25 commits intostagingfrom
waleedlatif1/airtable-selectors
Open

feat(selectors): add dropdown selectors for 14 integrations#3433
waleedlatif1 wants to merge 25 commits intostagingfrom
waleedlatif1/airtable-selectors

Conversation

@waleedlatif1
Copy link
Collaborator

Summary

  • Add dropdown selectors (basic mode) with manual ID fallback (advanced mode) for 14 integrations: Airtable, Asana, Attio, Cal.com, Confluence, Google BigQuery, Google Tasks, JSM, Microsoft Planner, Notion, Pipedrive, SharePoint, Trello, Zoom
  • 19 new internal API routes to fetch selectable entities (bases, tables, workspaces, boards, etc.)
  • 20 new selector registry entries with fetchList/fetchById support
  • Cascading selectors for Airtable (base→table), BigQuery (dataset→table), JSM (serviceDesk→requestType)
  • All original subBlock IDs preserved as advanced-mode inputs for backward compatibility

Type of Change

  • New feature

Testing

  • 76/76 block tests passing
  • Zero TypeScript errors
  • Validated canonical param pairing, condition alignment, and backward compatibility across all 14 blocks

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@cursor
Copy link

cursor bot commented Mar 6, 2026

PR Summary

Medium Risk
Adds many new server routes that proxy OAuth-backed third‑party listing APIs and refactors existing SharePoint/Planner selector endpoints to a new auth flow, so regressions could break selector UX or inadvertently change access behavior despite centralized authorizeCredentialUse checks.

Overview
Adds basic-mode dropdown selectors (with advanced manual-ID fallbacks via canonicalParamId) across Airtable, Asana, Attio, Cal.com, Confluence, BigQuery, Google Tasks, JSM, Microsoft Planner, Notion, Pipedrive, SharePoint, Trello, and Zoom.

Implements new internal /api/tools/* POST routes to list selectable entities (e.g., bases/tables, workspaces, datasets/tables, service desks/request types, plans/tasks, sites/lists, boards, meetings) using authorizeCredentialUse + refreshAccessTokenIfNeeded, and refactors existing SharePoint sites + Planner tasks selector endpoints from query-parameter GET/session checks to this shared credential-authorization flow.

Expands selector infrastructure (selectors/registry, selector context/resolution, display-name resolution, workflow comparison resolution) to support new cascading context keys like baseId, datasetId, serviceDeskId, and fileId, updates block configs to wire dependencies for cascading selectors, and adds validateSharePointSiteId plus a small blocks test adjustment to ignore trigger-mode subBlocks during canonical ID collision checks.

Written by Cursor Bugbot for commit ed6feb3. Configure here.

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 6, 2026 7:40am

Request Review

@waleedlatif1 waleedlatif1 force-pushed the waleedlatif1/airtable-selectors branch from d700133 to 665e22c Compare March 6, 2026 01:28
@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR adds dropdown selectors (basic mode) with manual ID fallback (advanced mode) for 14 integrations across 45 files, introducing 19 new internal API routes, 20 new selector registry entries, and cascading selectors for Airtable, BigQuery, and JSM. The implementation is generally consistent and well-structured — all new routes use authorizeCredentialUse, credential access flows through refreshAccessTokenIfNeeded, and the previously-flagged security issues (OAuth tokens in query params, missing ensureCredential guards, authorization bypass for personal credentials, siteId path injection) have all been addressed.

Key observations:

  • read:user:confluence scope removed from V1 ConfluenceBlock — silently dropped without comment; new V1 authentications will lack this scope, potentially causing incomplete user data in Confluence responses. Should be confirmed as intentional.
  • Zoom Topic field unintentionally promoted to basic modemode: 'advanced' was removed from the Topic sub-block for zoom_update_meeting, making it visible in basic mode for all users and changing the UI experience for existing workflows.
  • trello/boards/route.ts requestId placement — declared inside the try block after an early API-key guard, inconsistent with every other new route in this PR which declares it at handler scope.
  • Microsoft Planner task selector dependsOn changedependsOn switched from planId to planSelector; since the task selector is itself basic-mode only this is functionally correct, but worth verifying the dependency resolution correctly forwards the canonical planId value from the planSelector sub-block into the task-selector context.

Confidence Score: 3/5

  • Generally safe to merge for new selector functionality, but the Confluence V1 scope removal and Zoom topic mode change are unintended regressions that should be addressed first.
  • The large majority of the security concerns raised in prior review rounds have been resolved. The remaining open items are: (1) a potentially breaking OAuth scope removal in the Confluence V1 block that hasn't been acknowledged, and (2) a clear UX regression in the Zoom block where a field was accidentally promoted from advanced to basic mode. These are not critical data-loss bugs but are user-facing regressions that warrant fixes before merging.
  • apps/sim/blocks/blocks/confluence.ts (scope removal) and apps/sim/blocks/blocks/zoom.ts (topic field mode change) require attention before merging.

Important Files Changed

Filename Overview
apps/sim/hooks/selectors/registry.ts Adds 20 new selector entries for 14 integrations. All new selectors correctly use ensureCredential and POST requests with body. Previously flagged issues (missing ensureCredential guards, OAuth tokens in URLs) have been resolved. AsanaWorkspace type now correctly uses id. Consistent pattern throughout.
apps/sim/blocks/blocks/confluence.ts Adds spaceSelector in basic mode to V2 block and sets spaceId to advanced mode. However, silently removes read:user:confluence scope from V1 block credential definition — a potentially breaking change for new V1 authentications.
apps/sim/blocks/blocks/zoom.ts Adds meetingSelector in basic mode for 7 meeting operations. Also unintentionally promotes the Topic field from advanced to basic mode for zoom_update_meeting by removing mode: 'advanced'.
apps/sim/app/api/tools/trello/boards/route.ts New route fetching Trello boards using API key + OAuth token in URL (required by Trello's auth model). Filters out closed boards. Minor: requestId is declared inside the try block rather than at handler scope, inconsistent with all other new routes in this PR.
apps/sim/app/api/tools/sharepoint/lists/route.ts New POST route for SharePoint lists. Uses authorizeCredentialUse, validates siteId with validateSharePointSiteId, filters hidden lists, and correctly propagates requestId at handler scope. Addresses all previously flagged security concerns.
apps/sim/app/api/tools/microsoft_planner/plans/route.ts New POST route for Microsoft Planner plans. Uses authorizeCredentialUse and correctly handles the credential lifecycle. requestId is at handler scope. Fetches from /me/planner/plans.
apps/sim/app/api/tools/microsoft_planner/tasks/route.ts Refactored from GET to POST with authorizeCredentialUse. Now validates planId with validateMicrosoftGraphId and uses the sanitized value in the Graph URL path. Security improvements are solid.
apps/sim/app/api/tools/sharepoint/sites/route.ts Refactored from GET (with credentialId in query param) to POST with authorizeCredentialUse. Fixes previously flagged authorization bypass issue for personal (non-workspace) credentials.
apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts New POST route for JSM request types. Uses authorizeCredentialUse, validates serviceDeskId with validateAlphanumericId and cloudId with validateJiraCloudId. Consistent with other new selectors.
apps/sim/lib/core/security/input-validation.ts Adds validateSharePointSiteId function that correctly handles compound site ID format (hostname,spsite-guid,spweb-guid), enforces 512-char max length, and uses an allowlist regex. Well-documented and consistent with existing validators.
apps/sim/blocks/blocks/notion.ts Consolidates previously-duplicated pageId and databaseId entries into single canonicalParamId-bearing entries, and adds selectors for pages, databases, and parent pages. Clean refactor with correct mode/condition pairings.
apps/sim/blocks/blocks/airtable.ts Adds cascading baseSelectortableSelector in basic mode while preserving original baseId/tableId inputs in advanced mode. canonicalParamId is properly set on both selector and raw-input entries.
apps/sim/hooks/selectors/types.ts Adds 20 new SelectorKey union members and 3 new optional context fields (baseId, datasetId, serviceDeskId) to SelectorContext. Clean, well-typed additions.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx Adds context field resolution for new selector IDs (baseId, datasetId, serviceDeskId, siteId, collectionId, spreadsheetId, fileId) with selector fallbacks. Properly threads values to useSelectorDisplayName.
apps/sim/lib/workflows/comparison/resolve-values.ts Adds baseId, datasetId, and serviceDeskId to ExtendedSelectorContext and wires them up in both resolveSelectorValue and resolveValueForDisplay with correct selector/raw-input fallback pattern.

Sequence Diagram

sequenceDiagram
    participant UI as Block UI (workflow-block)
    participant Hook as useSelectorSetup / useSelector
    participant Registry as selector registry
    participant API as /api/tools/{integration}/...
    participant Ext as External API

    Note over UI,Ext: Basic mode: dropdown selector flow
    UI->>Hook: context (credentialId, domain, baseId, etc.)
    Hook->>Registry: fetchList({ context })
    Registry->>API: POST { credential, workflowId, [contextParams] }
    API->>API: authorizeCredentialUse()
    API->>API: refreshAccessTokenIfNeeded()
    API->>Ext: GET/POST with Bearer token
    Ext-->>API: raw data
    API-->>Registry: { items[] }
    Registry-->>Hook: SelectorItem[] (id, label)
    Hook-->>UI: dropdown options

    Note over UI,Ext: Advanced mode: raw ID input (backward compat)
    UI->>UI: user types raw ID into short-input
    UI->>UI: canonicalParamId merges both modes

    Note over UI,Ext: Cascading selector (e.g. Airtable base→table)
    UI->>Hook: context with baseId from baseSelector
    Hook->>Registry: fetchList({ context: { baseId } })
    Registry->>API: POST { credential, workflowId, baseId }
    API->>Ext: GET /meta/bases/{baseId}/tables
    Ext-->>API: tables[]
    API-->>Registry: { tables[] }
    Registry-->>Hook: table SelectorItem[]
    Hook-->>UI: table dropdown options
Loading

Comments Outside Diff (1)

  1. apps/sim/blocks/blocks/microsoft_planner.ts, line 133 (link)

    Task selector dependsOn now references planSelector instead of planId

    The existing microsoft.planner (task) selector's dependsOn was changed from ['credential', 'planId'] to ['credential', 'planSelector']. Since the task selector is mode: 'basic', this works correctly in basic mode where planSelector is also visible and populated.

    However, this is worth double-checking: if a user saved a workflow in basic mode with a planSelector value, then opens it later and the selector system re-resolves dependencies, the task dropdown will correctly populate. But if any code path reads dependsOn to determine the context key and the implementation maps it to the canonical planId, the context forwarded to microsoft.planner's fetchList (which reads context.planId) should still be resolved from planSelector's canonical param. Please verify the dependency-to-context resolution handles this correctly, particularly that planSelector's stored value is properly propagated as planId in the selector context.

Last reviewed commit: 13c25ec

…utes

Convert JSM selector-servicedesks, selector-requesttypes, and Confluence
selector-spaces routes from GET (with access token in URL query params) to
POST with authorizeCredentialUse + refreshAccessTokenIfNeeded pattern. Also
adds missing ensureCredential guard to microsoft.planner.plans registry entry.
Use serviceDeskIdValidation.sanitized instead of raw serviceDeskId in JSM
request types URL. Add encodeURIComponent to SharePoint siteId to prevent
URL path injection.
SharePoint site IDs use the format "hostname,guid,guid" with commas that
must remain unencoded for the Microsoft Graph API. The encodeURIComponent
call would convert commas to %2C and break the API call.
@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

Use cloudIdValidation.sanitized instead of raw cloudId in URL construction
for consistency with the validation pattern, even though the current
validator returns the input unchanged.
@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1 waleedlatif1 reopened this Mar 6, 2026
…ntial to sharepoint.lists, and siteId validation

- Add baseId, datasetId, serviceDeskId to SelectorResolutionArgs,
  ExtendedSelectorContext, extractExtendedContext, useSelectorDisplayName,
  and resolveSelectorForSubBlock so cascading selectors resolve correctly
  through the resolution path.
- Add ensureCredential guard to sharepoint.lists registry entry.
- Add regex validation for SharePoint siteId format (hostname,GUID,GUID).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Collaborator Author

@cursor review

…to POST+authorizeCredentialUse

- Use planIdValidation.sanitized in MS Planner tasks fetch URL
- Convert sharepoint/lists and sharepoint/sites from GET+getSession to POST+authorizeCredentialUse
- Update registry entries to match POST pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@greptile

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@waleedlatif1
Copy link
Collaborator Author

@greptile

…mpatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

…tor display name fallbacks

- Add validateSharePointSiteId to input-validation.ts
- Use validation util in SharePoint lists route instead of inline regex
- Add || fallback to selector IDs in workflow-block.tsx so cascading
  display names resolve in basic mode (baseSelector, planSelector, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@greptile

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Collaborator Author

@greptile

@@ -84,7 +84,6 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
'write:content.property:confluence',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read:user:confluence scope silently removed from V1 block

The read:user:confluence OAuth scope has been removed from the V1 ConfluenceBlock credential definition. While the V2 block still requests this scope, users who authenticate through the V1 block will no longer have it in their granted scopes — meaning any Confluence API call that returns user objects (e.g., author/created-by fields on pages and blog posts, contributor lookups) may return incomplete data or a 403 for that sub-resource.

Existing V1 users are unaffected until they re-authorize, but new V1 authentications and token refreshes for expired credentials will be issued without this scope.

Please confirm this removal is intentional and that no V1 block operation path depends on user-profile data. If it is intentional, a migration note or deprecation comment would help future maintainers understand why the scope was dropped.

@@ -114,7 +141,6 @@ export const ZoomBlock: BlockConfig<ZoomResponse> = {
title: 'Topic',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Topic field promoted from advanced to basic mode unexpectedly

The mode: 'advanced' property was removed from the Topic sub-block for zoom_update_meeting. This means Topic is now visible in basic mode, changing the UI for all existing Zoom blocks. Users who previously relied on the field being hidden (i.e., scoped to advanced mode only) will now see an unexpected Topic input in their workflows.

If this is intentional (e.g., making topic a first-class field for updates), consider whether it might confuse users with existing saved workflows that don't expect this field to appear in basic mode.

const requestId = generateRequestId()
const body = await request.json()
const { credential, workflowId } = body

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requestId declared inside try block, inconsistent with other routes

requestId is generated inside the try block (after the early apiKey check), while every other new route in this PR declares it as the first statement of the handler before try. If an exception is ever thrown and you want to add requestId to the catch-block error log, it will be out of scope.

Consider hoisting const requestId = generateRequestId() to the very top of the handler function (before the try), consistent with sharepoint/lists/route.ts, microsoft_planner/plans/route.ts, and all other new routes in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant