Skip to content

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

Merged
waleedlatif1 merged 32 commits intostagingfrom
waleedlatif1/airtable-selectors
Mar 6, 2026
Merged

feat(selectors): add dropdown selectors for 14 integrations#3433
waleedlatif1 merged 32 commits intostagingfrom
waleedlatif1/airtable-selectors

Conversation

@waleedlatif1
Copy link
Collaborator

@waleedlatif1 waleedlatif1 commented Mar 6, 2026

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
  • Guard selector queries against unresolved variable references (<Block.output>, {{ENV_VAR}}): skip fetchById and context population when values are design-time placeholders rather than real IDs

Type of Change

  • New feature
  • Bug fix

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 multiple new OAuth-backed API routes and refactors existing Microsoft Planner/SharePoint selector endpoints to a new authz + POST contract; bugs here could break selector UX or incorrectly gate credential access. Input validation and reference-guarding reduce but don’t eliminate integration/API edge-case risk.

Overview
Adds dropdown selectors for 14 integrations by introducing new selector-backed subBlocks (basic mode) while keeping existing manual ID inputs as advanced-mode fallbacks.

Introduces new internal selector API routes (Airtable bases/tables, Asana workspaces, Attio lists/objects, Cal.com event types/schedules, Confluence spaces, BigQuery datasets/tables, Google Tasks lists, JSM service desks/request types, Microsoft Planner plans, Notion pages/databases, Pipedrive pipelines, SharePoint lists, Trello boards, Zoom meetings), all using authorizeCredentialUse + refreshAccessTokenIfNeeded.

Updates selector plumbing: expands SelectorKey/context fields (e.g., baseId, datasetId, serviceDeskId), adds registry entries with fetchList/fetchById, switches existing SharePoint sites + Planner tasks selectors to POST body calls, and prevents context/detail lookups when values are unresolved references (<Block.output>, {{ENV_VAR}}).

Hardens validation/testing: adds validateSharePointSiteId, validates Airtable baseId, and adjusts block canonical-param tests to ignore trigger-mode subBlocks.

Written by Cursor Bugbot for commit db9a9fa. 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 6:32pm

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) across 14 integrations, introducing 19 new POST API routes and 20 new registry entries. The overall architecture is consistent and well-executed. Security concerns raised in earlier review rounds have been addressed: credentials are now passed in POST request bodies via authorizeCredentialUse, ensureCredential guards are present in all new registry entries, the SharePoint sites route was migrated from a GET-with-credential-in-query-string to POST, and design-time placeholder values (<Block.output>, {{ENV_VAR}}) are now guarded against in both use-selector-query.ts and use-selector-setup.ts.

Key points:

  • Cascading selectors (Airtable base→table, BigQuery dataset→table, JSM serviceDesk→requestType) are correctly wired through the canonical-parameter index and the new CONTEXT_FIELD_SET entries.
  • Backward compatibility is preserved: all original sub-block IDs are retained as advanced-mode inputs with their canonicalParamId set, so existing saved values continue to work.
  • Minor concern: The Attio lists and objects routes return api_slug as the id. Users who previously stored a UUID in the listIdOrSlug / objectType field will see the raw UUID in the selector display (because fetchById matches against slugs), though tool execution itself is unaffected.
  • microsoft.planner task selector now depends on planSelector rather than the canonical planId field, which could cause the task dropdown to appear disabled when the plan ID is populated in advanced mode and the user switches back to basic mode. Adding planId to dependsOn alongside planSelector would make the context resolution mode-agnostic.
  • The GET /me/planner/plans endpoint only returns plans where the calling user has explicit membership, silently omitting group-owned plans visible in the Planner UI — worth a note in the UI placeholder or inline comment.

Confidence Score: 4/5

  • Safe to merge with minor follow-up items; no blocking security or correctness issues in the new code.
  • The PR is large but follows a consistent, well-reviewed pattern. Prior security concerns (OAuth tokens in query strings, missing ensureCredential guards, missing authorization checks) have been resolved. The remaining flagged items — Attio api_slug vs UUID display-name miss, the microsoft.planner task selector dependsOn edge case, and the Graph API /me/planner/plans scope limitation — are either non-blocking UX issues or documentation gaps rather than correctness bugs. All 76 block tests pass and TypeScript reports no errors.
  • Pay attention to apps/sim/blocks/blocks/microsoft_planner.ts (task selector dependsOn change) and apps/sim/app/api/tools/attio/lists/route.ts / apps/sim/app/api/tools/attio/objects/route.ts (api_slug as id).

Important Files Changed

Filename Overview
apps/sim/hooks/selectors/registry.ts Adds 20 new selector definitions following a consistent POST-body pattern with ensureCredential guards. Previous concerns about missing guards have been addressed. Minor note: fetchById for most selectors fetches the full list and filters client-side, which is fine for the selector use-case but means no backend optimization for single-item lookups.
apps/sim/app/api/tools/sharepoint/lists/route.ts Well-structured POST route using the new authorizeCredentialUse pattern. Validates siteId with the new validateSharePointSiteId helper before inserting into the Graph API URL. Hidden lists are filtered server-side. requestId is correctly hoisted before the try block.
apps/sim/app/api/tools/sharepoint/sites/route.ts Migrated from GET (with credential ID in query string) to POST (credential in body), fixing the OAuth token exposure concern raised in previous review rounds. Now uses authorizeCredentialUse for consistent authorization.
apps/sim/app/api/tools/attio/lists/route.ts Returns api_slug as the list id. This is correct for new workflows, but existing users who manually typed a UUID into the listIdOrSlug field will get a silent display-name resolution miss in fetchById (raw UUID shown instead of list name), though tool operations themselves will still work since the Attio API accepts both.
apps/sim/hooks/selectors/use-selector-query.ts Adds isReference/isEnvVarReference guard before calling fetchById, preventing spurious network requests when the stored value is a design-time placeholder like <Block.output> or {{ENV_VAR}}.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx Refactors context-value extraction into a resolveContextValue helper using the canonical-parameter index, and adds the new cascading context fields (baseId, datasetId, serviceDeskId, siteId, collectionId, spreadsheetId, fileId) for selector display-name resolution.
apps/sim/app/api/tools/microsoft_planner/plans/route.ts New POST route using authorizeCredentialUse and ensureCredential correctly. Uses GET /me/planner/plans which silently omits group-owned plans visible in the Planner UI — a Graph API limitation worth documenting.
apps/sim/blocks/blocks/microsoft_planner.ts Adds planSelector (basic) / planId (advanced) pair. The existing task sub-block's dependsOn was changed from ['credential', 'planId'] to ['credential', 'planSelector'], which may cause the task dropdown to appear disabled when the plan ID originates from the advanced-mode text input.

Sequence Diagram

sequenceDiagram
    participant UI as SubBlockRow (UI)
    participant Setup as useSelectorSetup
    participant Query as useSelectorQuery
    participant Registry as SelectorRegistry
    participant API as API Route
    participant Ext as External API

    UI->>Setup: dependsOn values
    Setup->>Setup: Skip isReference / isEnvVarReference values
    Setup->>Query: SelectorContext (credentialId, baseId, datasetId, etc.)

    alt fetchList (dropdown open)
        Query->>Registry: fetchList(context)
        Registry->>Registry: ensureCredential(context)
        Registry->>API: POST /api/tools/{service}/{resource}
        API->>API: authorizeCredentialUse()
        API->>API: refreshAccessTokenIfNeeded()
        API->>Ext: GET upstream API
        Ext-->>API: data
        API-->>Registry: { items: [...] }
        Registry-->>Query: SelectorOption[]
        Query-->>UI: dropdown list
    end

    alt fetchById (display name for saved value)
        Query->>Query: guard: skip if isReference or isEnvVarReference
        Query->>Registry: fetchById(context, detailId)
        Registry->>API: POST /api/tools/{service}/{resource}
        API-->>Registry: { items: [...] }
        Registry->>Registry: find item by id
        Registry-->>Query: SelectorOption | null
        Query-->>UI: displayName (or raw ID fallback)
    end

    note over UI,Ext: Cascading (Airtable base→table, BigQuery dataset→table,<br/>JSM serviceDesk→requestType): parent selector value<br/>flows into child context via canonicalIndex
Loading

Comments Outside Diff (1)

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

    Task selector dependsOn references planSelector, breaking context resolution for advanced-mode plan IDs

    The task sub-block (microsoft.planner selector key, readTaskId) now declares dependsOn: ['credential', 'planSelector']. In basic mode this is correct — the plan dropdown populates planId, which the task dropdown then reads from context.

    However, the task selector is itself mode: 'basic', so it is only visible in basic mode. In advanced mode a user enters planId directly and is expected to enter readTaskId via another mechanism. The change to dependsOn is therefore safe UI-wise, but the context-building in use-selector-setup.ts iterates dependsOn to populate context.planId. If the user switches from basic to advanced and back, or if the component re-renders with an empty planSelector while planId was set in advanced mode, context.planId could be undefined, and the task dropdown would show as disabled even though a plan ID is available.

    Consider also listing planId in dependsOn (the canonical text-input sub-block) so the context is populated regardless of mode:

    dependsOn: ['credential', 'planSelector', 'planId'],

    This mirrors the broader pattern where cascading selectors depend on the canonical context field rather than only the basic-mode selector sub-block ID.

Last reviewed commit: db9a9fa

…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).
@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

…nonical-aware resolution

Use resolveDependencyValue to resolve context values for
useSelectorDisplayName, eliminating manual || getStringValue('*Selector')
fallbacks that required updating for each new selector pair.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rscores

SharePoint composite site IDs use hostname,guid,guid format where only
alphanumerics, periods, hyphens, and commas are valid characters.

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

…ello closed board filter

Pipedrive pipelines and Cal.com event-types/schedules routes now
consistently return string IDs via String() conversion.

Trello boards route no longer filters out closed boards, preserving
them for fetchById lookups. The closed filter is applied only in the
registry's fetchList so archived boards don't appear in dropdowns
but can still be resolved by ID for display names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1 waleedlatif1 force-pushed the waleedlatif1/airtable-selectors branch from d03b467 to 6b301b7 Compare March 6, 2026 18:08
@waleedlatif1
Copy link
Collaborator Author

@greptile

Zoom API returns numeric meeting IDs. Convert with String() to match
the string ID convention used by all other selector routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Routes already convert numeric IDs to strings via String(), so update
the registry types (CalcomEventType, CalcomSchedule, PipedrivePipeline,
ZoomMeeting) from id: number to id: string and remove the now-redundant
String() coercions in fetchList/fetchById.

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

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

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 waleedlatif1 merged commit 244cf4f into staging Mar 6, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/airtable-selectors branch March 6, 2026 20:34
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