# Rule Enable/Disable Toggle Switch Implementation **Date:** 2025-01-30 **Status:** Complete ## Overview Added a toggle switch to the Rule Detail page that allows authenticated users to enable or disable rules directly from the UI, with proper permission checking and visual feedback. ## Changes Made ### 1. Backend API (Already Existed) The backend already had the necessary endpoints: - `POST /api/v1/rules/{ref}/enable` - Enable a rule - `POST /api/v1/rules/{ref}/disable` - Disable a rule Both endpoints: - Require authentication (`RequireAuth` middleware) - Update the rule's `enabled` status in the database - Publish RabbitMQ messages (`RuleEnabled`/`RuleDisabled`) to notify the sensor service - Return the updated rule in the response ### 2. Frontend Hooks (`web/src/hooks/useRules.ts`) Added two new React hooks for toggling rule status: ```typescript // Enable rule hook export function useEnableRule() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (ref: string) => { const response = await RulesService.enableRule({ ref }); return response; }, onSuccess: (_, ref) => { queryClient.invalidateQueries({ queryKey: ["rules"] }); queryClient.invalidateQueries({ queryKey: ["rules", ref] }); }, }); } // Disable rule hook export function useDisableRule() { // Similar implementation for disabling } ``` These hooks: - Use TanStack Query's `useMutation` for state management - Automatically invalidate relevant queries after success to refresh the UI - Handle API calls to the enable/disable endpoints ### 3. UI Component (`web/src/pages/rules/RulesPage.tsx`) #### Updated Imports - Added `useEnableRule` and `useDisableRule` hooks - Added `useAuth` context for permission checking #### Added State and Handler ```typescript const { isAuthenticated } = useAuth(); const enableRule = useEnableRule(); const disableRule = useDisableRule(); const [isTogglingEnabled, setIsTogglingEnabled] = useState(false); const handleToggleEnabled = async () => { if (!rule?.data) return; setIsTogglingEnabled(true); try { if (rule.data.enabled) { await disableRule.mutateAsync(ruleRef); } else { await enableRule.mutateAsync(ruleRef); } } catch (err) { console.error("Failed to toggle rule enabled status:", err); } finally { setIsTogglingEnabled(false); } }; ``` #### Toggle Switch UI Replaced the static status badge with an interactive toggle switch: - **Toggle Switch**: Tailwind CSS-based toggle with proper styling - **Status Label**: Shows "Enabled" (green) / "Disabled" (gray) / "Updating..." (gray) - **Disabled State**: Toggle is disabled when: - User is not authenticated (`!isAuthenticated`) - Toggle operation is in progress (`isTogglingEnabled`) - **Visual Feedback**: - Focus ring on keyboard interaction - Smooth transition animation - Color change (gray → blue when enabled) - Loading state during API call ## User Experience ### Toggle Location The toggle switch is positioned near the top of the Rule Detail page, next to the rule title, making it easily accessible and immediately visible. ### Permission Handling - **Authenticated Users**: Can toggle the switch freely - **Unauthenticated Users**: Toggle is disabled (grayed out) - **During Update**: Toggle shows "Updating..." and is disabled to prevent double-clicks ### Visual States 1. **Enabled**: Blue toggle, green "Enabled" label 2. **Disabled**: Gray toggle, gray "Disabled" label 3. **Loading**: Gray toggle (disabled), "Updating..." label 4. **No Permission**: Gray toggle (disabled), current status label ### Real-time Updates - On successful toggle, the UI immediately updates via React Query cache invalidation - The sensor service receives notifications via RabbitMQ and adjusts monitoring accordingly - Rule list view automatically reflects the new status ## Technical Details ### Permission System Currently uses simple authentication check (`isAuthenticated`): - Any authenticated user can enable/disable rules - Backend validates JWT token via `RequireAuth` middleware - Future: Can be extended to check fine-grained permissions when RBAC is fully implemented ### State Management - Uses TanStack Query for server state management - Optimistic updates are not used (waiting for server confirmation) - Cache invalidation ensures all views stay in sync - Local `isTogglingEnabled` state prevents UI race conditions ### Error Handling - Errors are logged to console - Toggle returns to previous state on failure - User sees the actual current state from the server ## Testing Recommendations ### Manual Testing 1. **Toggle Enabled → Disabled**: - Navigate to an enabled rule - Click the toggle switch - Verify it shows "Updating..." - Verify it changes to "Disabled" after API response - Check that sensor service stops monitoring the trigger 2. **Toggle Disabled → Enabled**: - Navigate to a disabled rule - Click the toggle switch - Verify it changes to "Enabled" - Check that sensor service starts monitoring the trigger 3. **Permission Check**: - Log out - Navigate to a rule detail page - Verify toggle is disabled 4. **Double-click Prevention**: - Toggle a rule - Try clicking again during update - Verify second click is ignored ### Integration Testing - Verify RabbitMQ messages are published correctly - Verify sensor service receives and processes messages - Verify database `enabled` field is updated - Verify rule executions respect the enabled flag ## Future Enhancements 1. **Fine-grained Permissions**: Add RBAC checks for `rule:enable` and `rule:disable` permissions 2. **Optimistic Updates**: Update UI immediately, rollback on error 3. **Toast Notifications**: Show success/error messages 4. **Bulk Operations**: Add ability to enable/disable multiple rules at once 5. **Audit Logging**: Track who enabled/disabled rules and when 6. **Confirmation Dialog**: Optional confirmation for critical rules ## Dependencies - React 19 - TanStack Query (React Query) - Tailwind CSS - Existing API endpoints (already implemented) ## Build Status ✅ TypeScript compilation successful ✅ Vite build successful ✅ No ESLint warnings