Skip to content

feat: Implemented autocomplete dropdown for GitHub organization search with chip support#87

Open
Ridima28 wants to merge 4 commits into
AOSSIE-Org:mainfrom
Ridima28:'adding-search-suggestion'
Open

feat: Implemented autocomplete dropdown for GitHub organization search with chip support#87
Ridima28 wants to merge 4 commits into
AOSSIE-Org:mainfrom
Ridima28:'adding-search-suggestion'

Conversation

@Ridima28

@Ridima28 Ridima28 commented Jun 23, 2026

Copy link
Copy Markdown

Addressed Issues:

Fixes #86

Screenshots/Recordings:

OrgExplorer.GitHub.Organization.Analytics.Repository.Insights.-.Comet.2026-06-23.12-00-08.mp4

Additional Notes:

  • This PR introduces a GitHub-powered organization autocomplete system to improve discoverability and reduce manual typing errors.
  • A debounced search (300ms) is used to prevent excessive API calls and improve performance.
  • Selected suggestions are converted into chips, supporting multi-organization analysis workflows.
  • GitHub Search API (search/users?q={query}+type:org) is used for fetching organization suggestions.

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

Release Notes

  • New Features

    • Organization Search with Autocomplete: Search GitHub organizations with real-time dropdown autocomplete suggestions. As you type, matching organization suggestions appear instantly. Select any suggestion to add it to your search query.
  • Documentation

    • Updated README to describe the new organization search with autocomplete feature.

@github-actions github-actions Bot added the enhancement New feature or request label Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

A new searchOrgs(query) function is added to the GitHub service layer. HomePage gains debounced autocomplete state and a useEffect that calls searchOrgs after 300ms, displaying up to 6 org suggestions in a dropdown. Selecting a suggestion chips it and clears the input. The README documents the new feature.

Changes

Org Autocomplete Search Dropdown

Layer / File(s) Summary
searchOrgs API helper
src/services/github.js
Exports searchOrgs(query) that fetches the GitHub Search Users endpoint filtered to organizations, handles non-OK responses, and returns data.items or [].
HomePage autocomplete state and logic
src/pages/HomePage.jsx
Adds suggestions and showSuggestion state, a debounced useEffect invoking searchOrgs after 300ms (slicing to 6 results), and selectSuggestion to deduplicate and chip the chosen login while clearing input. Imports updated to include useEffect and searchOrgs.
Autocomplete dropdown render + unchanged sections
src/pages/HomePage.jsx
Adds a conditional dropdown under the search input listing org.login values; each item triggers selectSuggestion on mouse down. Loading, Recent, Quick explore, and Stats bar sections are preserved as-is.
README feature entry
README.md
Adds a Features bullet describing Smart Organization Search with Autocomplete.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant HomePage
  participant searchOrgs
  participant GitHubSearchAPI

  rect rgba(100, 149, 237, 0.5)
    Note over User,HomePage: Typing triggers debounce
    User->>HomePage: types in search input
    HomePage->>HomePage: debounce 300ms
    HomePage->>searchOrgs: searchOrgs(input.trim())
    searchOrgs->>GitHubSearchAPI: GET /search/users?q=...&type=org
    GitHubSearchAPI-->>searchOrgs: { items: [...] }
    searchOrgs-->>HomePage: items array (max 6)
    HomePage->>User: renders dropdown with org.login suggestions
  end

  rect rgba(144, 238, 144, 0.5)
    Note over User,HomePage: Selecting a suggestion
    User->>HomePage: mousedown on suggestion
    HomePage->>HomePage: selectSuggestion — dedup, add to chips
    HomePage->>User: clears input, hides dropdown
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

Typescript Lang, Documentation

Poem

🐇 Hippity-hop, I type and I seek,
A dropdown appears — no more hide-and-seek!
GitHub orgs appear with a shimmer and glow,
One click adds a chip, off to explore we go!
The rabbit found friends with just a few keys. 🌟

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main change: implementing autocomplete dropdown for GitHub organization search with chip support, which matches the primary objective.
Linked Issues check ✅ Passed All requirements from issue #86 are met: GitHub organization search API integration, dropdown list display of matching organizations, clicking suggestions adds chips, and debounced search implementation.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the autocomplete dropdown feature: GitHub API integration, HomePage state management, UI rendering, and documentation updates align with the stated objectives.
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

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.

@github-actions github-actions Bot added documentation Documentation updates frontend Frontend changes javascript JavaScript/TypeScript changes size/L 201-500 lines changed first-time-contributor First time contributor and removed size/L 201-500 lines changed labels Jun 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/HomePage.jsx`:
- Around line 18-29: The useEffect hook in HomePage.jsx has a race condition
where multiple searchOrgs calls can complete out of order, showing stale
results, and lacks error handling if the search fails. Add a cancelled flag
within the useEffect to track whether the current debounced request is still
valid, then before updating state with setSuggestion and setShowSuggestions,
check that the flag is false to prevent stale results from overwriting newer
ones. Additionally, wrap the searchOrgs call in a try-catch block to handle
potential errors (network failures, rate limits), and when an error occurs,
either clear suggestions or set an error state to provide user feedback instead
of silently failing. Make sure to set the cancelled flag to true in the cleanup
function before clearing the timeout to ensure cancelled requests don't update
state.
- Around line 109-111: The button element with the onClick handler for go() and
the "EXPLORE" label is missing an explicit type attribute, causing it to default
to type="submit" which can trigger unintended form submissions. Add
type="button" attribute to this button element. Additionally, locate and apply
the same fix to the other button elements referenced on lines 172 and 186 by
adding the type="button" attribute to each of those buttons as well.
- Around line 15-16: Fix the state variable naming inconsistencies in the
useState declarations by ensuring setter names match their corresponding state
variable names. Change the setter `setSuggestion` to `setSuggestions` to match
the state variable `suggestions`, and change the setter `setShowSuggestions` to
`setShowSuggestion` to match the state variable `showSuggestion`. Then update
all references throughout the HomePage component where these setters are called,
including calls to setSuggestion in the input change handlers and search result
handlers, as well as the reference to showSuggestion in any conditional
rendering logic.
- Around line 100-107: The input element has two issues that need fixing: first,
the onBlur handler that calls addChip(input) can fire before suggestion
selection handlers, causing duplicate chips to be added when users click on
suggestions. Fix this by adding a check for !showSuggestions in the onBlur
condition so the handler only runs when the suggestion dropdown is not visible.
Second, the input element is missing an aria-label attribute which is required
for accessibility and screen reader compatibility. Add an appropriate aria-label
to the input element that describes its purpose, such as indicating it's for
adding organization names.
- Around line 117-154: The autocomplete dropdown suggestions lack accessibility
and keyboard navigation support. First, add role="button" to the suggestion
items (the divs with onMouseDown handlers) and include hover styles for visual
feedback. Second, implement keyboard navigation by adding a useEffect hook that
listens for ArrowDown, ArrowUp, and Escape key events to navigate through
suggestions and close the dropdown. Third, externalize the hardcoded "org"
string label used in the suggestions list to an i18n resource file instead of
keeping it as a literal string in the JSX, following the path instructions for
internationalization compliance.

In `@src/services/github.js`:
- Around line 88-98: Refactor the searchOrgs function to use the existing
fetchWithCache infrastructure instead of making a direct fetch call, following
the same pattern as fetchOrg and fetchRepos functions. The searchOrgs function
currently bypasses authentication, caching, and rate limit handling. To fix
this, replace the direct fetch implementation with a call to fetchWithCache,
passing the GitHub search users API endpoint and the query parameter. You will
need to obtain the PAT token from the useApp() context hook and pass it to
fetchWithCache to enable proper authentication and access the higher rate
limits, along with the established caching and rate limit error handling
mechanisms.
🪄 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: e42877ff-50ef-4207-ba92-6d01d792e6fa

📥 Commits

Reviewing files that changed from the base of the PR and between 46c5c95 and 4784ff0.

📒 Files selected for processing (3)
  • README.md
  • src/pages/HomePage.jsx
  • src/services/github.js

Comment thread src/pages/HomePage.jsx Outdated
Comment thread src/pages/HomePage.jsx
Comment on lines +18 to +29
useEffect(() => {
if (!input.trim()) {
setSuggestion([])
return
}
const t = setTimeout(async () => {
const result = await searchOrgs(input.trim())
setSuggestion(result.slice(0,6))
setShowSuggestions(true)
}, 300)
return () => clearTimeout(t)
}, [input])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add race condition protection and error handling.

The debounced search has two issues:

  1. Race condition: Multiple async searchOrgs calls can complete out of order. If a user types "face" → "faceb" → "faceboo" quickly, all three API calls execute, and whichever completes last wins—potentially showing stale results for "face" after the user has typed "faceboo".

  2. Silent failures: If searchOrgs fails (rate limit, network error), the user sees no feedback.

🔒 Proposed fix with cancellation and error handling
  useEffect(() => {
    if (!input.trim()) {
      setSuggestion([])
+     setShowSuggestions(false)
      return
    }
+   let cancelled = false
    const t = setTimeout(async () =>  {
-     const result = await searchOrgs(input.trim())
-     setSuggestion(result.slice(0,6))
-     setShowSuggestions(true)
+     try {
+       const result = await searchOrgs(input.trim())
+       if (!cancelled) {
+         setSuggestion(result.slice(0,6))
+         setShowSuggestions(result.length > 0)
+       }
+     } catch (err) {
+       if (!cancelled) {
+         setSuggestion([])
+         setShowSuggestions(false)
+       }
+     }
    }, 300)
-   return () => clearTimeout(t)
+   return () => {
+     clearTimeout(t)
+     cancelled = true
+   }
  }, [input])

The cancelled flag ensures stale results from earlier searches don't overwrite newer ones.

🤖 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/HomePage.jsx` around lines 18 - 29, The useEffect hook in
HomePage.jsx has a race condition where multiple searchOrgs calls can complete
out of order, showing stale results, and lacks error handling if the search
fails. Add a cancelled flag within the useEffect to track whether the current
debounced request is still valid, then before updating state with setSuggestion
and setShowSuggestions, check that the flag is false to prevent stale results
from overwriting newer ones. Additionally, wrap the searchOrgs call in a
try-catch block to handle potential errors (network failures, rate limits), and
when an error occurs, either clear suggestions or set an error state to provide
user feedback instead of silently failing. Make sure to set the cancelled flag
to true in the cleanup function before clearing the timeout to ensure cancelled
requests don't update state.

Comment thread src/pages/HomePage.jsx
Comment thread src/pages/HomePage.jsx Outdated
Comment thread src/pages/HomePage.jsx
Comment on lines +117 to +154
{showSuggestion && suggestions.length > 0 && (
<div style={{
position: 'relative',
width: '100%',
}}>
<div style={{
position: 'absolute',
top: 6,
left: 0,
right: 0,
background: 'var(--surface)',
border: '1px solid var(--border)',
borderRadius: 8,
zIndex: 20,
maxHeight: 220,
overflowY: 'auto'
}}>
{suggestions.map(org => (
<div
key={org.login}
onMouseDown={() => selectSuggestion(org.login)}
style={{
padding: '10px 12px',
cursor: 'pointer',
fontSize: 13,
display: 'flex',
justifyContent: 'space-between'
}}
>
<span>{org.login}</span>
<span style={{ color: 'var(--text3)', fontSize: 11 }}>
org
</span>
</div>
))}
</div>
</div>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Enhance accessibility and keyboard navigation.

The autocomplete dropdown has several gaps:

  1. Semantic HTML: Clickable <div> elements should use role="button" or be actual <button> elements for screen reader users.
  2. Keyboard navigation: Users cannot use arrow keys to navigate suggestions or Escape to close the dropdown.
  3. Hover feedback: No visual indication when hovering over suggestions.
  4. Internationalization: The hardcoded "org" label violates the i18n requirement in path instructions.
♻️ Suggested improvements

1. Add semantic role and hover styles:

  {suggestions.map(org => (
    <div
      key={org.login}
+     role="button"
+     tabIndex={0}
      onMouseDown={() => selectSuggestion(org.login)}
+     onKeyDown={(e) => e.key === 'Enter' && selectSuggestion(org.login)}
      style={{
        padding: '10px 12px',
        cursor: 'pointer',
        fontSize: 13,
        display: 'flex',
        justifyContent: 'space-between'
      }}
+     onMouseEnter={(e) => e.currentTarget.style.background = 'var(--hover)'}
+     onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
    >

2. Add keyboard navigation in useEffect:

Add handling for ArrowDown, ArrowUp, and Escape keys to navigate through suggestions.

3. Externalize "org" string:

As per path instructions, user-visible strings should be externalized to resource files for internationalization.

As per path instructions, user-visible strings should be externalized and the code should adhere to React best practices and accessibility standards.

🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 145-145: A list component should have a key to prevent re-rendering
Context: {org.login}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 146-148: A list component should have a key to prevent re-rendering
Context: <span style={{ color: 'var(--text3)', fontSize: 11 }}>
org

Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

🪛 React Doctor (0.5.8)

[warning] 135-135: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.

Give clickable static elements a role, or use a button or link.

(no-static-element-interactions)

🤖 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/HomePage.jsx` around lines 117 - 154, The autocomplete dropdown
suggestions lack accessibility and keyboard navigation support. First, add
role="button" to the suggestion items (the divs with onMouseDown handlers) and
include hover styles for visual feedback. Second, implement keyboard navigation
by adding a useEffect hook that listens for ArrowDown, ArrowUp, and Escape key
events to navigate through suggestions and close the dropdown. Third,
externalize the hardcoded "org" string label used in the suggestions list to an
i18n resource file instead of keeping it as a literal string in the JSX,
following the path instructions for internationalization compliance.

Sources: Path instructions, Linters/SAST tools

Comment thread src/services/github.js
Comment on lines +88 to +98
export const searchOrgs = async (query) => {
if (!query) return []

const res = await fetch(
`https://api.github.com/search/users?q=${encodeURIComponent(query)}+type:org`
)
if (!res.ok) return []

const data = await res.json()
return data.items || []
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Refactor to use the existing fetchWithCache infrastructure.

searchOrgs bypasses the established API helper pattern used by fetchOrg and fetchRepos. This causes several issues:

  1. No PAT authentication — Search is limited to 60 requests/hour instead of 5,000/hour with a token.
  2. No caching — Repeated autocomplete queries (e.g., typing "face", "faceb", "faceboo") make redundant API calls.
  3. No rate limit handling — Unlike fetchWithCache (line 64), this won't throw 'RATE_LIMIT' errors for downstream handling.
  4. Inconsistent error handling — Returns [] instead of throwing, unlike other helpers.
♻️ Proposed refactor to reuse fetchWithCache
-export const searchOrgs = async (query) => {
-  if (!query) return []
-
-  const res = await fetch(
-    `https://api.github.com/search/users?q=${encodeURIComponent(query)}+type:org`
-  )
-  if (!res.ok) return []
-  
-  const data = await res.json()
-  return data.items || []
-}
+export const searchOrgs = async (query, pat) => {
+  if (!query) return []
+  
+  try {
+    const url = `https://api.github.com/search/users?q=${encodeURIComponent(query)}+type:org`
+    const data = await fetchWithCache(url, pat)
+    return data.items || []
+  } catch (err) {
+    // Return empty on errors (NOT_FOUND, RATE_LIMIT, etc.)
+    return []
+  }
+}

This will require passing pat from HomePage through to searchOrgs. You can access it via useApp() context.

As per path instructions, the code should adhere to performance best practices.

🤖 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/services/github.js` around lines 88 - 98, Refactor the searchOrgs
function to use the existing fetchWithCache infrastructure instead of making a
direct fetch call, following the same pattern as fetchOrg and fetchRepos
functions. The searchOrgs function currently bypasses authentication, caching,
and rate limit handling. To fix this, replace the direct fetch implementation
with a call to fetchWithCache, passing the GitHub search users API endpoint and
the query parameter. You will need to obtain the PAT token from the useApp()
context hook and pass it to fetchWithCache to enable proper authentication and
access the higher rate limits, along with the established caching and rate limit
error handling mechanisms.

Source: Path instructions

@github-actions github-actions Bot added size/L 201-500 lines changed and removed size/L 201-500 lines changed labels Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation updates enhancement New feature or request first-time-contributor First time contributor frontend Frontend changes javascript JavaScript/TypeScript changes size/L 201-500 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Adding a dropdown search suggestion

1 participant