Skip to content

feat(ui): add rule-based segment editing to the console - #2753

Merged
cre8ivejp merged 3 commits into
mainfrom
segment-based-rule
Aug 7, 2026
Merged

feat(ui): add rule-based segment editing to the console#2753
cre8ivejp merged 3 commits into
mainfrom
segment-based-rule

Conversation

@cre8ivejp

@cre8ivejp cre8ivejp commented Aug 7, 2026

Copy link
Copy Markdown
Member

Fix #2722

feat(ui): add rule-based segment editing to the console

Overview

This PR adds console support for rule-based user segments. A segment can now have
attribute-based rules in addition to (or instead of) its uploaded user-ID list.
A user is a member of the segment if their ID is in the included-user list OR
they match any rule. Within a rule, all conditions are ANDed; across rules, ORed.

The backend already accepts and evaluates segment rules
(CreateSegmentRequest.rules, UpdateSegmentRequest.rules as RuleListValue);
this PR wires the console up to it. No proto or Go changes.

Segment editor is now a full page

Screenshot 2026-08-07 at 9 26 07 AM

The old slide modal was too narrow for a comfortable rule builder, so segment
create/update moved to a dedicated page (pages/create-update-segment/),
following the same pattern as flag creation: nested routes under
UserSegmentsRoot, a details header with back navigation, and a card-based
form layout (General info / User-ID list / Rules). The URLs are unchanged
(/segments/new, /segments/:id), so deep links keep working.

Editor details:

  • Rule builder reuses the exact design and interactions of the flag targeting
    tab: sortable rule cards (drag or arrow buttons), add/remove rules and
    conditions, attribute-key suggestions from SDK-reported keys.
  • No variation/serve/strategy UI — matching a rule simply means "in the segment".
  • Context kind offers only Compare (the server rejects segment and
    feature-flag operators inside segment rules; the date kind is not offered).
  • Centered OR chips between rule cards and between the user-ID list card and
    the rules card, reflecting the evaluation semantics.
  • Each card explains its semantics ("Users in this list are always included…",
    "A user is included in this segment if… Within a rule, all conditions must match.").
  • On update, an info banner shows the current user-ID count, notes that
    uploading a new list replaces it, and offers a Download User Segment
    action (same behavior as the list page's download).
  • Validation mirrors the server rules: each rule needs at least one condition,
    and each condition needs an attribute, an operator, and at least one value.

Shared rule builder

The clause-row editor was extracted from the targeting tab into
elements/rule-clauses-form/ (along with attribute-key-select), and the
targeting tab's segment-rule/rule.tsx is now a thin wrapper around it —
the targeting tab UI is unchanged.

API layer

  • Create: rules are sent on CreateSegment when present (IDs empty;
    the server generates them).
  • Update: the RuleListValue wrapper is sent only when the user actually
    modified rules
    (including reordering); when absent, rules stay unchanged.
    Existing rule/clause IDs are preserved when editing.

Warnings

Saving a segment whose rules changed while it is referenced by flags opens a
confirmation modal listing all affected flags, since changing membership
affects targeting in every connected flag.

Segment list

A Rules column shows each segment's rule count alongside the existing
user count and connected-flags info.

Flag targeting tab — segment clause

The segment clause value is now a multi-select (multiple segments in one
clause = OR). Each option shows a short summary (N users · M rules), and the
selected segments are listed under the field with links to their segment pages.

Misc

  • Fixed the unsaved-changes prompt incorrectly appearing during the redirect
    after a successful save.
  • The uploading indicator on the list page still appears immediately after
    saving a segment with a new user-ID file (passed via navigation state).
  • All new strings are localized (English and Japanese).

Testing

  • Unit tests for the rule mapping utilities: form/API conversion, ID
    preservation, and change detection (pages/user-segments/utils.test.ts).
  • yarn tsc, yarn lint, yarn prettier --check, yarn test, and
    yarn build all pass.
  • Verified manually against a dev environment: list-based, rule-based, and
    mixed segments; AND within a rule / OR across rules / list-OR-rule
    evaluation via the gateway.

Segments can now have attribute-based rules in addition to the uploaded
user-ID list. Adds a full-page segment create/update editor with a rule
builder shared with the flag targeting tab, sends rules on create and a
RuleListValue only when rules change on update, shows rule counts on the
segment list, warns about impact on connected flags, and makes the
targeting tab's segment clause a multi-select.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings August 7, 2026 00:27

Copilot AI 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.

Pull request overview

This PR updates the Bucketeer console UI to support rule-based user segments (in addition to included-user lists), reusing the existing targeting rule/clause model and wiring rule payloads into the segment create/update API calls. It also refactors the segment editor UX from a slide modal to a dedicated full-page editor and updates flag targeting’s SEGMENT clause UI to support multi-select (OR semantics).

Changes:

  • Add segment rule form/value mapping utilities (+ unit tests) and send rules on segment create/update (with “send only when changed” semantics on update).
  • Replace the segment create/update slide modal with a full-page create/update flow under nested UserSegmentsRoot routes.
  • Extract a shared RuleClausesForm component and update targeting SEGMENT value display + UI to support multiple selected segments.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ui/dashboard/src/pages/user-segments/utils.ts Adds segment rule form models plus API payload mapping and “changed” detection helpers.
ui/dashboard/src/pages/user-segments/utils.test.ts Adds unit tests for rule mapping, ID preservation, and change detection.
ui/dashboard/src/pages/user-segments/user-segment-modal/segment-warning.tsx Introduces a reusable warning component listing connected flags.
ui/dashboard/src/pages/user-segments/user-segment-modal/segment-create-update-form/index.tsx Removes the old slide-modal segment editor.
ui/dashboard/src/pages/user-segments/user-segment-modal/delete-segment-modal/index.tsx Updates import path for the new SegmentWarning component.
ui/dashboard/src/pages/user-segments/types.ts Extends the segment form type to include rules.
ui/dashboard/src/pages/user-segments/page-loader.tsx Switches add/edit flows from modal+URL actions to navigation-based routes; keeps upload indicator via navigation state.
ui/dashboard/src/pages/user-segments/form-schema.ts Adds Yup validation for segment rules and clauses.
ui/dashboard/src/pages/user-segments/collection-layout/data-collection.tsx Adds a Rules column (rule count) to the segment list table.
ui/dashboard/src/pages/feature-flag-details/targeting/utils.ts Updates segment value label formatting to support multiple segments (comma-joined).
ui/dashboard/src/pages/feature-flag-details/targeting/segment-rule/rule.tsx Refactors to use the extracted shared RuleClausesForm.
ui/dashboard/src/pages/create-update-segment/segment-form/segment-rules.tsx Adds sortable rule-card UI for segment rules in the new full-page editor.
ui/dashboard/src/pages/create-update-segment/segment-form/index.tsx Implements the new create/update segment form page (general info, user list, rules, impact confirmation).
ui/dashboard/src/pages/create-update-segment/segment-form/confirm-rules-impact-modal.tsx Adds confirmation modal when saving rule changes that impact connected flags.
ui/dashboard/src/pages/create-update-segment/page-loader.tsx Loads segment data for update flows and renders the page-level layout/header.
ui/dashboard/src/pages/create-update-segment/page-content.tsx Wraps the form in a page layout container.
ui/dashboard/src/pages/create-update-segment/index.tsx Adds the top-level Create/Update Segment page entry point.
ui/dashboard/src/elements/rule-clauses-form/index.tsx Extracts shared clause-row editor used by targeting and segment rules.
ui/dashboard/src/elements/rule-clauses-form/attribute-key-select.tsx Fixes UserMessage import to match its new location after extraction.
ui/dashboard/src/app/routers.tsx Adds UserSegmentsRoot with nested routes for list/new/:id.
ui/dashboard/src/app/index.tsx Switches the /segments/* route to use UserSegmentsRoot.
ui/dashboard/src/@types/user-segment.ts Adds types for segment rule payloads and RuleListValue wrapper.
ui/dashboard/src/@locales/en/form.json Adds localized strings for segment rule editor + impact copy + list/rules semantics.
ui/dashboard/src/@locales/ja/form.json Adds localized strings for segment rule editor + impact copy + list/rules semantics.
ui/dashboard/src/@locales/en/common.json Adds or localization key.
ui/dashboard/src/@locales/ja/common.json Adds or localization key.
ui/dashboard/src/@api/user-segment/user-segment-updater.ts Extends update payload typing to optionally include rules (RuleListValue).
ui/dashboard/src/@api/user-segment/user-segment-creator.ts Extends create payload typing to optionally include rules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/dashboard/src/pages/create-update-segment/segment-form/index.tsx
Comment thread ui/dashboard/src/pages/create-update-segment/segment-form/segment-rules.tsx Outdated
Allow DATE clauses in the segment rule condition dropdown (the schema,
mapping utilities, and server already support them), and await the bulk
upload so failures surface as an error toast instead of being swallowed
by the FileReader callback.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated no new comments.

Suppressed comments (3)

ui/dashboard/src/pages/create-update-segment/segment-form/segment-rules.tsx:190

  • The segment rule editor currently offers RuleClauseType.DATE in the context-kind dropdown ([RuleClauseType.COMPARE, RuleClauseType.DATE]). This contradicts the PR description/issue text stating that the date kind is not offered for segment rules. Please align behavior and documentation (either remove DATE support from the segment UI/schema/mappers/tests, or update the PR description if DATE is intended to be supported).
  const segmentSituationOptions = useMemo(
    () =>
      (situationOptions as SituationOption[]).filter(option =>
        [RuleClauseType.COMPARE, RuleClauseType.DATE].includes(option.value)
      ),

ui/dashboard/src/pages/feature-flag-details/targeting/utils.ts:644

  • getValueLabel for SEGMENT joins names in the order of segmentUsers rather than the order of the selected values. This can display segment names in an unexpected order relative to the user’s selection (and is less stable if the backing list order changes). Prefer mapping in values order and then filtering out unknown IDs.
    return segmentUsers
      .filter(item => values.includes(item.id))
      .map(item => item.name)
      .join(', ');

ui/dashboard/src/pages/create-update-segment/segment-form/index.tsx:122

  • The download flow creates an object URL via URL.createObjectURL(...) but never revokes it. For large segment lists this can leak memory until the tab is closed. Revoke the URL after triggering the download.
        window.document.body.appendChild(link);
        link.click();
        if (link.parentNode) {
          link.parentNode.removeChild(link);
        }

… leak

Render selected segment names in selection order in the targeting clause
label, and revoke the object URL after triggering the segment user list
download.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated no new comments.

Suppressed comments (2)

ui/dashboard/src/pages/feature-flag-details/targeting/utils.ts:645

  • getValueLabel now renders multiple selected segments by doing segmentUsers.find(...) for each selected id. That becomes O(values × segmentUsers) and is called while rendering targeting rules, so it can get noticeably slow if the segment list is large. Consider building an id→name map once and then looking up names in selection order.
    // Map in values order so names render in the user's selection order.
    return values
      .map(value => segmentUsers.find(item => item.id === value)?.name)
      .filter(name => !!name)
      .join(', ');

ui/dashboard/src/pages/create-update-segment/segment-form/segment-rules.tsx:190

  • The PR description says the segment rule builder does not offer the DATE context kind, but the segment editor code currently includes RuleClauseType.DATE in segmentSituationOptions. Please confirm the intended behavior and keep the PR description and UI consistent (either allow DATE in the UI everywhere, or remove DATE support consistently).
  // Segment rules reject the SEGMENT and FEATURE_FLAG operators server-side;
  // only attribute comparisons and date conditions are offered.
  const segmentSituationOptions = useMemo(
    () =>
      (situationOptions as SituationOption[]).filter(option =>
        [RuleClauseType.COMPARE, RuleClauseType.DATE].includes(option.value)
      ),

@cre8ivejp
cre8ivejp marked this pull request as ready for review August 7, 2026 00:58
@cre8ivejp
cre8ivejp merged commit 0d76807 into main Aug 7, 2026
4 checks passed
@cre8ivejp
cre8ivejp deleted the segment-based-rule branch August 7, 2026 04:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: support for rule-based user segments

2 participants