Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): enhance GitHub repo picker with search and sorting #5783

Merged
merged 45 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
62fae43
feat(frontend): enhance GitHub repo picker with search and sorting
openhands-agent Dec 24, 2024
43e643b
fix: add stargazers_count to GitHubRepository type
openhands-agent Dec 24, 2024
e56b09e
fix: use GitHub API directly and improve star count display
openhands-agent Dec 24, 2024
e2a82de
refactor: move GitHub API logic and improve repo picker UI
openhands-agent Dec 24, 2024
d9fdd4a
fix: improve repo picker filtering and selection behavior
openhands-agent Dec 24, 2024
e866df7
fix: improve repo filtering and search relevance
openhands-agent Dec 24, 2024
ef864ef
fix: handle undefined query in repo filter
openhands-agent Dec 24, 2024
d32db88
fix: update NextUI Autocomplete integration
openhands-agent Dec 24, 2024
8a8a227
fix: revert to original array mapping pattern for NextUI Autocomplete
openhands-agent Dec 24, 2024
2e8553e
fix: use defaultFilter instead of filter for NextUI Autocomplete
openhands-agent Dec 24, 2024
9d5cc02
actually working
rbren Dec 24, 2024
c579ddf
fix first item
rbren Dec 24, 2024
980cd4d
fix array
rbren Dec 24, 2024
b799cbb
delint
rbren Dec 24, 2024
6bb99ce
delint
rbren Dec 24, 2024
89adac2
delint
rbren Dec 24, 2024
830c8b7
Fix pr #5783: feat(frontend): enhance GitHub repo picker with search …
openhands-agent Dec 26, 2024
b2b7537
Fix linting and formatting issues in github-repo-selector.tsx
openhands-agent Dec 26, 2024
3d7a83a
Update frontend/src/components/features/github/github-repo-selector.tsx
neubig Dec 26, 2024
4f95435
Fix pr #5783: feat(frontend): enhance GitHub repo picker with search …
openhands-agent Dec 26, 2024
1b8a8db
delint
rbren Dec 26, 2024
09eca76
use sections
rbren Dec 26, 2024
1b41f90
allow full repo urls
rbren Dec 26, 2024
fc87611
delint
rbren Dec 26, 2024
e11630c
Fix: Update model-selector test with improved debugging and simplifie…
openhands-agent Dec 27, 2024
ff83e22
Merge main and resolve conflicts in model-selector test
openhands-agent Dec 27, 2024
aab5ecb
Fix TypeScript errors in model-selector.test.tsx
openhands-agent Dec 27, 2024
4e883f7
refactor: Improve repo search with TanStack Query and clean up tests
openhands-agent Dec 29, 2024
652dfbc
fix: Add onModelChange prop to ModelSelector
openhands-agent Dec 29, 2024
9b012da
fix: Pass empty string instead of null to onModelChange
openhands-agent Dec 29, 2024
e91abf4
Merge branch 'main' into enhance-repo-picker
neubig Dec 29, 2024
c4a1bf9
test: Mock useClickOutsideElement with ref and remove event listener
openhands-agent Dec 30, 2024
7e6b8a2
test: Fix TypeScript errors in tests
openhands-agent Dec 30, 2024
dc09c70
Fix pr #5783: feat(frontend): enhance GitHub repo picker with search …
openhands-agent Dec 30, 2024
2801221
Fix pr #5783: feat(frontend): enhance GitHub repo picker with search …
openhands-agent Dec 30, 2024
21ddf7c
Merge branch 'main' into enhance-repo-picker
neubig Dec 30, 2024
58ee68f
Fix pr #5783: feat(frontend): enhance GitHub repo picker with search …
openhands-agent Dec 30, 2024
dabaa1e
Update frontend/src/components/features/github/github-repo-selector.tsx
rbren Jan 2, 2025
d3a882a
Update frontend/src/components/features/github/github-repo-selector.tsx
rbren Jan 2, 2025
c9faf33
Merge and resolve
amanape Jan 3, 2025
63fe3a9
Remove .Provider from context in favour of uodated React 19 semantics
amanape Jan 3, 2025
f23dd5e
Refactor
amanape Jan 3, 2025
778831b
Replace deprecated
amanape Jan 3, 2025
009b76f
Refactor
amanape Jan 3, 2025
66286b2
Revert
amanape Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions frontend/src/api/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,34 @@ export const retrieveGitHubUser = async () => {
return user;
};

export const searchPublicRepositories = async (
query: string,
per_page = 1,
sort: "" | "updated" | "stars" | "forks" = "",
order: "desc" | "asc" = "desc",
): Promise<GitHubRepository[]> => {
if (!query.trim()) {
return [];
}

try {
const response = await github.get<{ items: GitHubRepository[] }>(
"/search/repositories",
{
params: {
q: query,
per_page,
sort,
order,
},
},
);
return response.data.items;
} catch (error) {
return [];
}
Copy link
Member

Choose a reason for hiding this comment

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

If/when you are going to outsource the logic in frontend/src/components/features/github/github-repo-selector.tsx into a custom hook with TanStack Query, you should let this throw. That way we can have better error handling via the query/mutation hooks (see https://tanstack.com/query/latest/docs/framework/react/guides/query-functions)

Copy link
Contributor

Choose a reason for hiding this comment

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

The error handling has been updated to let errors propagate through TanStack Query. This allows for better error handling at the component level using the query hooks error states. (by OpenHands)

};

export const retrieveLatestGitHubCommit = async (
repository: string,
): Promise<GitHubCommit> => {
Expand Down
73 changes: 49 additions & 24 deletions frontend/src/components/features/github/github-repo-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useDispatch } from "react-redux";
import posthog from "posthog-js";
import { setSelectedRepository } from "#/state/initial-query-slice";
import { useConfig } from "#/hooks/query/use-config";
import { searchPublicRepositories } from "#/api/github";

interface GitHubRepositorySelectorProps {
onSelect: () => void;
Expand All @@ -16,24 +17,33 @@ export function GitHubRepositorySelector({
}: GitHubRepositorySelectorProps) {
const { data: config } = useConfig();
const [selectedKey, setSelectedKey] = React.useState<string | null>(null);
const [searchQuery, setSearchQuery] = React.useState<string>("");
const [searchedRepo, setSearchedRepo] =
React.useState<GitHubRepository | null>(null);

// Add option to install app onto more repos
const finalRepositories =
config?.APP_MODE === "saas"
? [{ id: -1000, full_name: "Add more repositories..." }, ...repositories]
: repositories;
React.useEffect(() => {
const searchPublicRepo = async () => {
const repos = await searchPublicRepositories(searchQuery);
setSearchedRepo(repos.length > 0 ? repos[0] : null);
};

const debounceTimeout = setTimeout(searchPublicRepo, 300);
return () => clearTimeout(debounceTimeout);
}, [searchQuery]);

const finalRepositories = repositories.map((i) => i);
if (searchedRepo && !repositories.find((r) => r.id === searchedRepo.id)) {
finalRepositories.unshift({
...searchedRepo,
fromPublicRepoSearch: true,
});
}

const dispatch = useDispatch();

const handleRepoSelection = (id: string | null) => {
const repo = finalRepositories.find((r) => r.id.toString() === id);
if (id === "-1000") {
if (config?.APP_SLUG)
window.open(
`https://github.com/apps/${config.APP_SLUG}/installations/new`,
"_blank",
);
} else if (repo) {
if (repo) {
// set query param
dispatch(setSelectedRepository(repo.full_name));
posthog.capture("repository_selected");
Expand All @@ -47,18 +57,7 @@ export function GitHubRepositorySelector({
dispatch(setSelectedRepository(null));
};

const emptyContent = config?.APP_SLUG ? (
<a
href={`https://github.com/apps/${config.APP_SLUG}/installations/new`}
target="_blank"
rel="noreferrer noopener"
className="underline"
>
Add more repositories...
</a>
) : (
"No results found."
);
const emptyContent = "No results found.";

return (
<Autocomplete
Expand All @@ -74,18 +73,44 @@ export function GitHubRepositorySelector({
},
}}
onSelectionChange={(id) => handleRepoSelection(id?.toString() ?? null)}
onInputChange={(value) => setSearchQuery(value)}
clearButtonProps={{ onClick: handleClearSelection }}
listboxProps={{
emptyContent,
}}
defaultFilter={(textValue, inputValue) =>
!inputValue ||
textValue.toLowerCase().includes(inputValue.toLowerCase())
}
>
{config?.APP_MODE === "saas" &&
config?.APP_SLUG &&
((
<AutocompleteItem key="install">
<a
href={`https://github.com/apps/${config.APP_SLUG}/installations/new`}
target="_blank"
rel="noreferrer noopener"
onClick={(e) => e.stopPropagation()}
>
Add more repositories...
</a>
</AutocompleteItem> // eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any)}
{finalRepositories.map((repo) => (
<AutocompleteItem
data-testid="github-repo-item"
key={repo.id}
value={repo.id}
className="data-[selected=true]:bg-default-100"
textValue={repo.full_name}
>
{repo.full_name}
{repo.fromPublicRepoSearch && repo.stargazers_count !== undefined && (
<span className="ml-1 text-gray-400">
({repo.stargazers_count}⭐)
</span>
)}
</AutocompleteItem>
))}
</Autocomplete>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types/github.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface GitHubUser {
interface GitHubRepository {
id: number;
full_name: string;
stargazers_count?: number;
fromPublicRepoSearch?: boolean;
Copy link
Member

Choose a reason for hiding this comment

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

Since we now extend this interface in the relevant component, we can remove the fromPublicRepoSearch property from here

Copy link
Contributor

Choose a reason for hiding this comment

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

The fromPublicRepoSearch property has been removed from the base GitHubRepository type and moved to a component-specific GitHubRepositoryWithFlag interface. This ensures better type safety and prevents potential issues with accessing non-existent properties. (by OpenHands)

}

interface GitHubAppRepository {
Expand Down
Loading