diff --git a/packages/frontend/src/components/projects/create/MockConnectGitCard.tsx b/packages/frontend/src/components/projects/create/MockConnectGitCard.tsx
index 5d214c94..abc49ab6 100644
--- a/packages/frontend/src/components/projects/create/MockConnectGitCard.tsx
+++ b/packages/frontend/src/components/projects/create/MockConnectGitCard.tsx
@@ -74,12 +74,12 @@ export const MockConnectGitCard = () => {
return (
{IMPORT_CONTENT.map((repo, index) => (
- <>
-
+
+
{index !== IMPORT_CONTENT.length - 1 && (
)}
- >
+
))}
);
diff --git a/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx
index 5b96ce37..dad6a9f7 100644
--- a/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx
+++ b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx
@@ -1,5 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { Octokit } from 'octokit';
import assert from 'assert';
import { useDebounce } from 'usehooks-ts';
@@ -14,20 +13,18 @@ import {
import { Select, SelectOption } from 'components/shared/Select';
import { Input } from 'components/shared/Input';
import { Button } from 'components/shared/Button';
+import { useOctokit } from 'context/OctokitContext';
const DEFAULT_SEARCHED_REPO = '';
const REPOS_PER_PAGE = 5;
-interface RepositoryListProps {
- octokit: Octokit;
-}
-
-export const RepositoryList = ({ octokit }: RepositoryListProps) => {
+export const RepositoryList = () => {
const [searchedRepo, setSearchedRepo] = useState(DEFAULT_SEARCHED_REPO);
const [selectedAccount, setSelectedAccount] = useState();
const [orgs, setOrgs] = useState([]);
// TODO: Add new type for Git user when required
const [gitUser, setGitUser] = useState();
+ const { octokit, isAuth } = useOctokit();
const [repositoryDetails, setRepositoryDetails] = useState<
GitRepositoryDetails[]
@@ -35,15 +32,23 @@ export const RepositoryList = ({ octokit }: RepositoryListProps) => {
useEffect(() => {
const fetchUserAndOrgs = async () => {
- const user = await octokit.rest.users.getAuthenticated();
- const orgs = await octokit.rest.orgs.listForAuthenticatedUser();
- setOrgs(orgs.data);
- setGitUser(user.data);
- setSelectedAccount({ label: user.data.login, value: user.data.login });
+ try {
+ const user = await octokit.rest.users.getAuthenticated();
+ const orgs = await octokit.rest.orgs.listForAuthenticatedUser();
+ setOrgs(orgs.data);
+ setGitUser(user.data);
+ setSelectedAccount({ label: user.data.login, value: user.data.login });
+ } catch (error) {
+ // Error handled by octokit error hook interceptor in Octokit context
+ console.error(error);
+ return;
+ }
};
- fetchUserAndOrgs();
- }, [octokit]);
+ if (isAuth) {
+ fetchUserAndOrgs();
+ }
+ }, [octokit, isAuth]);
const debouncedSearchedRepo = useDebounce(searchedRepo, 500);
diff --git a/packages/frontend/src/context/OctokitContext.tsx b/packages/frontend/src/context/OctokitContext.tsx
index 21ffe246..4fd8f6c4 100644
--- a/packages/frontend/src/context/OctokitContext.tsx
+++ b/packages/frontend/src/context/OctokitContext.tsx
@@ -8,8 +8,11 @@ import React, {
useEffect,
} from 'react';
import { Octokit, RequestError } from 'octokit';
+import { useNavigate, useParams } from 'react-router-dom';
+import { useDebounceCallback } from 'usehooks-ts';
import { useGQLClient } from './GQLClientContext';
+import { useToast } from 'components/shared/Toast';
const UNAUTHORIZED_ERROR_CODE = 401;
@@ -26,17 +29,17 @@ const OctokitContext = createContext({
});
export const OctokitProvider = ({ children }: { children: ReactNode }) => {
- const [authToken, setAuthToken] = useState('');
+ const [authToken, setAuthToken] = useState(null);
const [isAuth, setIsAuth] = useState(false);
-
+ const navigate = useNavigate();
+ const { orgSlug } = useParams();
+ const { toast, dismiss } = useToast();
const client = useGQLClient();
const fetchUser = useCallback(async () => {
const { user } = await client.getUser();
- if (user.gitHubToken) {
- setAuthToken(user.gitHubToken);
- }
+ setAuthToken(user.gitHubToken);
}, []);
const updateAuth = useCallback(() => {
@@ -57,6 +60,23 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
fetchUser();
}, []);
+ const debouncedUnauthorizedGithubHandler = useDebounceCallback(
+ useCallback(
+ (error: RequestError) => {
+ toast({
+ id: 'unauthorized-github-token',
+ title: `GitHub authentication error: ${error.message}`,
+ variant: 'error',
+ onDismiss: dismiss,
+ });
+
+ navigate(`/${orgSlug}/projects/create`);
+ },
+ [toast, navigate, orgSlug],
+ ),
+ 500,
+ );
+
useEffect(() => {
// TODO: Handle React component error
const interceptor = async (error: RequestError | Error) => {
@@ -66,6 +86,8 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
) {
await client.unauthenticateGithub();
await fetchUser();
+
+ debouncedUnauthorizedGithubHandler(error);
}
throw error;
@@ -77,7 +99,7 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
// Remove the interceptor when the component unmounts
octokit.hook.remove('request', interceptor);
};
- }, [octokit, client]);
+ }, [octokit, client, debouncedUnauthorizedGithubHandler]);
return (
diff --git a/packages/frontend/src/pages/org-slug/projects/create/index.tsx b/packages/frontend/src/pages/org-slug/projects/create/index.tsx
index 49eeed96..a01de914 100644
--- a/packages/frontend/src/pages/org-slug/projects/create/index.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/create/index.tsx
@@ -31,7 +31,7 @@ const NewProject = () => {
Import a repository
-
+
>
) : (
diff --git a/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx b/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx
index 305f2fa1..47bd0eb9 100644
--- a/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx
@@ -26,7 +26,7 @@ type SubmitRepoValues = {
};
const CreateRepo = () => {
- const { octokit } = useOctokit();
+ const { octokit, isAuth } = useOctokit();
const { template } = useOutletContext<{ template: Template }>();
const client = useGQLClient();
@@ -104,18 +104,26 @@ const CreateRepo = () => {
useEffect(() => {
const fetchUserAndOrgs = async () => {
- const user = await octokit?.rest.users.getAuthenticated();
- const orgs = await octokit?.rest.orgs.listForAuthenticatedUser();
+ try {
+ const user = await octokit?.rest.users.getAuthenticated();
+ const orgs = await octokit?.rest.orgs.listForAuthenticatedUser();
- if (user && orgs) {
- const orgsLoginArr = orgs.data.map((org) => org.login);
+ if (user && orgs) {
+ const orgsLoginArr = orgs.data.map((org) => org.login);
- setGitAccounts([user.data.login, ...orgsLoginArr]);
+ setGitAccounts([user.data.login, ...orgsLoginArr]);
+ }
+ } catch (error) {
+ // Error handled by octokit error hook interceptor in Octokit context
+ console.error(error);
+ return;
}
};
- fetchUserAndOrgs();
- }, [octokit]);
+ if (isAuth) {
+ fetchUserAndOrgs();
+ }
+ }, [octokit, isAuth]);
const { handleSubmit, control, reset } = useForm({
defaultValues: {