Skip to content

Conversation

@karenvicent
Copy link
Contributor

@karenvicent karenvicent commented Dec 18, 2025

Describe your changes

Incidents Management - Version 1
Overview
Initial implementation of the incidents management system with basic functionality for fetching, displaying, and resolving incidents.
Features Included (v1)
✅ Fetch incidents by team with filtering (status, monitor, date range, pagination)
✅ Display active and resolved incidents
✅ Manual incident resolution
✅ Incident summary statistics panel
✅ Basic incident table with pagination
Future Enhancements (v2)
🔜 Comment options for incident resolution
🔜 Confirmation modal for manual resolution
🔜 Incident detail view/modal

Write your issue number after "Fixes "

Fixes #2860 #3006

Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.

  • (Do not skip this or your PR will be closed) I deployed the application locally.
  • (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
  • I have included the issue # in the PR.
  • I have added i18n support to visible strings (instead of <div>Add</div>, use):
const { t } = useTranslation();
<div>{t('add')}</div>
  • I have not included any files that are not related to my pull request, including package-lock and package-json if dependencies have not changed
  • I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
  • I made sure font sizes, color choices etc are all referenced from the theme. I don't have any hardcoded dimensions.
  • My PR is granular and targeted to one specific feature.
  • I ran npm run format in server and client directories, which automatically formats your code.
  • I took a screenshot or a video and attached to this PR if there is a UI change.
Captura de pantalla 2025-12-17 a la(s) 6 48 16 p m Captura de pantalla 2025-12-17 a la(s) 6 48 09 p m Captura de pantalla 2025-12-17 a la(s) 6 46 24 p m Captura de pantalla 2025-12-17 a la(s) 6 45 50 p m

Summary by CodeRabbit

  • New Features

    • Added "Checks" menu item and new Checks routes.
    • New Incidents2 page with Summary panels (Active, Latest, Statistics), IncidentTable, OptionsHeader, pagination, and filtering by monitor/status/date.
    • Reusable SummaryCard, panel skeletons, IncidentItem, ActiveIncidentsPanel, LatestIncidentsPanel, StatisticsPanel, and data hook with resolve actions.
  • Bug Fixes

    • Fixed loading image background styling in fallback UI.
  • Documentation

    • Updated incident summary API docs (limit-based response).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Note

.coderabbit.yml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'release_notes'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

A new Incidents2 page and related summary panels/components are added; the sidebar and routes gain a "Checks" entry and route while the original Incidents component is renamed to Checks and incidents route now renders Incidents2. Client networking and server DB/service layers gain incident list, detail, resolve, and summary endpoints and logic. Translations expanded.

Changes

Cohort / File(s) Summary
Navigation & Routes
client/src/Components/v1/Sidebar/index.jsx, client/src/Routes/index.jsx, client/src/Pages/v1/Incidents/index.jsx
Added "Checks" menu entry and new checks/:monitorId? route; renamed Incidents component export to Checks; switched incidents/:monitorId? route to render new Incidents2.
New Incidents2 Page
client/src/Pages/v1/Incidents2/index.jsx
New page composing Breadcrumbs, IncidentsSummaryPanel, OptionsHeader and IncidentTable; manages filters, pagination, monitor lookup and update trigger; wires to fetch hooks.
Summary Panels & Reusable UI
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/index.jsx, client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx, client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx
New IncidentsSummaryPanel orchestrating sub-panels; SummaryCard reusable container; PanelSkeleton for loading states.
Active / Latest / Statistics Panels
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx, client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx, client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx, client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx
Added panels: active incidents summary, latest incidents list (with IncidentItem and duration calc), and statistics panel (resolutions breakdown, averages).
Options Header
client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx
New header with monitor selector, filter select, and date-range buttons; exposes selection callbacks via props.
Incident Table
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx
New paginated incident table with loading/error/empty states, columns (monitor, status, times, resolution, HTTP status, message, actions) and resolve action flow.
Data Fetching Hook
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js
New hook providing fetchIncidentsByTeam, fetchActiveIncidents, fetchResolvedIncidents, fetchIncidentById, resolveIncident, fetchIncidentSummary; manages loading, count, errors and toasts.
Network Client Extensions
client/src/Utils/NetworkService.js
Added getIncidentsByTeam, getIncidentById, resolveIncidentManually, getIncidentSummary; exported setNetworkService and networkService reference.
Translations
client/src/locales/en.json
Added checks menu text, checksPageTitle, checks action keys, incidentsPage object and filter labels (including incidentsOptionsHeaderFilterActive) and other incident-related strings.
Client UI Fix
client/src/Components/v1/GenericFallback/index.jsx
Replaced invalid Box prop with backgroundColor: "transparent" in sx styling for loading image.
Server: DB & Service
server/src/db/v1/modules/incidentModule.js, server/src/service/v1/business/incidentService.js
getIncidentsByTeam added with date-range handling and monitor lookup; getIncidentSummary signature changed to accept { limit = 10 } and now returns aggregated metrics (totals, avg resolution hours, top monitor, latestIncidents); service layer updated to pass limit.
Server Docs
server/src/controllers/v1/incidentController.js
JSDoc updated to reflect new summary parameters/response shape.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Page as Incidents2 (Page)
    participant Hook as useFetchIncidents (Hook)
    participant Client as NetworkService (Client)
    participant API as Backend API

    User->>Page: Open page / change filter / paginate
    Page->>Hook: fetchIncidentsByTeam(config)
    Hook->>Hook: set isLoading
    Hook->>Client: getIncidentsByTeam(config)
    Client->>API: GET /incidents/team (filters, page, rows)
    API-->>Client: incidents[], incidentsCount
    Client-->>Hook: response
    Hook-->>Page: incidents, incidentsCount (isLoading=false)
    Page->>Page: render IncidentTable

    Page->>Hook: fetchIncidentSummary({ limit })
    Hook->>Client: getIncidentSummary({ limit })
    Client->>API: GET /incidents/team/summary?limit=...
    API-->>Client: summary{totalActive, avgResolutionTimeHours, topMonitor, latestIncidents}
    Client-->>Hook: summary
    Hook-->>Page: summary
    Page->>Page: render Active/Latest/Statistics panels

    User->>IncidentTable: Click Resolve
    IncidentTable->>Hook: resolveIncident(id)
    Hook->>Client: resolveIncidentManually(id)
    Client->>API: PUT /incidents/{id}/resolve
    API-->>Client: success
    Client-->>Hook: success
    Hook->>Page: toggle updateTrigger
    Page->>Hook: re-fetch incidents & summary
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Review focus:
    • server/src/db/v1/modules/incidentModule.js — aggregation pipelines, index usage, monitor lookup correctness and performance
    • client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js — state transitions, error/toast handling, concurrent requests
    • client/src/Pages/v1/Incidents2/index.jsx and child components — prop wiring, pagination edge cases, updateTrigger correctness
    • NetworkService additions — consistent error handling and API contract (query params)
    • Translation keys and route/sidebar changes — ensure no missing keys or broken links

Poem

🐇 I hopped through code, a carrot in my paw,
New panels, checks, and tables—what a draw!
Filters flutter, summaries shine bright,
Incidents2 leaps into the night.
Hooray for fixes, snacks, and flight! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses issue #2860 (successive failed pings as separate incidents) by implementing incidents aggregation logic and display infrastructure, but the PR lacks explicit backend logic to merge/collapse consecutive failures into single incidents. Verify that backend incident aggregation logic prevents duplicate incidents for successive failures and that frontend correctly displays aggregated incidents; consider adding server-side deduplication or merge logic if not present.
Out of Scope Changes check ⚠️ Warning The PR includes several out-of-scope changes: renaming Incidents page to Checks, creating a separate Checks route, and restructuring menu navigation—these exceed the stated objective of fixing incidents duplication. Isolate incidents management changes into a separate, focused PR; move Checks page renaming, routing changes, and menu restructuring to a distinct PR to maintain PR granularity.
Title check ❓ Inconclusive The PR title 'Fix incidents duplication front end' is vague and overly broad; it does not clearly convey the main implementation purpose (Incidents Management v1 with filtering, display, and resolution). Revise title to better reflect the primary objective, e.g., 'Implement incidents management v1 with filtering and resolution' or 'Add incidents dashboard with summary, table, and manual resolution'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description comprehensively covers the changes, linked issues, feature implementation, future enhancements, and includes all required checklist items marked complete with verification artifacts (screenshots).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-incidents-duplication-front-end

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@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.

Actionable comments posted: 8

🧹 Nitpick comments (10)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (1)

10-10: Unused onClick prop declared but not implemented.

The onClick prop is defined in PropTypes (line 150) but is never destructured from props (line 10) or attached to any element. The component has cursor: "pointer" styling (line 52) suggesting click functionality was intended.

Either implement the click handler or remove the unused prop and cursor styling:

-const IncidentItem = ({ incident }) => {
+const IncidentItem = ({ incident, onClick }) => {

And attach it to the outer Box:

 <Box
+  onClick={onClick}
   sx={{
     cursor: "pointer",

Or if click handling is not needed yet, remove the prop and cursor:

-  cursor: "pointer",
-  onClick: PropTypes.func,

Also applies to: 49-56, 139-151

server/src/db/v1/modules/incidentModule.js (1)

299-340: Multiple sequential aggregations may impact performance.

getIncidentSummary executes 4 separate aggregate pipelines (countsPipeline, resolutionTimePipeline, monitorPipeline, latestIncidentsPipeline). While each is efficient individually, running them sequentially increases latency.

Consider consolidating into a single aggregation using $facet if performance becomes a concern:

const combinedPipeline = [
  { $match: matchStage },
  {
    $facet: {
      counts: [...groupingStages],
      resolutionTime: [...resolutionStages],
      topMonitor: [...monitorStages],
      latestIncidents: [...latestStages]
    }
  }
];

For now, this is acceptable given the improved code readability.

client/src/Components/v1/Sidebar/index.jsx (1)

51-52: Consider using the Incidents icon for "Checks" instead of Docs.

The "Checks" menu item reuses the Docs icon, but semantically "Checks" relates more to incident/monitoring functionality. Using a distinct or more relevant icon would improve visual differentiation from the actual "Docs" link in the other menu section (line 72).

client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)

1-2: Prefer named import for consistency.

The import uses destructured named import from @mui/material which may bundle more than needed. Consider importing directly from the subpath:

-import { Skeleton } from "@mui/material";
+import Skeleton from "@mui/material/Skeleton";

This aligns with the pattern used elsewhere (e.g., SummaryCard import) and can improve tree-shaking.

client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (1)

83-97: Consider removing unused onIncidentClick prop.

The onIncidentClick prop is declared in PropTypes but is never used in the component implementation or passed to child components. This may be intended for future functionality (v2 enhancements mentioned in PR description), but currently creates a minor inconsistency.

If this prop is not needed for current functionality, consider removing it from PropTypes. If it's reserved for future use, consider adding a JSDoc comment noting it's for future implementation.

client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (1)

37-37: Consider explicit null return for clarity.

The early return when !shouldRender returns undefined implicitly. While valid in React, explicitly returning null would be clearer and more conventional.

-if (!shouldRender) return;
+if (!shouldRender) return null;
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (1)

138-143: Consider removing unused onIncidentClick prop.

Similar to LatestIncidentsPanel, the onIncidentClick prop is declared but never used. This is likely reserved for future functionality (v2 enhancements) but creates a minor inconsistency in the current implementation.

client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)

168-179: Add t to useCallback dependency array for correctness.

The fetchIncidentSummary function uses t from useTranslation but doesn't include it in the dependency array. While t is typically stable, including it ensures correctness and satisfies exhaustive-deps.

-}, []);
+}, [t]);
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (2)

86-103: Consider making the resolution type color mapping more maintainable.

The color logic hardcodes "manual" to accent and everything else to success. If additional resolution types (e.g., "auto", "scheduled", "api") are added in the future, they'll all default to the success color without explicit handling.

Consider creating a mapping object for better maintainability:

+const resolutionTypeColors = {
+  manual: "accent",
+  auto: "success",
+  // Add more types as needed
+};
+
 {
   id: "resolutionType",
   content: t("incidentsPage.resolutionType"),
   render: (row) => {
     if (row.resolutionType) {
+      const colorKey = resolutionTypeColors[row.resolutionType] || "success";
       return (
         <Typography
           variant="body2"
           sx={{
             textTransform: "capitalize",
-            color:
-              row.resolutionType === "manual"
-                ? theme.palette.accent.main
-                : theme.palette.success.main,
+            color: theme.palette[colorKey].main,
           }}
         >
           {row.resolutionType}
         </Typography>
       );
     }
     return "-";
   },
 },

64-70: Document the startTime fallback behavior.

The code falls back to row.createdAt when startTime is missing. While this may be intentional (legacy data migration or backward compatibility), it should be documented to clarify why this fallback exists.

Add a comment explaining the fallback:

 render: (row) => {
+  // Fallback to createdAt for backward compatibility with older incident records
   const formattedDate = formatDateWithTz(
     row.startTime || row.createdAt,
     "YYYY-MM-DD HH:mm:ss A",
     uiTimezone
   );
   return formattedDate;
 },
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ffce11 and 75acb1a.

📒 Files selected for processing (19)
  • client/src/Components/v1/Sidebar/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents/index.jsx (3 hunks)
  • client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1 hunks)
  • client/src/Pages/v1/Incidents2/index.jsx (1 hunks)
  • client/src/Routes/index.jsx (2 hunks)
  • client/src/Utils/NetworkService.js (1 hunks)
  • client/src/locales/en.json (5 hunks)
  • server/src/controllers/v1/incidentController.js (1 hunks)
  • server/src/db/v1/modules/incidentModule.js (4 hunks)
  • server/src/service/v1/business/incidentService.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (1)
  • SummaryCard (5-61)
server/src/service/v1/business/incidentService.js (2)
client/src/Pages/v1/Incidents/index.jsx (1)
  • summary (40-42)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/index.jsx (1)
  • summary (13-21)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/index.jsx (4)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (2)
  • useFetchIncidents (24-194)
  • fetchIncidentSummary (168-179)
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (1)
  • ActiveIncidentsPanel (23-136)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (1)
  • LatestIncidentsPanel (20-81)
client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (1)
  • StatisticsPanel (33-226)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (10)
client/src/Components/v1/Sidebar/index.jsx (1)
  • theme (83-83)
client/src/Pages/v1/Incidents/index.jsx (1)
  • theme (38-38)
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (1)
  • theme (24-24)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (1)
  • theme (32-32)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (1)
  • theme (12-12)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (1)
  • theme (21-21)
client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (1)
  • theme (20-20)
client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (1)
  • theme (34-34)
client/src/Pages/v1/Incidents2/index.jsx (1)
  • theme (54-54)
client/src/Pages/v1/StatusPage/Status/index.jsx (1)
  • sx (38-38)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (11)
client/src/Components/v1/Sidebar/index.jsx (2)
  • theme (83-83)
  • useTranslation (84-84)
client/src/Pages/v1/Incidents/index.jsx (2)
  • theme (38-38)
  • useTranslation (23-23)
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (2)
  • theme (24-24)
  • useTranslation (25-25)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (2)
  • theme (32-32)
  • useTranslation (31-31)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (3)
  • theme (12-12)
  • useTranslation (11-11)
  • IncidentItem (10-137)
client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (2)
  • theme (20-20)
  • useTranslation (21-21)
client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (2)
  • theme (34-34)
  • useTranslation (35-35)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (2)
  • theme (6-6)
  • SummaryCard (5-61)
client/src/Pages/v1/Incidents2/index.jsx (2)
  • theme (54-54)
  • useTranslation (20-20)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (3)
  • useTranslation (29-29)
  • isLoading (27-27)
  • incidents (25-25)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)
  • PanelSkeleton (8-18)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (1)
client/src/Components/v1/Label/index.jsx (1)
  • StatusLabel (135-156)
client/src/Utils/NetworkService.js (1)
client/src/Utils/timeUtils.js (1)
  • options (118-126)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (2)
client/src/Components/v1/Label/index.jsx (1)
  • StatusLabel (135-156)
client/src/Utils/timeUtils.js (1)
  • formattedDate (135-135)
client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (9)
client/src/Components/v1/Sidebar/index.jsx (2)
  • theme (83-83)
  • useTranslation (84-84)
client/src/Pages/v1/Incidents/index.jsx (6)
  • theme (38-38)
  • useTranslation (23-23)
  • monitors (39-39)
  • selectedMonitor (28-28)
  • filter (29-29)
  • dateRange (30-30)
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (2)
  • theme (24-24)
  • useTranslation (25-25)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (2)
  • theme (32-32)
  • useTranslation (31-31)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/IncidentItem.jsx (2)
  • theme (12-12)
  • useTranslation (11-11)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (2)
  • theme (21-21)
  • useTranslation (22-22)
client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (2)
  • theme (34-34)
  • useTranslation (35-35)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (1)
  • theme (6-6)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)
  • useTranslation (29-29)
client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (4)
client/src/Pages/v1/Incidents/index.jsx (2)
  • theme (38-38)
  • useTranslation (23-23)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (2)
  • theme (32-32)
  • useTranslation (31-31)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (2)
  • theme (6-6)
  • SummaryCard (5-61)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)
  • PanelSkeleton (8-18)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)
client/src/Utils/NetworkService.js (1)
  • networkService (1187-1187)
🔇 Additional comments (24)
client/src/Pages/v1/Incidents/index.jsx (1)

21-25: LGTM! Component renamed consistently from Incidents to Checks.

The renaming is applied uniformly across the component definition, breadcrumbs, action button labels, and the default export.

Also applies to: 87-88, 118-118

client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (1)

1-68: LGTM! Clean reusable component implementation.

The SummaryCard component is well-structured with appropriate prop types and theme-based styling. Minor note: there's an empty line at line 41 inside the sx object that could be removed for cleaner formatting.

client/src/Utils/NetworkService.js (2)

1153-1182: LGTM! New incident API methods follow established patterns.

The new methods (getIncidentsByTeam, getIncidentById, resolveIncidentManually, getIncidentSummary) are consistent with existing NetworkService patterns and handle query parameters appropriately.


1187-1192: LGTM! Dependency injection pattern for NetworkService.

The exported setNetworkService setter and networkService reference enable test doubles or alternate implementations to be injected, which is a good pattern for testability.

client/src/locales/en.json (2)

1145-1190: LGTM! Comprehensive translation keys for the new Incidents feature.

The incidentsPage namespace provides well-organized keys covering filters, panels, statuses, and error messages for the new incident management UI.


467-468: LGTM! New Checks-related translation keys added consistently.

The menu.checks, checksPageTitle, and action button translation keys align with the component renaming in the Incidents/index.jsx file.

Also applies to: 477-477, 1068-1068, 1070-1070

server/src/db/v1/modules/incidentModule.js (4)

190-209: Date range filtering logic looks correct.

The conditional logic properly handles the three status cases:

  • Active incidents: no date filter (always visible)
  • Resolved incidents: filter by endTime
  • All incidents: $or to combine both

The empty if block on lines 196-198 is intentional but could benefit from a brief inline comment explaining the no-op is deliberate.


218-259: Consider moving the $lookup after $facet to reduce memory usage.

The $lookup is performed on all matched documents before pagination. For large datasets, this could be inefficient since monitor details are fetched for documents that will be skipped.

However, given the $facet structure and the need to include monitorName in results, this approach is acceptable for the current use case. If performance becomes an issue with large incident volumes, consider restructuring the pipeline.


272-297: LGTM on counts pipeline structure.

The grouping by status with resolution type counting is correct and efficient as a single pass through the data.


404-418: Return structure is well-documented and comprehensive.

The summary object provides useful metrics for the UI. The rounding of avgResolutionTimeHours to 2 decimal places is appropriate.

server/src/service/v1/business/incidentService.js (1)

212-236: Clean implementation aligning with module changes.

The service correctly passes the limit parameter to the database module. Error handling and logging remain consistent with other methods.

client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)

8-18: Simple and reusable skeleton implementation.

The component correctly wraps SummaryCard with a rounded skeleton placeholder. The minHeight: "25vh" provides consistent sizing across loading states.

server/src/controllers/v1/incidentController.js (1)

73-110: Documentation accurately reflects the API changes.

The JSDoc updates properly document:

  • The new limit parameter with default value of 10
  • The comprehensive return object structure including totalActive, avgResolutionTimeHours, topMonitor, etc.
  • Updated example endpoint path
client/src/Routes/index.jsx (1)

32-33: LGTM! Route configuration is correct.

The new routes for Checks and Incidents2 are properly configured and follow the existing routing patterns in the application.

Also applies to: 133-140

client/src/Pages/v1/Incidents2/index.jsx (2)

60-76: Verify fetch function stability and consider adding to dependencies.

The useEffect calls fetchActiveIncidents, fetchResolvedIncidents, or fetchIncidents but doesn't include them in the dependency array. While this works if these functions remain stable, examining the useFetchIncidents hook reveals that these functions are not wrapped in useCallback, meaning they're recreated on every render.

This could lead to:

  1. ESLint warnings about missing dependencies
  2. Potential stale closure issues if the functions capture values that change

Consider either:

  • Adding these functions to the dependency array (requires memoizing them in the hook)
  • Using a ref to store the latest config and calling a stable fetch function

Review the useFetchIncidents hook implementation to confirm whether the fetch functions should be memoized with useCallback.


98-105: LGTM! Pagination handlers are correctly implemented.

The pagination logic properly resets the page to 0 when rowsPerPage changes, which is good UX practice and prevents edge cases where the new page count might be less than the current page.

client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/index.jsx (1)

26-50: LGTM! Summary fetching logic is well-structured.

The useEffect correctly handles loading states, errors, and data updates. The dependency array properly includes fetchIncidentSummary (which is memoized in the hook) and updateTrigger.

client/src/Pages/v1/Incidents2/Components/ActiveIncidentsPanel/index.jsx (1)

23-135: LGTM! Well-structured panel with clear state handling.

The component properly handles all UI states (loading, error, zero count, active incidents) with appropriate visual feedback and theming. The conditional rendering logic is clear and maintainable.

client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (1)

93-121: Remove the non-existent filled prop from MUI Button.

The filled prop is not part of Material-UI's Button component API. MUI Button uses the variant prop to control button styling (e.g., variant="contained" for filled buttons). The current implementation passes an invalid prop that will be ignored. Either remove the filled prop or use the correct MUI variant prop if you intend to change button styling based on the dateRange state.

Likely an incorrect or invalid review comment.

client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (5)

1-15: LGTM!

The imports are well-organized, grouped logically (components, then utils/libraries), and all are utilized within the component.


17-32: LGTM!

Component props are well-defined with sensible defaults, and the hooks (Redux selector, i18n, theme) are appropriately initialized.


149-157: LGTM!

The loading and network error states are handled correctly with appropriate early returns and fallback components.


167-184: LGTM!

The defensive array normalization and render logic are well-structured. The DataTable and Pagination components receive all necessary props correctly.


187-198: LGTM!

PropTypes validation is comprehensive and correctly marks required vs. optional props (e.g., networkError is appropriately optional).

Copy link

@llamapreview llamapreview bot left a comment

Choose a reason for hiding this comment

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

AI Code Review by LlamaPReview

🎯 TL;DR & Recommendation

Recommendation: Request Changes

This PR introduces a new incidents management system but has a critical UI inconsistency where the checks page displays incorrect titles, alongside several minor bugs and architectural coupling issues that could lead to silent failures or breakages.

📄 Documentation Diagram

This diagram documents the new incidents management workflow introduced in this PR.

sequenceDiagram
    participant U as User
    participant I as Incidents2 Component
    participant H as useFetchIncidents Hook
    participant B as Backend API
    U->>I: Navigate to /incidents
    I->>H: Fetch incidents summary and data
    H->>B: Call getIncidentSummary and getIncidentsByTeam
    B-->>H: Return incidents data
    H-->>I: Update state with data
    I->>I: Render summary panels and table
    note over I: PR #35;3086 added new summary panels
    I-->>U: Display incidents management interface
Loading

🌟 Strengths

  • Comprehensive feature addition with new summary panels, filtering, and table components.
  • Good use of hooks and modular design for incidents data fetching.
Priority File Category Impact Summary (≤12 words) Anchors
P1 client/src/Pages/v1/Incidents/index.jsx Architecture UI inconsistency: Checks page shows "Incidents" title incorrectly. path:Routes/index.jsx
P2 Pages/v1/Incidents2/index.jsx Bug State initialization could cause unexpected UI behavior with undefined filters. method:fetchIncidentsByTeam
P2 Pages/v1/Incidents2/hooks/useFetchIncidents.js Architecture Tight coupling with backend logic risks breakage on API changes. path:server/.../incidentModule.js
P2 Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx Bug NaN calculation for resolution percentages may hide data errors.
P2 Pages/v1/Incidents2/Components/IncidentTable/index.jsx Maintainability Unhandled promise rejection could lead to silent UI failures. method:resolveIncident

🔍 Notable Themes

  • State Management Fragility: Multiple findings highlight reliance on undefined values and implicit backend contracts, increasing maintenance risk.
  • Defensive Programming Gaps: Lack of null/undefined checks in calculations and error handling could obscure bugs in production.

📈 Risk Diagram

This diagram illustrates the risk of UI inconsistency due to incorrect translation keys after component renaming.

sequenceDiagram
    participant U as User
    participant R as Router
    participant C as Checks Component
    participant T as Translation Service
    U->>R: Navigate to /checks
    R->>C: Route to Checks component
    C->>T: Request translation for "incidentsPageTitle"
    T-->>C: Return "Incidents" (incorrect key)
    C->>C: Render with "Incidents" title
    note over C,T: R1(P1): UI inconsistency in page title
    C-->>U: Display page titled "Incidents" instead of "Checks"
Loading
⚠️ **Unanchored Suggestions (Manual Review Recommended)**

The following suggestions could not be precisely anchored to a specific line in the diff. This can happen if the code is outside the changed lines, has been significantly refactored, or if the suggestion is a general observation. Please review them carefully in the context of the full file.


📁 File: client/src/Pages/v1/Incidents/index.jsx

This file is being renamed from Incidents to Checks and its default export changed. The Routes/index.jsx file confirms the route /incidents now points to Incidents2, and /checks points to this (renamed) component. However, the component's internal breadcrumb and UI text still reference "Incidents" (via the t("incidentsPageTitle") key). The user will navigate to /checks but see a page titled "Incidents". This is a direct user-facing inconsistency and a breaking change for the UI/UX. The translation key usage must be updated to "checksPageTitle" as added to the locale file.

Suggestion:

const BREADCRUMBS = [{ name: t("checksPageTitle"), path: "/checks" }];

Related Code:

const Incidents = () => {
  // Redux state
  const { t } = useTranslation();

  const BREADCRUMBS = [
    { name: t("incidentsPageTitle", "Incidents"), path: "/incidents" },
  ];


💡 Have feedback? We'd love to hear it in our GitHub Discussions.
✨ This review was generated by LlamaPReview Advanced, which is free for all open-source projects. Learn more.

Comment on lines 26 to 30
const [selectedMonitor, setSelectedMonitor] = useState(undefined);
const [filter, setFilter] = useState(undefined);
const [dateRange, setDateRange] = useState("all");
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: High

The component initializes selectedMonitor and filter as undefined. However, the fetchIncidentsByTeam method (called in the effect) and the backend's getIncidentsByTeam function treat undefined values differently from explicit "all" filters. The backend expects monitorId: undefined and status: undefined to mean "no filter". While this works, it creates a hidden dependency on default behavior that could break if the backend logic changes. More importantly, the OptionsHeader component passes these values to child components without null-checking undefined, which could lead to unexpected UI behavior (like displaying "undefined" in dropdowns).

Suggested change
const [selectedMonitor, setSelectedMonitor] = useState(undefined);
const [filter, setFilter] = useState(undefined);
const [dateRange, setDateRange] = useState("all");
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [selectedMonitor, setSelectedMonitor] = useState("0"); // "0" represents "all monitors"
const [filter, setFilter] = useState("all");

Evidence: method:fetchIncidentsByTeam, method:getIncidentsByTeam

} catch (error) {
setNetworkError(true);
console.error(t("incidentsPage.errorFetchingIncidents"), error);
createToast({ body: error.message || t("incidentsPage.errorFetchingIncidents") });
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: High

The hook's fetchIncidentsByTeam directly passes the config object to networkService.getIncidentsByTeam. The related context shows the backend's getIncidentsByTeam method in incidentModule.js has complex, conditional date-range logic that differs for active vs. resolved vs. "all" incidents. The frontend's config object includes dateRange and status (via filter). If the status is undefined (representing "all"), the backend's logic applies an $or clause. This creates a tight, undocumented coupling between the frontend's state representation (undefined for "all") and the backend's aggregation pipeline. Changing one side without the other will break filtering. This is a high-risk architectural pattern for a core data-fetching hook.

Comment on lines 36 to 41
const totalResolutions =
summary?.totalManualResolutions + summary?.totalAutomaticResolutions;
const automaticPercentage =
totalResolutions > 0
? (summary?.totalAutomaticResolutions / totalResolutions) * 100
: 0;
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: High

The calculation for totalResolutions directly adds two potentially undefined values from the summary object. If either totalManualResolutions or totalAutomaticResolutions is undefined, the addition will result in NaN (e.g., undefined + 5 = NaN). This will cause totalResolutions to be NaN, making the condition totalResolutions > 0 evaluate to false, and automaticPercentage will be set to 0, hiding the calculation error. The UI may show a 0% bar incorrectly. The backend's getIncidentSummary method should always return numbers, but defensive programming is required.

Suggested change
const totalResolutions =
summary?.totalManualResolutions + summary?.totalAutomaticResolutions;
const automaticPercentage =
totalResolutions > 0
? (summary?.totalAutomaticResolutions / totalResolutions) * 100
: 0;
const manual = summary?.totalManualResolutions || 0;
const auto = summary?.totalAutomaticResolutions || 0;
const totalResolutions = manual + auto;
const automaticPercentage = totalResolutions > 0 ? (auto / totalResolutions) * 100 : 0;

Comment on lines 34 to 37
const handleResolveIncident = async (incidentId) => {
await resolveIncident(incidentId);
handleUpdateTrigger();
};
Copy link

Choose a reason for hiding this comment

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

P2 | Confidence: Medium

The resolveIncident function from the hook returns a Promise, but the handleResolveIncident function does not handle potential rejection (network errors, server errors). The resolveIncident hook method already shows a toast on error, so the UI feedback exists. However, the await without a try/catch means an unhandled promise rejection will occur in the React component if the hook's error handling fails or throws. This is a minor maintainability and robustness issue. It's better to wrap the call and silently catch or explicitly handle the error at the call site.

Code Suggestion:

const handleResolveIncident = async (incidentId) => {
  try {
    await resolveIncident(incidentId);
    handleUpdateTrigger();
  } catch (error) {
    // Error is already handled by resolveIncident hook's toast.
    // Optional: Log for debugging.
    console.debug('Incident resolution failed silently at UI layer:', error);
  }
};

Evidence: method:resolveIncident, path:client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js

Copy link

@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.

Actionable comments posted: 5

♻️ Duplicate comments (1)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)

42-58: Add t to the dependency array.

The fetchIncidentsByTeam function uses t from useTranslation (line 53-54) but omits it from the dependency array. When the user changes language, the callback won't update, resulting in stale error messages.

🔎 Apply this diff to fix the dependency array:
-	}, []);
+	}, [t]);
🧹 Nitpick comments (3)
server/src/db/v1/modules/incidentModule.js (2)

169-200: Documentation is thorough but verbose.

The extensive documentation explaining the status parameter contract is helpful for maintainability. However, it could be more concise while still conveying the essential information. Consider reducing the WARNING section and consolidating the parameter descriptions.


305-457: Consider consolidating aggregation pipelines for better performance.

The method executes 4 separate aggregation queries against the incidents collection. While functionally correct, this could impact performance with large datasets. Consider using MongoDB's $facet operator to combine related pipelines (e.g., counts and resolution time) into a single aggregation.

Note: Line 410 properly validates the limit parameter with Math.max(1, parseInt(limit) || 10), which addresses the previous review comment about validating limit input.

Example consolidation approach
const summaryPipeline = [
  { $match: matchStage },
  {
    $facet: {
      counts: [
        {
          $group: {
            _id: "$status",
            count: { $sum: 1 },
            manualResolutions: { $sum: { $cond: [{ $eq: ["$resolutionType", "manual"] }, 1, 0] } },
            automaticResolutions: { $sum: { $cond: [{ $eq: ["$resolutionType", "automatic"] }, 1, 0] } }
          }
        }
      ],
      resolutionTime: [
        { $match: { status: false, endTime: { $exists: true, $ne: null } } },
        {
          $group: {
            _id: null,
            avgResolutionTime: { $avg: { $subtract: ["$endTime", "$startTime"] } }
          }
        }
      ],
      topMonitor: [
        { $group: { _id: "$monitorId", count: { $sum: 1 } } },
        { $sort: { count: -1 } },
        { $limit: 1 },
        // ... lookup and project
      ],
      latestIncidents: [
        { $sort: { createdAt: -1 } },
        { $limit: Math.max(1, parseInt(limit) || 10) },
        // ... lookup and project
      ]
    }
  }
];

This reduces database round-trips from 4 to 1.

client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (1)

228-232: Consider using PropTypes.shape for better type safety.

The summary and error props use generic PropTypes.object, which doesn't provide detailed validation. Consider using PropTypes.shape() to document and validate the expected structure, especially for summary which has multiple accessed properties.

🔎 Example with more specific PropTypes:
 StatisticsPanel.propTypes = {
-  summary: PropTypes.object,
+  summary: PropTypes.shape({
+    total: PropTypes.number,
+    avgResolutionTimeHours: PropTypes.number,
+    topMonitor: PropTypes.shape({
+      monitorName: PropTypes.string,
+    }),
+    totalManualResolutions: PropTypes.number,
+    totalAutomaticResolutions: PropTypes.number,
+  }),
   isLoading: PropTypes.bool,
   error: PropTypes.object,
 };
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75acb1a and 9555ff4.

📒 Files selected for processing (7)
  • client/src/Components/v1/GenericFallback/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (1 hunks)
  • client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1 hunks)
  • client/src/Pages/v1/Incidents2/index.jsx (1 hunks)
  • client/src/locales/en.json (5 hunks)
  • server/src/db/v1/modules/incidentModule.js (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/src/locales/en.json
  • client/src/Pages/v1/Incidents2/index.jsx
🧰 Additional context used
🧬 Code graph analysis (4)
client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (3)
client/src/Components/v1/GenericFallback/index.jsx (2)
  • theme (15-15)
  • GenericFallback (14-83)
client/src/Components/v1/Label/index.jsx (1)
  • StatusLabel (135-156)
client/src/Utils/timeUtils.js (1)
  • formattedDate (135-135)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)
client/src/Utils/NetworkService.js (1)
  • networkService (1187-1187)
server/src/db/v1/modules/incidentModule.js (4)
client/src/Pages/v1/Incidents2/index.jsx (3)
  • dateRange (28-28)
  • page (29-29)
  • rowsPerPage (30-30)
client/src/Pages/v1/Incidents/index.jsx (1)
  • dateRange (30-30)
server/src/db/v1/modules/monitorModuleQueries.js (1)
  • matchStage (1089-1089)
client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js (1)
  • incidents (25-25)
client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx (7)
client/src/Components/v1/GenericFallback/index.jsx (1)
  • theme (15-15)
client/src/Pages/v1/Incidents/index.jsx (3)
  • theme (38-38)
  • useTranslation (23-23)
  • summary (40-42)
client/src/Components/v1/Sidebar/index.jsx (2)
  • theme (83-83)
  • useTranslation (84-84)
client/src/Pages/v1/Incidents2/Components/LatestIncidentsPanel/index.jsx (2)
  • theme (21-21)
  • useTranslation (22-22)
client/src/Pages/v1/Incidents2/Components/SummaryCard/index.jsx (2)
  • theme (6-6)
  • SummaryCard (5-61)
client/src/Pages/v1/Incidents2/Components/OptionsHeader/index.jsx (2)
  • theme (20-20)
  • useTranslation (21-21)
client/src/Pages/v1/Incidents2/Components/IncidentsSummaryPanel/skeleton.jsx (1)
  • PanelSkeleton (8-18)
🔇 Additional comments (6)
client/src/Components/v1/GenericFallback/index.jsx (1)

49-49: LGTM! Correct use of MUI styling.

Moving the background color styling into the sx prop is the proper approach for MUI components, and explicitly setting backgroundColor: "transparent" ensures the GIF's transparency is preserved.

server/src/db/v1/modules/incidentModule.js (2)

226-242: Date range filtering logic is correct.

The conditional date filtering with $or logic for the "all incidents" case (when statusBoolean === undefined) correctly handles the three scenarios:

  • Active incidents: no date filter (they're ongoing)
  • Resolved incidents: filter by endTime
  • All incidents: show active + resolved within range

The MongoDB query structure properly ANDs the $or clause with other filters in matchStage.


251-291: Monitor lookup and projection implementation is solid.

The $lookup stage joins the monitors collection, and the $map projection correctly extracts monitorName using $mergeObjects. While the nested structure is complex, it handles the array unpacking and null cases properly.

client/src/Pages/v1/Incidents2/Components/IncidentTable/index.jsx (3)

34-41: LGTM! Error handling now prevents UI inconsistency.

The handleResolveIncident function now properly wraps the API call in try-catch and only triggers the UI update on success. This addresses the past review concern about the UI refreshing even when the resolution fails.


163-169: LGTM! Empty state check now works correctly.

The empty state logic now properly checks incidents?.length === 0 instead of the previous incidents == undefined, which correctly displays the "No incidents found" message when there are zero incidents.


43-151: Well-structured table headers with proper fallbacks.

The headers array is comprehensive with appropriate render functions for each column. All render functions include proper fallbacks (e.g., "N/A", "-") for missing data, which prevents UI errors.

Comment on lines +13 to +32
/**
* StatisticsPanel Component
*
* Displays key metrics and statistics about incidents.
*
* @param {Object} props
* @param {Object} props.statistics - Statistics data object
* @param {number} props.statistics.total - Total incidents count
* @param {number} props.statistics.totalTrend - Trend percentage for total (optional)
* @param {string} props.statistics.mttr - Mean Time To Resolve (formatted string, e.g., "2h 15m")
* @param {number} props.statistics.mttrTrend - Trend percentage for MTTR (optional)
* @param {Object} props.statistics.topMonitor - Top monitor with most incidents
* @param {string} props.statistics.topMonitor.name - Monitor name
* @param {number} props.statistics.topMonitor.count - Incident count
* @param {number} props.statistics.topMonitor.percentage - Percentage of total
* @param {string} props.statistics.uptimeAffected - Total downtime (formatted string, e.g., "12h 45m")
* @param {number} props.statistics.availability - Availability percentage
* @param {boolean} props.isLoading - Loading state
* @param {Object} props.error - Error object if any
*/
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update JSDoc to match actual prop structure.

The JSDoc documents a statistics prop, but the component actually receives a summary prop (line 33). Additionally, the documented properties don't match the actual structure used in the render logic (e.g., mttr, totalTrend, uptimeAffected, availability are documented but never used; actual properties like avgResolutionTimeHours, totalManualResolutions, totalAutomaticResolutions are used but not documented).

🔎 Apply this diff to correct the JSDoc:
 /**
  * StatisticsPanel Component
  *
  * Displays key metrics and statistics about incidents.
  *
  * @param {Object} props
- * @param {Object} props.statistics - Statistics data object
- * @param {number} props.statistics.total - Total incidents count
- * @param {number} props.statistics.totalTrend - Trend percentage for total (optional)
- * @param {string} props.statistics.mttr - Mean Time To Resolve (formatted string, e.g., "2h 15m")
- * @param {number} props.statistics.mttrTrend - Trend percentage for MTTR (optional)
- * @param {Object} props.statistics.topMonitor - Top monitor with most incidents
- * @param {string} props.statistics.topMonitor.name - Monitor name
- * @param {number} props.statistics.topMonitor.count - Incident count
- * @param {number} props.statistics.topMonitor.percentage - Percentage of total
- * @param {string} props.statistics.uptimeAffected - Total downtime (formatted string, e.g., "12h 45m")
- * @param {number} props.statistics.availability - Availability percentage
+ * @param {Object} props.summary - Summary data object
+ * @param {number} props.summary.total - Total incidents count
+ * @param {number} props.summary.avgResolutionTimeHours - Average resolution time in hours
+ * @param {Object} props.summary.topMonitor - Top monitor with most incidents
+ * @param {string} props.summary.topMonitor.monitorName - Monitor name
+ * @param {number} props.summary.totalManualResolutions - Count of manual resolutions
+ * @param {number} props.summary.totalAutomaticResolutions - Count of automatic resolutions
  * @param {boolean} props.isLoading - Loading state
  * @param {Object} props.error - Error object if any
  */
🤖 Prompt for AI Agents
In client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx around
lines 13 to 32, the JSDoc currently documents a statistics prop that does not
match the component which actually receives a summary prop and different fields;
update the JSDoc to reference props.summary (not props.statistics) and document
the real fields used by the component (e.g., summary.total,
summary.avgResolutionTimeHours, summary.totalManualResolutions,
summary.totalAutomaticResolutions, summary.topMonitor { name, count, percentage
}, plus props.isLoading and props.error), remove the unused/incorrect entries
(mttr, totalTrend, uptimeAffected, availability, etc.), and ensure each field
has a brief type and description matching how the component reads them.

Comment on lines +38 to +41
const automaticPercentage =
totalResolutions > 0
? (summary?.totalAutomaticResolutions / totalResolutions) * 100
: 0;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use nullish-coalesced value for consistency in percentage calculation.

Line 40 uses summary?.totalAutomaticResolutions directly, but this could be undefined, resulting in NaN for automaticPercentage. For consistency with the totalResolutions calculation (lines 36-37), use a nullish-coalesced value.

🔎 Apply this diff to fix the inconsistency:
 const totalResolutions =
   (summary?.totalManualResolutions || 0) + (summary?.totalAutomaticResolutions || 0);
 const automaticPercentage =
   totalResolutions > 0
-    ? (summary?.totalAutomaticResolutions / totalResolutions) * 100
+    ? ((summary?.totalAutomaticResolutions || 0) / totalResolutions) * 100
     : 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const automaticPercentage =
totalResolutions > 0
? (summary?.totalAutomaticResolutions / totalResolutions) * 100
: 0;
const totalResolutions =
(summary?.totalManualResolutions || 0) + (summary?.totalAutomaticResolutions || 0);
const automaticPercentage =
totalResolutions > 0
? ((summary?.totalAutomaticResolutions || 0) / totalResolutions) * 100
: 0;
🤖 Prompt for AI Agents
In client/src/Pages/v1/Incidents2/Components/StatisticsPanel/index.jsx around
lines 38 to 41, the percentage calculation uses
summary?.totalAutomaticResolutions which can be undefined and lead to NaN;
change the numerator to use a nullish-coalesced value (e.g.
summary?.totalAutomaticResolutions ?? 0) so the expression becomes safe and
consistent with the totalResolutions calculation, keeping the existing guard
(totalResolutions > 0) and percentage math unchanged.

Comment on lines +110 to +130
const fetchIncidentById = useCallback(async (incidentId) => {
if (!incidentId) {
console.error(t("incidentsPage.noIncidentIdProvided"));
return null;
}

try {
setIsLoading(true);
setNetworkError(false);

const res = await networkService.getIncidentById(incidentId);
return res.data?.data || null;
} catch (error) {
setNetworkError(true);
console.error(t("incidentsPage.errorFetchingIncident"), error);
createToast({ body: error.message || t("incidentsPage.errorFetchingIncident") });
return null;
} finally {
setIsLoading(false);
}
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add t to the dependency array.

The fetchIncidentById function uses t from useTranslation (lines 112, 124, 125) but omits it from the dependency array. This can cause stale translations after language changes.

🔎 Apply this diff to fix the dependency array:
-	}, []);
+	}, [t]);
🤖 Prompt for AI Agents
In client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js around lines 110 to
130, the fetchIncidentById callback references the translation function t but
does not include it in the dependency array; update the useCallback dependency
array to include t so the function is recreated when translations change (i.e.,
change the final [] to [t]).

Comment on lines +141 to +168
const resolveIncident = useCallback(async (incidentId, options = {}) => {
if (!incidentId) {
console.error(t("incidentsPage.noIncidentIdProvided"));
return;
}

try {
setIsLoading(true);
setNetworkError(false);

const res = await networkService.resolveIncidentManually(incidentId, options);
if (res.data?.success) {
createToast({ body: t("incidentsPage.incidentResolvedSuccessfully") });
} else {
createToast({ body: t("incidentsPage.errorResolvingIncident") });
}
} catch (error) {
setNetworkError(true);
console.error(t("incidentsPage.errorResolvingIncident"), error);
const errorMessage =
error.response?.data?.message ||
error.message ||
t("incidentsPage.errorResolvingIncident");
createToast({ body: errorMessage });
} finally {
setIsLoading(false);
}
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add t to the dependency array.

The resolveIncident function uses t from useTranslation (lines 143, 153, 155, 159, 163) but omits it from the dependency array. Without this, translated strings won't update when the user switches languages.

🔎 Apply this diff to fix the dependency array:
-	}, []);
+	}, [t]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resolveIncident = useCallback(async (incidentId, options = {}) => {
if (!incidentId) {
console.error(t("incidentsPage.noIncidentIdProvided"));
return;
}
try {
setIsLoading(true);
setNetworkError(false);
const res = await networkService.resolveIncidentManually(incidentId, options);
if (res.data?.success) {
createToast({ body: t("incidentsPage.incidentResolvedSuccessfully") });
} else {
createToast({ body: t("incidentsPage.errorResolvingIncident") });
}
} catch (error) {
setNetworkError(true);
console.error(t("incidentsPage.errorResolvingIncident"), error);
const errorMessage =
error.response?.data?.message ||
error.message ||
t("incidentsPage.errorResolvingIncident");
createToast({ body: errorMessage });
} finally {
setIsLoading(false);
}
}, []);
const resolveIncident = useCallback(async (incidentId, options = {}) => {
if (!incidentId) {
console.error(t("incidentsPage.noIncidentIdProvided"));
return;
}
try {
setIsLoading(true);
setNetworkError(false);
const res = await networkService.resolveIncidentManually(incidentId, options);
if (res.data?.success) {
createToast({ body: t("incidentsPage.incidentResolvedSuccessfully") });
} else {
createToast({ body: t("incidentsPage.errorResolvingIncident") });
}
} catch (error) {
setNetworkError(true);
console.error(t("incidentsPage.errorResolvingIncident"), error);
const errorMessage =
error.response?.data?.message ||
error.message ||
t("incidentsPage.errorResolvingIncident");
createToast({ body: errorMessage });
} finally {
setIsLoading(false);
}
}, [t]);
🤖 Prompt for AI Agents
In client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js around lines 141 to
168, the useCallback for resolveIncident references the translation function t
but omits it from the dependency array; update the dependency array to include t
so translations update when the language changes (ensure you add t to the array
while keeping other necessary dependencies as appropriate).

Comment on lines +177 to +188
const fetchIncidentSummary = useCallback(async (config = {}) => {
try {
const res = await networkService.getIncidentSummary(config);
return res.data?.data || null;
} catch (error) {
console.error(t("incidentsPage.errorFetchingIncidentSummary"), error);
createToast({
body: error.message || t("incidentsPage.errorFetchingIncidentSummary"),
});
return null;
}
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add t to the dependency array.

The fetchIncidentSummary function uses t from useTranslation (lines 182, 184) but omits it from the dependency array. This will prevent error messages from updating when the language changes.

🔎 Apply this diff to fix the dependency array:
-	}, []);
+	}, [t]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fetchIncidentSummary = useCallback(async (config = {}) => {
try {
const res = await networkService.getIncidentSummary(config);
return res.data?.data || null;
} catch (error) {
console.error(t("incidentsPage.errorFetchingIncidentSummary"), error);
createToast({
body: error.message || t("incidentsPage.errorFetchingIncidentSummary"),
});
return null;
}
}, []);
const fetchIncidentSummary = useCallback(async (config = {}) => {
try {
const res = await networkService.getIncidentSummary(config);
return res.data?.data || null;
} catch (error) {
console.error(t("incidentsPage.errorFetchingIncidentSummary"), error);
createToast({
body: error.message || t("incidentsPage.errorFetchingIncidentSummary"),
});
return null;
}
}, [t]);
🤖 Prompt for AI Agents
In client/src/Pages/v1/Incidents2/hooks/useFetchIncidents.js around lines 177 to
188, the useCallback for fetchIncidentSummary captures the translation function
t but does not include it in the dependency array; update the hook's dependency
array to include t (e.g., change [] to [t]) so the callback is recreated when
the translation function changes and error messages reflect language updates.

@ajhollid ajhollid merged commit 14768bd into develop Dec 18, 2025
8 checks passed
@ajhollid ajhollid deleted the fix-incidents-duplication-front-end branch December 18, 2025 18:51
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.

Successive failed pings are counted as separate incidents

3 participants