Skip to content

Commit 4c1c5ef

Browse files
committed
fix(coda): enable inline token setup and clarify search guide
1 parent ae684d1 commit 4c1c5ef

11 files changed

Lines changed: 98 additions & 18 deletions

File tree

‎apps/docs/content/docs/search/coda.mdx‎

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,27 @@ Sign in to Coda with a dedicated integration account that can read the documents
1919

2020
Use a standard REST API token. Do not select the MCP restriction.
2121

22-
<Image className="mx-auto h-auto w-full max-w-2xl" src="/static/search/coda-api-token.jpg" alt="Coda API connections with the Generate new token dialog" width={1280} height={720} />
22+
<Image className="mx-auto h-auto w-full max-w-xl" loading="eager" src="/static/search/coda-token-creation.jpg" alt="Coda Generate new token dialog with a name and no restriction selected" width={600} height={281} />
2323

2424
</Step>
2525
<Step>
2626

27-
### Add the source
27+
### Add the credential
2828

29-
In Sim, open **Settings → Sources → Add source → Coda**. Add or select a Coda service account credential and enter the token when prompted.
29+
In Sim, open **Settings → Sources → Add source → Coda**. If Coda is already listed, open it and select **Add connection**.
30+
31+
Open **Service account → Add API token**. Paste the token, give it a recognizable display name, then select **Add API token**. You can also choose an existing Coda credential.
32+
33+
<Image className="mx-auto h-auto w-full max-w-md" src="/static/search/coda-credential.jpg" alt="Add Coda API token form with token, display name, and optional description fields" width={516} height={435} />
34+
35+
</Step>
36+
<Step>
37+
38+
### Choose documents
39+
40+
Select the documents to index, or leave the selection empty for discovery.
41+
42+
<Image className="mx-auto h-auto w-full max-w-md" src="/static/search/coda-setup.jpg" alt="Coda connection setup with a saved credential, Documents selector, and optional Enterprise organization ID" width={516} height={458} />
3043

3144
| Field | What to enter |
3245
|---|---|
@@ -40,7 +53,7 @@ The picker shows accessible documents the token owner has opened. Use IDs for ot
4053

4154
### Sync and verify
4255

43-
Select **Connect & Sync**. Open the source's **Documents** and **Sync history** to check indexing. Content and permission changes appear after synchronization.
56+
Select **Connect & Sync**. Open the source's **Documents** and **Sync history** to check indexing. Content and permission changes appear after synchronization. Have a teammate with a matching verified email search for a shared document, and confirm that an unshared teammate cannot find it.
4457

4558
To rotate the token, add the replacement credential, update the source, and verify a sync before revoking the old token.
4659

@@ -59,8 +72,15 @@ Ordinary connections index visible canvas text and base-table rows. Enterprise c
5972

6073
Enterprise mode excludes deactivated and deleted users. Direct-share guests absent from the organization directory are excluded; guests explicitly listed in a group or workspace may receive that membership's access. Ordinary connections cannot check Coda organization deactivation, so manage departing users' Sim membership too.
6174

62-
Sim refreshes permissions even when content is unchanged. Unverified permissions never become broad access, and Sim admin status does not override Coda sharing. For setup failures or missing results, check the token's access, Enterprise admin role if applicable, the teammate's verified email, and **Sync history**.
75+
Sim refreshes permissions even when content is unchanged. Unverified permissions never become broad access, and Sim admin status does not override Coda sharing.
6376

64-
In a regular knowledge base, **Workspace access** intentionally shares all indexed content with that Sim workspace and does not use the Enterprise organization ID. The permissions above apply to organization Search and **Admin access** sources.
77+
## Troubleshooting
78+
79+
| Problem | Next step |
80+
|---|---|
81+
| Document missing from the picker | Open it in Coda with the token owner, or enter its document ID. |
82+
| Enterprise setup fails | Confirm the organization ID and Enterprise org-admin role. A workspace admin token is insufficient. |
83+
| Teammate sees no results | Check organization membership, their verified Sim email, the Coda share, and **Sync history**. |
84+
| Token expired or revoked | Replace the credential in the connection's **Settings**, then verify a sync. |
6585

6686
See Coda's [public API](https://coda.io/developers/apis/v1) and [Enterprise Admin API](https://coda.io/developers/apis/admin/v1).
-47.7 KB
Binary file not shown.
27.4 KB
Loading
27 KB
Loading
15.3 KB
Loading

‎apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx‎

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { createRoot, type Root } from 'react-dom/client'
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
77
import type { Credential } from '@/lib/oauth'
88
import type { SourceSelectionLabels } from '@/lib/sim-search/source-identity'
9-
import type { ServiceAccountConnectTarget } from '@/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal'
9+
import type {
10+
ServiceAccountConnectTarget,
11+
useServiceAccountConnectTarget,
12+
} from '@/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal'
1013
import type { ConnectorConfigFieldsProps } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-config-fields/connector-config-fields'
1114
import type { ConfigFieldMap } from '@/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields'
1215

@@ -26,6 +29,7 @@ const mocks = vi.hoisted(() => ({
2629
refetchCredentials: vi.fn(),
2730
oauthModal: vi.fn(),
2831
serviceAccountModal: vi.fn(),
32+
serviceAccountTargetInput: vi.fn(),
2933
githubSetup: vi.fn(),
3034
serviceAccountTarget: null as ServiceAccountConnectTarget | null,
3135
memberAccess: true,
@@ -77,6 +81,7 @@ vi.mock('@/hooks/use-permission-config', () => ({
7781
['gmail_v2', { oauthAvailable: true, state: 'ready' }],
7882
['google_calendar_v2', { oauthAvailable: true, state: 'ready' }],
7983
['confluence_v2', { oauthAvailable: true, state: 'ready' }],
84+
['coda', { oauthAvailable: false, state: 'ready' }],
8085
]),
8186
oauthServiceAvailability: new Map(
8287
[
@@ -173,7 +178,12 @@ vi.mock(
173178
</button>
174179
) : null
175180
},
176-
useServiceAccountConnectTarget: () => mocks.serviceAccountTarget,
181+
useServiceAccountConnectTarget: (
182+
args: Parameters<typeof useServiceAccountConnectTarget>[0]
183+
) => {
184+
mocks.serviceAccountTargetInput(args)
185+
return args.serviceAccountProviderId ? mocks.serviceAccountTarget : null
186+
},
177187
})
178188
)
179189
vi.mock('@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-config-fields', () => ({
@@ -223,6 +233,7 @@ vi.mock('@/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config
223233
}))
224234

225235
import { AddConnectorModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal'
236+
import { codaConnectorMeta } from '@/connectors/coda/meta'
226237
import { confluenceConnectorMeta } from '@/connectors/confluence/meta'
227238
import { googleDriveConnectorMeta } from '@/connectors/google-drive/meta'
228239
import { useConnectorSetupStore } from '@/stores/connector-setup/store'
@@ -916,6 +927,55 @@ describe('Account connection dropdown', () => {
916927
)
917928
}
918929
)
930+
it.each([true, false])(
931+
'creates a Coda token credential inline (Search: %s)',
932+
async (isSearchIndex) => {
933+
mocks.credentials = []
934+
mocks.serviceAccountTarget = {
935+
serviceAccountProviderId: 'coda-service-account',
936+
serviceName: 'Coda',
937+
serviceIcon: codaConnectorMeta.icon,
938+
label: 'Add API token',
939+
hidden: false,
940+
}
941+
await render({
942+
initialConnectorType: 'coda',
943+
lockedAccessMode: 'admin',
944+
isSearchIndex,
945+
scope: isSearchIndex
946+
? { kind: 'organization', organizationId: 'org-1' }
947+
: { kind: 'workspace', workspaceId: 'workspace-1' },
948+
})
949+
expect(mocks.serviceAccountTargetInput).toHaveBeenLastCalledWith(
950+
expect.objectContaining({ serviceAccountProviderId: 'coda-service-account' })
951+
)
952+
expect(button('Connect & Sync')).toBeDisabled()
953+
await act(async () => combobox('Select a service account').click())
954+
const options = Array.from(document.querySelectorAll<HTMLElement>('[role="option"]'))
955+
expect(options.map((option) => option.textContent?.trim())).toEqual(['Add API token'])
956+
await act(async () =>
957+
options[0].dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))
958+
)
959+
expect(mocks.serviceAccountModal).toHaveBeenLastCalledWith(
960+
expect.objectContaining({
961+
serviceAccountProviderId: 'coda-service-account',
962+
...(isSearchIndex ? { organizationId: 'org-1' } : { workspaceId: 'workspace-1' }),
963+
})
964+
)
965+
await act(async () => button('Finish service account setup').click())
966+
await act(async () => button('Connect & Sync').click())
967+
expect(mocks.create).toHaveBeenCalledWith(
968+
expect.objectContaining({
969+
connectorType: 'coda',
970+
credentialId: 'new-service-account',
971+
accessMode: 'admin',
972+
}),
973+
expect.any(Object)
974+
)
975+
expect(mocks.oauthModal).not.toHaveBeenCalled()
976+
}
977+
)
978+
919979
it.each(['google_drive', 'gmail', 'google_calendar'])(
920980
'opens only service-account creation for a central %s source and submits that credential',
921981
async (connectorType) => {

‎apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
import { ArrowLeft, ChevronDown, ChevronRight, Plus, Search } from '@sim/emcn/icons'
2020
import type { ConnectorData } from '@/lib/api/contracts/knowledge/connectors'
2121
import { type ResourceScope, resourceScopeFields } from '@/lib/core/resource-scope'
22+
import { asServiceAccountProviderId } from '@/lib/credentials/service-account-provider-ids'
2223
import { getIntegrationsForCredentialProvider } from '@/lib/integrations/credential-display'
2324
import { initialConnectorAccessMode } from '@/lib/knowledge/connectors/access-modes'
2425
import {
@@ -247,10 +248,8 @@ export function AddConnectorModal({
247248
!isConnectorCredentialTypeAllowed(connectorConfig.auth, access.accessMode, 'oauth')
248249
const serviceAccountTarget = useServiceAccountConnectTarget({
249250
serviceAccountProviderId:
250-
(isSearchIndex || requiresServiceAccount) &&
251-
(serviceAccountProviderId === 'google-service-account' ||
252-
serviceAccountProviderId === 'atlassian-service-account')
253-
? serviceAccountProviderId
251+
isSearchIndex || requiresServiceAccount
252+
? asServiceAccountProviderId(serviceAccountProviderId)
254253
: undefined,
255254
serviceName: connectorConfig?.name,
256255
serviceIcon: connectorConfig?.icon,

‎apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.test.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ vi.mock(
113113
)
114114

115115
import { ConnectorSettingsFields } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields'
116+
import { codaConnectorMeta } from '@/connectors/coda/meta'
116117
import { confluenceConnectorMeta } from '@/connectors/confluence/meta'
117118
import { githubConnectorMeta } from '@/connectors/github/meta'
118119
import { googleDriveConnectorMeta } from '@/connectors/google-drive/meta'
@@ -507,6 +508,7 @@ describe('connector settings service-account choices', () => {
507508
product: 'confluence',
508509
},
509510
{ meta: googleDriveConnectorMeta, provider: 'google-service-account', product: undefined },
511+
{ meta: codaConnectorMeta, provider: 'coda-service-account', product: undefined },
510512
])(
511513
'opens the correct $meta.name service-account setup from Search settings',
512514
async ({ meta, provider, product }) => {

‎apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { ChevronDown, ChevronRight, Plus } from '@sim/emcn/icons'
1313
import type { ConnectorAccessMode } from '@/lib/api/contracts/knowledge/connectors'
1414
import { type ResourceScope, resourceScopeFields } from '@/lib/core/resource-scope'
15+
import { asServiceAccountProviderId } from '@/lib/credentials/service-account-provider-ids'
1516
import {
1617
getProviderIdFromServiceId,
1718
getServiceAccountProviderForProviderId,
@@ -174,10 +175,8 @@ export function ConnectorSettingsFields({
174175
: undefined
175176
const serviceAccountTarget = useServiceAccountConnectTarget({
176177
serviceAccountProviderId:
177-
(isSearchIndex || requiresServiceAccount) &&
178-
(serviceAccountProviderId === 'google-service-account' ||
179-
serviceAccountProviderId === 'atlassian-service-account')
180-
? serviceAccountProviderId
178+
isSearchIndex || requiresServiceAccount
179+
? asServiceAccountProviderId(serviceAccountProviderId)
181180
: undefined,
182181
serviceName: connectorConfig?.name,
183182
serviceIcon: connectorConfig?.icon,

‎apps/sim/connectors/coda/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The application test uses disposable PostgreSQL/Redis, real credentials, Coda, s
7272
- Focused connector, selector, credential, navigation, configuration, and integration-availability tests passed. App and deployment-config type checks, Biome, and the strict API-contract audit passed.
7373
- Live provider tests cover page/table hydration, page edits, and row edits. Coda's real initialization `409` led to an explicit retry path.
7474
- Real application setup and ingestion passed in both workspace and organization scope (the live sharing cases require a workspace that allows the intended cross-domain share). Organization scope creates the token credential through the authorized application use case. Owner search/chunks were allowed; another verified user, unverified owner, and workspace API key were denied. Embeddings were substituted, so external embedding-provider behavior was not tested.
75-
- Sim's browser showed the Coda source Active, both indexed documents, the live document picker, the saved organization credential, and preserved selection across connection/input modes. Browser checks caught and fixed missing Search URL registration, scope loss when switching modes, and deployment metadata rejecting Coda's token credential. Coda's official browser app showed the fixture content.
75+
- Sim's browser showed the Coda source Active, both indexed documents, the live document picker, inline API-token creation, credential replacement followed by a successful sync, and preserved selection across connection/input modes. Browser checks caught and fixed missing Search URL registration, scope loss when switching modes, deployment metadata rejecting Coda's token credential, and a setup allowlist hiding inline Coda credential creation. Coda's official browser app showed the fixture content.
7676
- Live sharing to the requested second account was rejected by the source policy: “Cross domain sharing is prohibited.” Grant/revoke tests remain unverified live, with unit coverage for ACL changes and incomplete responses.
7777
- The available test account returned no Enterprise organizations; the official UI offers sales-assisted Enterprise setup rather than a self-service trial. Admin API behavior is checked against published schemas and mocked responses; organization-wide crawling, deactivation, and group/workspace/domain permission parity still require an Enterprise tenant test before being considered release-verified.
7878

0 commit comments

Comments
 (0)