You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(connectors): align connector scopes with oauth config and fix kb modal UX (#3573)
* fix(connectors): align connector scopes with oauth config and fix kb modal UX
* fix(connectors): restore onCheckedChange for keyboard accessibility
* feat(connectors): add dynamic selectors to knowledge base connector config
Replace manual ID text inputs with dynamic selector dropdowns that fetch
options from the existing selector registry. Users can toggle between
selector and manual input via canonical pairs (basic/advanced mode).
Adds selector support to 12 connectors: Airtable (cascading base→table),
Slack, Gmail, Google Calendar, Linear (cascading team→project), Jira,
Confluence, MS Teams (cascading team→channel), Notion, Asana, Webflow,
and Outlook. Dependency clearing propagates across canonical siblings to
prevent stale cross-mode data on submit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* updated animated blocks UI
* fix(connectors): clear canonical siblings of dependents and resolve active mode values
Fixes three issues from PR review:
- Dependency clearing now includes canonical siblings of dependent fields
(e.g., changing base clears both tableSelector AND tableIdOrName)
- Selector context and depsResolved now resolve dependency values through
the active canonical mode, not just the raw depFieldId
- Tooltip text changed from "Switch to manual ID" to "Switch to manual input"
to correctly describe dropdown fallbacks (e.g., Outlook folder)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: linter class ordering fixes and docs link update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(connectors): reset apiKeyFocused on connector re-selection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The add-connector modal renders these automatically — no custom UI needed.
119
119
120
+
Three field types are supported: `short-input`, `dropdown`, and `selector`.
121
+
120
122
```typescript
121
123
// Text input
122
124
{
@@ -141,6 +143,136 @@ The add-connector modal renders these automatically — no custom UI needed.
141
143
}
142
144
```
143
145
146
+
## Dynamic Selectors (Canonical Pairs)
147
+
148
+
Use `type: 'selector'` to fetch options dynamically from the existing selector registry (`hooks/selectors/registry.ts`). Selectors are always paired with a manual fallback input using the **canonical pair** pattern — a `selector` field (basic mode) and a `short-input` field (advanced mode) linked by `canonicalParamId`.
149
+
150
+
The user sees a toggle button (ArrowLeftRight) to switch between the selector dropdown and manual text input. On submit, the modal resolves each canonical pair to the active mode's value, keyed by `canonicalParamId`.
151
+
152
+
### Rules
153
+
154
+
1.**Every selector field MUST have a canonical pair** — a corresponding `short-input` (or `dropdown`) field with the same `canonicalParamId` and `mode: 'advanced'`.
155
+
2.**`required` must be set identically on both fields** in a pair. If the selector is required, the manual input must also be required.
156
+
3.**`canonicalParamId` must match the key the connector expects in `sourceConfig`** (e.g. `baseId`, `channel`, `teamId`). The advanced field's `id` should typically match `canonicalParamId`.
157
+
4.**`dependsOn` references the selector field's `id`**, not the `canonicalParamId`. The modal propagates dependency clearing across canonical siblings automatically — changing either field in a parent pair clears dependent children.
158
+
159
+
### Selector canonical pair example (Airtable base → table cascade)
160
+
161
+
```typescript
162
+
configFields: [
163
+
// Base: selector (basic) + manual (advanced)
164
+
{
165
+
id: 'baseSelector',
166
+
title: 'Base',
167
+
type: 'selector',
168
+
selectorKey: 'airtable.bases', // Must exist in hooks/selectors/registry.ts
169
+
canonicalParamId: 'baseId',
170
+
mode: 'basic',
171
+
placeholder: 'Select a base',
172
+
required: true,
173
+
},
174
+
{
175
+
id: 'baseId',
176
+
title: 'Base ID',
177
+
type: 'short-input',
178
+
canonicalParamId: 'baseId',
179
+
mode: 'advanced',
180
+
placeholder: 'e.g. appXXXXXXXXXXXXXX',
181
+
required: true,
182
+
},
183
+
// Table: selector depends on base (basic) + manual (advanced)
184
+
{
185
+
id: 'tableSelector',
186
+
title: 'Table',
187
+
type: 'selector',
188
+
selectorKey: 'airtable.tables',
189
+
canonicalParamId: 'tableIdOrName',
190
+
mode: 'basic',
191
+
dependsOn: ['baseSelector'], // References the selector field ID
### Selector with domain dependency (Jira/Confluence pattern)
210
+
211
+
When a selector depends on a plain `short-input` field (no canonical pair), `dependsOn` references that field's `id` directly. The `domain` field's value maps to `SelectorContext.domain` automatically via `SELECTOR_CONTEXT_FIELDS`.
212
+
213
+
```typescript
214
+
configFields: [
215
+
{
216
+
id: 'domain',
217
+
title: 'Jira Domain',
218
+
type: 'short-input',
219
+
placeholder: 'yoursite.atlassian.net',
220
+
required: true,
221
+
},
222
+
{
223
+
id: 'projectSelector',
224
+
title: 'Project',
225
+
type: 'selector',
226
+
selectorKey: 'jira.projects',
227
+
canonicalParamId: 'projectKey',
228
+
mode: 'basic',
229
+
dependsOn: ['domain'],
230
+
placeholder: 'Select a project',
231
+
required: true,
232
+
},
233
+
{
234
+
id: 'projectKey',
235
+
title: 'Project Key',
236
+
type: 'short-input',
237
+
canonicalParamId: 'projectKey',
238
+
mode: 'advanced',
239
+
placeholder: 'e.g. ENG, PROJ',
240
+
required: true,
241
+
},
242
+
]
243
+
```
244
+
245
+
### How `dependsOn` maps to `SelectorContext`
246
+
247
+
The connector selector field builds a `SelectorContext` from dependency values. For the mapping to work, each dependency's `canonicalParamId` (or field `id` for non-canonical fields) must exist in `SELECTOR_CONTEXT_FIELDS` (`lib/workflows/subblocks/context.ts`):
0 commit comments