Skip to content

feat(WIP): New IssueExplor PR - #412

Closed
aceppaluni wants to merge 38 commits into
hiero-ledger:mainfrom
aceppaluni:IssueTab
Closed

feat(WIP): New IssueExplor PR#412
aceppaluni wants to merge 38 commits into
hiero-ledger:mainfrom
aceppaluni:IssueTab

Conversation

@aceppaluni

@aceppaluni aceppaluni commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR aims to add the Issue Explorer Tab to help users find new tasks to work on.

Changes Made

  • Added...
  • Modified...
  • Fixed...

Related Issues

Fixes: #398

Screenshots (if applicable)

Checklist

  • Tests added/updated
  • Documentation updated
  • Linting passes
  • Branch up-to-date with main

Deployment Notes

Additional Notes

Summary by CodeRabbit

  • New Features

    • Issue Explorer page: search and filter GitHub open issues by difficulty and SDK, with debounced controls and in-memory caching.
    • Responsive issue grid with direct links to GitHub and menu navigation entry for quick access.
  • Bug Fixes / Reliability

    • Improved issue loading UX: clear loading and error states, safer API error handling, duplicate results deduplicated.

Signed-off-by: aceppaluni <aceppaluni@gmail.com>
@netlify

netlify Bot commented Apr 27, 2026

Copy link
Copy Markdown

Deploy Preview for hiero-open-source ready!

Name Link
🔨 Latest commit 803cc10
🔍 Latest deploy log https://app.netlify.com/projects/hiero-open-source/deploys/6a03828638090200083c9ad0
😎 Deploy Preview https://deploy-preview-412--hiero-open-source.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

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1cef2565-76d9-4d9a-87f6-acc8cfd21966

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an "Issue Explorer" feature: a client page with debounced filters that queries a new internal API backed by GitHub search, plus TypeScript models and menu entry. Separately updates Netlify and Next.js deployment configuration to publish the Next.js output and register the Netlify Next.js plugin.

Changes

Build Configuration

Layer / File(s) Summary
Netlify deployment
netlify.toml
Changed [build].publish from out to .next and added [[plugins]] block registering @netlify/plugin-nextjs. Build command and NODE_VERSION unchanged.
Next.js output mode
next.config.ts
Removed output: "export" (commented-out) so static export mode is no longer enabled; images.unoptimized = true remains.

Issue Explorer (feature + API + lib + UI)

Layer / File(s) Summary
Data Shape / Models
src/lib/github/issues.ts, src/app/api/issues/route.ts
Adds GitHubIssue and GitHubSearchResponse interfaces describing the GitHub search response shape.
Core GitHub integration
src/lib/github/issues.ts
Adds searchIssues(query) which calls GitHub Search API with Accept/User-Agent headers, optional Authorization: Bearer when GITHUB_TOKEN present, throws on non-OK responses, and returns parsed JSON.
API Route
src/app/api/issues/route.ts
New GET(req: Request) handler parsing q from URL, calling typed searchIssues, returning JSON on success, and returning structured error payloads with derived status on failure.
Client page logic
src/app/issues/page.tsx
Adds client-only GoodFirstIssues page with useDebouncedValue hook, in-memory cache (Map), abortable fetches to /api/issues?q=..., chunked repository queries, deduplication by id, local difficulty keyword filtering, and loading/error state handling.
Wiring / Navigation
src/components/Menu/index.tsx
Adds "Issue Explorer" menu item linking to /issues/ to surface the new page in navigation.
UI / Presentation
src/app/issues/page.tsx
Renders filter <select> controls, conditional loading/error messages, and a grid of issue cards linking to issue.html_url with title via RichText and repo name extracted from repository_url.

Sequence Diagram

sequenceDiagram
    participant Client as Client (Browser)
    participant Page as Issues Page
    participant API as /api/issues Route
    participant GitHub as GitHub REST API

    Client->>Page: Visit /issues
    activate Page
    Page->>Page: Render filter controls
    Client->>Page: Select difficulty & SDK
    Page->>Page: Build query string
    Page->>API: GET /api/issues?q=<encoded_query>
    activate API
    API->>API: Parse q, call searchIssues
    API->>GitHub: GET /search/issues (Accept/User-Agent, optional Bearer)
    activate GitHub
    GitHub-->>API: 200 + search JSON
    deactivate GitHub
    API-->>Page: 200 + issues data
    deactivate API
    Page->>Page: Update state, dedupe, filter, render grid
    Page-->>Client: Display issue cards with links
    deactivate Page
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested reviewers

  • exploreriii
  • danielmarv
  • jwagantall

Poem

🐰 I hopped along the code-lined trail,
Found issues, queries, and a fetchy tale.
Filters ready, menus bright,
Explorer hums into the night—
A patch of bugs, now soft and hale.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Changes to netlify.toml and next.config.ts appear out-of-scope for issue #398, which focuses on the Issue Explorer feature. These infrastructure changes require clarification or a separate issue. Clarify whether netlify.toml and next.config.ts changes are necessary for the Issue Explorer feature, or move them to a separate PR if they represent independent infrastructure work.
Title check ❓ Inconclusive The PR title is vague and incomplete—'IssueExplor PR' is truncated and doesn't clearly convey the main feature being implemented, which is adding an Issue Explorer tab to the navigation. Update the title to be clear and complete, such as 'feat: Add Issue Explorer tab to navigation' or 'feat: Add Issue Explorer page with GitHub issue filtering'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description provides an overview and a valid related issue link but contains mostly unchecked placeholder checklist items without detailed information about specific changes made (Added/Modified/Fixed).
Linked Issues check ✅ Passed All primary coding requirements from issue #398 are met: new Issue Explorer tab in navigation, dedicated page at src/app/issues, GitHub issue search functionality, and styling consistency maintained.

✏️ 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.

@lfdt-bot

lfdt-bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@aceppaluni aceppaluni changed the title feat: New IssueExplor PR feat(WIP): New IssueExplor PR Apr 27, 2026
@codacy-production

codacy-production Bot commented Apr 27, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 27 high

Alerts:
⚠ 27 issues (≤ 0 issues of at least minor severity)

Results:
27 new issues

Category Results
ErrorProne 26 high
Security 1 high

View in Codacy

🟢 Metrics 35 complexity · 0 duplication

Metric Results
Complexity 35
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
@aceppaluni
aceppaluni marked this pull request as ready for review April 28, 2026 17:43
@aceppaluni
aceppaluni requested review from a team as code owners April 28, 2026 17:43
@aceppaluni aceppaluni changed the title feat(WIP): New IssueExplor PR feat: New IssueExplor PR Apr 28, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
next.config.ts (1)

4-4: Remove commented config to avoid deployment ambiguity.

Line 4 leaves output: "export" as commented code. Since this app now relies on server runtime behavior (e.g., src/app/api/issues/route.ts Lines 1-10), keeping this commented setting is easy to misread and accidentally re-enable later.

Suggested cleanup
 const nextConfig: NextConfig = {
-  //output: "export",
   images: {
     unoptimized: true,
   },
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@next.config.ts` at line 4, Remove the commented-out Next config entry
`output: "export"` from next.config.ts to prevent accidental re-enabling and
deployment ambiguity; locate the commented line containing `//output: "export"`
and delete it so the active server/runtime behavior (e.g., server routes under
src/app/api) remains unambiguous.
src/app/issues/page.tsx (2)

45-77: Remove commented-out legacy blocks.

These commented sections add noise and make the active logic harder to follow.

Also applies to: 89-108

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

In `@src/app/issues/page.tsx` around lines 45 - 77, Remove the commented-out
legacy buildQuery block and the other commented sections referring to
sdk/difficulty logic to reduce noise; specifically delete the commented function
buildQuery and any commented code that references sdkMap, difficultyMap,
getSdkValue/getDifficultyValue, sdk, and difficulty so only the active
query-building logic remains; ensure you only remove commented legacy code and
leave any live functions, imports, or variables used elsewhere intact.

30-43: Stabilize map constants to resolve Hook dependency warning cleanly.

difficultyMap and sdkMap are recreated on each render but used in Line 109 effect. Move them to module scope (or memoize) to avoid dependency ambiguity and lint noise.

Also applies to: 109-151

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

In `@src/app/issues/page.tsx` around lines 30 - 43, The difficultyMap and sdkMap
objects are recreated every render and cause a hook dependency warning for the
effect that references them (the effect around Line 109); to fix, lift
difficultyMap and sdkMap out of the React component into module scope as
top-level consts (or alternatively wrap them with useMemo inside the component)
so they are stable references, then adjust the effect dependencies accordingly
(if moved to module scope, remove them from the dependency array; if memoized,
keep the memo values in the array). Ensure you update references to
difficultyMap and sdkMap in the effect and elsewhere to use the new stable
identifiers.
src/lib/github/issues.ts (1)

34-40: Remove the library-level GET handler to avoid duplicated API entrypoints.

This file should stay as a data client (searchIssues) only. Keeping GET here duplicates route concerns already handled in src/app/api/issues/route.ts.

Suggested cleanup
-export async function GET(req: Request) {
-  const { searchParams } = new URL(req.url);
-  const q = searchParams.get("q") || "";
-
-  const data = await searchIssues(q);
-  return Response.json(data);
-}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/github/issues.ts` around lines 34 - 40, Remove the library-level HTTP
handler by deleting the exported async function GET in this module so the file
only exposes the data client (searchIssues); ensure searchIssues remains
exported and update any internal references to not import GET (only import
searchIssues) so routing is only handled by the existing api route handler
(src/app/api/issues/route.ts) and there are no duplicate entrypoints.
🤖 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/app/api/issues/route.ts`:
- Around line 7-10: Wrap the await searchIssues(q) call in a try/catch inside
the route handler; if searchIssues throws, catch the error and return a JSON
response using Response.json with a body like { items: [], error: <error
message> } and an appropriate status (e.g., 500). Update the handler where
searchIssues and Response.json are used so the happy path still returns
Response.json(data) but failures return the structured JSON error shape instead.

In `@src/app/issues/page.tsx`:
- Line 174: Update the option text for the select option with value "" in the
page component so the label reads "All Repos" instead of "All Repo's"; locate
the <option value="">All Repo&apos;s</option> occurrence in the component
(page.tsx) and change the displayed string to "All Repos".
- Around line 156-180: The two <select> controls bound to state variables
difficulty (with setDifficulty) and sdk (with setSdk) lack accessible labels;
add visible <label> elements for each select and associate them via id/for
attributes (e.g., give the difficulty select an id like "filter-difficulty" and
the sdk select an id like "filter-sdk"), or alternatively add clear aria-label
attributes if visible labels are undesired, ensuring the label text (e.g.,
"Difficulty" and "SDK") uniquely identifies each control for assistive tech.
- Around line 109-151: The fetch effect can leak older responses; create a new
AbortController inside the useEffect (used by fetchIssues), pass
controller.signal into getIssues, and abort the controller in the effect cleanup
so previous requests are cancelled when difficulty/sdk change; inside
fetchIssues catch AbortError specifically and avoid calling setError or
overwriting setIssues for aborted requests, while still ensuring
setLoading(false) runs in finally. Ensure references: useEffect, buildQuery,
fetchIssues, getIssues, setLoading, setError, setIssues.

In `@src/lib/github/issues.ts`:
- Around line 25-31: Update the fetch call that assigns to const res so it uses
an AbortController with a configurable timeout (e.g., 10s) and passes
controller.signal to fetch to avoid hangs, then on non-OK responses throw an
Error that includes res.status and the response body text (await res.text()) for
debugging; locate the fetch(...) invocation and the subsequent if (!res.ok)
branch in src/lib/github/issues.ts and replace the simple throw with a
propagated error containing HTTP status and body after the timeout-enabled
request.

---

Nitpick comments:
In `@next.config.ts`:
- Line 4: Remove the commented-out Next config entry `output: "export"` from
next.config.ts to prevent accidental re-enabling and deployment ambiguity;
locate the commented line containing `//output: "export"` and delete it so the
active server/runtime behavior (e.g., server routes under src/app/api) remains
unambiguous.

In `@src/app/issues/page.tsx`:
- Around line 45-77: Remove the commented-out legacy buildQuery block and the
other commented sections referring to sdk/difficulty logic to reduce noise;
specifically delete the commented function buildQuery and any commented code
that references sdkMap, difficultyMap, getSdkValue/getDifficultyValue, sdk, and
difficulty so only the active query-building logic remains; ensure you only
remove commented legacy code and leave any live functions, imports, or variables
used elsewhere intact.
- Around line 30-43: The difficultyMap and sdkMap objects are recreated every
render and cause a hook dependency warning for the effect that references them
(the effect around Line 109); to fix, lift difficultyMap and sdkMap out of the
React component into module scope as top-level consts (or alternatively wrap
them with useMemo inside the component) so they are stable references, then
adjust the effect dependencies accordingly (if moved to module scope, remove
them from the dependency array; if memoized, keep the memo values in the array).
Ensure you update references to difficultyMap and sdkMap in the effect and
elsewhere to use the new stable identifiers.

In `@src/lib/github/issues.ts`:
- Around line 34-40: Remove the library-level HTTP handler by deleting the
exported async function GET in this module so the file only exposes the data
client (searchIssues); ensure searchIssues remains exported and update any
internal references to not import GET (only import searchIssues) so routing is
only handled by the existing api route handler (src/app/api/issues/route.ts) and
there are no duplicate entrypoints.
🪄 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: 1e2a1c46-c139-467f-acf0-c238da54478e

📥 Commits

Reviewing files that changed from the base of the PR and between 6ef16f7 and cb8c6f0.

📒 Files selected for processing (6)
  • netlify.toml
  • next.config.ts
  • src/app/api/issues/route.ts
  • src/app/issues/page.tsx
  • src/components/Menu/index.tsx
  • src/lib/github/issues.ts

Comment thread src/app/api/issues/route.ts Outdated
Comment thread src/app/issues/page.tsx Outdated
Comment thread src/app/issues/page.tsx
Comment thread src/app/issues/page.tsx Outdated
Comment thread src/lib/github/issues.ts Outdated
@aceppaluni aceppaluni changed the title feat: New IssueExplor PR feat(WIP): New IssueExplor PR Apr 28, 2026
@aceppaluni aceppaluni added the status: needs discussion blocked until discussion resolved label Apr 28, 2026
@aceppaluni aceppaluni changed the title feat(WIP): New IssueExplor PR feat: New IssueExplor PR May 4, 2026
Comment thread src/app/issues/page.tsx Outdated
danielmarv

This comment was marked as duplicate.

@danielmarv danielmarv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@aceppaluni Thanks for working on the Issue Explorer. but before this is merged, please align the new /issues page with the existing layout system.

The page currently renders its content inside a plain top-level <div>. Since the project already has a reusable Container component, this page should use it to keep spacing, max-width behavior, and responsive layout consistent with the rest of the site.

Please update src/app/issues/page.tsx to import and use the shared container:

import Container from "@/components/Container";

Then wrap the page content with it, for example:

return (
  <Container className="py-12">
    {/* Filters */}
    <div className="mb-6 flex gap-4">
      ...
    </div>

    {/* Issues Grid */}
    ...
  </Container>
);

This avoids introducing one-off layout wrappers and keeps the new Issue Explorer page consistent with the existing design system.
Please use the shared Container component here instead of a plain top-level <div>. This page is introducing a new full-page layout, so wrapping the filters and issue grid in Container will keep the width, spacing, and responsive behavior consistent with the rest of the site.

for that addressed it will good to go

Signed-off-by: aceppaluni <aceppaluni@gmail.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/app/issues/page.tsx (1)

172-198: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Accessible labels for <select> controls are still missing.

Both filter selects have no associated <label> element and no aria-label, so assistive technology cannot identify them. This was flagged in the previous review and remains unresolved.

♿ Proposed fix
       <div className="flex gap-4 mb-6">
+        <label htmlFor="filter-difficulty" className="sr-only">
+          Difficulty
+        </label>
         <select
+          id="filter-difficulty"
           value={difficulty}
           onChange={e => setDifficulty(e.target.value)}
           className="p-2 rounded border">
           ...
         </select>

+        <label htmlFor="filter-sdk" className="sr-only">
+          Repository
+        </label>
         <select
+          id="filter-sdk"
           value={sdk}
           onChange={e => setSdk(e.target.value)}
           className="p-2 rounded border">
🤖 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/app/issues/page.tsx` around lines 172 - 198, Add accessible labels for
the two select controls that currently use value={difficulty} onChange={e =>
setDifficulty(e.target.value)} and value={sdk} onChange={e =>
setSdk(e.target.value)}: either add a visually-present <label> linked via
htmlFor to each <select> id (e.g., id="difficulty-select" and id="sdk-select")
or add clear aria-label attributes (e.g., aria-label="Filter by difficulty" and
aria-label="Filter by repository / SDK") so screen readers can identify them;
ensure IDs/labels match and keep existing className and onChange handlers.
🧹 Nitpick comments (3)
src/app/issues/page.tsx (2)

65-85: ⚡ Quick win

Move getIssues and matchesDifficulty to module scope to fix missing useEffect dependencies.

Both functions are declared inside the component body but close over no component state — they access only module-level cache and their own parameters. Because they're re-created on every render, they are technically unstable references omitted from the useEffect dependency array at line 166, which will trigger react-hooks/exhaustive-deps warnings. Moving them to module scope fixes the lint violation with zero behavior change.

♻️ Proposed refactor
+const getIssues = async (
+  query: string,
+  signal?: AbortSignal,
+): Promise<GitHubSearchResponse> => {
+  if (cache.has(query)) {
+    return cache.get(query)!;
+  }
+  const res = await fetch(`/api/issues?q=${encodeURIComponent(query)}`, { signal });
+  const data = (await res.json()) as GitHubSearchResponse;
+  if (!res.ok) {
+    throw new Error(data.error ?? "Failed to fetch issues");
+  }
+  cache.set(query, data);
+  return data;
+};
+
+const matchesDifficulty = (issue: GitHubIssue, difficulty: string) => {
+  // ... same body
+};
+
 export default function GoodFirstIssues() {
   // ...
-  const getIssues = async (...) => { ... };
-  const matchesDifficulty = (...) => { ... };

Also applies to: 90-108, 166-166

🤖 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/app/issues/page.tsx` around lines 65 - 85, The functions getIssues and
matchesDifficulty are defined inside the component causing unstable references
and ESLint exhaustives-deps warnings; move both getIssues (which uses the
module-level cache and fetch) and matchesDifficulty to module scope (outside the
React component) so they no longer get re-created on each render, update any
imports/exports if necessary, and ensure their signatures remain the same
(getIssues(query: string, signal?: AbortSignal): Promise<GitHubSearchResponse>)
so existing useEffect calls can depend on stable references without behavior
change.

7-17: ⚡ Quick win

Consolidate shared types into a single module.

GitHubIssue and GitHubSearchResponse are now declared in three places: src/lib/github/issues.ts, src/app/api/issues/route.ts, and here. Any divergence (like the error? field being in some but not others) will silently cause type drift. Extract to a shared src/types/github.ts (or re-export from the lib) and import from one source.

🤖 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/app/issues/page.tsx` around lines 7 - 17, The GitHubIssue and
GitHubSearchResponse types are duplicated across the codebase; create a single
shared module that exports the types (e.g., export type GitHubIssue and export
type GitHubSearchResponse with the optional error? field) and update all places
that currently redeclare them to import these types instead (replace local
declarations in the modules that define/use GitHubIssue and GitHubSearchResponse
with imports from the shared module and ensure the optional error? field is
consistent everywhere).
src/app/api/issues/route.ts (1)

3-18: ⚡ Quick win

Remove duplicate interface definitions and the dead-code workaround.

Three problems in this block:

  1. GitHubIssue (lines 3–8) duplicates the exported interface from src/lib/github/issues.ts with identical fields.
  2. GitHubSearchResponse (lines 10–13) re-declares the lib type with only error? added and total_count dropped — the sole reason for the rawSearchIssues as SearchIssuesFn cast.
  3. Line 17 is a dead-code artifact (/*const searchIssues = rawSearchIssues as searchIssues;*/).

Import GitHubIssue from the lib and define only a minimal local error-response type:

♻️ Proposed refactor
-import { searchIssues as rawSearchIssues } from "src/lib/github/issues";
+import { searchIssues, GitHubIssue } from "src/lib/github/issues";

-interface GitHubIssue {
-  id: number;
-  title: string;
-  html_url: string;
-  repository_url: string;
-}
-
-interface GitHubSearchResponse {
-  items: GitHubIssue[];
-  error?: string;
-}
+interface ApiErrorResponse {
+  items: GitHubIssue[];
+  error: string;
+}

-// eslint-disable-next-line `@typescript-eslint/no-unused-vars`
-type SearchIssuesFn = (_query: string) => Promise<GitHubSearchResponse>;
-/*const searchIssues = rawSearchIssues as searchIssues;*/
-const searchIssues = rawSearchIssues as SearchIssuesFn;

Then update the error-path return to use the new type:

-    return Response.json({ items: [], error: message }, { status });
+    return Response.json({ items: [], error: message } satisfies ApiErrorResponse, { status });
🤖 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/app/api/issues/route.ts` around lines 3 - 18, Remove the duplicate type
definitions and dead-code cast: import the existing GitHubIssue interface from
the lib instead of re-declaring it, delete the locally duplicated
GitHubSearchResponse, remove the commented-out workaround (/*const
searchIssues...*/), and replace the local SearchIssuesFn/typed cast by declaring
a minimal local error response type (e.g., { error?: string }) used only for
error-path returns; keep the actual search function reference as const
searchIssues = rawSearchIssues and update any error return to use the new
minimal error-response type so the code no longer masks the original lib types.
🤖 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/app/issues/page.tsx`:
- Around line 90-108: matchesDifficulty currently inspects issue.title for
difficulty keywords (function matchesDifficulty) which is wrong; instead remove
this client-side title filter and wire the selected difficulty into the GitHub
search query/labels when fetching issues (the issue fetcher / query builder
where issues are requested) so the API returns only issues with the appropriate
label (e.g., "good first issue" or repo-specific "skill: beginner"). Delete or
disable the map and matchesDifficulty usage and update the search parameter
construction to add label:<labelName> (or multiple label qualifiers) based on
the difficulty select value; ensure the select option values match actual repo
label names and fallback to no label when difficulty is empty.

---

Duplicate comments:
In `@src/app/issues/page.tsx`:
- Around line 172-198: Add accessible labels for the two select controls that
currently use value={difficulty} onChange={e => setDifficulty(e.target.value)}
and value={sdk} onChange={e => setSdk(e.target.value)}: either add a
visually-present <label> linked via htmlFor to each <select> id (e.g.,
id="difficulty-select" and id="sdk-select") or add clear aria-label attributes
(e.g., aria-label="Filter by difficulty" and aria-label="Filter by repository /
SDK") so screen readers can identify them; ensure IDs/labels match and keep
existing className and onChange handlers.

---

Nitpick comments:
In `@src/app/api/issues/route.ts`:
- Around line 3-18: Remove the duplicate type definitions and dead-code cast:
import the existing GitHubIssue interface from the lib instead of re-declaring
it, delete the locally duplicated GitHubSearchResponse, remove the commented-out
workaround (/*const searchIssues...*/), and replace the local
SearchIssuesFn/typed cast by declaring a minimal local error response type
(e.g., { error?: string }) used only for error-path returns; keep the actual
search function reference as const searchIssues = rawSearchIssues and update any
error return to use the new minimal error-response type so the code no longer
masks the original lib types.

In `@src/app/issues/page.tsx`:
- Around line 65-85: The functions getIssues and matchesDifficulty are defined
inside the component causing unstable references and ESLint exhaustives-deps
warnings; move both getIssues (which uses the module-level cache and fetch) and
matchesDifficulty to module scope (outside the React component) so they no
longer get re-created on each render, update any imports/exports if necessary,
and ensure their signatures remain the same (getIssues(query: string, signal?:
AbortSignal): Promise<GitHubSearchResponse>) so existing useEffect calls can
depend on stable references without behavior change.
- Around line 7-17: The GitHubIssue and GitHubSearchResponse types are
duplicated across the codebase; create a single shared module that exports the
types (e.g., export type GitHubIssue and export type GitHubSearchResponse with
the optional error? field) and update all places that currently redeclare them
to import these types instead (replace local declarations in the modules that
define/use GitHubIssue and GitHubSearchResponse with imports from the shared
module and ensure the optional error? field is consistent everywhere).
🪄 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: 3f6bb07e-85ce-46e4-8bf4-99900f315566

📥 Commits

Reviewing files that changed from the base of the PR and between cb8c6f0 and b2ccc0c.

📒 Files selected for processing (3)
  • src/app/api/issues/route.ts
  • src/app/issues/page.tsx
  • src/lib/github/issues.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/github/issues.ts

Comment thread src/app/issues/page.tsx Outdated
aceppaluni added 2 commits May 4, 2026 19:04
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>

@exploreriii exploreriii left a comment

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.

The codacy issues here will block you

I’d recommend splitting this into smaller, more manageable units

Right now src/app/issues/page.tsx contains UI, fetch logic, caching, filtering, maps, debounce logic, and response-shape assumptions in one client component. That makes the page harder to review, test, and maintain and means if you have a codacy issue, its difficult to solve it as there are lots of other things mixed in

Suggested structure:

  • move GitHub/API fetching into a helper or service module
  • move useDebouncedValue into a shared hook
  • move repo/difficulty maps and filtering helpers into a separate utility file
  • keep page.tsx focused on rendering and composing smaller components
  • extract filters and issue cards into separate components
  • strictly type the API response and validate it before using it

There are also type-safety issues flagged by Codacy. In particular, searchIssues() currently casts the GitHub response directly to GitHubSearchResponse, and the route then trusts that shape. We should validate the JSON response before returning it.

One other issue: src/lib/github/issues.ts appears to include a GET route handler at the bottom. That should not live in the lib file; route handlers should stay under src/app/api/.../route.ts.

Additionally, I would really focus on stripping this to be simpler

  • for example, do we need cache and debouncing right now?
  • why filter by issue title, we can filter by the issue labels? then you don't need to add custom sort logic
  • we don't need to fetch all repos

eg
Page.tsx
renders page only

separate components:
IssueFilters.tsx
IssueCard.tsx
IssueGrid.tsx
etc

separate hooks eg:
hooks/useIssues.ts

ssues/types.ts
ssues/filters.ts

@exploreriii
exploreriii marked this pull request as draft May 5, 2026 10:28
@aceppaluni aceppaluni changed the title feat: New IssueExplor PR feat(WIP): New IssueExplor PR May 5, 2026
aceppaluni and others added 23 commits May 5, 2026 19:04
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
@aceppaluni aceppaluni closed this May 12, 2026
@aceppaluni aceppaluni mentioned this pull request May 12, 2026
7 tasks
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.

[Intermediate]: Make a New Tab for Locating Issues

4 participants