Skip to content

feat: add org analytics dashboard with charts and dynamic org support#52

Open
yanamavani wants to merge 1 commit intoAOSSIE-Org:mainfrom
yanamavani:feature/analytics-dashboard
Open

feat: add org analytics dashboard with charts and dynamic org support#52
yanamavani wants to merge 1 commit intoAOSSIE-Org:mainfrom
yanamavani:feature/analytics-dashboard

Conversation

@yanamavani
Copy link

@yanamavani yanamavani commented Mar 23, 2026

Addressed Issues:
Fixes #51

Screenshots/Recordings:
Dashboard Page :
image

Additional Notes :
This PR adds an Org Analytics Dashboard feature.

Features included:

  • Displays total repositories, stars, and forks
  • Shows most starred repository
  • Dynamic organization search
  • Organization logo display
  • Bar chart visualization for top repositories
  • Loading and error handling

The feature uses GitHub REST API and is implemented as a client-side solution.

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 organization analytics dashboard displaying key metrics including repository count, total stars, total forks, and top repository
    • Integrated interactive bar chart visualization of top 5 repositories by star count
    • Included loading and error states for seamless data retrieval experience

@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

Walkthrough

This 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

Cohort / File(s) Summary
Dependency Updates
package.json
Added recharts (^3.8.0) dependency to enable chart visualization library support.
App Integration
src/App.tsx
Updated root component to import and render the new Dashboard component, replacing the static greeting text.
Dashboard Component
src/components/Dashboard.tsx
New analytics dashboard component that fetches GitHub organization and repository data via REST API, computes aggregate statistics (total repos, stars, forks, top repository), manages UI state (loading, error, input), and renders summary stat cards alongside a Recharts bar chart displaying the top 5 repositories by star count.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

Typescript Lang

Poem

🐰 A dashboard springs to life with glee,
GitHub data flows wild and free,
Charts of repos dance in the light,
Recharts paints the stats just right! ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding an organization analytics dashboard with chart visualization and dynamic organization search support.
Linked Issues check ✅ Passed The PR implementation fully addresses all coding requirements from issue #51: dashboard with repo/stars/forks/top repo stats, bar chart for top 5 repos, GitHub REST API integration, client-side only, dynamic org search, org branding/logo display, and Recharts visualization.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the dashboard feature: package.json adds recharts dependency, App.tsx integrates the Dashboard component, and Dashboard.tsx implements the complete analytics dashboard feature with no extraneous modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

📥 Commits

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

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

Comment on lines +8 to +9
const [repos, setRepos] = useState<any[]>([]);
const [orgData, setOrgData] = useState<any>(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 | 🟠 Major

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

Comment on lines +26 to +29
fetch(`https://api.github.com/orgs/${org}/repos`)
.then((res) => {
if (!res.ok) throw new Error("Invalid org");
return res.json();
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

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.

Comment on lines +61 to +65
fetch(`https://api.github.com/orgs/${org}`)
.then((res) => res.json())
.then((data) => {
setOrgData(data);
});
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

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.

Comment on lines +68 to +70
useEffect(() => {
fetchData();
}, [org]);
Copy link

Choose a reason for hiding this comment

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

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

Comment on lines +97 to +99
<h1 style={{ color: "black" }}>
📊 {orgData?.login || org} Analytics Dashboard
</h1>
Copy link

Choose a reason for hiding this comment

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

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

Comment on lines +184 to +189
data={repos
.slice(0, 5)
.map((repo: any) => ({
name: repo.name,
stars: repo.stargazers_count,
}))}
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

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.

Suggested change
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.

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.

FEATURE : Enhance dashboard with dynamic organization branding and analytics charts

1 participant