refactor: reduce cognitive complexity - web batch 2#394
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughSmall formatting change in analytics-dashboard and refactors in HealthCards and PerformanceDashboard: HealthCards gains MetricCard, ProgressBar, and metric/computation helpers; PerformanceDashboard extracts error/series/histogram builders and centralizes error message extraction. No public API/signature changes. Changes
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
|
🚅 Deployed to the volvox-bot-pr-394 environment in volvox-bot
|
|
| Filename | Overview |
|---|---|
| web/src/components/dashboard/health-cards.tsx | Extracts MetricCard, ProgressBar, computeHeapMetrics, computeCpuMetrics, formatErrorValue, and errorValueColor helpers — behavior-preserving refactor with one minor type inconsistency (cpuPct returned as string) |
| web/src/components/dashboard/performance-dashboard.tsx | Extracts extractErrorMessage, buildMemChartData, buildCpuChartData, and buildRtHistogram helpers from the main component body — clean, behavior-preserving refactor with no issues |
| web/src/components/dashboard/analytics-dashboard.tsx | Only change is a single blank line added between the RANGE_PRESETS constant and the AnalyticsDashboard export — no logic changes |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
HC[HealthCards] --> MC[MetricCard\nreusable card wrapper]
HC --> PB[ProgressBar\nshared progress bar]
HC --> CHM[computeHeapMetrics\nheap MB + %]
HC --> CCM[computeCpuMetrics\nuser/sys sec + %]
HC --> FEV[formatErrorValue\nnull-safe toLocaleString]
HC --> EVC[errorValueColor\nnull-safe errorColor]
PD[PerformanceDashboard] --> EEM[extractErrorMessage\nparse JSON error body]
PD --> BMC[buildMemChartData\nheap + RSS series]
PD --> BCC[buildCpuChartData\nCPU series]
PD --> BRH[buildRtHistogram\n500ms buckets]
AD[AnalyticsDashboard] -->|blank line only| AD2[No logic change]
Prompt To Fix All With AI
This is a comment left during a code review.
Path: web/src/components/dashboard/health-cards.tsx
Line: 103-104
Comment:
**`cpuPct` returned as `string`, forcing a `Number()` round-trip at call site**
`computeCpuMetrics` returns `cpuPct` as a `string` (via `.toFixed(1)`), which makes the return type `{ cpuUserSec: number; cpuSystemSec: number; cpuPct: string }`. This forces the caller to convert it back to a number with `Number(cpu.cpuPct)` when passing to `ProgressBar` (line 216). Returning `cpuPct` as a raw `number` and formatting it at display time is cleaner and avoids the implicit type mismatch:
```suggestion
const cpuPct = Math.min(Math.max(rawPct, 0), 100);
return { cpuUserSec, cpuSystemSec, cpuPct };
```
Then the display value becomes `` `${cpu.cpuPct.toFixed(1)}%` `` and the `ProgressBar` call simply uses `cpu.cpuPct` directly.
How can I resolve this? If you propose a fix, please make it concise.Reviews (3): Last reviewed commit: "style: fix Biome lint formatting" | Re-trigger Greptile
There was a problem hiding this comment.
Pull request overview
Refactors several Next.js dashboard components to reduce SonarCloud cognitive complexity while keeping behavior the same by extracting repeated logic into small helpers/components.
Changes:
- Extracted helper functions in
performance-dashboard.tsxfor error parsing and derived chart data building. - Extracted reusable card/presentation helpers in
health-cards.tsxto simplify KPI rendering. - Extracted KPI rendering helpers in
analytics-dashboard.tsx(card item, delta display, nullable metric formatting).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| web/src/components/dashboard/performance-dashboard.tsx | Extracts error/derived-data helper functions to simplify the main component logic. |
| web/src/components/dashboard/health-cards.tsx | Introduces MetricCard/ProgressBar and metric computation helpers to reduce repeated JSX/logic. |
| web/src/components/dashboard/analytics-dashboard.tsx | Extracts KPI card rendering + delta helpers and centralizes nullable metric formatting. |
| const heapUsedMb = health.memory.heapUsed / 1_048_576; | ||
| const heapTotalMb = health.memory.heapTotal / 1_048_576; | ||
| const heapPct = heapTotalMb > 0 ? (heapUsedMb / heapTotalMb) * 100 : 0; | ||
| return { heapUsedMb, heapTotalMb, heapPct }; |
There was a problem hiding this comment.
computeHeapMetrics() returns heapUsedMb and heapTotalMb, but those properties aren’t used anywhere in this component (only heapPct is). Consider returning only the values that are actually consumed, or use the extra fields in the UI to avoid carrying dead code in this refactor.
| return { heapUsedMb, heapTotalMb, heapPct }; | |
| return { heapPct }; |
| const cpuSystemSec = health.system.cpuUsage.system / 1_000_000; | ||
| const cpuTotalSec = cpuUserSec + cpuSystemSec; | ||
| const rawPct = health.uptime > 0 ? (cpuTotalSec / health.uptime) * 100 : 0; | ||
| const cpuPct = Math.min(Math.max(rawPct, 0), 100).toFixed(1); |
There was a problem hiding this comment.
computeCpuMetrics() formats cpuPct with toFixed(), which makes it a string, but later it needs to be converted back to a number for the progress bar (Number(cpu.cpuPct)). Returning cpuPct as a number (and formatting only at render time) would avoid this string↔number churn and keep the data shape consistent.
| const cpuPct = Math.min(Math.max(rawPct, 0), 100).toFixed(1); | |
| const cpuPct = Math.min(Math.max(rawPct, 0), 100); |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| return String((json as Record<string, unknown>).error); | ||
| } | ||
| return fallback; | ||
| } |
There was a problem hiding this comment.
Duplicated extractErrorMessage utility across two files
Low Severity
The newly extracted extractErrorMessage function in performance-dashboard.tsx duplicates an existing extractErrorMessage in moderation-store.ts with the same name, signature, and near-identical logic. Extracting inline code into a named function is the ideal moment to consolidate into a shared utility instead of creating a second copy.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/components/dashboard/analytics-dashboard.tsx`:
- Around line 133-146: Mark the props objects as readonly to indicate
immutability: update DeltaIcon's props signature from ({ delta }: { delta:
number | null }) to use a readonly property (e.g., { readonly delta: number |
null }) and update KpiCardItem's props type so each field is readonly (e.g., {
readonly card: KpiCard; readonly analytics: DashboardAnalytics | null; readonly
compareMode: boolean }). This keeps intent explicit and resolves the Sonar
warning for both DeltaIcon and KpiCardItem.
In `@web/src/components/dashboard/health-cards.tsx`:
- Around line 57-62: Make the props interfaces immutable by marking their
properties readonly: update MetricCardProps and ProgressBarProps so every field
(e.g., title, icon, iconBg, children in MetricCardProps and whatever fields
exist in ProgressBarProps) are declared readonly to satisfy the immutability
contract and silence Sonar warnings; locate the interface declarations in
web/src/components/dashboard/health-cards.tsx (MetricCardProps and
ProgressBarProps) and change each property to readonly while keeping types
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5381cf96-9082-45d4-a882-b7d973016507
📒 Files selected for processing (3)
web/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsxweb/src/components/dashboard/performance-dashboard.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Greptile Review
- GitHub Check: Cursor Bugbot
- GitHub Check: Lint
- GitHub Check: E2E Tests (1/2)
- GitHub Check: E2E Tests (2/2)
- GitHub Check: Test
- GitHub Check: Docker Build Validation
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{js,ts,tsx}: Use single quotes for strings (except in JSON files); no double quotes
Always include semicolons at the end of statements
Use 2-space indentation (spaces, not tabs)
Always include trailing commas in multi-line arrays, objects, and function parameters
Maintain a maximum line width of 100 characters
Files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use
console.*methods in web dashboard code; use appropriate logging mechanisms for React applications
Files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: ESM only - do not use CommonJS modules
Use src/logger.js; do not use console.*
Files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/tests/**/*.test.{ts,tsx} : Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
📚 Learning: 2026-03-11T06:42:38.728Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T06:42:38.728Z
Learning: Applies to web/src/pages/dashboard/**/*.{ts,tsx} : Use shared title helpers from web/src/lib/page-titles.ts for setting browser titles in dashboard pages
Applied to files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
📚 Learning: 2026-03-11T05:32:46.325Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-11T05:32:46.325Z
Learning: Applies to web/src/app/**/*.{ts,tsx} : Apply static metadata to server-rendered dashboard entry pages and use title template format for root app metadata
Applied to files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/src/app/dashboard/**/*.tsx : For dashboard routes, add a matcher entry to `dashboardTitleMatchers` in `web/src/lib/page-titles.ts`: use exact equality for leaf routes (`pathname === '/dashboard/my-route'`) and subtree checks (`pathname.startsWith('/dashboard/my-route/')`); export `metadata` using `createPageMetadata(title)` for SSR entry points
Applied to files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsxweb/src/components/dashboard/health-cards.tsx
📚 Learning: 2026-03-26T00:04:14.673Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-26T00:04:14.673Z
Learning: Applies to {web/src/lib/page-titles.ts,web/src/**/+page.ts,web/src/**/+page.svelte} : New dashboard routes need title wiring in web/src/lib/page-titles.ts: use createPageMetadata() for SSR and keep DashboardTitleSync aligned for client navigation.
Applied to files:
web/src/components/dashboard/performance-dashboard.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/tests/**/*.test.{ts,tsx} : Maintain test coverage thresholds of 85% across all metrics (statements, branches, functions, lines) for web dashboard tests
Applied to files:
web/src/components/dashboard/performance-dashboard.tsx
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to web/src/components/layout/dashboard-shell.tsx : Dashboard page titles should sync with route changes using DashboardTitleSync component mounted in dashboard-shell.tsx and canonical title string 'Volvox.Bot - AI Powered Discord Bot'
Applied to files:
web/src/components/dashboard/performance-dashboard.tsxweb/src/components/dashboard/analytics-dashboard.tsx
📚 Learning: 2026-03-12T02:03:36.493Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-12T02:03:36.493Z
Learning: Applies to web/src/**/*.{ts,tsx} : Never use `console.*` methods in web dashboard code; use appropriate logging mechanisms for React applications
Applied to files:
web/src/components/dashboard/performance-dashboard.tsx
📚 Learning: 2026-03-10T23:21:49.730Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-10T23:21:49.730Z
Learning: Applies to web/src/components/dashboard/config-workspace/**/*.{ts,tsx} : Web dashboard config editor should use category workspace navigation with reusable SettingsFeatureCard pattern (header + master toggle + Basic/Advanced blocks)
Applied to files:
web/src/components/dashboard/health-cards.tsx
🪛 GitHub Check: SonarCloud Code Analysis
web/src/components/dashboard/analytics-dashboard.tsx
[warning] 138-146: Mark the props of the component as read-only.
[warning] 133-133: Mark the props of the component as read-only.
web/src/components/dashboard/health-cards.tsx
[warning] 80-80: Mark the props of the component as read-only.
[warning] 64-64: Mark the props of the component as read-only.
[warning] 112-112: Unexpected negated condition.
🔇 Additional comments (4)
web/src/components/dashboard/performance-dashboard.tsx (2)
123-162: Helper extraction is clean and behavior-preserving.The extracted error/message and chart-data helpers keep logic equivalent while reducing cognitive complexity and duplication.
195-196: Call-site integration looks correct.Using the new helpers in fetch/save error handling and derived chart data wiring is consistent and improves maintainability.
Also applies to: 239-240, 257-259
web/src/components/dashboard/analytics-dashboard.tsx (1)
109-113: Nice refactor on KPI/realtime rendering.
formatNullableMetricplusKpiCardItemkeeps display logic consistent and reduces repeated conditional branches without changing output behavior.Also applies to: 607-614, 638-655
web/src/components/dashboard/health-cards.tsx (1)
91-113: Refactor quality is solid here.The extracted metric/error helpers and shared card primitives reduce duplication and keep the health KPI rendering straightforward.
Also applies to: 126-229
| function DeltaIcon({ delta }: { delta: number | null }) { | ||
| if (delta === null || delta === 0) return <Minus className="h-3 w-3" />; | ||
| return delta > 0 ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />; | ||
| } | ||
|
|
||
| function KpiCardItem({ | ||
| card, | ||
| analytics, | ||
| compareMode, | ||
| }: { | ||
| card: KpiCard; | ||
| analytics: DashboardAnalytics | null; | ||
| compareMode: boolean; | ||
| }) { |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Mark component props as readonly.
DeltaIcon and KpiCardItem props are immutable by design; marking them readonly will satisfy the Sonar warning and tighten intent.
♻️ Suggested update
-function DeltaIcon({ delta }: { delta: number | null }) {
+function DeltaIcon({ delta }: Readonly<{ delta: number | null }>) {
if (delta === null || delta === 0) return <Minus className="h-3 w-3" />;
return delta > 0 ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />;
}
+type KpiCardItemProps = Readonly<{
+ card: KpiCard;
+ analytics: DashboardAnalytics | null;
+ compareMode: boolean;
+}>;
+
function KpiCardItem({
card,
analytics,
compareMode,
-}: {
- card: KpiCard;
- analytics: DashboardAnalytics | null;
- compareMode: boolean;
-}) {
+}: KpiCardItemProps) {📝 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.
| function DeltaIcon({ delta }: { delta: number | null }) { | |
| if (delta === null || delta === 0) return <Minus className="h-3 w-3" />; | |
| return delta > 0 ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />; | |
| } | |
| function KpiCardItem({ | |
| card, | |
| analytics, | |
| compareMode, | |
| }: { | |
| card: KpiCard; | |
| analytics: DashboardAnalytics | null; | |
| compareMode: boolean; | |
| }) { | |
| function DeltaIcon({ delta }: Readonly<{ delta: number | null }>) { | |
| if (delta === null || delta === 0) return <Minus className="h-3 w-3" />; | |
| return delta > 0 ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />; | |
| } | |
| type KpiCardItemProps = Readonly<{ | |
| card: KpiCard; | |
| analytics: DashboardAnalytics | null; | |
| compareMode: boolean; | |
| }>; | |
| function KpiCardItem({ | |
| card, | |
| analytics, | |
| compareMode, | |
| }: KpiCardItemProps) { |
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis
[warning] 138-146: Mark the props of the component as read-only.
[warning] 133-133: Mark the props of the component as read-only.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/dashboard/analytics-dashboard.tsx` around lines 133 - 146,
Mark the props objects as readonly to indicate immutability: update DeltaIcon's
props signature from ({ delta }: { delta: number | null }) to use a readonly
property (e.g., { readonly delta: number | null }) and update KpiCardItem's
props type so each field is readonly (e.g., { readonly card: KpiCard; readonly
analytics: DashboardAnalytics | null; readonly compareMode: boolean }). This
keeps intent explicit and resolves the Sonar warning for both DeltaIcon and
KpiCardItem.
| interface MetricCardProps { | ||
| title: string; | ||
| icon: React.ReactNode; | ||
| iconBg: string; | ||
| children: React.ReactNode; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Use readonly props for extracted components.
MetricCard and ProgressBar props should be readonly to match the immutability contract and clear the Sonar warnings.
♻️ Suggested update
-interface MetricCardProps {
+interface MetricCardProps {
title: string;
icon: React.ReactNode;
iconBg: string;
children: React.ReactNode;
}
-function MetricCard({ title, icon, iconBg, children }: MetricCardProps) {
+function MetricCard({ title, icon, iconBg, children }: Readonly<MetricCardProps>) {
return (
<Card className="kpi-card rounded-2xl">
@@
-function ProgressBar({ percent }: { percent: number }) {
+function ProgressBar({ percent }: Readonly<{ percent: number }>) {
return (Also applies to: 64-80
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/dashboard/health-cards.tsx` around lines 57 - 62, Make the
props interfaces immutable by marking their properties readonly: update
MetricCardProps and ProgressBarProps so every field (e.g., title, icon, iconBg,
children in MetricCardProps and whatever fields exist in ProgressBarProps) are
declared readonly to satisfy the immutability contract and silence Sonar
warnings; locate the interface declarations in
web/src/components/dashboard/health-cards.tsx (MetricCardProps and
ProgressBarProps) and change each property to readonly while keeping types
unchanged.
- health-cards.tsx: Extract MetricCard, ProgressBar, computeHeapMetrics, computeCpuMetrics helpers (complexity 23 → ~10) - performance-dashboard.tsx: Extract extractErrorMessage, buildMemChartData, buildCpuChartData, buildRtHistogram helpers (complexity 21 → ~12) - analytics-dashboard.tsx: Extract KpiCardItem, DeltaIcon, getDeltaColor, formatNullableMetric helpers (complexity 20 → ~10)
188c53e to
b1fd637
Compare
|
| return ( | ||
| data?.timeSeries.memoryHeapMb.map((pt, i) => ({ | ||
| time: formatTs(pt.timestamp), | ||
| heap: pt.value, | ||
| rss: data.timeSeries.memoryRssMb[i]?.value ?? 0, | ||
| })) ?? [] | ||
| ); |
There was a problem hiding this comment.
buildMemChartData uses data?.timeSeries...map(...) but still references data.timeSeries... inside the map callback. TypeScript won’t narrow data inside the closure, so this typically triggers an "Object is possibly 'null'" type error (and can be avoided without losing readability). Consider returning early when data is null, or capturing the needed arrays in locals (e.g., const rssSeries = data.timeSeries.memoryRssMb) before mapping.
| return ( | |
| data?.timeSeries.memoryHeapMb.map((pt, i) => ({ | |
| time: formatTs(pt.timestamp), | |
| heap: pt.value, | |
| rss: data.timeSeries.memoryRssMb[i]?.value ?? 0, | |
| })) ?? [] | |
| ); | |
| if (!data) { | |
| return []; | |
| } | |
| const rssSeries = data.timeSeries.memoryRssMb; | |
| return data.timeSeries.memoryHeapMb.map((pt, i) => ({ | |
| time: formatTs(pt.timestamp), | |
| heap: pt.value, | |
| rss: rssSeries[i]?.value ?? 0, | |
| })); |





Refactors three dashboard components to reduce SonarCloud cognitive complexity to ≤15:
MetricCard,ProgressBar,computeHeapMetrics,computeCpuMetrics,formatErrorValue,errorValueColorhelpersextractErrorMessage,buildMemChartData,buildCpuChartData,buildRtHistogramhelpersKpiCardItem,DeltaIcon,getDeltaColor,formatNullableMetrichelpersNo behavior changes. TypeScript compiles clean.