Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit 9489026

Browse files
committed
chore: improve github repo search workflow
1 parent ee68f9f commit 9489026

12 files changed

Lines changed: 329 additions & 396 deletions

File tree

src/pages/apps/new/_components/RepoList.tsx

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import Box from "@mui/material/Box";
55
import TextField from "@mui/material/TextField";
66
import Button from "@mui/lab/LoadingButton";
77
import SearchIcon from "@mui/icons-material/Search";
8+
import Typography from "@mui/material/Typography";
89
import ArrowRightIcon from "@mui/icons-material/ArrowForwardIos";
910
import { useSelectedTeam } from "~/layouts/TopMenu/Teams/actions";
1011
import { AuthContext } from "~/pages/auth/Auth.context";
11-
import Typography from "@mui/material/Typography";
1212
import githubLogo from "~/assets/logos/github-logo.svg";
1313
import bitbucketLogo from "~/assets/logos/bitbucket-logo.svg";
1414
import gitlabLogo from "~/assets/logos/gitlab-logo.svg";
1515
import { insertRepo } from "./actions";
16+
import { CircularProgress } from "@mui/material";
1617

1718
const logos: Record<Provider, string> = {
1819
github: githubLogo,
@@ -23,23 +24,23 @@ const logos: Record<Provider, string> = {
2324
export interface Props {
2425
repositories: Repo[];
2526
provider: Provider;
26-
loading: boolean;
27+
isLoadingList: boolean;
2728
isLoadingMore: boolean;
28-
error?: string;
2929
hasNextPage: boolean;
3030
onNextPage: () => void;
31+
onSearch?: (term: string) => void;
3132
}
3233

3334
let filterTimer: NodeJS.Timeout;
3435

3536
export default function RepoList({
3637
repositories,
3738
provider,
38-
loading,
39+
isLoadingList,
3940
isLoadingMore,
40-
error,
4141
hasNextPage,
4242
onNextPage,
43+
onSearch,
4344
}: Props) {
4445
const [filter, setFilter] = useState<string>("");
4546
const [loadingInsert, setLoadingInsert] = useState("");
@@ -69,33 +70,37 @@ export default function RepoList({
6970

7071
return (
7172
<>
72-
{((repos.length > 0 && !loading) || filter) && (
73-
<TextField
74-
fullWidth
75-
label="Filter repos"
76-
variant="filled"
77-
placeholder="Filter repos by name"
78-
sx={{ mb: 2 }}
79-
onChange={e => {
80-
setFilter(e.target.value);
81-
clearTimeout(filterTimer);
82-
filterTimer = setTimeout(() => {
73+
<TextField
74+
fullWidth
75+
label={onSearch ? "Search repositories" : "Filter repositories"}
76+
variant="filled"
77+
placeholder="Search repositories by name"
78+
sx={{ mb: 2 }}
79+
autoFocus
80+
onChange={e => {
81+
clearTimeout(filterTimer);
82+
filterTimer = setTimeout(() => {
83+
if (onSearch) {
84+
onSearch(e.target.value);
85+
} else {
8386
setFilter(e.target.value);
84-
}, 250);
85-
}}
86-
InputLabelProps={{
87-
sx: {
88-
pl: 1,
89-
},
90-
}}
91-
InputProps={{
87+
}
88+
}, 250);
89+
}}
90+
slotProps={{
91+
inputLabel: { sx: { pl: 1 } },
92+
input: {
9293
sx: {
9394
pl: 0.75,
9495
},
95-
endAdornment: <SearchIcon sx={{ width: 24 }} />,
96-
}}
97-
/>
98-
)}
96+
endAdornment: isLoadingList ? (
97+
<CircularProgress size="1rem" />
98+
) : (
99+
<SearchIcon sx={{ width: "1rem" }} />
100+
),
101+
},
102+
}}
103+
/>
99104

100105
{repos.map(r => (
101106
<Box

src/pages/apps/new/bitbucket/NewBitbucketApp.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function NewBitbucketApp() {
1616

1717
return (
1818
<Box maxWidth="md" sx={{ width: "100%", margin: "0 auto" }}>
19-
<Card sx={{ width: "100%", mb: 4 }}>
19+
<Card sx={{ width: "100%", mb: 4 }} error={error}>
2020
<CardHeader>
2121
<Typography>
2222
<Link
@@ -34,8 +34,7 @@ export default function NewBitbucketApp() {
3434
<RepoList
3535
repositories={repos}
3636
provider="bitbucket"
37-
error={error}
38-
loading={loading}
37+
isLoadingList={loading}
3938
isLoadingMore={isLoadingMore}
4039
hasNextPage={hasNextPage}
4140
onNextPage={() => setPage(page + 1)}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { RenderResult } from "@testing-library/react";
2+
import { describe, expect, it, vi, beforeEach, Mock } from "vitest";
3+
import { fireEvent, render } from "@testing-library/react";
4+
import ConnectMoreRepos from "./ConnectMoreRepos";
5+
6+
describe("~/pages/apps/new/github/ConnectMoreRepos.tsx", () => {
7+
let wrapper: RenderResult;
8+
let setRefreshToken: Mock;
9+
let setInstallationId: Mock;
10+
11+
const createWrapper = () => {
12+
wrapper = render(
13+
<ConnectMoreRepos
14+
setInstallationId={setInstallationId}
15+
setRefreshToken={setRefreshToken}
16+
openPopupURL="my-url"
17+
/>
18+
);
19+
};
20+
21+
beforeEach(() => {
22+
setRefreshToken = vi.fn();
23+
setInstallationId = vi.fn();
24+
25+
Object.defineProperty(window, "location", {
26+
value: {
27+
reload: vi.fn(),
28+
},
29+
});
30+
31+
Object.defineProperty(window, "open", {
32+
value: vi.fn(),
33+
});
34+
35+
createWrapper();
36+
});
37+
38+
it("should render the button", async () => {
39+
expect(wrapper.getByText("Connect more repositories")).toBeTruthy();
40+
});
41+
42+
it("clicking connect more should open a popup so that the user can configure permissions", () => {
43+
const button = wrapper.getByText("Connect more repositories");
44+
fireEvent.click(button);
45+
expect(window.open).toHaveBeenCalledWith(
46+
"my-url",
47+
"Add repository",
48+
"toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=1000,height=600,left=100,top=100"
49+
);
50+
});
51+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Button from "@mui/material/Button";
2+
import Box from "@mui/material/Box";
3+
import openPopup from "~/utils/helpers/popup";
4+
5+
interface Props {
6+
setInstallationId: (id?: string) => void;
7+
setRefreshToken: (token: number) => void;
8+
openPopupURL: string;
9+
}
10+
11+
export default function ConnectMoreRepos({
12+
setInstallationId,
13+
setRefreshToken,
14+
openPopupURL,
15+
}: Props) {
16+
return (
17+
<Button
18+
color="secondary"
19+
variant="contained"
20+
onClick={() => {
21+
openPopup({
22+
url: openPopupURL,
23+
title: "Add repository",
24+
width: 1000,
25+
onClose: () => {
26+
setInstallationId(undefined);
27+
setRefreshToken(Date.now());
28+
},
29+
});
30+
}}
31+
>
32+
<Box
33+
component="span"
34+
sx={{ display: { xs: "none", md: "inline-block" } }}
35+
>
36+
Connect more repositories
37+
</Box>
38+
<Box
39+
component="span"
40+
sx={{ display: { xs: "inline-block", md: "none" } }}
41+
>
42+
More repos
43+
</Box>
44+
</Button>
45+
);
46+
}

0 commit comments

Comments
 (0)