Skip to content

feat: add GitHub API rate limit indicator to monitor API usage#36

Open
Aarya-Chaudhari wants to merge 1 commit intoAOSSIE-Org:mainfrom
Aarya-Chaudhari:rate
Open

feat: add GitHub API rate limit indicator to monitor API usage#36
Aarya-Chaudhari wants to merge 1 commit intoAOSSIE-Org:mainfrom
Aarya-Chaudhari:rate

Conversation

@Aarya-Chaudhari
Copy link

@Aarya-Chaudhari Aarya-Chaudhari commented Mar 7, 2026

Description

This PR adds a GitHub API Rate Limit Indicator to the OrgExplorer UI.
The indicator displays the remaining API requests, total limit, and reset time using the GitHub rate limit endpoint.

This helps users monitor API usage and avoid hitting GitHub's rate limits when exploring large organizations.

Changes Made

  • Created a new component RateLimitIndicator.tsx
  • Fetches data from the GitHub API endpoint /rate_limit
  • Displays remaining requests, total limit, and reset time
  • Added the component to App.tsx

Why This Feature

Since OrgExplorer relies heavily on GitHub API calls, displaying the current API usage status improves transparency and helps prevent unexpected API request failures.

Screenshots/Recordings:

Screenshot 2026-03-07 120859

Additional Notes:

Checklist

  • My code follows the project's code style and conventions
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contributing Guidelines

⚠️ AI Notice - Important!

We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact.

Summary by CodeRabbit

  • New Features
    • Added a rate limit indicator displaying remaining requests, total limit, and reset time in a fixed-position UI element.
    • The indicator loads data on startup and displays a loading message until information is available.

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

Walkthrough

A new RateLimitIndicator component is introduced that fetches GitHub API rate limit data on mount and displays it in a fixed-position UI. The component is integrated into the App component's JSX to show remaining requests, total limits, and reset time.

Changes

Cohort / File(s) Summary
App Integration
src/App.tsx
Added import and component invocation for RateLimitIndicator in the App component's JSX.
Rate Limit Display
src/RateLimitIndicator.tsx
New React component that fetches GitHub rate limit data from the public API endpoint on mount, manages state for the response, handles errors via logging, and renders a fixed-position display showing remaining requests, total limit, and reset time. Includes loading state handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

Typescript Lang

Poem

🐰 A little indicator hops into view,
Watching the GitHub limits brew,
With resets and counts on display,
Keeping rate limits at bay!
🔄✨

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main addition to the codebase: a GitHub API rate limit indicator component for monitoring API usage.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@github-actions github-actions bot added size/M and removed size/M labels Mar 7, 2026
@Aarya-Chaudhari
Copy link
Author

Hello @Zahnentferner
I am Aarya Chaudhari, a GSoC'26 aspirant.

I have implemented the GitHub API Rate Limit Indicator which displays the remaining API requests and reset time using the /rate_limit endpoint. This helps monitor API usage when exploring organizations.

Please review the PR and let me know if any changes required

@github-actions github-actions bot added size/M and removed size/M labels Mar 7, 2026
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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/RateLimitIndicator.tsx`:
- Around line 31-50: The component RateLimitIndicator currently hardcodes
user-facing strings ("Loading API status...", "GitHub API Status", "Remaining",
"Reset"); replace these with i18n lookups by importing the app's translation
helper (e.g., useTranslation or t) and using keys like rateLimit.loading,
rateLimit.title, rateLimit.remaining, and rateLimit.reset in the JSX; add the
corresponding entries to the i18n resource files for all supported locales and
update the component to call the translation function where the literals are
used (including the strong title and the two <p> labels) so no user-visible text
remains hardcoded.
- Around line 12-29: The current useEffect fetchRateLimit runs only on mount so
remaining/reset go stale; update RateLimitIndicator by either subscribing to the
app's GitHub request layer (e.g., hook into the same client/event emitter) or
implement polling inside useEffect: move fetchRateLimit into a named async
function (fetchRateLimit) and call it on an interval via setInterval, storing
the timer and clearing it on cleanup, and continue to call setRateLimit with
data.rate.*; ensure useEffect returns a cleanup that clears the interval to
avoid leaks.
- Around line 15-31: The fetchRateLimit function leaves rateLimit null on HTTP
errors/unexpected payloads which makes the UI show "Loading API status..."
forever; update fetchRateLimit to check response.ok after the fetch, handle
non-OK statuses by calling setRateLimit with an explicit error/unavailable
sentinel (e.g., an object like {error: true, message: ...}) and also validate
the parsed payload before reading data.rate; ensure the component reads
rateLimit.error (or similar) to render an "API unavailable" or error state
instead of the loading message, and keep console.error for debugging inside the
catch branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 093a237b-8479-428e-ae1a-a222929dad12

📥 Commits

Reviewing files that changed from the base of the PR and between 1cfc3e7 and ab026ef.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • src/App.tsx
  • src/RateLimitIndicator.tsx

Comment on lines +12 to +29
useEffect(() => {
async function fetchRateLimit() {
try {
const response = await fetch("https://api.github.com/rate_limit");
const data = await response.json();

setRateLimit({
limit: data.rate.limit,
remaining: data.rate.remaining,
reset: data.rate.reset,
});
} catch (error) {
console.error("Error fetching rate limit:", error);
}
}

fetchRateLimit();
}, []);
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

Refresh the quota after GitHub API activity.

This effect runs only once on mount, so remaining and reset become stale as soon as the user makes more GitHub requests. That undercuts the goal of using this widget to monitor quota while exploring orgs. Please either wire it to the same GitHub request layer the app uses or poll/refetch on an interval.

♻️ Minimal polling-based fix
   useEffect(() => {
+    let cancelled = false;
+
     async function fetchRateLimit() {
       try {
         const response = await fetch("https://api.github.com/rate_limit");
         const data = await response.json();
 
-        setRateLimit({
-          limit: data.rate.limit,
-          remaining: data.rate.remaining,
-          reset: data.rate.reset,
-        });
+        if (!cancelled) {
+          setRateLimit({
+            limit: data.rate.limit,
+            remaining: data.rate.remaining,
+            reset: data.rate.reset,
+          });
+        }
       } catch (error) {
         console.error("Error fetching rate limit:", error);
       }
     }
 
     fetchRateLimit();
+    const intervalId = window.setInterval(fetchRateLimit, 30000);
+
+    return () => {
+      cancelled = true;
+      window.clearInterval(intervalId);
+    };
   }, []);
📝 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
useEffect(() => {
async function fetchRateLimit() {
try {
const response = await fetch("https://api.github.com/rate_limit");
const data = await response.json();
setRateLimit({
limit: data.rate.limit,
remaining: data.rate.remaining,
reset: data.rate.reset,
});
} catch (error) {
console.error("Error fetching rate limit:", error);
}
}
fetchRateLimit();
}, []);
useEffect(() => {
let cancelled = false;
async function fetchRateLimit() {
try {
const response = await fetch("https://api.github.com/rate_limit");
const data = await response.json();
if (!cancelled) {
setRateLimit({
limit: data.rate.limit,
remaining: data.rate.remaining,
reset: data.rate.reset,
});
}
} catch (error) {
console.error("Error fetching rate limit:", error);
}
}
fetchRateLimit();
const intervalId = window.setInterval(fetchRateLimit, 30000);
return () => {
cancelled = true;
window.clearInterval(intervalId);
};
}, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/RateLimitIndicator.tsx` around lines 12 - 29, The current useEffect
fetchRateLimit runs only on mount so remaining/reset go stale; update
RateLimitIndicator by either subscribing to the app's GitHub request layer
(e.g., hook into the same client/event emitter) or implement polling inside
useEffect: move fetchRateLimit into a named async function (fetchRateLimit) and
call it on an interval via setInterval, storing the timer and clearing it on
cleanup, and continue to call setRateLimit with data.rate.*; ensure useEffect
returns a cleanup that clears the interval to avoid leaks.

Comment on lines +15 to +31
const response = await fetch("https://api.github.com/rate_limit");
const data = await response.json();

setRateLimit({
limit: data.rate.limit,
remaining: data.rate.remaining,
reset: data.rate.reset,
});
} catch (error) {
console.error("Error fetching rate limit:", error);
}
}

fetchRateLimit();
}, []);

if (!rateLimit) return <p>Loading API status...</p>;
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

Don't leave the widget stuck in loading on failed responses.

If GitHub returns 403/5xx or an unexpected payload, the catch path only logs and rateLimit stays null, so the UI keeps showing Loading API status... forever even though loading already finished. Check response.ok and render an explicit unavailable/error state.

🛠️ Suggested error-state handling
 export default function RateLimitIndicator() {
   const [rateLimit, setRateLimit] = useState<RateLimitData | null>(null);
+  const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");
 
   useEffect(() => {
     async function fetchRateLimit() {
       try {
         const response = await fetch("https://api.github.com/rate_limit");
+        if (!response.ok) {
+          throw new Error(`GitHub rate limit request failed: ${response.status}`);
+        }
         const data = await response.json();
 
         setRateLimit({
           limit: data.rate.limit,
           remaining: data.rate.remaining,
           reset: data.rate.reset,
         });
+        setStatus("ready");
       } catch (error) {
         console.error("Error fetching rate limit:", error);
+        setStatus("error");
       }
     }
 
     fetchRateLimit();
   }, []);
 
-  if (!rateLimit) return <p>Loading API status...</p>;
+  if (status === "loading") return <p>Loading API status...</p>;
+  if (status === "error" || !rateLimit) return <p>API status unavailable</p>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/RateLimitIndicator.tsx` around lines 15 - 31, The fetchRateLimit function
leaves rateLimit null on HTTP errors/unexpected payloads which makes the UI show
"Loading API status..." forever; update fetchRateLimit to check response.ok
after the fetch, handle non-OK statuses by calling setRateLimit with an explicit
error/unavailable sentinel (e.g., an object like {error: true, message: ...})
and also validate the parsed payload before reading data.rate; ensure the
component reads rateLimit.error (or similar) to render an "API unavailable" or
error state instead of the loading message, and keep console.error for debugging
inside the catch branch.

Comment on lines +31 to +50
if (!rateLimit) return <p>Loading API status...</p>;

const resetTime = new Date(rateLimit.reset * 1000).toLocaleTimeString();

return (
<div
style={{
position: "fixed",
bottom: "20px",
right: "20px",
background: "#1f2937",
padding: "12px",
borderRadius: "8px",
color: "white",
fontSize: "14px",
}}
>
<strong>GitHub API Status</strong>
<p>Remaining: {rateLimit.remaining} / {rateLimit.limit}</p>
<p>Reset: {resetTime}</p>
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

Externalize the new UI copy.

Loading API status..., GitHub API Status, Remaining, and Reset are hardcoded here. Please move them into the app's i18n resources before shipping.

As per coding guidelines, "Internationalization: User-visible strings should be externalized to resource files (i18n)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/RateLimitIndicator.tsx` around lines 31 - 50, The component
RateLimitIndicator currently hardcodes user-facing strings ("Loading API
status...", "GitHub API Status", "Remaining", "Reset"); replace these with i18n
lookups by importing the app's translation helper (e.g., useTranslation or t)
and using keys like rateLimit.loading, rateLimit.title, rateLimit.remaining, and
rateLimit.reset in the JSX; add the corresponding entries to the i18n resource
files for all supported locales and update the component to call the translation
function where the literals are used (including the strong title and the two <p>
labels) so no user-visible text remains hardcoded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant