Skip to content

feat(experiments): targeted audience selection in rollout configuration - #8475

Open
Zaimwa9 wants to merge 3 commits into
mainfrom
feat/experiment-targeted-audience-fe
Open

feat(experiments): targeted audience selection in rollout configuration#8475
Zaimwa9 wants to merge 3 commits into
mainfrom
feat/experiment-targeted-audience-fe

Conversation

@Zaimwa9

@Zaimwa9 Zaimwa9 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • 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

Dashboard UI for experiment targeted audiences. The API side landed in #8472, so this now targets main.

The rollout step of the create-experiment wizard now takes an optional audience, so an experiment reads as Segment > % rollout > % variant weights. The review step and the experiment detail page show it back; the detail page is display-only, since the audience is frozen once the experiment starts.

  • AudiencePicker — pick a segment; the picker hides once one is chosen. Cohorts are filtered to the experiment's environment, and segments the API would reject (feature-specific, other-environment cohorts, percentage splits, no rules) are filtered out of the dropdown.
  • AudienceSegmentList — variant-style card per segment: name, description, cohort source, membership count, remove.
  • SegmentSelect — options now carry the description, cohort source and the environment's membership count, so you can size an audience before picking it.

The API stores the audience as segment references and reads the rules off the rollout segment, so the segments shown here are provenance: a source segment can be deleted or edited without changing what a running experiment evaluates. A segment deleted after configuration renders muted with "(deleted)".

One segment for now, matching MAX_AUDIENCE_SEGMENTS on the API side. The multi-segment UI is built and ships dormant — the ANY/ALL toggle renders as soon as a second segment is possible — but the cap holds it to one until the Java SDK is fixed:

Warning

A multi-segment any audience evaluates as all under Java local evaluation. Raise the cap in both places only once the Java engine respects the rule type for sub-rules.

How did you test this code?

Unit tests for the audience payload, summary and segment-eligibility helpers: 147 tests across 9 suites.

Manually against a local API: built an experiment targeting a segment at 50% rollout with a 50/50 split, checked the audience renders through wizard → review → detail, that the picker hides once a segment is chosen, and that identities outside the segment aren't enrolled. Also checked the empty case (no segment = all identities) and a deleted segment rendering as "(deleted)".

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
flagsmith-frontend-preview Ready Ready Preview Sep 8, 2026 3:56pm UTC
flagsmith-frontend-staging Ready Ready Preview Sep 8, 2026 3:56pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
docs Ignored Ignored Preview Sep 8, 2026 3:56pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: cf261e07-5354-46eb-994d-846c6a20dc04

📥 Commits

Reviewing files that changed from the base of the PR and between 105eadc and 9fdbed9.

📒 Files selected for processing (6)
  • frontend/common/types/responses.ts
  • frontend/web/components/experiments/AudiencePicker/utils.ts
  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.tsx
  • frontend/web/components/experiments/errors.ts
  • frontend/web/components/experiments/results/ExperimentRolloutCard.tsx
  • frontend/web/components/experiments/rollout.ts
💤 Files with no reviewable changes (1)
  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change adds experiment audience types and rollout payload helpers. The experiment wizard can select segments and configure ANY or ALL matching. Review and result views display audience segments and membership counts. Rollout updates preserve stored audience data. Error handling extracts nested API messages. Segment queries and project identifiers are converted to numbers.

Priority: ⬇️ Low — Defer this experiment audience-targeting change because the supplied scope is a dashboard feature with optional segment selection and display updates, without evidence of elevated external urgency.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 9fdbe

This change adds experiment audience targeting through selection, creation, review, and display flows. The feature behavior is covered by supplied payload and eligibility tests, but two frontend convention issues remain open and should be addressed or explicitly accepted before merging.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Zaimwa9

Zaimwa9 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@Flagsmith Flagsmith deleted a comment from themis-blindfold Bot Sep 7, 2026
Comment thread frontend/web/components/experiments/AudiencePicker/utils.ts Outdated
@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: 🟠 Fix before merge

The targeted-audience flow is wired through creation, review and the experiment detail view, but the picker still exposes an audience the API rejects. CI completed successfully, including unit tests and changed-file linting.

Area Score
🎯 Correctness 3/5
🧪 Test coverage 3/5
📐 Code quality 4/5
🚀 Product impact 4/5

🟠 Majors

📝 Walkthrough
  • Audience picker - adds segment selection, eligibility filtering, audience-size hints and gated multi-segment controls.
  • Experiment wizard - carries the selected audience through rollout, review and creation payloads.
  • Rollout display - renders the immutable audience alongside an active experiment and preserves it on rollout edits.
  • Shared segment selector - carries segment descriptions, cohort metadata and environment membership counts into the picker.
🧪 How to verify
  1. Run cd frontend && npm run test:unit -- --runInBand web/components/experiments/AudiencePicker/__tests__/utils.test.ts web/components/experiments/__tests__/rollout.test.ts web/components/experiments/__tests__/errors.test.ts.
  2. Add or seed a project segment with no rules, then confirm it is absent from the targeted-audience selector.
  3. Create an experiment targeting a normal segment and confirm only matching identities enter the rollout.
  4. With the multi-segment flag disabled, confirm selecting one segment hides the selector but leaves the remove control available.

Automate: Add a picker-level test that asserts rule-less segments are filtered out before the create request is enabled.

Product take: A solid experiment-targeting improvement with clear audience visibility across the workflow.
The remaining invalid-segment path turns a selectable option into a failed experiment creation request.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

Audience targeting lands neatly; this guard keeps the wizard from offering a trapdoor. · reviewed at b2eb767

@Zaimwa9

Zaimwa9 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: ✅ Ship it

Targeted audience selection is wired through experiment creation, shown consistently in review and detail views, and preserves the frozen audience during subsequent rollout edits. Completed CI checks, including unit tests and changed-file linting, passed.

Area Score
🎯 Correctness 5/5
🧪 Test coverage 4/5
📐 Code quality 5/5
🚀 Product impact 4/5

⚖️ Acknowledged

  • Rule-less segments are excluded from the audience picker — thread resolved by @Zaimwa9
📝 Walkthrough
  • Audience selection - filters ineligible segments, carries the selected IDs and match mode into creation, and caps multi-segment selection behind its feature flag.
  • Rollout editing - shapes requests in one helper so an existing audience remains unchanged when only allocation settings are edited.
  • Experiment views - displays frozen audience provenance, deletion state, cohort badges, and membership counts across the wizard and detail page.
🧪 How to verify
  1. Create an experiment targeting an eligible segment and confirm only identities in that segment enter the configured rollout.
  2. Confirm feature-specific, percentage-split, rule-less, wrong-environment cohort, and deleting-cohort segments cannot be selected.
  3. Edit an experiment's rollout percentage and variant weights, then confirm its displayed audience and evaluated targeting remain unchanged.
  4. Delete a source segment after creating an experiment and confirm the detail view marks it deleted while the frozen audience still applies.
    Automate: run cd frontend && npm run test:unit -- --runInBand web/components/experiments/__tests__/rollout.test.ts web/components/experiments/__tests__/errors.test.ts web/components/experiments/AudiencePicker/__tests__/utils.test.ts.

Product take: Solid improvement: experiment authors can constrain exposure to a known audience without losing visibility into the audience they launched.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

The audience gets a proper guest list now · reviewed at 71abbc5

@Zaimwa9
Zaimwa9 marked this pull request as ready for review September 7, 2026 14:08
@Zaimwa9
Zaimwa9 requested a review from a team as a code owner September 7, 2026 14:08
@Zaimwa9
Zaimwa9 requested review from kyle-ssg and talissoncosta and removed request for a team and kyle-ssg September 7, 2026 14:08
@github-actions github-actions Bot removed the feature New feature or request label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

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

@github-actions github-actions Bot added the feature New feature or request label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-16 — run #20301 (attempt 1)

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

passed  2 passed

Details

stats  2 tests across 2 suites
duration  28.6 seconds
commit  44ceb99
info  🔄 Run: #20301 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20301 (attempt 1)

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

passed  3 passed

Details

stats  3 tests across 3 suites
duration  1 minute, 3 seconds
commit  44ceb99
info  🔄 Run: #20301 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20301 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  34.9 seconds
commit  44ceb99
info  🔄 Run: #20301 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20301 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  44.2 seconds
commit  44ceb99
info  🔄 Run: #20301 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20292 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 4 suites
duration  56.5 seconds
commit  9fdbed9
info  🔄 Run: #20292 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #20292 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  56.5 seconds
commit  9fdbed9
info  🔄 Run: #20292 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20292 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  34.6 seconds
commit  9fdbed9
info  🔄 Run: #20292 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20292 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.3 seconds
commit  9fdbed9
info  🔄 Run: #20292 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #20289 (attempt 1)

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

passed  2 passed

Details

stats  2 tests across 2 suites
duration  49.8 seconds
commit  105eadc
info  🔄 Run: #20289 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20289 (attempt 1)

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

passed  3 passed

Details

stats  3 tests across 3 suites
duration  39.1 seconds
commit  105eadc
info  🔄 Run: #20289 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20289 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.7 seconds
commit  105eadc
info  🔄 Run: #20289 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20289 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.5 seconds
commit  105eadc
info  🔄 Run: #20289 (attempt 1)

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 8d3e076b-4282-4c02-8b1a-1d8b2e290e63

📥 Commits

Reviewing files that changed from the base of the PR and between 83da18a and 71abbc5.

📒 Files selected for processing (21)
  • frontend/common/types/requests.ts
  • frontend/common/types/responses.ts
  • frontend/web/components/SegmentSelect.tsx
  • frontend/web/components/experiments/AudiencePicker/AudiencePicker.tsx
  • frontend/web/components/experiments/AudiencePicker/__tests__/utils.test.ts
  • frontend/web/components/experiments/AudiencePicker/index.ts
  • frontend/web/components/experiments/AudiencePicker/utils.ts
  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.scss
  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.tsx
  • frontend/web/components/experiments/AudienceSegmentList/index.ts
  • frontend/web/components/experiments/CreateExperimentWizard.tsx
  • frontend/web/components/experiments/RolloutSummary/RolloutSummary.tsx
  • frontend/web/components/experiments/WizardStepper/WizardStepper.tsx
  • frontend/web/components/experiments/__tests__/errors.test.ts
  • frontend/web/components/experiments/__tests__/rollout.test.ts
  • frontend/web/components/experiments/errors.ts
  • frontend/web/components/experiments/results/ExperimentRolloutCard.tsx
  • frontend/web/components/experiments/rollout.ts
  • frontend/web/components/experiments/steps/ReviewStep.tsx
  • frontend/web/components/experiments/steps/RolloutStep.tsx
  • frontend/web/components/pages/SegmentPage.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.

Comment thread frontend/web/components/experiments/CreateExperimentWizard.tsx
Comment thread frontend/web/components/experiments/errors.ts Outdated
Comment thread frontend/web/components/experiments/rollout.ts
@Zaimwa9
Zaimwa9 requested a review from a team as a code owner September 7, 2026 15:40
@Zaimwa9
Zaimwa9 requested review from matthewelwell and removed request for a team September 7, 2026 15:40
@Zaimwa9
Zaimwa9 force-pushed the feat/experiment-targeted-audience-fe branch from 891efa1 to 1bd4ebd Compare September 7, 2026 15:41
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Sep 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 9bdbb74b-1d5e-4b62-931d-3dc57c841ba5

📥 Commits

Reviewing files that changed from the base of the PR and between 891efa1 and 1bd4ebd.

📒 Files selected for processing (4)
  • frontend/web/components/experiments/AudiencePicker/AudiencePicker.tsx
  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.tsx
  • frontend/web/components/experiments/errors.ts
  • frontend/web/components/experiments/rollout.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.

Base automatically changed from feat/experiment-targeted-audience-api to main September 8, 2026 13:27
@Zaimwa9

Zaimwa9 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

className='audience-segment-list__icon'
width={18}
height={18}
fill='#656D7B'

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 · ⚡ Quick win

Use the theme token for both audience icons.

Observed: both new #656D7B fills bypass colorIconSecondary; Predicted: they would remain too dark on the dark surface instead of adapting with the theme—use colorIconSecondary for both fills.

@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: 🧹 Ship it, nits inside

Targeted audiences are wired through experiment creation, wizard summaries, and the rollout detail card, while preserving the API's one-segment cap and frozen-audience behaviour. Completed CI checks, including unit, lint, build, and E2E checks, passed.

Area Score
🎯 Correctness 5/5
🧪 Test coverage 4/5
📐 Code quality 4/5
🚀 Product impact 4/5

🧹 Nits

  • frontend/web/components/experiments/AudienceSegmentList/AudienceSegmentList.tsx — use the semantic icon colour token so the new icons adapt to dark mode.

⚖️ Acknowledged

  • Rule-less segments are excluded from audience selection — thread resolved by @Zaimwa9
  • The audience remove control has an accessible name — thread resolved by @coderabbitai[bot]
  • Wizard imports use the configured aliases — thread resolved by @Zaimwa9
  • Error-data assertion uses a named type — thread resolved by @coderabbitai[bot]
  • Rollout helper union types are named — thread resolved by @Zaimwa9
  • Audience picker imports use the configured alias — thread resolved by @Zaimwa9
  • Audience picker has a co-located stylesheet — thread resolved by @Zaimwa9
📝 Walkthrough
  • AudiencePicker - filters the project segment list to backend-eligible audience candidates and carries selected segment metadata through the wizard.
  • rollout helpers and request types - shape the optional audience payload and describe the narrowed rollout consistently.
  • Experiment rollout card - displays frozen audience provenance while leaving later rollout edits unable to replace it.
🧪 How to verify
  1. Create an experiment with an eligible segment and confirm the create request includes its ID under experiment_rollout.audience.
  2. Try feature-specific, cross-environment cohort, rule-less, and percentage-split segments; confirm none can be selected.
  3. Start the experiment, edit its rollout percentage, and confirm the saved audience remains unchanged and is still displayed.
  4. View the new audience cards in dark mode and confirm both icons use the muted semantic colour.

Automate: render AudienceSegmentList in light and dark themes and assert both icon fills use colorIconSecondary.

Product take: A solid experiment-control improvement: teams can keep tests focused on the people for whom a hypothesis is relevant.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

A narrowly targeted feature with one un-targeted hue · reviewed at 9fdbed9

@talissoncosta talissoncosta left a comment

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.

Looks good! only 2 minor questions. Approving it in case you wanna tackle it as a follow up. Good job @Zaimwa9 !

Comment on lines +45 to +51
const environmentDbId = useMemo(
() =>
(ProjectStore.getEnvironmentIdFromKey(environmentId) as
| number
| undefined) ?? undefined,
[environmentId],
)

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.

Do you think this could use the RTK hook instead of ProjectStore?

    const { getEnvironmentIdFromKey } = useProjectEnvironments(projectId)
    const environmentDbId = getEnvironmentIdFromKey(environmentId)

className='flex-shrink-0'
width={18}
height={18}
fill='#656D7B'

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.

Do you think colorIconSecondary would work here instead of the hex? It's the same value in light and follows the theme in dark. Same on line 73.

import { colorIconSecondary } from 'common/theme/tokens'

fill={colorIconSecondary}

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.

2 participants