Skip to content

Conversation

@talissoncosta
Copy link
Contributor

@talissoncosta talissoncosta commented Nov 21, 2025

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

  • 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?
  • I have used a Conventional Commit title for this Pull Request

Changes

Overview

Migrated OrganisationSettingsPage from a 466-line JavaScript class component to a modern TypeScript functional component architecture, replacing legacy Flux patterns with RTK Query and decomposing the monolithic component into well-structured, reusable modules.

Key Improvements

1. Migration to TypeScript

  • Converted from JavaScript class component to TypeScript functional component
  • Added proper type definitions for all props, state, and API responses
  • Full type safety throughout the component tree
  • Created UpdateOrganisationBody type in requests.ts
  • Added OrganisationSettingsTab type for tab configuration

2. RTK Query Integration

  • Replaced legacy stores: Eliminated AccountStore and OrganisationProvider dependencies
  • Added new endpoints to useOrganisation.ts:
    • getOrganisation - Fetch single organisation with proper cache tags
    • updateOrganisation - Update organisation with optimistic updates
    • deleteOrganisation - Delete organisation with cache invalidation
  • Optimistic updates: Organisation updates appear immediately in UI with automatic rollback on error
  • Automatic cache invalidation: Changes propagate to all components using the same data

3. Custom Hooks for Reusable Logic

  • useUpdateOrganisationWithToast: Encapsulates update logic with toast notifications and error handling
  • useDeleteOrganisationWithToast: Handles organisation deletion with:
    • Automatic calculation of next available organisation for navigation
    • Legacy store synchronization via AppActions.refreshOrganisation() for backward compatibility
    • Toast notifications for success/error states
    • Loading state management

4. Component Decomposition

Broke down the monolithic 466-line component into focused, maintainable modules:

organisation-settings/
├── OrganisationSettingsPage.tsx (136 lines) - Main orchestrator
├── hooks/
│   ├── useUpdateOrganisationWithToast.ts - Update hook with toast
│   └── useDeleteOrganisationWithToast.ts - Delete hook with navigation
└── tabs/
    ├── general-tab/
    │   ├── index.tsx - GeneralTab orchestrator
    │   └── sections/
    │       ├── OrganisationInformation.tsx - Name update form
    │       ├── DeleteOrganisation.tsx - Deletion UI
    │       └── admin-settings/
    │           ├── Force2FASetting.tsx - 2FA toggle
    │           └── RestrictProjectCreationSetting.tsx - Project creation restriction
    ├── BillingTab.tsx - Billing & subscription management
    ├── LicensingTab.tsx - Enterprise licensing
    ├── CustomFieldsTab.tsx - Custom fields management
    ├── APIKeysTab.tsx - API keys management
    ├── WebhooksTab.tsx - Webhook configuration
    └── SAMLTab.tsx - SAML authentication

5. Modern React Patterns

  • Hooks over HOCs: Removed withRouter and ConfigProvider HOCs
  • useRouteContext: Replaced match.params with context-based routing
  • useHistory: Direct hook usage instead of prop drilling
  • Proper imports: Uses { FC, ReactNode } instead of React.FC
  • Functional components: All components are now functional with hooks

6. Navigation Improvements

  • Explicit navigation logic: After organisation deletion, explicitly calculates next organisation
  • Smart routing:
    • If user has other orgs → navigate to /organisation/{nextOrgId}/projects
    • If no orgs remaining → navigate to /organisations (org list)
  • No reliance on global state: Navigation based on RTK Query data, not AccountStore

7. Loading States & UX

  • Delete button: Shows "Deleting..." text and disables during operation
  • Update button: Shows "Updating" text and disables during save
  • Page-level loading: Displays centered loader during initial data fetch
  • Error states: Shows clear error messages for failed operations

8. Backward Compatibility

  • Maintains AppActions.refreshOrganisation(): Ensures legacy components (navbar, permissions UI) stay in sync
  • Dual sync strategy: RTK Query handles modern components, AppActions handles legacy components
  • Gradual migration path: Allows incremental migration away from legacy stores

9. Tab Array Pattern

Implemented clean, declarative tab configuration matching ProjectSettingsPage:

const tabs: OrganisationSettingsTab[] = [
  {
    component: <GeneralTab organisation={organisation} />,
    isVisible: true,
    key: 'general',
    label: 'General',
  },
  // ... more tabs
].filter(({ isVisible }) => isVisible)

10. Permission Handling

  • Direct API checks: Permission checks from organisation.role instead of AccountStore
  • Feature flag integration: Uses Utils.getFlagsmithHasFeature() for conditional features
  • Payment method checks: Billing tab visibility based on organisation.subscription.payment_method

How did you test this code?

Manual Testing Performed

Organisation Information Updates

  • Update organisation name → verified name updates in navbar
  • Update with empty name → verified validation prevents submission
  • Update with very long name → verified it saves correctly
  • Cancel edit → verified changes are discarded
  • Check loading state → "Updating" text appears during save

Admin Settings

  • Toggle "Force 2FA" setting → verified it persists after page reload
  • Toggle "Restrict Project Creation" → verified setting saves correctly
  • Verify settings persist across page reloads
  • Check that non-admin users cannot access these settings

Organisation Deletion

  • Delete organisation with multiple orgs → navigates to next organisation's projects page
  • Delete organisation (last one) → navigates to /organisations page
  • Check confirmation modal appears before deletion
  • Verify loading state during deletion ("Deleting..." text)
  • Cancel deletion → modal closes without action
  • Verify deleted org disappears from navbar immediately

Tab Navigation

  • Switch between all tabs → all tabs load correctly
  • Billing tab visibility → hidden for AWS Marketplace customers
  • Licensing tab visibility → only visible in enterprise installations
  • Tab state persists in URL (?tab=billing)
  • Direct URL access to specific tab works correctly

Permission Checks

  • Admin user → can access all settings
  • Non-admin user → sees "You do not have permission" message
  • Org not found → error message displays
  • Network error → error message displays

Loading States

  • Initial page load → centered loader appears
  • Organisation update → button shows "Updating"
  • Organisation delete → button shows "Deleting..." and is disabled
  • Tab switches → content updates immediately (no loader needed, already cached)

Backward Compatibility

  • Navbar organisation list updates after changes
  • Legacy permissions UI components still function
  • Organisation selector in other components reflects changes
  • No console errors related to store updates

Error Handling

  • API error during load → error message displays
  • API error during update → toast notification appears
  • API error during delete → toast notification appears
  • Network timeout → appropriate error handling

Edge Cases

  • Organisation ID not in URL → handled gracefully
  • Invalid organisation ID → error message displays
  • Multiple rapid clicks on save → prevents double submission
  • Multiple rapid clicks on delete → prevents double submission
  • Browser back/forward buttons → navigation works correctly

Closes #5779

@vercel
Copy link

vercel bot commented Nov 21, 2025

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

Project Deployment Preview Comments Updated (UTC)
flagsmith-frontend-preview Ready Ready Preview Comment Nov 21, 2025 0:52am
flagsmith-frontend-staging Ready Ready Preview Comment Nov 21, 2025 0:52am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
docs Ignored Ignored Preview Nov 21, 2025 0:52am

@github-actions github-actions bot added the front-end Issue related to the React Front End Dashboard label Nov 21, 2025
@talissoncosta talissoncosta force-pushed the refactor/migrate-organisationsettingspage branch from f6a71c3 to 397b391 Compare November 21, 2025 11:26
@talissoncosta talissoncosta force-pushed the refactor/migrate-organisationsettingspage branch from 397b391 to 05441c7 Compare November 21, 2025 11:27
@talissoncosta talissoncosta marked this pull request as ready for review November 21, 2025 11:27
@talissoncosta talissoncosta requested a review from a team as a code owner November 21, 2025 11:27
@talissoncosta talissoncosta requested review from kyle-ssg and removed request for a team November 21, 2025 11:27
@talissoncosta talissoncosta marked this pull request as draft November 21, 2025 11:28
@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

Docker builds report

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

talissoncosta and others added 16 commits November 21, 2025 09:48
- 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
- Add OrganisationInformation component for name updates
- Add Force2FASetting toggle component
- Add RestrictProjectCreationSetting toggle component
- Add DeleteOrganisation danger zone component with useHistory hook
- All components use RTK Query mutations via custom hooks

Part of OrganisationSettingsPage TypeScript migration
- Compose all General tab sections
- Include JSONReference for debugging
- Organize with SettingTitle sections
- Clean component structure with proper TypeScript types

Part of OrganisationSettingsPage TypeScript migration
- Add BillingTab with RTK Query useGetSubscriptionMetadataQuery
- Add LicensingTab, CustomFieldsTab, APIKeysTab wrappers
- Add WebhooksTab and SAMLTab wrappers
- All tabs accept organisationId and use existing components

Part of OrganisationSettingsPage TypeScript migration
- Use useRouteContext for organisationId (no URL param parsing)
- Use useGetOrganisationQuery for all organisation data
- Check permissions from organisation.role (no AccountStore)
- Implement tabs array pattern matching ProjectSettingsPage
- Add proper loading and error states
- No legacy HOCs (withRouter, ConfigProvider)
- Export directly without wrappers

BREAKING CHANGE: Completely removes OrganisationProvider and AccountStore dependencies
- Remove old 466-line JavaScript class component
- Update routes to import from organisation-settings folder
- Complete migration to modern React with hooks and RTK Query

Closes #5779
Replace legacy AccountStore usage with RTK Query for determining next
organisation after deletion. The hook now fetches the organisations
list and calculates the next available organisation ID, passing it to
the onSuccess callback for explicit navigation handling.

Changes:
- useDeleteOrganisationWithToast: Add useGetOrganisationsQuery hook
- Calculate next organisation ID before passing to callback
- DeleteOrganisation: Remove AccountStore and Utils imports
- Use direct URL construction for navigation
- Navigate to /organisation/{id}/projects or /organisations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add AppActions.refreshOrganisation() call after successful organisation
deletion to ensure legacy components (navbar, permissions UI) that still
use OrganisationStore stay in sync. This follows the same pattern as
useUpdateOrganisationWithToast and useUpdateProjectWithToast hooks.

Without this, legacy store-based components would show stale data after
an organisation is deleted, while RTK Query components would update
correctly via cache invalidation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add isLoading state to Delete Organisation button to prevent double-clicks
and provide visual feedback during deletion. Button is disabled and shows
"Deleting..." text while the deletion is in progress.

This matches the pattern already implemented in OrganisationInformation
for the Update button.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Remove self-explanatory comments that don't add value:
- useUpdateOrganisationWithToast: Remove "Don't re-throw" comment
- OrganisationSettingsPage: Remove "Check permission" comment
- DeleteOrganisation: Remove navigation redirect comment

Keep important comments that explain backward compatibility decisions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
During the migration, the data-test attribute was changed from
'organisation-name' to 'org-name', breaking E2E tests that rely on
this selector.

Restored the original 'organisation-name' selector to maintain
compatibility with existing E2E tests in invite-test.ts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

front-end Issue related to the React Front End Dashboard refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate critical components: OrganisationSettingsPage

2 participants