Skip to content

feat: add issues tracking page with filters and sorting#273

Open
isauravanand wants to merge 1 commit into
GitMetricsLab:mainfrom
isauravanand:feature/track-issues
Open

feat: add issues tracking page with filters and sorting#273
isauravanand wants to merge 1 commit into
GitMetricsLab:mainfrom
isauravanand:feature/track-issues

Conversation

@isauravanand
Copy link
Copy Markdown

@isauravanand isauravanand commented May 16, 2026

Related Issue


Description

This PR introduces a new Issues Tracking Page (/issues) that allows users to explore open GitHub issues directly from the platform.

Features Implemented

  • Integrated the GitHub Search API to dynamically fetch and display open issues

  • Added filtering options based on:

    • Programming Languages (JavaScript, Python, Go, etc.)
    • Labels/Tags (good first issue, bug, etc.)
  • Implemented sorting functionality for:

    • Newest Issues
    • Oldest Issues
  • Added /issues route integration in both desktop and mobile Navbar components

  • Improved code quality by:

    • Fixing strict TypeScript typings (SelectChangeEvent)
    • Removing unused imports
    • Ensuring clean build and lint compatibility

How Has This Been Tested?

  • Tested the feature locally using the Vite development server
  • Verified GitHub API requests and query parameter handling
  • Confirmed filters and sorting work correctly
  • Tested API error handling (including rate-limit scenarios)
  • Verified responsive UI behavior across different screen sizes
  • Ensured there are no TypeScript or ESLint errors in modified files

Screenshots

image

Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a new Issues page to browse and filter GitHub issues with pagination.
    • Integrated GitHub Issues API search with pagination and multiple sorting options.
    • Added configurable filters for programming language, issue labels/tags, and result ordering.
    • Included error handling for API rate limits and connection issues.
    • Added navigation link to the Issues page in both desktop and mobile menus.

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 16, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 3dbd9ba
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a0820a690291f000867c6c5
😎 Deploy Preview https://deploy-preview-273--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

📝 Walkthrough

Walkthrough

This PR adds a new Issues page that fetches and displays GitHub issues with language, label, and sort order filters. It includes the page component with API integration and pagination, plus routing and navbar navigation to make it accessible from the app.

Changes

Issues Page Feature

Layer / File(s) Summary
Issues page component with API fetching and state management
src/pages/Issues/Issues.tsx
Issues component manages state for pagination, filters, and loading/error status. It fetches GitHub issues via search query, renders filter dropdowns for language/labels/sort, handles rate-limit errors with user-visible alerts, and displays results in a paginated MUI table with issue icons and external links.
Route registration and navbar navigation
src/Routes/Router.tsx, src/components/Navbar.tsx
Router registers /issues route mapped to Issues component. Navbar adds "Issues" navigation links in both desktop and mobile menus, with mobile menu closing on navigation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A new Issues page hops into view,
With filters and tables and pagination too!
From GitHub's great API, issues now flow,
Through navbar and routes, watch the feature grow! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding a new issues tracking page with filter and sorting capabilities, which aligns with the primary objective of the PR.
Description check ✅ Passed The description comprehensively covers all required template sections including related issue, detailed feature description, testing methodology, screenshots, and change type selection.
Linked Issues check ✅ Passed The PR successfully implements all objectives from issue #55: a page to track GitHub issues with language and label filters, sorting by newest/oldest, and route integration in navigation components.
Out of Scope Changes check ✅ Passed All code changes are directly related to the linked issue #55: adding the Issues page component, integrating GitHub API, adding filters and sorting, and updating navigation routes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🎉 Thank you @isauravanand for your contribution. Please make sure your PR follows https://github.com/GitMetricsLab/github_tracker/blob/main/CONTRIBUTING.md#-pull-request-guidelines

Copy link
Copy Markdown
Contributor

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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/Issues/Issues.tsx`:
- Around line 50-90: fetchIssues can race when multiple requests are in-flight;
create an AbortController ref (e.g., abortControllerRef) and before starting a
new fetch in fetchIssues abort any existing controller, then create a new
controller and pass its signal to fetch; in the catch block ignore abort errors
(check err.name === 'AbortError' or err instanceof DOMException) and only
setError for real failures; also abort any pending request in the useEffect
cleanup (return () => abortControllerRef.current?.abort()) so stale responses
never overwrite newer state.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6d52a1d-61db-4469-baea-c94533ed0b45

📥 Commits

Reviewing files that changed from the base of the PR and between 7a15543 and 3dbd9ba.

📒 Files selected for processing (3)
  • src/Routes/Router.tsx
  • src/components/Navbar.tsx
  • src/pages/Issues/Issues.tsx

Comment on lines +50 to +90
const fetchIssues = useCallback(async (currentPage: number, currentLanguage: string, currentTag: string, currentOrder: string) => {
setLoading(true);
setError("");

try {
let q = "is:issue is:open";
if (currentLanguage) {
q += ` language:${currentLanguage}`;
}
if (currentTag) {
q += ` label:"${currentTag}"`;
}

const response = await fetch(
`https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}`
);

if (!response.ok) {
if (response.status === 403) {
throw new Error("GitHub API rate limit exceeded.");
}
throw new Error("Failed to fetch data");
}

const data = await response.json();
setIssues(data.items);
setTotalIssues(data.total_count > 1000 ? 1000 : data.total_count); // GitHub limits search results to 1000
} catch (err: unknown) {
if (err instanceof Error) {
setError(err.message || "Failed to fetch issues");
} else {
setError("Failed to fetch issues");
}
} finally {
setLoading(false);
}
}, []);

useEffect(() => {
fetchIssues(page, language, tag, sortOrder);
}, [page, language, tag, sortOrder, fetchIssues]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether request cancellation is implemented for Issues fetching.
rg -n --type=tsx -e 'AbortController' -e 'controller\.abort' -e 'signal' -e 'fetchIssues\(' src/pages/Issues/Issues.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 100


🏁 Script executed:

fd -i "issues.tsx" -o -i "issues.ts"

Repository: GitMetricsLab/github_tracker

Length of output: 189


🏁 Script executed:

fd -type f "Issues" src/pages/

Repository: GitMetricsLab/github_tracker

Length of output: 243


🏁 Script executed:

find src/pages/ -name "*Issues*" -type f

Repository: GitMetricsLab/github_tracker

Length of output: 100


🏁 Script executed:

cat src/pages/Issues/Issues.tsx

Repository: GitMetricsLab/github_tracker

Length of output: 7909


Prevent stale results from out-of-order fetch responses.

Multiple in-flight requests can race here; an older response can arrive last and overwrite the latest filter/page state. This happens because rapid filter/page/sort changes trigger new fetchIssues calls via the dependency array [page, language, tag, sortOrder, fetchIssues] without canceling the previous request.

💡 Suggested fix (abort previous request + ignore abort errors)
-  const fetchIssues = useCallback(async (currentPage: number, currentLanguage: string, currentTag: string, currentOrder: string) => {
+  const fetchIssues = useCallback(
+    async (
+      currentPage: number,
+      currentLanguage: string,
+      currentTag: string,
+      currentOrder: string,
+      signal: AbortSignal
+    ) => {
     setLoading(true);
     setError("");
@@
-      const response = await fetch(
-        `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}`
-      );
+      const response = await fetch(
+        `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}`,
+        { signal }
+      );
@@
       const data = await response.json();
+      if (signal.aborted) return;
       setIssues(data.items);
       setTotalIssues(data.total_count > 1000 ? 1000 : data.total_count); // GitHub limits search results to 1000
     } catch (err: unknown) {
+      if (err instanceof DOMException && err.name === "AbortError") return;
       if (err instanceof Error) {
         setError(err.message || "Failed to fetch issues");
       } else {
         setError("Failed to fetch issues");
       }
     } finally {
       setLoading(false);
     }
-  }, []);
+  }, []);
@@
-  useEffect(() => {
-    fetchIssues(page, language, tag, sortOrder);
-  }, [page, language, tag, sortOrder, fetchIssues]);
+  useEffect(() => {
+    const controller = new AbortController();
+    fetchIssues(page, language, tag, sortOrder, controller.signal);
+    return () => controller.abort();
+  }, [page, language, tag, sortOrder, fetchIssues]);
📝 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 fetchIssues = useCallback(async (currentPage: number, currentLanguage: string, currentTag: string, currentOrder: string) => {
setLoading(true);
setError("");
try {
let q = "is:issue is:open";
if (currentLanguage) {
q += ` language:${currentLanguage}`;
}
if (currentTag) {
q += ` label:"${currentTag}"`;
}
const response = await fetch(
`https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}`
);
if (!response.ok) {
if (response.status === 403) {
throw new Error("GitHub API rate limit exceeded.");
}
throw new Error("Failed to fetch data");
}
const data = await response.json();
setIssues(data.items);
setTotalIssues(data.total_count > 1000 ? 1000 : data.total_count); // GitHub limits search results to 1000
} catch (err: unknown) {
if (err instanceof Error) {
setError(err.message || "Failed to fetch issues");
} else {
setError("Failed to fetch issues");
}
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchIssues(page, language, tag, sortOrder);
}, [page, language, tag, sortOrder, fetchIssues]);
const fetchIssues = useCallback(
async (
currentPage: number,
currentLanguage: string,
currentTag: string,
currentOrder: string,
signal: AbortSignal
) => {
setLoading(true);
setError("");
try {
let q = "is:issue is:open";
if (currentLanguage) {
q += ` language:${currentLanguage}`;
}
if (currentTag) {
q += ` label:"${currentTag}"`;
}
const response = await fetch(
`https://api.github.com/search/issues?q=${encodeURIComponent(q)}&sort=created&order=${currentOrder}&per_page=${ROWS_PER_PAGE}&page=${currentPage + 1}`,
{ signal }
);
if (!response.ok) {
if (response.status === 403) {
throw new Error("GitHub API rate limit exceeded.");
}
throw new Error("Failed to fetch data");
}
const data = await response.json();
if (signal.aborted) return;
setIssues(data.items);
setTotalIssues(data.total_count > 1000 ? 1000 : data.total_count); // GitHub limits search results to 1000
} catch (err: unknown) {
if (err instanceof DOMException && err.name === "AbortError") return;
if (err instanceof Error) {
setError(err.message || "Failed to fetch issues");
} else {
setError("Failed to fetch issues");
}
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
const controller = new AbortController();
fetchIssues(page, language, tag, sortOrder, controller.signal);
return () => controller.abort();
}, [page, language, tag, sortOrder, fetchIssues]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Issues/Issues.tsx` around lines 50 - 90, fetchIssues can race when
multiple requests are in-flight; create an AbortController ref (e.g.,
abortControllerRef) and before starting a new fetch in fetchIssues abort any
existing controller, then create a new controller and pass its signal to fetch;
in the catch block ignore abort errors (check err.name === 'AbortError' or err
instanceof DOMException) and only setError for real failures; also abort any
pending request in the useEffect cleanup (return () =>
abortControllerRef.current?.abort()) so stale responses never overwrite newer
state.

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: Add a page to track all github issues with filters of programming language, labels

1 participant