improvement(kb-connectors): multi-select fields + Slack bot/app message extraction#4711
Conversation
…ge extraction Adds multi-value support to KB connector configuration fields and applies it across 8 connectors: Jira (projects), Confluence (spaces), Slack (channels), Microsoft Teams (channels), Google Calendar (calendars), Gmail (labels), Notion (databases), and Linear (teams + projects). Each connector emits byte-identical externalId for legacy single-value configs so existing rows reconcile in place via the sync engine's externalId-keyed matching. Framework changes: - ConnectorConfigField gains `multi?: boolean` - New `parseMultiValue` helper in @/connectors/utils - useConnectorConfigFields state model upgraded to string|string[] - ConnectorSelectorField renders Combobox in multi-select mode when `field.multi` - Add/edit connector modals handle array values end-to-end Per-connector specifics: - Jira: JQL `project in (...)` for 2+ keys, `project = X` for one - Confluence: routes through CQL `space in (...)` when multi; v2 fast path stays for single+no-label; also fixes selector returning space.id instead of space.key - Slack: loops per channel emitting one document each; extracts text from attachments and Block Kit blocks (incl. nested attachment.blocks where GitHub embeds PR bodies); contentHash bumped to slack-v2: to force one-time re-embed - Microsoft Teams: loops per channel within a single team - Google Calendar: compound cursor across calendars; single-calendar keeps legacy externalId/contentHash for zero-churn - Gmail: (label:A OR label:B) with quoted-form for labels with spaces - Notion: sequential walk via JSON compound cursor; single-DB keeps bare cursor - Linear: GraphQL IdComparator.in for multi, eq for single
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Updates multiple connectors to support multi-value filtering. Confluence/Jira/Linear/Gmail/Google Calendar/Notion/Slack/MS Teams now normalize config via Improves Slack ingestion fidelity and forces re-embed. Slack now extracts user-visible text from bot/app messages by parsing attachments and Block Kit blocks (including nested Fixes selector ID mapping for Confluence spaces. The Confluence spaces selector now uses Reviewed by Cursor Bugbot for commit 84c3159. Configure here. |
…i-array Existing connectors created before multi-select store sourceConfig values as scalars (e.g. projectKey: "ENG"). With the field now declared multi: true, resolveSourceConfig returns an array (["ENG"]), and the original valuesEqual fell through to a strict reference comparison — falsely flagging unsaved changes on open and triggering an unnecessary string→array shape rewrite on save. valuesEqual now normalizes both sides to string[] via CSV-split when either is an array, so persisted scalar and in-memory array of the same content compare equal. Single-value (non-multi) fields keep strict string equality.
|
@greptile |
|
@cursor review |
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge. The multi-select plumbing is backward-compatible, the Slack content-hash bump causes a known one-time re-embed, and the Confluence key fix is a clean bug correction. All connector changes are additive behind the No files require special attention, though a UI smoke test of the multi-select Combobox for each connector is recommended before merge as noted in the PR checklist. Important Files Changed
Reviews (5): Last reviewed commit: "fix(gmail-connector): always wrap OR-con..." | Re-trigger Greptile |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit e6d8ccd. Configure here.
… skip, valuesEqual order - google-calendar getDocument: derive isMultiCalendar from the externalId's `:` separator instead of the current config count. Prevents duplicates when a user downgrades from multi to single calendar — previously the returned doc lost its `calendarId:` prefix and was treated as a new row by the sync engine, orphaning the original. - slack listDocuments: throw on unresolvable channel instead of silently skipping. Matches MS Teams behaviour. Silent skip would let the sync engine orphan-delete the previously indexed channel content if a bot was removed or a channel was archived/renamed mid-life. - edit-connector-modal valuesEqual: order-insensitive comparison for multi- select arrays via Set membership. Multi-select UI doesn't guarantee insertion order matches the server-returned order, so `["A","B"]` vs `["B","A"]` would otherwise flag false unsaved changes.
Greptile SummaryThis PR adds multi-select support to 8 KB connectors (Jira, Confluence, Slack, MS Teams, GCal, Gmail, Notion, Linear) via a new
Confidence Score: 3/5The core multi-select infrastructure and most connectors are solid, but two defects in Microsoft Teams and Google Calendar warrant fixes before merge. The Microsoft Teams apps/sim/connectors/microsoft-teams/microsoft-teams.ts (throw vs. skip in the channel loop) and apps/sim/connectors/google-calendar/google-calendar.ts (isMultiCalendar derivation in getDocument) Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
UI["UI: multi-select Combobox\n(ConnectorSelectorField)"] -->|"string[]"| Hook
UI2["UI: CSV Input\n(short-input + multi:true)"] -->|"string (CSV)"| Hook
Hook["useConnectorConfigFields\nresolveSourceConfig()"] -->|"Record<string, unknown>\n(string | string[])"| Modal
Modal["Add/Edit Connector Modal\nsubmits sourceConfig"] --> Connector
subgraph Connector["Connector listDocuments / validateConfig"]
PMV["parseMultiValue(value)\n→ string[]"]
PMV --> Single{"length === 1?"}
Single -->|Yes| LegacyPath["Legacy single-value path\n(same externalId as before)"]
Single -->|No| MultiPath["Multi-value path\n(fan-out or IN clause)"]
end
subgraph GCal["GCal getDocument"]
ExId["externalId.indexOf(':')"]
ExId -->|"-1 (no colon)"| BareId["eventId = externalId\ncalendarId = config[0]"]
ExId -->|">=0 (namespaced)"| SplitId["calendarId:eventId split"]
end
Connector --> SyncEngine["Sync Engine\n(externalId + contentHash dedupe)"]
|
…or consistency
Behavior unchanged — isValuePopulated('') and isValuePopulated([]) both return
false — but reading the field-typed fallback inline matches the convention
used elsewhere in the hook (coerceForField, handleFieldChange, resolveSourceConfig).
|
@greptile |
|
@cursor review |
…d teams
When the team selector is in multi-select mode, the basic-mode projects
dropdown was passing only the first team ID into the linear.projects
selector context (via readFirst in resolveDepValue), so projects from other
selected teams were invisible.
resolveDepValue now joins multi-value parents into a CSV string so dependent
selectors receive every selected parent ID. The /api/tools/linear/projects
route splits the CSV teamId, fetches projects from each team in parallel,
and dedupes by project ID. Single-team configs pass through unchanged
(`split(",")` on a bare ID yields a one-element array).
The AND-of-filters semantics in buildIssuesQuery is intentional and matches
standard GraphQL filter behavior — a user filtering on teams [A,B] and
projects [X,Y] gets issues in (A or B) AND (X or Y). With this fix the
project dropdown now shows every project under any selected team so the
user can compose the right project set.
|
@greptile |
|
@cursor review |
…t unwrapped ones The previous check `!/^\(.*\)$/.test(trimmedCustom)` was supposed to avoid double-wrapping an already-parenthesized expression, but it false-positives on inputs like `(from:alice) OR (from:bob)` where the parens don't bracket the whole string. Those would skip wrapping and the top-level OR would bind across the preceding label / category / date filters instead of the custom clause. Always wrap when an OR is present — double-parens are a no-op in Gmail search syntax, so `((from:a OR from:b))` parses the same as `(from:a OR from:b)`. Simpler than walking parens depth and provably safe.
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 84c3159. Configure here.
Summary
multi?: booleanflag onConnectorConfigFieldexternalIdfor existing single-value configs, so the sync engine reconciles in placeattachment.blocks; contentHash bumped to force one-time re-embedspace.idinstead ofspace.keyType of Change
Testing
Tested manually via tsc + connector test suite (86/86 passing). Four rounds of static audit against live API docs for each connector. UI smoke test recommended before merge.
Checklist