Skip to content

Commit

Permalink
feat: add GitHub Org Repositories sync to insight page creation (#2023)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts authored Oct 31, 2023
1 parent d6b1ed3 commit e5f38ac
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 11 deletions.
117 changes: 106 additions & 11 deletions components/organisms/InsightPage/InsightPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@ import SuggestedRepositoriesList from "../SuggestedRepoList/suggested-repo-list"
const DeleteInsightPageModal = dynamic(() => import("./DeleteInsightPageModal"));
const TeamMembersConfig = dynamic(() => import("components/molecules/TeamMembersConfig/team-members-config"));

enum RepoLookupError {
const enum RepoLookupError {
Initial = 0,
NotIndexed = 1,
Invalid = 3,
Error = 4,
}

const enum OrgLookupError {
Initial = 0,
Invalid = 1,
Error = 2,
}

interface InsightPageProps {
edit?: boolean;
insight?: DbUserInsight;
Expand Down Expand Up @@ -113,11 +119,13 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
const [addRepoLoading, setAddRepoLoading] = useState({ repoName: "", isAddedFromCart: false, isLoading: false });

const [name, setName] = useState(insight?.name || "");
const [organization, setOrganization] = useState("");
const [isNameValid, setIsNameValid] = useState(false);
const [submitted, setSubmitted] = useState(false);
const [repos, setRepos] = useState<DbRepo[]>([]);
const [repoHistory, setRepoHistory] = useState<DbRepo[]>([]);
const [addRepoError, setAddRepoError] = useState<RepoLookupError>(RepoLookupError.Initial);
const [syncOrganizationError, setSyncOrganizationError] = useState<OrgLookupError>(OrgLookupError.Initial);
const [isPublic, setIsPublic] = useState(!!insight?.is_public);
const insightRepoLimit = useStore((state) => state.insightRepoLimit);
const [isModalOpen, setIsModalOpen] = useState(false);
Expand Down Expand Up @@ -183,6 +191,10 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
setIsNameValid(validateName(value));
};

const handleOnOrganizationChange = (value: string) => {
setOrganization(value);
};

const disableCreateButton = () => {
if ((insight?.name && validateName(name)) || (repos.length && validateName(name))) return false;
if (submitted) return true;
Expand Down Expand Up @@ -380,6 +392,18 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
return <RepoNotIndexed />;
}

return null;
};

const getOrganizationLookupError = (code: OrgLookupError) => {
if (code === OrgLookupError.Error) {
return <Error errorMessage="There was error retrieving this organization's public repositories." />;
}

if (code === OrgLookupError.Invalid) {
return <Error errorMessage="This organization entered is invalid." />;
}

return <></>;
};

Expand Down Expand Up @@ -434,6 +458,49 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
}
}, 250);

const handleAddOrganizationRepositories = async () => {
setSyncOrganizationError(OrgLookupError.Initial);

const orgReposResponse = await fetch(
`https://api.github.com/orgs/${organization}/repos?type=public&sort=pushed&direction=desc`,
{
headers: providerToken
? {
Authorization: `Bearer ${providerToken}`,
}
: {},
}
);

if (orgReposResponse.ok) {
const orgReposData = await orgReposResponse.json();

// create a stub repo to send to API
const orgRepos = orgReposData
.filter(
(orgRepo: { id: number; full_name: string }) => !repos.find((repo) => orgRepo.full_name === repo.full_name)
)
.slice(0, 10)
.map((orgRepo: { id: number; full_name: string }) => ({
id: orgRepo.id,
full_name: orgRepo.full_name,
})) as DbRepo[];

setRepos((repos) => {
return [...repos, ...orgRepos];
});

setSyncOrganizationError(OrgLookupError.Initial);
setOrganization("");
} else {
if (orgReposResponse.status === 404) {
setSyncOrganizationError(OrgLookupError.Invalid);
} else {
setSyncOrganizationError(OrgLookupError.Error);
}
}
};

useEffect(() => {
setSuggestions([]);
if (!repoSearchTerm) return;
Expand Down Expand Up @@ -461,9 +528,35 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
<TextInput placeholder="Page Name (ex: My Team)" value={name} handleChange={handleOnNameChange} />
</div>

<div className="flex flex-col gap-4 py-6 border-light-slate-8">
<div className="flex flex-col gap-4 border-light-slate-8">
<Title className="!text-1xl !leading-none " level={4}>
Sync GitHub Organization
</Title>

<div className="w-full flex gap-3 md:items-center flex-col md:flex-row">
<TextInput
placeholder="Organization Name (ex: open-sauced)"
value={organization}
handleChange={handleOnOrganizationChange}
/>
</div>
<div>
<Button
disabled={repos.length >= insightRepoLimit! || organization.trim().length < 3}
onClick={handleAddOrganizationRepositories}
variant="outline"
className="shrink-0 w-max"
>
Sync Organization
</Button>
</div>

<div>{getOrganizationLookupError(syncOrganizationError)}</div>
</div>

<div className="flex flex-col gap-4 border-light-slate-8">
<Title className="!text-1xl !leading-none " level={4}>
Add Repositories
Add Repository
</Title>
<Search
isLoading={createLoading}
Expand Down Expand Up @@ -503,14 +596,16 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
</span>
</div>

<SuggestedRepositoriesList
reposData={recommendedReposWithoutSelected}
loadingData={addRepoLoading}
isLoading={isLoading}
onAddRepo={(repo) => {
addSuggestedRepo(repo);
}}
/>
<div className="py-4">
<SuggestedRepositoriesList
reposData={recommendedReposWithoutSelected}
loadingData={addRepoLoading}
isLoading={isLoading}
onAddRepo={(repo) => {
addSuggestedRepo(repo);
}}
/>
</div>
</div>

<div>{getRepoLookupError(addRepoError)}</div>
Expand Down
2 changes: 2 additions & 0 deletions pages/hub/insights/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import InsightPage from "components/organisms/InsightPage/InsightPage";
import HubLayout from "layouts/hub";

import { WithPageLayout } from "interfaces/with-page-layout";
import useSession from "lib/hooks/useSession";

const NewInsightPage: WithPageLayout = () => {
useSession(true);
return <InsightPage />;
};

Expand Down

0 comments on commit e5f38ac

Please sign in to comment.