refactor: scope-aware project and organisation integrations#7311
refactor: scope-aware project and organisation integrations#7311
Conversation
…ion pages
Clarify which integrations belong at which scope, tighten permission gating,
and let admins add project-level integrations from the org page.
- Project page: surface GitHub (org-only) with a permission-gated link to
org settings; dual-level integrations (Jira, Grafana) expose both an
"Add to project" primary CTA and a "Manage at organisation level" link.
- Org page: list all integrations, grouped into org-level (actionable) and
project-level (now actionable via a project selector in the standard
modal, gated by org admin via renderWithPermission).
- Integration modal: adds a project dropdown when required, seeds formData
with field defaults so validation borders reflect actual state, suppresses
autocomplete on all fields, and switches to edit mode when the selected
project (and env, for per-env integrations) already has a configuration.
- Integration tiles: action area is now a single primary button or an
ellipsis menu styled like the feature-row menu; each added config row
gets its own Edit/Delete menu.
- Add to project / Add to organisation labelling, with Edit {scope}
integration when an existing non-per-env config is present.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, reopen this pull request to trigger a review.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Docker builds report
|
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
|
Visual Regression16 screenshots compared. See report for details. |
…, reset form on project switch - Add useGetIntegrationQuery to replace ad-hoc _data fetches for existing integration config - Extract ProjectSelect component mirroring EnvironmentSelect - Reset form state when the selected project changes so stale values (notably flagsmithEnvironment, used to key per-environment queries) don't leak between projects - Initialise every field key in default form data so controlled inputs actually clear instead of going uncontrolled - Collapse the external-integration CTA ladder into a single getPrimaryCta helper - Simplify renderActions to honour action.requiresOrgAdmin/disabled directly Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ration summary Render each read-only entry as a col-md-3 cell with label above value inside a shared row, so multiple entries flow side-by-side instead of stacking. Edit mode rendering is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ct renderField - Add create/update RTK mutations for integration config; modal submit goes through them with tag-based invalidation - Alphabetise integrations by display title on both project and organisation pages - Extract renderField helpers to remove nested ternary in the fields loop - Tighten Res['integration'] to (ActiveIntegration & Record<string, any>)[] - Shorten a couple of stale comments Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
talissoncosta
left a comment
There was a problem hiding this comment.
Thanks for handling that @kyle-ssg.
I've added some comments, mostly clarifications..
| const ReadOnlyEnvironmentName: FC<{ environmentId?: string }> = ({ | ||
| environmentId, | ||
| }) => { | ||
| const { data: environment } = useGetEnvironmentQuery( | ||
| { id: environmentId as any }, | ||
| { skip: !environmentId }, | ||
| ) | ||
| return <>{environment?.name || ''}</> |
There was a problem hiding this comment.
Is environmentId here the api_key or the numeric id? Req['getEnvironment'] is { id: number }, so the as any looks like it's papering over a mismatch. If it's the api_key, could we rename to environmentApiKey: string to match the standardisation ?
| getIntegration: { | ||
| integrationId: string | ||
| projectId?: string | ||
| environmentId?: string |
There was a problem hiding this comment.
Could you confirm the value is the api_key? If so, can we name the field environmentApiKey: string to align?
| <IntegrationActionsMenu | ||
| actions={[ |
There was a problem hiding this comment.
Can you please check if this component can be replaced by DropdownMenu ?
| <IntegrationActionsMenu | |
| actions={[ | |
| <DropdownMenu | |
| items={[ |
| } | ||
| return button | ||
| } | ||
| return <IntegrationActionsMenu actions={actions} /> |
There was a problem hiding this comment.
Can you please check if this component can be replaced by DropdownMenu ?
| return <IntegrationActionsMenu actions={actions} /> | |
| return <DropdownMenu items={actions} /> |
| const onError = (err: any) => { | ||
| const defaultError = | ||
| 'There was an error adding your integration. Please check the details and try again.' | ||
| res.text().then((errorText) => { | ||
| try { | ||
| const err = JSON.parse(errorText) | ||
| setError(err[0] || defaultError) | ||
| } catch { | ||
| setError(defaultError) | ||
| } finally { | ||
| setIsLoading(false) | ||
| } | ||
| }) | ||
| try { | ||
| const payload = err?.data ?? err | ||
| setError( | ||
| (Array.isArray(payload) ? payload[0] : undefined) || defaultError, | ||
| ) | ||
| } catch { | ||
| setError(defaultError) | ||
| } finally { | ||
| setIsLoading(false) | ||
| } | ||
| } |
There was a problem hiding this comment.
The try/catch/finally here isn't doing anything — nothing inside the try can throw now that we're not parsing JSON. Could flatten to its body.
| integrationData[b]?.title || b, | ||
| ), | ||
| ) | ||
| const organisationId = AccountStore.getOrganisation()?.id |
There was a problem hiding this comment.
Can we get orgId from another source to avoid getting this data from flux ?
| {!!projectIntegrations.length && ( | ||
| <> | ||
| <h5 className='mt-5 mb-3'>Project-level integrations</h5> | ||
| <IntegrationList | ||
| organisationId={organisationId} | ||
| integrations={projectIntegrations} | ||
| isOrgAdmin={isOrgAdmin} | ||
| /> | ||
| </> | ||
| )} |
There was a problem hiding this comment.
I tried this end-to-end and the UX confused me. Steps:
- Opened the org integrations page.
- In the "Project-level integrations" section, clicked Add on a project-level integration, picked a project, filled in the fields, hit save.
- Nothing appeared on the org page after closing the modal — I thought the save had failed.
- Navigated to that project's integrations page, and the integration was there.
Is this the intended behaviour?
Thanks for submitting a PR! Please check the boxes below:
docs/if required so people know about the feature.Changes
connected (fixes the GitHub dead-end).
Project integrations page
Organistaion integrations page with the ability to create/edit at project level
abc.mov
How did you test this code?