Skip to content

feat(GitLab): Browse GitLab issues and merge requests (frontend)#7273

Open
emyller wants to merge 11 commits intomainfrom
feat/gitlab-browse-frontend
Open

feat(GitLab): Browse GitLab issues and merge requests (frontend)#7273
emyller wants to merge 11 commits intomainfrom
feat/gitlab-browse-frontend

Conversation

@emyller
Copy link
Copy Markdown
Contributor

@emyller emyller commented Apr 17, 2026

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Contributes to #7160

Stack: #7270 (backend) → #7273 (this) → #7274 (linking)

With the backend proxy endpoints in place (#7270), the frontend can now let users browse their GitLab projects, issues, and merge requests directly from the feature flag Links tab.

How to review

  • Start from the Links tab wiring in modals/create-feature/index.tsx.
  • GitLabLinkSection and GitHubLinkSection are siblings.

Review effort: 2/5

How did you test this code?

Manual UI testing. Screenshots:

image image image image image

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flagsmith-frontend-preview Ready Ready Preview, Comment Apr 17, 2026 11:39pm
flagsmith-frontend-staging Ready Ready Preview, Comment Apr 17, 2026 11:39pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Apr 17, 2026 11:39pm

Request Review

@github-actions github-actions bot added the front-end Issue related to the React Front End Dashboard label Apr 17, 2026
@github-actions github-actions bot added the feature New feature or request label Apr 17, 2026
@emyller emyller changed the title feat(GitLab): Browse GitLab issues and MRs (frontend) feat(GitLab): Browse GitLab issues and MRs from the feature modal Apr 17, 2026
@emyller emyller changed the title feat(GitLab): Browse GitLab issues and MRs from the feature modal feat(GitLab): Browse GitLab issues and merge requests (frontend) Apr 17, 2026
@emyller emyller marked this pull request as ready for review April 17, 2026 00:48
@emyller emyller requested a review from a team as a code owner April 17, 2026 00:48
@emyller emyller requested review from talissoncosta and removed request for a team April 17, 2026 00:48
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

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.

@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-api-test:pr-7273 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-e2e:pr-7273 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-7273 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-7273 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-7273 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-frontend:pr-7273 Finished ✅ Results

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  24.5 seconds
commit  8075549
info  🔄 Run: #16157 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  10.5 seconds
commit  8075549
info  🔄 Run: #16157 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  17 passed

Details

stats  17 tests across 14 suites
duration  52 seconds
commit  8075549
info  🔄 Run: #16157 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  1 minute, 4 seconds
commit  8075549
info  🔄 Run: #16157 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  43.8 seconds
commit  c4a4307
info  🔄 Run: #16178 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  29.5 seconds
commit  c4a4307
info  🔄 Run: #16178 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  17 passed

Details

stats  17 tests across 14 suites
duration  58.2 seconds
commit  c4a4307
info  🔄 Run: #16178 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  47.4 seconds
commit  c4a4307
info  🔄 Run: #16178 (attempt 1)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

Visual Regression

16 screenshots compared. See report for details.
View full report

Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one. Couple of comments, the encodeURIComponent is the one worth fixing while we are at it. Ideally the error message in the Select.

I allowed myself a couple of less important and style comments that could be tackled at the same time.

And whether you want to use a flag

Comment thread frontend/common/services/useGitlab.ts Outdated
query: (query: Req['getGitLabIssues']) => ({
url:
`projects/${query.project_id}/gitlab/issues/` +
`?gitlab_project_id=${query.gitlab_project_id}&page_size=${query.page_size ?? 100}&page=${query.page ?? 1}&search_text=${query.q || ''}&state=opened`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would use encodeURIComponent here to avoid corrupting the url with spaces for example

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also state is part of the type and hardcoded here. If we don't plan to use it and leave it hardcoded here, we should remove it from the type (as unused).

I would prefer instead to show the intention and have state={query.state || "opened"} here to avoid surprises later.

Same below

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would use encodeURIComponent here to avoid corrupting the url with spaces for example

1b4b870

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also state is part of the type and hardcoded here. If we don't plan to use it and leave it hardcoded here, we should remove it from the type (as unused).

Good call. I made it clearer in the code (see aee2bda) that we only intend to query open items.

Comment thread frontend/common/services/useGitlab.ts Outdated
query: (query: Req['getGitLabMergeRequests']) => ({
url:
`projects/${query.project_id}/gitlab/merge-requests/` +
`?gitlab_project_id=${query.gitlab_project_id}&page_size=${query.page_size ?? 100}&page=${query.page ?? 1}&search_text=${query.q || ''}&state=opened`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with encodeUriComponent

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

githubTypes[0]?.resourceType,
)

const addGithubResource = (githubResource: GithubResource) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: I know this was legacy but it would be nice to catch and toast the error here. And would be great to turn it async/await at the same time

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I realise now these changes actually belong in #7274. I've removed the code from this branch, and will address it in the next one in series.

Comment on lines +33 to +42
value={
data?.results
? data.results
.map((p) => ({
label: p.path_with_namespace,
value: p.id,
}))
.find((o) => o.value === value)
: null
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
value={
data?.results
? data.results
.map((p) => ({
label: p.path_with_namespace,
value: p.id,
}))
.find((o) => o.value === value)
: null
}
value={data?.results
?.map((p) => ({ label: p.path_with_namespace, value: p.id }))
.find((o) => o.value === value) ?? null}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +60 to +68
options={data?.results
?.filter(
(r: GitLabIssue | GitLabMergeRequest) =>
!linkedUrls.includes(r.web_url),
)
.map((r: GitLabIssue | GitLabMergeRequest) => ({
label: `${r.title} #${r.iid}`,
value: r,
}))}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: we could avoid this heavy syntax in the JSX and extract it in a variable (I think it would make the type inference straightforward too)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c4a4307 — nicer indeed, thanks!

Comment on lines +27 to +32
isLoading
? 'Loading...'
: isError
? 'Failed to load projects'
: 'Select GitLab Project'
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like the right place to show the error. On top of the disabled state of the select, it will be easy to miss out.

Maybe use <ErrorMessage /> below the select?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you prefer the <ErrorMessage /> for this particular use case, or a toast? I wonder where to draw the line.

Copy link
Copy Markdown
Contributor Author

@emyller emyller Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I know where the line is drawn: toast happens if you click a button.

See ed874d6 — I wish ErrorMessage would support adding a "Retry" action, and a link to Integrations as convenience.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also added to the PR description:

image

Comment thread frontend/common/hooks/useHasGitLabIntegration.ts
Copy link
Copy Markdown
Contributor

@talissoncosta talissoncosta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really solid review from @Zaimwa9

Agree with all of it. Just adding a few small points on top, just to prevent the any's to spread around.

Comment thread frontend/common/services/useGitlab.ts Outdated
>({
providesTags: [{ id: 'LIST', type: 'GitLab' }],
query: (query: Req['getGitLabIssues']) => ({
url:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These URLs aren't encoded, so a search like foo&state=closed sneaks in as extra query params. Any chance we can switch to URLSearchParams here? Same thing exists in useGithub.ts already, but nice not to spread it further.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1b4b870

URLSearchParams was also my instinct, but I learned we already ship with an utility. See above.

githubId={githubId}
resourceType={githubResourceType}
setResourceType={setGithubResourceType}
onChange={addGithubResource as any}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not trying to nitpick — just keen to avoid the two any casts slipping in here. The request types downstream (getGithubRepositories, getGithubResources) are already organisation_id: number / github_id: number, but the select components above them are typed as string, which is what forces the casts at the call site.

The onChange cast is a separate issue: the prop is declared (value: string) => void but the component actually passes a GithubResource (see GitHubResourcesSelect.tsx:104-107), which is why addGithubResource as any is needed.

If you're up for it, a few small edits clear both anys and make the chain consistent:

// useHasGithubIntegration.ts — drop the '' fallback
githubId: data?.results?.[0]?.id,   // number | undefined
// MyRepositoriesSelect.tsx props
githubId: number   // was string
orgId: number      // was string
// GitHubResourcesSelect.tsx props
onChange: (value: GithubResource) => void   // was (value: string) => void
githubId: number                             // was string
orgId: number                                // was string
// GitHubLinkSection.tsx props
githubId: number   // was string

Then the JSX in GitHubLinkSection is just:

onChange={addGithubResource}
orgId={organisationId}

GitHubLinkSection is the only consumer of GitHubResourcesSelect, and MyRepositoriesSelect is only used inside GitHubResourcesSelect itself — so no wider fallout. Happy for it to be a follow-up PR if you'd rather keep this one tight.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disclaimer: I am not the author of this code, and I intended minimal-to-no changes to existing code. That said, as per this other comment, I may address this if it's a quick win, but in the next pull request in the series (#7274).

import GitLabSearchSelect from 'components/GitLabSearchSelect'
import type { GitLabIssue, GitLabMergeRequest } from 'common/types/responses'

type GitLabLinkType = 'issue' | 'merge_request'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is defined inlined again as linkType: 'issue' | 'merge_request' in GitLabSearchSelect. Worth pulling it out once in common/types/responses.ts) and importing in both places — keeps them from drifting if we ever add e.g. 'epic'.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout! 6477ce8

Side note: it bugs me a bit that this module is named common/types/responses, and yet, this, and some other types already in it, are not related to API responses.

Base automatically changed from feat/gitlab-link-issues-mrs to main April 17, 2026 17:18
@emyller emyller requested a review from a team as a code owner April 17, 2026 17:18
@emyller emyller requested review from Zaimwa9 and removed request for a team April 17, 2026 17:18
@github-actions github-actions bot removed the feature New feature or request label Apr 17, 2026
@github-actions github-actions bot added the feature New feature or request label Apr 17, 2026
@emyller emyller marked this pull request as ready for review April 17, 2026 23:42
@github-actions github-actions bot added feature New feature or request and removed feature New feature or request labels Apr 17, 2026
@emyller
Copy link
Copy Markdown
Contributor Author

emyller commented Apr 17, 2026

Thanks for such a great review @Zaimwa9 and @talissoncosta, and for the patience guiding me through 2026 frontend land! All comments addressed — please resolve each thread, or respond with advice. Thanks in advance.

@emyller emyller requested a review from talissoncosta April 17, 2026 23:45
Comment on lines +75 to +77
{isProjectsError && (
<ErrorMessage error='Failed to load GitLab projects' />
)}
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to resolve.
Your question when to use toast versus ErrorMessage made me think and what could make sense to me is to show a toast following a punctual action that failed (button click etc, PUT / POST) and using an ErrorMessage on a component that can't be used persistently because fetching the data failed without action from the user.

Wdyt @talissoncosta ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants