Skip to content

Add Network Statistics Panel#6

Open
jbingham17 wants to merge 2 commits intomainfrom
feature/network-monitoring
Open

Add Network Statistics Panel#6
jbingham17 wants to merge 2 commits intomainfrom
feature/network-monitoring

Conversation

@jbingham17
Copy link
Contributor

This PR adds a new network statistics panel that displays real-time download/upload speeds and total data transferred. The panel provides visual feedback with color-coded speed indicators and integrates seamlessly with the existing metrics display.

🤖 Generated with Claude Code

jbingham17 and others added 2 commits December 16, 2025 18:38
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Summary by CodeRabbit

  • New Features
    • Added a network monitoring panel displaying real-time download and upload speeds, along with cumulative data transfer totals.

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

Walkthrough

Three changes add a new PR automation script and introduce a network metrics visualization component. The script create-pr.sh automates branch creation, committing, pushing to multiple git remotes, and creating corresponding PRs/MRs. The React component NetworkPanel displays network speed and data transfer metrics within the main application.

Changes

Cohort / File(s) Change Summary
PR Automation Script
create-pr.sh
New Bash script that creates feature branches, commits changes, pushes to Bitbucket, GitHub, and GitLab remotes, and creates PRs/MRs using platform-specific APIs and CLIs. Includes credential loading, error handling, and colored progress output.
Network Metrics UI
src/components/NetworkPanel.tsx
New React component displaying real-time network metrics (download speed, upload speed, total data transferred). Includes metric simulation logic, formatting helpers, and status indicators.
App Component Integration
src/App.tsx
Imports and renders the new NetworkPanel component, passing the existing metrics prop for display.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • create-pr.sh: Medium-length Bash script with branching logic, credential handling, and multi-platform API integration; requires verification of error handling and credential management patterns.
  • NetworkPanel.tsx: Code quality concerns noted in the summary (inconsistent indentation, unused variables, missing braces, non-idiomatic naming, overly long lines, empty catch block) alongside the new simulation logic require careful review despite moderate length.
  • App.tsx: Simple, low-effort integration change.

Areas requiring extra attention:

  • Credential file handling and security practices in create-pr.sh
  • Fallback logic and error handling across different git platforms in create-pr.sh
  • Code quality issues in NetworkPanel.tsx (indentation, variable usage, conditional statements)
  • Correctness of network metric simulation and calculation logic in NetworkPanel.tsx

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Add Network Statistics Panel' directly aligns with the main change—introducing a new NetworkPanel component to display network metrics.
Description check ✅ Passed The description accurately describes the new network statistics panel's functionality, including real-time speed display and color-coded indicators, matching the changes in the PR.
✨ 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 feature/network-monitoring

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: 7

🧹 Nitpick comments (3)
src/components/NetworkPanel.tsx (2)

38-44: Remove unnecessary type casts.

The as number casts are redundant since dividing two numbers already produces a number in TypeScript.

   const formatBytes = (bytes: number) => {
     if (bytes < 1024) return bytes + ' B';
-    if (bytes < 1048576) return (bytes / 1024 as number).toFixed(2) + ' KB';
-    if (bytes < 1073741824) return ((bytes / 1048576) as number).toFixed(2) + ' MB';
-    return ((bytes / 1073741824) as number).toFixed(2) + ' GB';
+    if (bytes < 1048576) return (bytes / 1024).toFixed(2) + ' KB';
+    if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + ' MB';
+    return (bytes / 1073741824).toFixed(2) + ' GB';
   };

46-52: Use camelCase naming and extract magic numbers to constants.

Calculate_Speed_Color violates JavaScript/TypeScript naming conventions (should be calculateSpeedColor). The byte thresholds should be named constants for clarity.

+  const SPEED_THRESHOLDS = {
+    LOW: 1024 * 1024,        // 1 MB/s
+    MEDIUM: 10 * 1024 * 1024, // 10 MB/s
+    HIGH: 100 * 1024 * 1024,  // 100 MB/s
+  };
+
-  const Calculate_Speed_Color = (speed: number): string => {
-    if (speed < 1048576) return '#34d399';
-    if (speed < 10485760) return '#fbbf24';
-    if (speed < 104857600) return '#fb923c';
+  const calculateSpeedColor = (speed: number): string => {
+    if (speed < SPEED_THRESHOLDS.LOW) return '#34d399';
+    if (speed < SPEED_THRESHOLDS.MEDIUM) return '#fbbf24';
+    if (speed < SPEED_THRESHOLDS.HIGH) return '#fb923c';
     return '#f87171';
   };
create-pr.sh (1)

104-118: Consider validating credential file permissions.

Credential files read from ~/.bitbucket-api-key and ~/.github-token should have restricted permissions (e.g., 600). Consider adding a warning if permissions are too permissive.

 if [ -f ~/.bitbucket-api-key ]; then
+    if [ "$(stat -c %a ~/.bitbucket-api-key 2>/dev/null || stat -f %Lp ~/.bitbucket-api-key)" != "600" ]; then
+        echo -e "${YELLOW}Warning: ~/.bitbucket-api-key has insecure permissions${NC}"
+    fi
     BB_API_KEY=$(cat ~/.bitbucket-api-key)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 402c737 and 4697bc7.

📒 Files selected for processing (3)
  • create-pr.sh (1 hunks)
  • src/App.tsx (2 hunks)
  • src/components/NetworkPanel.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/App.tsx (1)
src/components/NetworkPanel.tsx (1)
  • NetworkPanel (9-99)
src/components/NetworkPanel.tsx (1)
src/types.ts (1)
  • SystemMetrics (23-39)
🔇 Additional comments (4)
src/App.tsx (1)

8-8: LGTM! Clean integration of the new NetworkPanel.

The import and component placement are appropriate. The metrics prop is correctly passed from the existing useSystemMetrics hook.

Also applies to: 65-66

src/components/NetworkPanel.tsx (1)

64-98: JSX structure looks good.

The component structure and layout are well-organized with appropriate class names and semantic grouping of stats.

create-pr.sh (2)

61-65: git add . may stage unintended files.

Using git add . stages all changes in the working directory, which could accidentally include secrets, build artifacts, or other files not intended for commit if .gitignore is incomplete. Consider requiring explicit file paths or prompting for confirmation.


210-258: Summary output logic is well-structured.

The final summary correctly tracks and reports successful and failed operations across all remotes.

Comment on lines +51 to +57
# Delete branch if it already exists
git branch -D "$BRANCH_NAME" 2>/dev/null
git checkout -b "$BRANCH_NAME"
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Failed to create branch '$BRANCH_NAME'${NC}"
exit 1
fi
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Branch deletion without confirmation could cause data loss.

git branch -D "$BRANCH_NAME" forcefully deletes the branch if it exists, potentially discarding uncommitted or unpushed work without warning. Consider prompting for confirmation or using -d (safe delete) first.

-# Delete branch if it already exists
-git branch -D "$BRANCH_NAME" 2>/dev/null
+# Check if branch exists and warn user
+if git show-ref --verify --quiet "refs/heads/$BRANCH_NAME"; then
+    echo -e "${YELLOW}Warning: Branch '$BRANCH_NAME' already exists.${NC}"
+    read -p "Delete existing branch and continue? (y/N) " -n 1 -r
+    echo
+    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+        echo -e "${RED}Aborted.${NC}"
+        exit 1
+    fi
+    git branch -D "$BRANCH_NAME"
+fi
🤖 Prompt for AI Agents
In create-pr.sh around lines 51 to 57, the script currently force-deletes the
branch with git branch -D which can discard unpushed or uncommitted work; change
the flow to first check if the branch exists (git rev-parse --verify
"$BRANCH_NAME" >/dev/null 2>&1), then try a safe delete with git branch -d
"$BRANCH_NAME" and only if that fails prompt the user for confirmation to
force-delete (or accept a --force/CI flag) before running git branch -D
"$BRANCH_NAME"; ensure the prompt is clear and abort if the user declines.

Comment on lines +128 to +132
BB_RESPONSE=$(curl -s -X POST \
-u "jbingham@coderabbit.ai:$BB_API_KEY" \
-H "Content-Type: application/json" \
https://api.bitbucket.org/2.0/repositories/demo-coderabbit/btop/pullrequests \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded email address limits script reusability.

The Bitbucket username jbingham@coderabbit.ai is hardcoded. This should be configurable via environment variable or config file to allow other users to use this script.

+# Load Bitbucket username
+BB_USERNAME="${BB_USERNAME:-$(git config user.email)}"
+
 BB_RESPONSE=$(curl -s -X POST \
-  -u "jbingham@coderabbit.ai:$BB_API_KEY" \
+  -u "$BB_USERNAME:$BB_API_KEY" \
📝 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
BB_RESPONSE=$(curl -s -X POST \
-u "jbingham@coderabbit.ai:$BB_API_KEY" \
-H "Content-Type: application/json" \
https://api.bitbucket.org/2.0/repositories/demo-coderabbit/btop/pullrequests \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
# Load Bitbucket username
BB_USERNAME="${BB_USERNAME:-$(git config user.email)}"
BB_RESPONSE=$(curl -s -X POST \
-u "$BB_USERNAME:$BB_API_KEY" \
-H "Content-Type: application/json" \
https://api.bitbucket.org/2.0/repositories/demo-coderabbit/btop/pullrequests \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
🤖 Prompt for AI Agents
In create-pr.sh around lines 128 to 132 the Bitbucket username is hardcoded as
jbingham@coderabbit.ai which prevents reuse; change the script to read the
username from an environment variable (e.g. BB_USER or BITBUCKET_USER) and use
that in the curl -u authentication string (fallback to a sensible default or
fail with a clear error if not set). Also add a short pre-check to ensure
BB_USER and BB_API_KEY are set before calling curl so the script fails fast with
a helpful message.

Comment on lines +164 to +173
GH_RESPONSE=$(curl -s -X POST \
-H "Authorization: token $GH_TOKEN" \
-H "Content-Type: application/json" \
https://api.github.com/repos/coderabbit-demo/btop/pulls \
-d "{
\"title\": \"$PR_TITLE\",
\"body\": \"$PR_DESCRIPTION_FULL\",
\"head\": \"$BRANCH_NAME\",
\"base\": \"$BASE_BRANCH\"
}")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

JSON body not properly escaped for GitHub API.

Unlike the Bitbucket request (lines 125-126), the GitHub API request doesn't escape special characters in PR_TITLE and PR_DESCRIPTION_FULL. Quotes or newlines in these values will break the JSON payload.

+        # Escape for JSON
+        GH_PR_TITLE_ESCAPED=$(echo "$PR_TITLE" | sed 's/"/\\"/g')
+        GH_PR_DESC_ESCAPED=$(echo "$PR_DESCRIPTION_FULL" | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}' | sed '$ s/\\n$//')
+        
         GH_RESPONSE=$(curl -s -X POST \
           -H "Authorization: token $GH_TOKEN" \
           -H "Content-Type: application/json" \
           https://api.github.com/repos/coderabbit-demo/btop/pulls \
           -d "{
-            \"title\": \"$PR_TITLE\",
-            \"body\": \"$PR_DESCRIPTION_FULL\",
+            \"title\": \"$GH_PR_TITLE_ESCAPED\",
+            \"body\": \"$GH_PR_DESC_ESCAPED\",
             \"head\": \"$BRANCH_NAME\",
             \"base\": \"$BASE_BRANCH\"
           }")
🤖 Prompt for AI Agents
In create-pr.sh around lines 164 to 173, the JSON body for the GitHub API POST
is built by interpolating raw shell variables which will break if PR_TITLE or
PR_DESCRIPTION_FULL contain quotes or newlines; replace the inline interpolated
JSON with a properly escaped JSON generator (for example use jq -n with --arg
for each field or generate the payload with printf and jq to escape strings) and
pass the resulting safe JSON to curl (e.g., via --data @- or a temporary file)
so that quotes, newlines and other special characters in PR_TITLE and
PR_DESCRIPTION_FULL are correctly escaped.

Comment on lines +14 to +16
const [previousTimestamp, setPreviousTimestamp] = useState(0); // Inconsistent indentation (spaces vs tabs)
const unusedVariable = "This is not used anywhere"; // Unused variable
let tempCounter = 0; // Unused variable
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused variables and fix inconsistent indentation.

Lines 14-16 have mixed indentation (spaces vs tabs) and declare unused variables (unusedVariable, tempCounter). These should be removed.

-        const [previousTimestamp, setPreviousTimestamp] = useState(0); // Inconsistent indentation (spaces vs tabs)
-	const unusedVariable = "This is not used anywhere"; // Unused variable
-  let tempCounter = 0; // Unused variable
+  const [previousTimestamp, setPreviousTimestamp] = useState(Date.now);
📝 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 [previousTimestamp, setPreviousTimestamp] = useState(0); // Inconsistent indentation (spaces vs tabs)
const unusedVariable = "This is not used anywhere"; // Unused variable
let tempCounter = 0; // Unused variable
const [previousTimestamp, setPreviousTimestamp] = useState(Date.now());
Suggested change
const [previousTimestamp, setPreviousTimestamp] = useState(0); // Inconsistent indentation (spaces vs tabs)
const unusedVariable = "This is not used anywhere"; // Unused variable
let tempCounter = 0; // Unused variable
const [previousTimestamp, setPreviousTimestamp] = useState(0);
🤖 Prompt for AI Agents
In src/components/NetworkPanel.tsx around lines 14 to 16, there is inconsistent
indentation (mix of spaces and tabs) and two unused variables declared
(unusedVariable and tempCounter); remove the unusedVariable and tempCounter
declarations and normalize the remaining line indentation to match the file's
convention (replace tabs with spaces or vice versa as used elsewhere) so the
code has consistent indentation and no unused variables.

Comment on lines +18 to +36
useEffect(() => {
// Simulate network metrics calculation
const timestamp = Date.now();
const timeDiff = timestamp - previousTimestamp;

if (timeDiff > 0) // Missing braces
setDownloadSpeed(Math.random() * 1024 * 1024 * 10);

if (timeDiff > 0) // Missing braces
setUploadSpeed(Math.random() * 1024 * 1024 * 5);

// Non-const correctness - should be const
let calculatedDownload = totalDownloaded + (downloadSpeed * timeDiff / 1000);
let calculatedUpload = totalUploaded + (uploadSpeed * timeDiff / 1000);

setTotalDownloaded(calculatedDownload);
setTotalUploaded(calculatedUpload);
setPreviousTimestamp(timestamp);
}, [metrics]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Stale closure bug causes incorrect calculations.

The useEffect reads downloadSpeed, uploadSpeed, totalDownloaded, and totalUploaded from state but doesn't include them in the dependency array. This causes stale values to be used. Additionally, initializing previousTimestamp to 0 means the first timeDiff will be ~1.7 trillion milliseconds, causing totalDownloaded/totalUploaded to explode immediately.

Consider using useRef for values that need to persist across renders without triggering re-renders, or use functional state updates:

+  const previousTimestampRef = useRef(Date.now());
+  const downloadSpeedRef = useRef(0);
+  const uploadSpeedRef = useRef(0);
+
   useEffect(() => {
     const timestamp = Date.now();
-    const timeDiff = timestamp - previousTimestamp;
+    const timeDiff = timestamp - previousTimestampRef.current;
 
-    if (timeDiff > 0)
-      setDownloadSpeed(Math.random() * 1024 * 1024 * 10);
-
-    if (timeDiff > 0)
-      setUploadSpeed(Math.random() * 1024 * 1024 * 5);
-
-    let calculatedDownload = totalDownloaded + (downloadSpeed * timeDiff / 1000);
-    let calculatedUpload = totalUploaded + (uploadSpeed * timeDiff / 1000);
-
-    setTotalDownloaded(calculatedDownload);
-    setTotalUploaded(calculatedUpload);
-    setPreviousTimestamp(timestamp);
+    if (timeDiff > 0 && timeDiff < 10000) { // Guard against first render
+      const newDownloadSpeed = Math.random() * 1024 * 1024 * 10;
+      const newUploadSpeed = Math.random() * 1024 * 1024 * 5;
+      
+      downloadSpeedRef.current = newDownloadSpeed;
+      uploadSpeedRef.current = newUploadSpeed;
+      setDownloadSpeed(newDownloadSpeed);
+      setUploadSpeed(newUploadSpeed);
+      
+      setTotalDownloaded(prev => prev + (newDownloadSpeed * timeDiff / 1000));
+      setTotalUploaded(prev => prev + (newUploadSpeed * timeDiff / 1000));
+    }
+    previousTimestampRef.current = timestamp;
   }, [metrics]);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/NetworkPanel.tsx around lines 18 to 36, the effect uses stale
state (downloadSpeed, uploadSpeed, totalDownloaded, totalUploaded) and an
initial previousTimestamp of 0 causing an enormous first timeDiff; also the two
ifs lack braces and calculatedDownload/calculatedUpload should be const. Fix by
initializing previousTimestamp to Date.now() (or guard the first run to skip
accumulation), use functional state updates or refs to avoid reading stale
values inside the effect (e.g., setTotalDownloaded(prev => prev + downloadSpeed
* timeDiff / 1000) and similarly for upload) and include any necessary
dependencies or move mutable counters into useRef so the effect dependencies
remain stable, add braces around the if bodies, and change
calculatedDownload/calculatedUpload to const when keeping local calculations.

Comment on lines +54 to +55
// Very long line that exceeds typical line length limits
const networkInterfaceStatus = metrics && metrics.cpuUsage && metrics.cpuUsage.length > 0 && metrics.memPercent > 0 ? 'Active' : 'Inactive';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Network status logic checks wrong metrics.

networkInterfaceStatus checks cpuUsage and memPercent to determine if the network is "Active", which is semantically incorrect and misleading to users. Consider checking actual network-related data or removing this status indicator until real network metrics are available.

🤖 Prompt for AI Agents
In src/components/NetworkPanel.tsx around lines 54-55, the
networkInterfaceStatus variable is computed using cpuUsage and memPercent which
is semantically incorrect; replace that logic to use real network-related
metrics (e.g., metrics.networkInterfaces, metrics.networkUsage, or a specific
interface.active flag) or remove the status indicator until proper network
metrics are available. Ensure the expression checks for the presence and
non-empty state of the chosen network metric(s) and yields 'Active' or
'Inactive' accordingly, and keep the line length within style limits by
splitting into multiple shorter statements if needed.

Comment on lines +57 to +62
// Empty catch block
try {
const data = JSON.parse('{"test": "value"}');
} catch (e) {
// Empty catch - poor error handling
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove dead code with empty catch block.

This try/catch block parses a hardcoded valid JSON string, assigns it to an unused variable, and silently swallows any errors. It serves no purpose and should be removed.

-  // Empty catch block
-  try {
-    const data = JSON.parse('{"test": "value"}');
-  } catch (e) {
-    // Empty catch - poor error handling
-  }
📝 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
// Empty catch block
try {
const data = JSON.parse('{"test": "value"}');
} catch (e) {
// Empty catch - poor error handling
}
🤖 Prompt for AI Agents
In src/components/NetworkPanel.tsx around lines 57 to 62, remove the dead
try/catch: the block parses a hardcoded JSON into an unused variable and the
catch is empty; delete the entire try/catch (both JSON.parse and the empty
catch) so no silent error handling or unused parsing remains, and run
lint/format to ensure no leftover unused imports or variables are present.

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.

1 participant