-
Notifications
You must be signed in to change notification settings - Fork 465
refactor(features): migrate FeaturesPage to RTK Query and eliminate legacy stores #6361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
talissoncosta
wants to merge
162
commits into
main
Choose a base branch
from
refactor/migrate-critical-components-featurespagejs-2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
refactor(features): migrate FeaturesPage to RTK Query and eliminate legacy stores #6361
talissoncosta
wants to merge
162
commits into
main
from
refactor/migrate-critical-components-featurespagejs-2
+1,526
−527
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Create reusable hook that wraps useUpdateProjectMutation with automatic toast notifications, supporting customizable messages and error callbacks.
Replace duplicated try/catch/toast patterns across 5 components with useUpdateProjectWithToast hook, eliminating ~70 lines of duplicated code.
Replace complex Omit/Partial approach with explicit Pick for better clarity and type safety. This makes it immediately clear which Project fields are updateable via the API.
Add RTK Query optimistic updates to updateProject mutation using onQueryStarted lifecycle hook. This immediately updates the cache when mutations are called and automatically rolls back on errors, providing instant UI feedback without manual rollback logic. Benefits: - Instant UI updates before server responds - Automatic error rollback via patchResult.undo() - Reduces component complexity by eliminating manual error handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove useEffect and manual rollback logic from 3 components that now benefit from mutation-level optimistic updates: - ProjectInformation: Remove useEffect syncing and onError rollback - AdditionalSettings: Remove useEffect syncing - FeatureNameValidation: Remove useEffect syncing and manual optimistic update Components now use local state only for form editing, with RTK Query handling all cache updates and automatic rollbacks on errors. Benefits: - Simpler components (~22 lines removed across 3 files) - No cursor jumps during typing when other settings update - No manual error handling needed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Create ChangeRequestsApprovalsSetting component following the same pattern as other settings (PreventFlagDefaultsSetting, CaseSensitivitySetting, FeatureNameValidation). Changes: - New ChangeRequestsApprovalsSetting.tsx component - AdditionalSettings simplified from 76 to 25 lines - All settings now follow consistent pattern (receive project prop) Benefits: - Better consistency across all setting components - Improved encapsulation (component owns its state) - Easier to test in isolation - Cleaner AdditionalSettings parent component 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove 9 unnecessary useCallback wrappers from project settings components. These callbacks had dependencies that change frequently (project properties, local state), causing recreation on every render and providing no memoization benefit. Changes across 7 files: - CaseSensitivitySetting: Remove useCallback from handleToggle - PreventFlagDefaultsSetting: Remove useCallback from handleToggle - FeatureNameValidation: Remove useCallback from handleToggle + handleSave - ProjectInformation: Remove useCallback from handleSubmit - ChangeRequestsApprovalsSetting: Remove useCallback from both functions - SDKSettingsTab: Remove useCallback from 2 toggle handlers - DeleteProject: Remove useCallback from handleDelete Benefits: - Simpler, more honest code (~36 lines removed) - Same performance (callbacks already recreated every render) - Removed unused useCallback imports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Call AppActions.refreshOrganisation() after project updates to ensure the legacy OrganisationStore stays in sync with RTK Query cache. This fixes the navbar not updating when project name changes, which was causing the E2E test (project-test.ts) to fail.
Fixed critical bug where the case sensitivity toggle had inverted behavior.
The backend field 'only_allow_lower_case_feature_names' has a negative
semantic (true = force lowercase), but the UI shows "Case sensitive features"
with a positive semantic (ON = allow uppercase).
Therefore we must invert the checked state to match the UI's meaning:
- checked={!project.only_allow_lower_case_feature_names}
Now when users enable "Case sensitive features", it correctly sets
only_allow_lower_case_feature_names=false, allowing uppercase characters.
This matches the original implementation and fixes the critical issue
documented in PROJECT_ORG_FIXES.md #1.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…etting - Add ?? null to handle undefined initial values from backend - Fix stale closure bug in auto-save by passing value explicitly to saveChangeRequests - Fix manual save by using arrow function closure for onSave prop - Ensure both toggle (auto-save) and manual save work correctly This fixes issues where: - Initial value could be undefined instead of null - Auto-save on toggle used stale state value - Manual save button passed event object instead of current state 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Add optional data-test prop to component type definition - Pass data-test to underlying Setting component - Follow kebab-case naming convention (js-change-request-approvals) This enables E2E testing by providing stable selectors that won't break with styling changes, following the pattern used by other settings in the codebase. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add E2E tests covering four critical scenarios: 1. Auto-save on toggle ON - verifies toggle saves immediately 2. Manual save after value change - verifies save button works 3. Auto-save on toggle OFF - verifies disable persists 4. Manual save with new value - verifies full workflow Each test includes navigation away and back to ensure values persist to backend, catching stale closure bugs that would otherwise pass with in-memory state. Test uses kebab-case data-test selector following codebase conventions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…lability Changed from early return pattern to wrapped conditional block following the pattern from initialise-tests.ts. This allows future tests added after the Change Requests tests to run regardless of the segment_change_requests feature flag status. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Add UpdateOrganisationBody type with optional fields - Add getOrganisation, updateOrganisation, deleteOrganisation request types - Support for organisation name, force_2fa, and project creation restrictions Part of OrganisationSettingsPage TypeScript migration
- Add getOrganisation query with cache tags - Add updateOrganisation mutation with optimistic updates - Add deleteOrganisation mutation with cache invalidation - Implement automatic rollback on error for optimistic updates Part of OrganisationSettingsPage TypeScript migration
- Add useUpdateOrganisationWithToast hook for consistent update handling - Add useDeleteOrganisationWithToast hook with success callbacks - Include toast notifications and error handling - Support legacy store sync via AppActions.refreshOrganisation() Part of OrganisationSettingsPage TypeScript migration
Use TypeScript's typeof operator for automatic type inference instead of manually maintaining the Utils type definition. This eliminates maintenance overhead when Utils methods are added or modified. Changes: - Replace manual type definition with `const Utils: typeof Utils` - Removes need to manually update type signatures Addresses kyle-ssg's review feedback.
Separates feature mutations from feature state mutations for better code organization and separation of concerns. Changes: - Move `updateFeatureState` mutation from useProjectFlag to useFeatureState - Add FeatureList and Environment to useFeatureState tag types - Export useUpdateFeatureStateMutation hook from useFeatureState - Add updateFeatureState helper function for legacy store usage - Update useToggleFeatureWithToast import to use useFeatureState This aligns with the principle of keeping features (project-level) separate from feature states (environment-level), making the codebase more maintainable. Addresses kyle-ssg's review feedback.
Merges PermissionGate functionality into the existing Permission component to reduce duplication and provide a single, unified API for permission-based rendering. Changes: - Add optional props to Permission: fallback, permissionName, showTooltip - Support both ReactNode and render function children patterns - Add tooltip rendering when permission is denied - Add fallback content support for denied permissions - Import Utils and Constants for tooltip rendering - Remove PermissionGate component (now redundant) - Update FeaturesPage and FeaturesPageHeader to use enhanced Permission The Permission component now handles all use cases previously split between Permission (render functions) and PermissionGate (UI wrapping). This maintains full backward compatibility with existing code. Addresses kyle-ssg's review feedback.
Remove auto-generated marker comments, outdated usage examples, and redundant inline comments that don't add value to the code. Changes: - Remove "END OF ENDPOINTS/EXPORTS/FUNCTION_EXPORTS" markers (6 total) - Remove outdated usage examples from service files (2 blocks) - Remove redundant inline comments in Permission component (2 comments) - Remove incomplete comment in useFeatureState The code is now cleaner and more maintainable without losing any meaningful documentation or context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
frontend/web/components/pages/features/components/FeaturesPageHeader.tsx
Show resolved
Hide resolved
Add detailed JSDoc documentation to improve developer experience: - Document PermissionType interface with descriptions for all props - Add JSDoc to useHasPermission hook explaining parameters and return values - Add comprehensive JSDoc to Permission component with 5 usage examples: * Basic usage with simple children * Render function pattern with permission state * Tooltip on permission denial * Fallback content when permission is denied * Tag-based permission checking BREAKING CHANGE: Change id type from any to number | string for better type safety. This improves type checking without breaking existing usage since all current usages pass either number (projectId, organisationId) or string (environmentId). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Fix usePageTracking dependency array to use individual context properties instead of the entire context object reference, preventing unnecessary effect re-runs on every render. **Changes:** - Update useEffect dependency array from `[saveToStorage, context]` to `[saveToStorage, context?.environmentId, context?.organisationId, context?.projectId]` - Uses optional chaining to safely access nested properties - Add explanatory comment and eslint-disable for intentional deviation **Impact:** - Eliminates excessive re-renders when context object reference changes but actual values remain the same - Improves performance on pages using page tracking (e.g., FeaturesPage) **Addresses:** Cursor Bugbot feedback - Bug #1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add environment metrics cache invalidation to removeProjectFlag mutation
to ensure metrics (e.g., enabled_features count) refresh immediately when
features are deleted.
**Changes:**
- Add `{ id: 'METRICS', type: 'Environment' }` to removeProjectFlag's
invalidatesTags array in useProjectFlag.ts
**Impact:**
- Environment metrics now update immediately after feature deletion
- No more stale metrics requiring manual page refresh
- Fixes metrics display in environment selectors and dashboards
**Addresses:** Cursor Bugbot feedback - Bug #3
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…functions
Fix Permission component to show tooltips when using render prop pattern.
Previously, render functions would return early before tooltip logic was reached.
**Changes:**
- Restructure render function logic to check showTooltip before returning
- Render children first, then conditionally wrap with tooltip based on
permission and showTooltip flag
- Remove debug console.log statements
**Impact:**
- Tooltips now display correctly when Permission uses render props
- Fixes tooltip display in FeaturesPageHeader and other components using
render prop pattern with showTooltip
**Example:**
```tsx
<Permission showTooltip permissionName="Create Features">
{({ permission }) => <Button disabled={!permission}>Create</Button>}
</Permission>
```
Now correctly shows tooltip when hovering over disabled button.
**Addresses:** Cursor Bugbot feedback - Bug #2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…ompatibility Add adapter functions in CompareEnvironments and CompareFeatures to bridge the signature mismatch between FeatureListProvider callbacks (4 params) and FeatureRow expectations (2 params). This fixes Cursor Bugbot issue #4 where callbacks were being passed with incorrect signatures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Destructure the error property from useProjectEnvironments and include it in the error condition check. Previously, if the project or environments queries failed, the page would show loading skeletons indefinitely because only the feature list error was being checked. Now users will see a proper error message instead of infinite loading when project/environment queries fail. Fixes Cursor Bugbot issue where getEnvironmentIdFromKey returns undefined due to failed queries, causing the feature list query to be skipped via skipToken, leaving users staring at loading skeletons forever. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Thanks for submitting a PR! Please check the boxes below:
docs/if required so people know about the feature!Summary
This PR completes the migration of FeaturesPage from legacy Flux stores to RTK Query with comprehensive refactoring, improved TypeScript type safety, better error handling, and cleaner documentation.
Changes
1. Core RTK Query Migration
useFeatureListWithFiltershook for filtered feature fetching with automatic API key to ID conversionuseProjectEnvironmentshook to replace ProjectStore functionality2. Custom Hooks & Code Organization
useCallbackwrappers with empty dependenciesfeatureFilterParams.tsfor global reusefeatureFilters.ts3. UI/UX Improvements
isTogglingandisRemovingstates from mutation hooksisSavingbehavior4. Component Refactoring
useFeaturePageDisplayhookrenderFeaturesList()helper functionshowCreateButtonprop (was always true)5. Type Safety Improvements
projectIdtype tonumberacross all components6. Documentation Cleanup
useFeatureListWithFilters.ts: 81→34 linesfeatureFilterParams.ts: Simplified 4 JSDoc blocksuseFeatureFilters.ts: 26→3 linesuseRemoveFeatureWithToast.ts: 18→1 lineuseToggleFeatureWithToast.ts: 18→1 lineuseProjectEnvironments.ts: 25→1 linefeatureFilters.ts: Simplified type comments7. Performance Optimizations
8. Code Quality
Files Changed
Created:
common/hooks/useFeatureListWithFilters.tscommon/hooks/useProjectEnvironments.tscommon/types/featureFilters.tscommon/utils/featureFilterParams.tsweb/components/pages/features/hooks/useFeatureFilters.tsweb/components/pages/features/hooks/useToggleFeatureWithToast.tsweb/components/pages/features/hooks/useRemoveFeatureWithToast.tsweb/components/feature-summary/FeatureRowSkeleton.tsxweb/styles/components/_feature-row-skeleton.scssModified:
web/components/pages/features/FeaturesPage.tsx(major refactor)web/components/pages/features/components/FeaturesPageHeader.tsxweb/components/pages/features/components/FeaturesTableFilters.tsxRemoved:
web/components/pages/features/components/FeaturesList.tsxweb/components/pages/features/hooks/useFeaturePageDisplay.tsBenefits
Breaking Changes
None - all functionality preserved, this is a pure refactor.
How did you test this code?
Manual Testing:
Features Page Load
Filter Functionality
Feature Actions
Error Handling
Type Safety
Accessibility
Validation: