feat: add org analytics dashboard with charts and dynamic org support#52
feat: add org analytics dashboard with charts and dynamic org support#52yanamavani wants to merge 1 commit intoAOSSIE-Org:mainfrom
Conversation
WalkthroughThis PR introduces a Dashboard component that displays GitHub organization analytics including repository statistics and a Recharts bar chart visualization, along with adding the recharts dependency to support charting functionality. Changes
Sequence DiagramsequenceDiagram
actor User
participant App as App Component
participant Dashboard as Dashboard<br/>(React Component)
participant GitHub as GitHub REST API
participant Recharts as Recharts<br/>(Chart Library)
User->>App: Load Application
App->>Dashboard: Mount Dashboard
Dashboard->>Dashboard: Initialize state<br/>(org, input, repos, orgData,<br/>stats, loading, error)
Dashboard->>GitHub: Fetch /orgs/{org}/repos
GitHub-->>Dashboard: Repository list
Dashboard->>Dashboard: Compute stats<br/>(total stars, forks,<br/>top repo)
Dashboard->>GitHub: Fetch /orgs/{org}
GitHub-->>Dashboard: Organization details
Dashboard->>Dashboard: Update state<br/>(repos, orgData, stats)
Dashboard->>Recharts: Render bar chart<br/>(Top 5 by stars)
Recharts-->>Dashboard: Chart component
Dashboard-->>User: Display dashboard<br/>(cards + chart)
User->>Dashboard: Change organization
Dashboard->>GitHub: Re-fetch data for<br/>new organization
GitHub-->>Dashboard: New data
Dashboard->>Dashboard: Update state & chart
Dashboard-->>User: Display updated<br/>dashboard
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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/components/Dashboard.tsx`:
- Around line 97-99: The hardcoded user-visible strings in Dashboard.tsx (e.g.,
the h1 text "📊 {orgData?.login || org} Analytics Dashboard" and other strings
at the indicated ranges like "Search", "Loading...", "Top 5 Repositories by
Stars" and stat labels) must be externalized for i18n: replace literal strings
with keys from the app's i18n/resource system (e.g., use the project’s
translation helper such as t('dashboard.analyticsTitle') or
strings.dashboard.analyticsTitle), add corresponding keys to the resource
file(s), and ensure dynamic parts (org/orgData) are composed with placeholders
or string templates supported by the i18n helper; update all occurrences
referenced (lines ~97, ~128, ~133, ~176-178) accordingly.
- Around line 26-29: The unauthenticated GitHub fetch in Dashboard.tsx (the
fetch(`https://api.github.com/orgs/${org}/repos`) call) can hit the 60/hr rate
limit; update the fetch handling to read rate-limit headers
(res.headers.get('X-RateLimit-Remaining') and 'X-RateLimit-Reset'), detect when
remaining === '0' or when res.status === 403, and surface a clear UI message
(e.g., set state like rateLimitRemaining and rateLimitReset and show it in the
component) instead of only throwing "Invalid org"; also document this limitation
in the README and/or component UI and consider allowing an authenticated token
option to increase limits.
- Around line 61-65: The fetch block that calls
fetch(`https://api.github.com/orgs/${org}`) lacks error handling and can leave
stale orgData via setOrgData; update it to check response.ok and parse only on
success, handle JSON/network errors with a .catch, and on failure clear or set
orgData to null and set an error state (use your existing error state setter or
add one, e.g., setOrgError) so the UI can show the failure and not display stale
data; also consider toggling any loading state (e.g., setIsLoadingOrg) around
the request.
- Around line 68-70: The useEffect in Dashboard calls fetchData but doesn’t
include it in the dependency array, causing an exhaustive-deps violation; either
move the fetch logic directly inside the useEffect callback (useEffect(() => {
/* fetch logic that uses org */ }, [org])) or memoize fetchData with useCallback
using [org] so you can keep calling fetchData elsewhere; update the dependency
array to include fetchData if you choose useCallback, and ensure the function
signature (fetchData) and the org dependency are consistent with the Dashboard
component’s state/props.
- Around line 8-9: Define explicit TypeScript interfaces for the GitHub
responses (e.g., interface Repo { id: number; name: string; full_name: string;
html_url: string; owner: { login: string; id: number; }; /* add other fields
your code uses */ } and an interface for organization data e.g., OrgData {
login: string; id: number; /* ... */ }), replace the useState<any[]> and
useState<any> with useState<Repo[]> and useState<OrgData | null> for the repos
and orgData state variables, and update the fetch callbacks (the places calling
setRepos and setOrgData) to parse/annotate responses as Repo[] and OrgData so
typings flow into components and handlers (update any function signatures or
parameters that currently accept any to use Repo or OrgData).
- Around line 184-189: The chart is using repos.slice(0, 5) from the unsorted
API response instead of the ranked list; use the already-created sorted array or
persist a sorted state so the top 5 by stargazers_count are shown. Locate the
sorting logic (the variable named sorted) and either setState with that sorted
array (e.g., setReposSorted or replace repos state) or change the chart data
prop to use sorted.slice(0,5). Ensure the data mapping still uses name and
stargazers_count (stars) so the chart reflects the top 5 repos by stars.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3ac99afd-0280-4ec3-8278-c860b5d63f7f
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
package.jsonsrc/App.tsxsrc/components/Dashboard.tsx
| const [repos, setRepos] = useState<any[]>([]); | ||
| const [orgData, setOrgData] = useState<any>(null); |
There was a problem hiding this comment.
Avoid using any type; define explicit interfaces.
The coding guidelines specify avoiding any and using explicit types. Define interfaces for the GitHub API response structures.
🛠️ Proposed fix
+interface Repo {
+ name: string;
+ stargazers_count: number;
+ forks_count: number;
+}
+
+interface OrgData {
+ login: string;
+ avatar_url: string;
+}
+
function Dashboard() {
const [org, setOrg] = useState("facebook");
const [input, setInput] = useState("facebook");
- const [repos, setRepos] = useState<any[]>([]);
- const [orgData, setOrgData] = useState<any>(null);
+ const [repos, setRepos] = useState<Repo[]>([]);
+ const [orgData, setOrgData] = useState<OrgData | null>(null);Then update the type annotations in the fetch callbacks (lines 37, 43, 186) to use Repo instead of any.
As per coding guidelines: "Avoid 'any', use explicit types".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 8 - 9, Define explicit TypeScript
interfaces for the GitHub responses (e.g., interface Repo { id: number; name:
string; full_name: string; html_url: string; owner: { login: string; id: number;
}; /* add other fields your code uses */ } and an interface for organization
data e.g., OrgData { login: string; id: number; /* ... */ }), replace the
useState<any[]> and useState<any> with useState<Repo[]> and useState<OrgData |
null> for the repos and orgData state variables, and update the fetch callbacks
(the places calling setRepos and setOrgData) to parse/annotate responses as
Repo[] and OrgData so typings flow into components and handlers (update any
function signatures or parameters that currently accept any to use Repo or
OrgData).
| fetch(`https://api.github.com/orgs/${org}/repos`) | ||
| .then((res) => { | ||
| if (!res.ok) throw new Error("Invalid org"); | ||
| return res.json(); |
There was a problem hiding this comment.
Consider GitHub API rate limiting for unauthenticated requests.
Unauthenticated requests to GitHub API are limited to 60 requests per hour. With two API calls per search, users can hit this limit quickly. Consider:
- Adding rate limit headers check (
X-RateLimit-Remaining) - Displaying remaining requests to users
- Documenting this limitation
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 26 - 29, The unauthenticated
GitHub fetch in Dashboard.tsx (the
fetch(`https://api.github.com/orgs/${org}/repos`) call) can hit the 60/hr rate
limit; update the fetch handling to read rate-limit headers
(res.headers.get('X-RateLimit-Remaining') and 'X-RateLimit-Reset'), detect when
remaining === '0' or when res.status === 403, and surface a clear UI message
(e.g., set state like rateLimitRemaining and rateLimitReset and show it in the
component) instead of only throwing "Invalid org"; also document this limitation
in the README and/or component UI and consider allowing an authenticated token
option to increase limits.
| fetch(`https://api.github.com/orgs/${org}`) | ||
| .then((res) => res.json()) | ||
| .then((data) => { | ||
| setOrgData(data); | ||
| }); |
There was a problem hiding this comment.
Missing error handling for organization details fetch.
If this request fails (network error, invalid org, rate limit), it silently fails without updating error state or notifying the user. The orgData could remain stale from a previous search.
🛠️ Proposed fix
fetch(`https://api.github.com/orgs/${org}`)
- .then((res) => res.json())
+ .then((res) => {
+ if (!res.ok) throw new Error("Failed to fetch org details");
+ return res.json();
+ })
.then((data) => {
setOrgData(data);
- });
+ })
+ .catch(() => {
+ setOrgData(null);
+ });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 61 - 65, The fetch block that
calls fetch(`https://api.github.com/orgs/${org}`) lacks error handling and can
leave stale orgData via setOrgData; update it to check response.ok and parse
only on success, handle JSON/network errors with a .catch, and on failure clear
or set orgData to null and set an error state (use your existing error state
setter or add one, e.g., setOrgError) so the UI can show the failure and not
display stale data; also consider toggling any loading state (e.g.,
setIsLoadingOrg) around the request.
| useEffect(() => { | ||
| fetchData(); | ||
| }, [org]); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Add fetchData to useEffect dependencies or wrap in useCallback.
fetchData is called inside useEffect but not listed in the dependency array. This violates React hooks exhaustive-deps rule and will likely trigger an ESLint warning.
♻️ Recommended approach: Move fetch logic inside useEffect
- const fetchData = () => {
- // ... fetch logic
- };
-
- useEffect(() => {
- fetchData();
- }, [org]);
+ useEffect(() => {
+ const fetchData = () => {
+ setLoading(true);
+ setError("");
+ // ... rest of fetch logic
+ };
+ fetchData();
+ }, [org]);Alternatively, wrap fetchData in useCallback with [org] dependencies if you need to call it from multiple places.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 68 - 70, The useEffect in
Dashboard calls fetchData but doesn’t include it in the dependency array,
causing an exhaustive-deps violation; either move the fetch logic directly
inside the useEffect callback (useEffect(() => { /* fetch logic that uses org */
}, [org])) or memoize fetchData with useCallback using [org] so you can keep
calling fetchData elsewhere; update the dependency array to include fetchData if
you choose useCallback, and ensure the function signature (fetchData) and the
org dependency are consistent with the Dashboard component’s state/props.
| <h1 style={{ color: "black" }}> | ||
| 📊 {orgData?.login || org} Analytics Dashboard | ||
| </h1> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Externalize user-visible strings for internationalization.
Hardcoded strings like "Analytics Dashboard", "Search", "Loading...", "Top 5 Repositories by Stars", and stat labels should be externalized to resource files for i18n support.
As per coding guidelines: "User-visible strings should be externalized to resource files (i18n)".
Also applies to: 128-128, 133-133, 176-178
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 97 - 99, The hardcoded
user-visible strings in Dashboard.tsx (e.g., the h1 text "📊 {orgData?.login ||
org} Analytics Dashboard" and other strings at the indicated ranges like
"Search", "Loading...", "Top 5 Repositories by Stars" and stat labels) must be
externalized for i18n: replace literal strings with keys from the app's
i18n/resource system (e.g., use the project’s translation helper such as
t('dashboard.analyticsTitle') or strings.dashboard.analyticsTitle), add
corresponding keys to the resource file(s), and ensure dynamic parts
(org/orgData) are composed with placeholders or string templates supported by
the i18n helper; update all occurrences referenced (lines ~97, ~128, ~133,
~176-178) accordingly.
| data={repos | ||
| .slice(0, 5) | ||
| .map((repo: any) => ({ | ||
| name: repo.name, | ||
| stars: repo.stargazers_count, | ||
| }))} |
There was a problem hiding this comment.
Bug: Chart displays unsorted repos instead of top 5 by stars.
repos.slice(0, 5) uses the unsorted array from the API response. The sorted array (line 42-44) is created but never stored in state, so the chart shows arbitrary repos rather than the top 5 by stars as labeled.
🐛 Proposed fix: Store sorted repos in state
Option 1 - Store sorted repos:
const sorted = [...data].sort(
(a: any, b: any) => b.stargazers_count - a.stargazers_count
);
+ setRepos(sorted);
- setRepos(data);
setStats({
- repos: data.length,
+ repos: sorted.length,
stars,
forks,
topRepo: sorted[0]?.name || "N/A",
});Option 2 - Sort inline in the chart (less efficient but minimal change):
data={repos
+ .sort((a, b) => b.stargazers_count - a.stargazers_count)
.slice(0, 5)
.map((repo: any) => ({📝 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.
| data={repos | |
| .slice(0, 5) | |
| .map((repo: any) => ({ | |
| name: repo.name, | |
| stars: repo.stargazers_count, | |
| }))} | |
| data={repos | |
| .sort((a, b) => b.stargazers_count - a.stargazers_count) | |
| .slice(0, 5) | |
| .map((repo: any) => ({ | |
| name: repo.name, | |
| stars: repo.stargazers_count, | |
| }))} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/Dashboard.tsx` around lines 184 - 189, The chart is using
repos.slice(0, 5) from the unsorted API response instead of the ranked list; use
the already-created sorted array or persist a sorted state so the top 5 by
stargazers_count are shown. Locate the sorting logic (the variable named sorted)
and either setState with that sorted array (e.g., setReposSorted or replace
repos state) or change the chart data prop to use sorted.slice(0,5). Ensure the
data mapping still uses name and stargazers_count (stars) so the chart reflects
the top 5 repos by stars.
Addressed Issues:
Fixes #51
Screenshots/Recordings:

Dashboard Page :
Additional Notes :
This PR adds an Org Analytics Dashboard feature.
Features included:
The feature uses GitHub REST API and is implemented as a client-side solution.
Checklist :
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