Skip to content

Improve reliability with centralized API error & log handling#54

Merged
cgalibern merged 55 commits intoopensvc:mainfrom
PaulJouvanceau:dev
Nov 3, 2025
Merged

Improve reliability with centralized API error & log handling#54
cgalibern merged 55 commits intoopensvc:mainfrom
PaulJouvanceau:dev

Conversation

@PaulJouvanceau
Copy link
Copy Markdown
Contributor

No description provided.

- Add null/undefined protection and safe data access patterns
- Improve error handling for heartbeat streams and namespace extraction
- Expand test coverage with edge cases and API error scenarios
- Implement reliable test targeting with data-testid attributes
- Maintain all existing functionality while improving resilience
Added rendering of resource logs in the NodeCard component's renderResourceRow
function. Logs are displayed with level-based color coding (warn: orange, error: red)
and proper indentation, ensuring accessibility with aria-labels. Only resources with
logs (res.log array) are affected.
…chNodes

- Wrapped `refreshDaemonStatus` in `useFetchDaemonStatus` with `useCallback` to ensure a stable `fetchNodes` reference, preventing unnecessary `useEffect` triggers in `NodesTable`.
- Added `eventSourceActive` flag in `NodesTable` useEffect to prevent multiple EventSource connections.
- Updated `eventSourceManager` to check for existing active EventSource before creating a new one, ensuring proper connection management.
- Applied `React.memo` to `NodeRow` to optimize rendering and prevent unnecessary re-renders.
- Added safeguards to avoid redundant EventSource creation and cleanup.

Resolves issue with infinite EventSource create/close loop in logs.
- Add real-time logs viewer accessible from nodes table
- Implement LogsViewer component with SSE connection
- Add logs column with dedicated open button in NodeRow
- Include filtering by log level and text search
- Support pause/resume, download, and auto-scroll features
- Handle connection errors with retry mechanism
- Use drawer layout for better space utilization
 - Prevented unnecessary state updates in `updateLogs` by checking if `logBufferRef` is non-empty before calling `setLogs`, eliminating UI flickering when no new logs are added.
 - Stabilized `isLoading` state by only setting it when not already connected, reducing unnecessary UI updates during reconnections.
 - Added `useMemo` for `renderedLogs` to cache log rendering, preventing re-renders unless `filteredLogs` changes, improving performance and reducing flicker.
 - Debounced `scrollIntoView` with a 100ms timeout in auto-scroll `useEffect` to reduce excessive scroll operations.
 - Retained previous optimizations: 2-second `UPDATE_INTERVAL`, self-referential log filtering, deduplication with `seenLogsRef`, and proper pause/resume handling with `isPausedRef`.
 - Maintained `whiteSpace: "pre-wrap"` and `flexWrap: "wrap"` for consistent log formatting and layout.
- Split buildTitle() into buildTitle() and buildSubtitle()
- Use DeleteOutline icon instead of Clear for delete action
- Remove redundant title (shown in parent Drawer)
- Display only nodename, status, and loading indicator in component header
… sorting

- Modified LogsViewer.jsx to enable multiple log level filtering by changing levelFilter state from string to array
- Updated Select component to use Checkbox and ListItemText for clearer multi-selection UI
- Adjusted FormControl label to "Select Log Levels" and improved renderValue to show "All Levels" when no filters are selected
- Increased FormControl minWidth to 200px for better visibility of selected items
- Capitalized log level labels in dropdown for improved readability
- Sorted log level options alphabetically (debug, error, info, warn) in the Select component
- Modified buildLogUrl to append ?follow=true for Server-Sent Events (SSE)
- Removed scheduled API polling (4-second intervals) in favor of real-time SSE updates
- Updated fetchLogs to handle continuous SSE stream and process events as received
- Eliminated updateIntervalRef and related polling logic
- Maintained existing functionality for pause, filtering, and auto-scroll
- Ensured proper cleanup of SSE connections on component unmount or pause
- Replace modal logs with persistent drawer in ObjectDetails for better UX
- Add resizable logs panel that works alongside main content
- Maintain scrollable ObjectDetails page while logs are open
- Reuse the same pattern implemented in NodesTable for consistency
- Remove local logs state from NodeCard in favor of parent control
- Add proper state management for logs viewer across components
- Ensure responsive behavior with adjustable drawer width
- Modified flex layout to prevent horizontal scrolling when LogsViewer is open
- Reduced drawer maxWidth from 90vw to 80vw for better screen utilization
- Added boxSizing: border-box consistently across containers
- Moved padding inside content container for proper width calculations
- Maintained independent scrolling for main content and logs drawer
- Ensured responsive behavior without overflow on standard screen sizes
- Add click handler on logs to clear search and level filters when filters are active
- Implement smooth scroll to selected log position after clearing filters
- Add visual feedback with temporary highlight on target log
- Display filter status chip indicating 'Filters active - Click any log to clear'
- Prevent auto-scroll conflict by managing manual scroll state
- Improve user experience by maintaining context when transitioning from filtered to full log view
- Add unique IDs to logs using __REALTIME_TIMESTAMP for reliable element targeting
- Ensure proper cleanup of timeouts and scroll handlers
…nent

- Created test suite for LogsViewer React component
- Added mocks for MUI, localStorage, fetch, and ReadableStream
- Implemented tests for rendering, log fetching, pausing/resuming, error handling, filtering, and downloading
- Covered edge cases including empty logs, malformed JSON, and authentication errors
- Ensured full branch and function coverage with additional tests for MockReadableStream
- Modified ConfigSection.jsx to display the section prefix before the index input field for indexed parameters
- Updated ManageParamsDialog to show the prefix in the section column for clarity when adding parameters
- Ensured input field for index is only editable for indexed parameters, maintaining existing behavior for non-indexed sections
- Adjusted UI to reflect the prefix in the section display for better user experience
- Added display of down and warn object counts in NavBar
- Implemented logic to count objects with 'down' and 'warn' status using getObjectStatus
- Added conditional rendering to show counts only when down or warn objects exist
- Included clickable links to filter objects page by down/warn status
- Integrated Material-UI Tooltip and icons for visual status indicators
- Ensured counts update reactively using useMemo and useEffect
-Add env-aware logger at logger.js (no-op in production; routes info/debug/error to console in dev/test for backward compatibility).
-Replace ad-hoc console.* calls across core hooks/components with logger.* and add missing imports where needed.
-Fix EventSource buffering and cleanup in eventSourceManager.jsx (clear flush timers, attach/_cleanup on instances, ensure cleanup on close) to prevent leaks and improve reconnection handling.
-Adjust logger.error to also emit to console.log in non-production so existing Jest spies continue to work.
Add ApiError class carrying status, statusText and parsed body.
Implement apiFetch(url, options) wrapper that:
distinguishes network vs HTTP errors,
parses JSON/text safely,
throws ApiError with detailed info on non-OK responses.
Update fetchDaemonStatus to use apiFetch so callers receive uniform, richer error objects.
…patibility

- Modify logger behavior to prevent duplicate console output in development mode
- Implement environment-aware logging: double calls in test mode for test compatibility, single calls in development
- Add isTest detection to maintain existing test expectations without modification
- Preserve all existing functionality for serialize method and environment handling

The logger now uses different behaviors:
- In test environment (NODE_ENV=test): maintains double console calls for test compatibility
- In development environment: uses single console calls to prevent duplicate logs
- In production: no logging occurs

This ensures:
- No duplicate logs in the application during development
- All existing tests pass without modification
- Backward compatibility with current test suite expectations
… eventSourceManager

- Implement navigationService using custom events for auth redirects
- Remove hard page reload on authentication errors and silent renew failures
- Use existing 'om3:auth-redirect' event system for consistency
- Improve error handling with SPA-compatible navigation
- Add redirect when max reconnection attempts are reached
- Maintain decoupling between EventSource and React components
- Add 'console' action to RESOURCE_ACTIONS with Terminal icon
- Implement postConsoleAction API call to /api/node/name/{nodename}/instance/path/{namespace}/{kind}/{name}/console
- Handle console URL response and open in new browser tab
- Filter console action to be available only for container resources
- Exclude console from batch resource actions
- Skip dialog confirmation for console action (direct execution)
- Add proper error handling and user feedback via snackbar

Key changes:
1. constants/actions.js: Added console action with TerminalIcon
2. ObjectDetails.js:
   - Implemented postConsoleAction function
   - Added handleOpenConsole callback
   - Fixed getFilteredResourceActions to show console only for containers
   - Excluded console from batch actions
3. NodeCard.js:
   - Added onOpenConsole prop
   - Special handling for console action in handleResourceActionClick
   - Fixed resource type filtering
4. ActionDialogManager.js:
   - Skip dialog initialization for console action
   - Prevent console from triggering confirmation dialogs

The console functionality allows users to open a shell session in container resources directly from the web interface, leveraging the tty-share backend service.
- Add ConsoleDialog component in ActionDialogs.js with checkbox confirmation
- Integrate console dialog in ActionDialogManager.js with proper state management
- Modify ObjectDetails.js to handle console action through dialog system:
  - Remove direct onOpenConsole callback
  - Update handleResourceActionClick to use openActionDialog for all actions
  - Add console action handling in handleDialogConfirm
  - Include 'console' in supported actions for ActionDialogManager
- Simplify NodeCard.js:
  - Remove onOpenConsole prop and direct console handling
  - Use setPendingAction for all resource actions including console
  - Maintain proper action filtering for container resources
- Ensure console action follows the same user confirmation flow as other actions

The console functionality now requires user confirmation with a checkbox before opening, providing better security and user awareness.
…ions and stale props

    The root cause of intermittent dialog bugs (checkboxes not resetting,
    Confirm button disabled incorrectly, dialogs reopening after cancel,
    and cross-browser inconsistencies) was the `dialogState` object.

    Problems fixed:
    - `dialogState` was used to track which dialog is open
    - It was set to `true` on every `pendingAction` change via `useEffect`
    - Clicking "Cancel" only closed it locally, but `useEffect` reopened it
      immediately if `pendingAction` was still present
    - Rapid action changes caused multiple dialogs to have `open: true`
    - `useMemo` captured stale `dialogState` and `checkboxState` → outdated
      `disabled` props
    - `checkboxState` was not reliably reset between actions

    Solution:
    - **Removed `dialogState` entirely**
    - Dialog openness is now derived **directly from `pendingAction`**
    - Only **one dialog is rendered** at a time using conditional return
    - `checkboxState` is **reset on every `pendingAction` change** in `useEffect`
    - `disabled` logic moved to child dialogs (always up-to-date)
    - `useMemo` no longer depends on `dialogState` → no stale closures

    Result:
    - No more dialog overlap
    - Checkboxes always reset
    - Confirm button enables correctly
    - Consistent behavior across all browsers
    - Simpler, more predictable state management
This resolves the issue on Safari where selecting a node action does not trigger the confirmation dialog. By handling setPendingAction and dialog opening directly within NodeCard's handleIndividualNodeActionClick, we ensure consistent behavior across browsers. Note: Menu closing (setIndividualNodeMenuAnchor(null)) was not included in this local handler; if needed, it can be added separately.
…jects and ObjectDetails

- Changed pendingAction structure in Objects from `{action, node}` to `{action, target}` for consistency with ActionDialogManager
- Updated handleActionClick to use `target` instead of `node`
- Modified handleExecuteActionOnSelected to use `pendingAction.target` for single object actions
- Updated ActionDialogManager target prop to use `pendingAction.target`
- Ensures UnprovisionDialog always shows 3 checkboxes (dataLoss, serviceInterruption, clusterwide) regardless of context
- Fixes inconsistent checkbox count between Objects list view and ObjectDetails view
… support

- Added touch event handling (`onTouchStart`, `touchmove`, `touchend`) to the drawer resize handle
- Updated `startResizing` to detect touch vs mouse events and use appropriate coordinates (`touches[0].clientX`)
- Added `passive: false` to touchmove to allow `preventDefault()` and ensure smooth resizing
- Added `onTouchStart` to the resize handle alongside `onMouseDown`
@cgalibern cgalibern merged commit fd91922 into opensvc:main Nov 3, 2025
2 checks passed
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.

2 participants