Skip to content

Commit a52d406

Browse files
committed
fix(search): streamline Atlassian source setup
1 parent 0009544 commit a52d406

54 files changed

Lines changed: 3650 additions & 206 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,9 @@ Open your organization's **Settings → Sources**, turn on **Confluence**, then
3838

3939
### Choose the account and spaces
4040

41-
Under **Indexing account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence Domain** as the credential, then choose **Spaces**. To enter comma-separated keys such as `ENG, PRODUCT`, use the switch beside the Spaces field.
41+
Under **Indexing account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence Domain** as the credential, then choose **Spaces**. **Select all** selects every space the account can currently browse; newly created spaces are not added automatically. Clear the picker search before selecting all.
4242

43-
<Image className="mx-auto h-auto w-full max-w-md"
44-
src="/static/search/confluence-setup.png"
45-
alt="Confluence source setup with a service account, site domain, and spaces"
46-
width={500}
47-
height={374}
48-
/>
43+
To enter comma-separated keys such as `ENG, PRODUCT`, use the switch beside **Spaces**. Switching between the picker and manual entry keeps your selection.
4944

5045
Open **More options** for content type, labels, and metadata tags. The default is **Pages only**; choose **All content** to include blog posts.
5146

@@ -65,9 +60,22 @@ For workspace Search, start from **Search → Add source**. Available methods de
6560

6661
## Connect member accounts
6762

68-
After an admin allows Confluence, open **Integrations → Connect**. If no source exists, enter **Confluence Domain** and **Space Keys**, then connect your account. To use another site or space scope, choose the row labeled **Connect a different site or content scope**.
63+
After an admin allows Confluence, open **Integrations → Connect**. For an existing source, authorize your account; you do not choose its spaces again.
64+
65+
If no source exists, or you choose **Connect a different site or content scope**:
66+
67+
1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email.
68+
2. Enter the hostname under **Atlassian site**, then choose **Spaces**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 spaces in this form.
69+
3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account.
70+
71+
<Image className="mx-auto h-auto w-full max-w-md"
72+
src="/static/search/confluence-personal-setup.png"
73+
alt="Confluence personal source setup with a saved account, Atlassian site, and selected spaces"
74+
width={500}
75+
height={462}
76+
/>
6977

70-
Admins manage these sources under **Settings → Sources → Confluence → Manage**. An **Account for browsing** populates the space picker; it does not enroll that account for Search. Manual space keys work without a browsing account.
78+
Admins manage these sources under **Settings → Sources → Confluence → Manage**. In **Add source**, an **Account for browsing** populates the space picker; a saved personal Search account can be reused here. Choosing a browsing account does not enroll it for Search. Manual space keys work without a browsing account.
7179

7280
## Using a service account
7381

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,11 @@ Open your organization's **Settings → Sources**, turn on **Jira**, then select
3737

3838
### Choose the projects
3939

40-
Enter **Jira Domain**. Under **Account for browsing**, select an account or choose **Connect Jira account**, then select **Projects**. To enter keys such as `ENG, SUPPORT` manually, use the switch beside Projects; this works without a browsing account.
40+
Under **Account for browsing**, select a saved account (including your personal Search account) or choose **Connect Jira account**. Enter **Jira Domain**, then choose **Projects**. **Select all** selects every project the account can currently browse; newly created projects are not added automatically. Clear the picker search before selecting all.
4141

42-
**Account for browsing** only loads the project picker, using OAuth or **Add service account**. It does not enroll anyone for Search. A service account needs Jira access and the [Jira read scopes](/integrations/atlassian-service-account#jira-and-jira-service-management); Confluence-only tokens do not work here.
42+
To enter keys such as `ENG, SUPPORT` manually, use the switch beside **Projects**; this works without a browsing account. Switching between the picker and manual entry keeps your selection.
4343

44-
<Image className="mx-auto h-auto w-full max-w-md"
45-
src="/static/search/jira-setup.png"
46-
alt="Jira source setup with an account for browsing, site domain, and projects"
47-
width={500}
48-
height={420}
49-
/>
44+
**Account for browsing** only loads the project picker, using OAuth or **Add service account**. It does not enroll anyone for Search. A service account needs Jira access and the [Jira read scopes](/integrations/atlassian-service-account#jira-and-jira-service-management); Confluence-only tokens do not work here.
5045

5146
</Step>
5247
<Step>
@@ -71,6 +66,21 @@ Each teammate follows this step. Existing authorized accounts may already be con
7166

7267
For workspace Search, start from **Search → Add source**; its source-creation button is **Create & Invite**. Search manages the sync schedule and hides item limits.
7368

69+
## Connect before a source exists
70+
71+
After an admin approves Jira, a teammate can start from **Integrations → Connect**. The same setup opens when you choose **Connect a different site or content scope**:
72+
73+
1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email.
74+
2. Enter the hostname under **Atlassian site**, then choose **Projects**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 projects in this form.
75+
3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account.
76+
77+
<Image className="mx-auto h-auto w-full max-w-md"
78+
src="/static/search/jira-personal-setup.png"
79+
alt="Jira personal source setup with a saved account, Atlassian site, and selected projects"
80+
width={500}
81+
height={462}
82+
/>
83+
7484
## Manage the source
7585

7686
Admins open **Settings → Sources → Jira → Manage**, then a source's **Documents**, **Settings**, or **Sync history**. Metadata tags include issue type, status, priority, labels, assignee, and last updated.
66.7 KB
Loading
-44.4 KB
Binary file not shown.
65.3 KB
Loading
-57.3 KB
Binary file not shown.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import {
2+
listPersonalSourceSetupAccountsContract,
3+
personalSourceSetupContract,
4+
} from '@/lib/api/contracts/knowledge/personal-source-setup'
5+
import {
6+
defineInternalJsonRoute,
7+
extendInternalErrorPolicy,
8+
internalErrorResponse,
9+
internalRateLimits,
10+
internalSessionAuth,
11+
} from '@/lib/api/server/routes'
12+
import { internalKnowledgeErrorPolicies } from '@/lib/knowledge/api/route-policies'
13+
import { knowledgeOperations } from '@/lib/knowledge/application/operations'
14+
import {
15+
listPersonalSourceSetupAccounts,
16+
personalSourceSetup,
17+
} from '@/lib/knowledge/application/personal-source-setup'
18+
import {
19+
SelectorConnectionUnavailableError,
20+
SelectorContextUnavailableError,
21+
SelectorOptionsUnavailableError,
22+
} from '@/lib/selectors/server/errors'
23+
import { IntegrationNotAllowedError } from '@/ee/access-control/utils/permission-check'
24+
25+
const errorPolicy = extendInternalErrorPolicy(
26+
internalKnowledgeErrorPolicies.connectAccount,
27+
(error) => {
28+
if (error instanceof SelectorConnectionUnavailableError)
29+
return internalErrorResponse(error.status, {
30+
error: 'Reconnect your account to choose projects or spaces',
31+
})
32+
if (error instanceof SelectorContextUnavailableError)
33+
return internalErrorResponse(400, {
34+
error: 'Enter your Atlassian site to choose projects or spaces',
35+
})
36+
if (error instanceof SelectorOptionsUnavailableError)
37+
return internalErrorResponse(error.status, {
38+
error:
39+
'Could not load projects or spaces. Check the site and account access, then try again.',
40+
})
41+
if (error instanceof IntegrationNotAllowedError)
42+
return internalErrorResponse(403, { error: error.message })
43+
return null
44+
}
45+
)
46+
47+
export const GET = defineInternalJsonRoute({
48+
contract: listPersonalSourceSetupAccountsContract,
49+
auth: internalSessionAuth,
50+
operation: knowledgeOperations.listPersonalSourceSetupAccounts,
51+
rateLimit: internalRateLimits.user({ bucketName: 'knowledge.search.personal-setup.accounts' }),
52+
errorPolicy,
53+
mapInput: ({ query }) => query,
54+
useCase: listPersonalSourceSetupAccounts,
55+
present: (data) => ({ success: true as const, data }),
56+
staticResponseHeaders: { 'Cache-Control': 'private, no-store' },
57+
})
58+
59+
export const POST = defineInternalJsonRoute({
60+
contract: personalSourceSetupContract,
61+
auth: internalSessionAuth,
62+
operation: knowledgeOperations.personalSourceSetup,
63+
rateLimit: internalRateLimits.user({ bucketName: 'knowledge.search.personal-setup' }),
64+
errorPolicy,
65+
parseOptions: { maxBodyBytes: 384 * 1024 },
66+
mapInput: ({ body }) => body,
67+
useCase: personalSourceSetup,
68+
present: (data) => ({ success: true as const, data }),
69+
staticResponseHeaders: { 'Cache-Control': 'private, no-store' },
70+
})

‎apps/sim/app/o/[organizationId]/integrations/connect-account-options.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ export function ConnectAccountOptions({
210210
</div>
211211
{enrollment.setupConnector && (
212212
<SourceSetupModal
213+
organizationId={organization.id}
213214
connector={enrollment.setupConnector}
214215
isPending={enrollment.isPending}
215216
onClose={enrollment.closeSetup}

‎apps/sim/app/o/[organizationId]/integrations/integrations.test.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,11 @@ describe('organization integrations role and source paths', () => {
192192
}
193193
)
194194

195-
it('keeps source setup fields after a failure without duplicating the toast inside the modal', async () => {
195+
it('keeps manual source setup fields after a failure without duplicating the toast inside the modal', async () => {
196196
const message = 'Connection unavailable'
197197
mocks.enrollmentError = message
198-
mocks.setupConnector = SEARCH_CONNECTORS.find((connector) => connector.type === 'jira') ?? null
198+
mocks.setupConnector =
199+
SEARCH_CONNECTORS.find((connector) => connector.type === 'github') ?? null
199200
await render()
200201
expect(document.querySelector('[role="dialog"]')).not.toBeNull()
201202
expect(document.body.textContent).not.toContain(message)

‎apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection.tsx‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ function SearchIntegrationConnectionControl({
5353
})
5454
const name = connector?.meta.name ?? target.provider
5555
const action = target.credentialId ? 'Reconnect' : 'Connect'
56-
const label = connection.connected
56+
const connected = connection.connected
57+
const label = connected
5758
? `Connected ${name}`
5859
: connection.isLoading
5960
? `Checking ${name} connections…`
@@ -76,18 +77,14 @@ function SearchIntegrationConnectionControl({
7677
!connector ||
7778
connection.isLoading ||
7879
connection.isStarting ||
79-
connection.connected ||
80+
connected ||
8081
(!connection.available && !connection.pending)
8182
}
8283
onClick={handleConnect}
8384
leading={
8485
connector && <BrandIcon icon={connector.serviceIcon} className='size-[16px] shrink-0' />
8586
}
86-
trailing={
87-
connection.connected ? (
88-
<Check className='size-[16px] text-[var(--text-icon)]' />
89-
) : undefined
90-
}
87+
trailing={connected ? <Check className='size-[16px] text-[var(--text-icon)]' /> : undefined}
9188
/>
9289
{connection.pending && <Chip onClick={connection.cancel}>Cancel</Chip>}
9390
{connection.error && (
@@ -100,6 +97,8 @@ function SearchIntegrationConnectionControl({
10097
)}
10198
{setupOpen && connector && (
10299
<SourceSetupModal
100+
organizationId={organizationId}
101+
onConnected={connection.completeSetup}
103102
connector={connector}
104103
onClose={() => setSetupOpen(false)}
105104
isPending={connection.isStarting}

0 commit comments

Comments
 (0)