Skip to content

refactor: extract CEL rule builder into reusable component and add menu portal support#2237

Merged
akshaydeo merged 3 commits intov1.5.0from
03-23-refactor_moved_celrulebuilder_to_lib_for_reusability
Apr 16, 2026
Merged

refactor: extract CEL rule builder into reusable component and add menu portal support#2237
akshaydeo merged 3 commits intov1.5.0from
03-23-refactor_moved_celrulebuilder_to_lib_for_reusability

Conversation

@impoiler
Copy link
Copy Markdown
Contributor

@impoiler impoiler commented Mar 23, 2026

Summary

Refactored the CEL Rule Builder component to be reusable across different contexts by extracting it from routing-specific code into a shared UI component library.

Changes

  • Extracted CEL Rule Builder components from ui/app/workspace/routing-rules/components/celBuilder/ to ui/components/ui/custom/celBuilder/ to make them reusable
  • Created a generic CELRuleBuilder component that accepts field definitions, operators, and conversion functions as props
  • Refactored the routing-specific CEL builder to use the new reusable component as a thin wrapper
  • Enhanced AsyncMultiSelect and ModelMultiselect components with menuPortalTarget and menuPosition props for better portal control in different contexts
  • Added optional regex validation support through context props
  • Added VS Code workspace configuration for bifrost development

Type of change

  • Refactor

Affected areas

  • UI (Next.js)

How to test

Verify that the routing rules CEL builder continues to work as expected:

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

Test the routing rules page to ensure the CEL builder functionality remains intact and that multiselect components render properly in different contexts.

Screenshots/Recordings

N/A - This is a refactoring change that maintains existing functionality.

Breaking changes

  • Yes
  • No

Related issues

N/A

Security considerations

No security implications - this is a pure refactoring change that maintains existing functionality.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Copy link
Copy Markdown
Contributor Author

impoiler commented Mar 23, 2026

@impoiler impoiler changed the base branch from feat/prompt-deployment-strategies-frontend to graphite-base/2237 March 23, 2026 09:58
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 296caca to 753ac5a Compare March 23, 2026 09:58
@impoiler impoiler force-pushed the graphite-base/2237 branch from 545776d to 5ce48bf Compare March 23, 2026 09:58
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 23, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a reusable rule builder with real-time expression generation and copy-to-clipboard functionality.
  • Improvements

    • Enhanced dropdown and selection menu positioning for better rendering within modal dialogs and overlay panels.
  • Refactor

    • Simplified rule builder implementation for improved maintainability and code reuse.

Walkthrough

The changes introduce a reusable CEL (Common Expression Language) rule builder component in a custom component library, refactor the routing-specific rule builder to delegate to this new base component, and enhance menu portal positioning controls across multiselect components through new optional props.

Changes

Cohort / File(s) Summary
CEL Rule Builder Library
ui/components/ui/custom/celBuilder/celRuleBuilder.tsx, ui/components/ui/custom/celBuilder/index.ts
New reusable CEL rule builder component with internal state management for rule groups, CEL expression generation, and react-querybuilder integration. Exports component and supporting interfaces for external consumption.
Routing-Specific CEL Builder Refactor
ui/app/workspace/routing-rules/components/celBuilder/celRuleBuilder.tsx
Refactored from full implementation to thin wrapper that delegates behavior to BaseCELRuleBuilder, removing local query management, CEL conversion logic, and copy controls.
Menu Portal Controls
ui/components/ui/asyncMultiselect.tsx, ui/components/ui/modelMultiselect.tsx, ui/components/ui/custom/celBuilder/valueEditor.tsx
Added optional menuPortalTarget and menuPosition props to control react-select menu rendering/positioning. Updated valueEditor to source regex validation from context and forward menu positioning props to AsyncMultiSelect.
VS Code Workspace Configuration
ui/app/workspace/mcp-logs/views/bifrost.code-workspace
Added new workspace configuration file defining folder roots and settings object.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A builder reborn, from many to one,
CEL expressions flow like carrots in the sun—
Rules group and delegate with elegant grace,
Menu portals bloom in their proper place! 🌸

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: extracting CEL rule builder into a reusable component and adding menu portal support, matching the core refactoring work across the changeset.
Description check ✅ Passed The PR description covers all template sections with substantial content: summary, changes, type, affected areas, testing instructions, and relevant checklist items completed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability

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

@impoiler impoiler force-pushed the graphite-base/2237 branch from 5ce48bf to f1baec5 Compare March 23, 2026 10:01
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 753ac5a to a73de82 Compare March 23, 2026 10:01
@impoiler impoiler changed the base branch from graphite-base/2237 to 03-18-add_support_for_variables_in_the_prompt_messages_backend March 23, 2026 10:02
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from f1baec5 to ef6d5bd Compare March 23, 2026 13:43
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch 2 times, most recently from 880f3fc to 143accc Compare March 24, 2026 04:35
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch 2 times, most recently from 201520b to 9a8c883 Compare March 24, 2026 13:18
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch 2 times, most recently from 3f7d339 to aa43ff3 Compare March 25, 2026 06:32
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch 2 times, most recently from 6589138 to 609a5b0 Compare March 26, 2026 06:06
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch 2 times, most recently from 238798b to 0020a22 Compare March 26, 2026 07:40
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from 609a5b0 to 62dc2af Compare March 26, 2026 07:40
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 0020a22 to 35a939d Compare March 26, 2026 09:41
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch 2 times, most recently from 783b0f9 to e68874c Compare March 26, 2026 10:47
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 52bf616 to dadb0ae Compare April 6, 2026 05:35
@impoiler impoiler force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch 2 times, most recently from 02bc9a2 to de54265 Compare April 6, 2026 10:30
@impoiler impoiler force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from dadb0ae to 80c486c Compare April 6, 2026 10:30
@roroghost17 roroghost17 force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 80c486c to 4a1e15a Compare April 6, 2026 10:50
@roroghost17 roroghost17 force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from de54265 to 1c7f2fa Compare April 6, 2026 10:50
@roroghost17 roroghost17 force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from 1c7f2fa to 8e42a3e Compare April 7, 2026 11:43
@roroghost17 roroghost17 force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from 4a1e15a to 3716f01 Compare April 7, 2026 11:43
@roroghost17 roroghost17 force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from 8e42a3e to d4adcd6 Compare April 7, 2026 19:50
@roroghost17 roroghost17 force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch 2 times, most recently from b1dc69a to f9d280f Compare April 9, 2026 13:20
@roroghost17 roroghost17 force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from 3a61ef7 to b43ac59 Compare April 9, 2026 13:22
@roroghost17 roroghost17 force-pushed the 03-23-refactor_moved_celrulebuilder_to_lib_for_reusability branch from f9d280f to 3e8b805 Compare April 9, 2026 13:22
@impoiler impoiler self-assigned this Apr 10, 2026
@impoiler impoiler changed the title refactor moved CELRuleBuilder to lib for reusability refactor: extract CEL rule builder into reusable component and add menu portal support Apr 10, 2026
@roroghost17 roroghost17 force-pushed the 03-18-add_support_for_variables_in_the_prompt_messages_backend branch from b43ac59 to eb1189e Compare April 10, 2026 07:03
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 10, 2026

Confidence Score: 3/5

Not safe to merge — the missing CSS file will break the build.

A P0 build-breaking issue (missing CSS file in the new library location) blocks merge. A P1 incomplete portal support for the provider multi-select also needs to be addressed. The rest of the refactoring is structurally sound.

ui/components/ui/custom/celBuilder/queryBuilderWrapper.tsx (missing CSS file) and ui/components/ui/custom/celBuilder/valueEditor.tsx (provider AsyncMultiSelect missing portal props).

Important Files Changed

Filename Overview
ui/components/ui/custom/celBuilder/queryBuilderWrapper.tsx Imports ./queryBuilderWrapper.css which was not moved to this directory — build-breaking missing file.
ui/components/ui/custom/celBuilder/valueEditor.tsx Provider AsyncMultiSelect doesn't forward menuPosition/menuPortalTarget; also inherits the unresolved context bare-variable bug (addressed in #2592).
ui/components/ui/custom/celBuilder/celRuleBuilder.tsx Generic reusable builder; correctly wraps convertToCEL in a ref; composes context cleanly; structurally sound.
ui/app/workspace/routing-rules/components/celBuilder/celRuleBuilder.tsx Clean thin wrapper delegating to the new shared component; no issues.
ui/components/ui/asyncMultiselect.tsx Added menuPosition/menuPortalTarget props and conditional radixDialogOnBlurWorkaround skip; logic is correct.
ui/components/ui/modelMultiselect.tsx Added menuPosition/menuPortalTarget props and forwards them correctly to AsyncMultiSelect.
ui/app/workspace/mcp-logs/views/bifrost.code-workspace Developer-specific VS Code workspace file with hard-coded path to bifrost-enterprise; likely unintentional commit.
ui/components/ui/custom/celBuilder/index.ts Barrel export for the new shared library; correct and complete.

Comments Outside Diff (1)

  1. ui/components/ui/custom/celBuilder/queryBuilderWrapper.tsx, line 7 (link)

    P0 CSS file not migrated — build will fail

    queryBuilderWrapper.tsx was moved to the new shared library location, but queryBuilderWrapper.css was not — it still only lives at ui/app/workspace/routing-rules/components/celBuilder/queryBuilderWrapper.css. Next.js/webpack will error on this unresolvable import and the build will fail.

    The fix is to copy the CSS file to ui/components/ui/custom/celBuilder/queryBuilderWrapper.css (or update the import to the absolute/relative old path).

Reviews (10): Last reviewed commit: "refactor moved CELRuleBuilder to lib for..." | Re-trigger Greptile

Comment thread ui/components/ui/custom/celBuilder/celRuleBuilder.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
ui/app/workspace/mcp-logs/views/bifrost.code-workspace (1)

6-8: Avoid committing environment-specific sibling-repo paths in shared workspace config.

"../../../../../../bifrost-enterprise" is machine/repo-layout specific and will break for contributors who don’t have that exact sibling checkout. Prefer a workspace file template, or keep this in user-local VS Code config instead of tracked app files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/mcp-logs/views/bifrost.code-workspace` around lines 6 - 8,
Remove the hard-coded sibling repo path value
("../../../../../../bifrost-enterprise") from the workspace file and replace it
with a non-committed solution: either convert this workspace entry into a
template placeholder (e.g., a "path": "<LOCAL_BIFROST_ENTERPRISE_PATH>" comment)
or remove the "path" entry entirely and document the expected local path in the
repo README; alternatively move this setting into a user-only VS Code
workspace/user settings so it is not tracked. Update the bifrost.code-workspace
to not contain environment-specific paths and add a short README note explaining
how contributors should set their local path.
ui/components/ui/custom/celBuilder/valueEditor.tsx (1)

179-191: Consider passing menu portal props to provider AsyncMultiSelect for consistency.

The ModelMultiselect components at lines 113-122 and 126-137 receive menuPosition and menuPortalTarget props, but the AsyncMultiSelect for provider selection (lines 179-191) does not. If the CEL builder is rendered inside a popover or dialog, this dropdown may also have positioning issues.

♻️ Proposed fix
 			return (
 				<AsyncMultiSelect
 					value={selectedOptions}
 					onChange={handleMultiselectChange}
 					defaultOptions={allOptions}
 					isNonAsync={true}
 					isClearable={false}
 					placeholder="Select providers..."
 					className="w-[360px]"
 					triggerClassName="!shadow-none !border-border h-10"
 					menuClassName="!z-[100] w-full cursor-pointer"
+					menuPosition={menuPosition}
+					menuPortalTarget={menuPortalTarget}
 				/>
 			);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/components/ui/custom/celBuilder/valueEditor.tsx` around lines 179 - 191,
The AsyncMultiSelect used for provider selection (component AsyncMultiSelect in
valueEditor.tsx) lacks the menuPosition and menuPortalTarget props which
ModelMultiselect components receive, causing potential dropdown positioning
issues inside popovers/dialogs; update the AsyncMultiSelect JSX to accept and
pass through the same menuPosition and menuPortalTarget props (and any existing
portal target prop variable used elsewhere) so its menu is rendered consistently
with ModelMultiselect and positioned correctly when the CEL builder is inside
overlays.
ui/components/ui/custom/celBuilder/celRuleBuilder.tsx (1)

157-176: Add data-testid to the Copy button for testability.

Per coding guidelines, new interactive UI elements should have data-testid attributes. The Copy button lacks one.

♻️ Proposed fix
 						<Button
 							variant="outline"
 							size="sm"
 							onClick={() => copy(celExpression)}
 							disabled={!celExpression}
 							className="gap-2"
 							type="button"
+							data-testid="cel-builder-copy-btn"
 						>

As per coding guidelines: ui/**/*.{tsx,ts}: Add new interactive UI elements with data-testid attributes following the pattern: data-testid="<entity>-<element>-<qualifier>".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/components/ui/custom/celBuilder/celRuleBuilder.tsx` around lines 157 -
176, The Copy Button in celRuleBuilder.tsx (the Button rendering with
onClick={() => copy(celExpression)} and text toggled by the copied variable) is
missing a data-testid; add a data-testid attribute following the project pattern
(e.g. data-testid="celrule-copy-button" or similar entity-element-qualifier) to
that Button element so tests can target it reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ui/app/workspace/mcp-logs/views/bifrost.code-workspace`:
- Around line 6-8: Remove the hard-coded sibling repo path value
("../../../../../../bifrost-enterprise") from the workspace file and replace it
with a non-committed solution: either convert this workspace entry into a
template placeholder (e.g., a "path": "<LOCAL_BIFROST_ENTERPRISE_PATH>" comment)
or remove the "path" entry entirely and document the expected local path in the
repo README; alternatively move this setting into a user-only VS Code
workspace/user settings so it is not tracked. Update the bifrost.code-workspace
to not contain environment-specific paths and add a short README note explaining
how contributors should set their local path.

In `@ui/components/ui/custom/celBuilder/celRuleBuilder.tsx`:
- Around line 157-176: The Copy Button in celRuleBuilder.tsx (the Button
rendering with onClick={() => copy(celExpression)} and text toggled by the
copied variable) is missing a data-testid; add a data-testid attribute following
the project pattern (e.g. data-testid="celrule-copy-button" or similar
entity-element-qualifier) to that Button element so tests can target it
reliably.

In `@ui/components/ui/custom/celBuilder/valueEditor.tsx`:
- Around line 179-191: The AsyncMultiSelect used for provider selection
(component AsyncMultiSelect in valueEditor.tsx) lacks the menuPosition and
menuPortalTarget props which ModelMultiselect components receive, causing
potential dropdown positioning issues inside popovers/dialogs; update the
AsyncMultiSelect JSX to accept and pass through the same menuPosition and
menuPortalTarget props (and any existing portal target prop variable used
elsewhere) so its menu is rendered consistently with ModelMultiselect and
positioned correctly when the CEL builder is inside overlays.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 53f48c3b-bd7e-4f83-a9b8-71ca05da056b

📥 Commits

Reviewing files that changed from the base of the PR and between eb1189e and 790544e.

📒 Files selected for processing (12)
  • ui/app/workspace/mcp-logs/views/bifrost.code-workspace
  • ui/app/workspace/routing-rules/components/celBuilder/celRuleBuilder.tsx
  • ui/components/ui/asyncMultiselect.tsx
  • ui/components/ui/custom/celBuilder/actionButton.tsx
  • ui/components/ui/custom/celBuilder/celRuleBuilder.tsx
  • ui/components/ui/custom/celBuilder/combinatorSelector.tsx
  • ui/components/ui/custom/celBuilder/fieldSelector.tsx
  • ui/components/ui/custom/celBuilder/index.ts
  • ui/components/ui/custom/celBuilder/operatorSelector.tsx
  • ui/components/ui/custom/celBuilder/queryBuilderWrapper.tsx
  • ui/components/ui/custom/celBuilder/valueEditor.tsx
  • ui/components/ui/modelMultiselect.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 10, 2026
Comment thread ui/components/ui/custom/celBuilder/valueEditor.tsx
Copy link
Copy Markdown
Contributor

akshaydeo commented Apr 16, 2026

Merge activity

  • Apr 16, 4:34 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 16, 4:36 PM UTC: @akshaydeo merged this pull request with Graphite.

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.

3 participants