diff --git a/spa/src/components/Error/KnownErrors/index.tsx b/spa/src/components/Error/KnownErrors/index.tsx
new file mode 100644
index 0000000000..8c63ab2137
--- /dev/null
+++ b/spa/src/components/Error/KnownErrors/index.tsx
@@ -0,0 +1,48 @@
+import styled from "@emotion/styled";
+import { token } from "@atlaskit/tokens";
+import { popup } from "../../../utils";
+import Button from "@atlaskit/button";
+
+const Paragraph = styled.div`
+ color: ${token("color.text.subtle")};
+`;
+const BulletSeparator = styled.span`
+ padding: 0 ${token("space.100")};
+`;
+const StyledLink = styled.a`
+ cursor: pointer;
+`;
+
+/************************************************************************
+ * UI view for the 3 known errors
+ ************************************************************************/
+export const ErrorForSSO = ({ orgName, accessUrl, resetCallback }: { orgName?: string; accessUrl: string; resetCallback: () => void;}) => <>
+
+ Can't connect, single sign-on(SSO) required{orgName && for {orgName}}.
+
+
+ 1. popup(accessUrl)}>Log into GitHub with SSO.
+
+
+ 2. Retry connection in Jira (once logged in).
+
+>;
+
+export const ErrorForNonAdmins = ({ orgName }: { orgName?: string; }) =>
+ Can't connect, you're not the organization owner{orgName && of {orgName}}.
Ask an owner to complete this step.
+;
+
+export const ErrorForIPBlocked = ({ orgName, resetCallback }: { orgName?: string; resetCallback: () => void }) => <>
+
+ Can't connect{orgName && to {orgName}}, blocked by your IP allow list.
+
+
+ •
+ Retry
+>;
diff --git a/spa/src/components/Error/index.tsx b/spa/src/components/Error/index.tsx
index 950f6a8a42..63aeb401b9 100644
--- a/spa/src/components/Error/index.tsx
+++ b/spa/src/components/Error/index.tsx
@@ -19,13 +19,13 @@ const ErrorWrapper = styled.div`
background: ${props => props.type === "warning" ? token("color.background.warning") : token("color.background.danger") };
border-radius: 3px;
align-items: center;
- div {
- padding-left: ${token("space.200")};
- }
span {
align-self: start;
}
`;
+const ErrorContent = styled.div`
+ padding-left: ${token("space.200")};
+`;
const Error = ({
type,
@@ -42,7 +42,7 @@ const Error = ({
type === "warning" ? :
}
- {message}
+ {message}
);
};
diff --git a/spa/src/pages/ConfigSteps/OrgsContainer/index.tsx b/spa/src/pages/ConfigSteps/OrgsContainer/index.tsx
index 1e5b6b3f17..7a811a7294 100644
--- a/spa/src/pages/ConfigSteps/OrgsContainer/index.tsx
+++ b/spa/src/pages/ConfigSteps/OrgsContainer/index.tsx
@@ -4,8 +4,8 @@ import styled from "@emotion/styled";
import { token } from "@atlaskit/tokens";
import { useState } from "react";
import WarningIcon from "@atlaskit/icon/glyph/warning";
-import { popup } from "../../../utils";
import OauthManager from "../../../services/oauth-manager";
+import { ErrorForIPBlocked, ErrorForNonAdmins, ErrorForSSO } from "../../../components/Error/KnownErrors";
type OrgDivType = {
key: number;
@@ -29,18 +29,10 @@ const OrgName = styled.span`
color: ${token("color.text")};
font-weight: 590;
`;
-const Paragraph = styled.div`
- color: ${token("color.text.subtle")};
-`;
const IconWrapper = styled.div`
padding-top: ${token("space.150")};
`;
-const BulletSeparator = styled.span`
- padding: 0 ${token("space.100")};
-`;
-const StyledLink = styled.a`
- cursor: pointer;
-`;
+
const OrganizationsList = ({
organizations,
@@ -73,42 +65,15 @@ const OrganizationsList = ({
// TODO: Update this to support GHE
const accessUrl = `https://github.com/organizations/${org.account.login}/settings/profile`;
- return <>
-
- Can't connect, single sign-on(SSO) required.
-
-
- 1. popup(accessUrl)}>Log into GitHub with SSO.
-
-
- 2. Retry connection in Jira (once logged in).
-
- >;
+ return ;
}
if (org.isIPBlocked) {
- return <>
-
- Can't connect, blocked by your IP allow list.
-
-
- •
- Retry
- >;
+ return ;
}
if (!org.isAdmin) {
- return <>
-
- Can't connect, you're not the organization owner.
Ask an owner to complete this step.
-
- >;
+ return ;
}
};
diff --git a/spa/src/pages/ConfigSteps/index.tsx b/spa/src/pages/ConfigSteps/index.tsx
index b1da4b668b..77fe7c80f0 100644
--- a/spa/src/pages/ConfigSteps/index.tsx
+++ b/spa/src/pages/ConfigSteps/index.tsx
@@ -19,6 +19,7 @@ import { reportError } from "../../utils";
import { GitHubInstallationType } from "../../../../src/rest-interfaces";
import OrganizationsList from "../ConfigSteps/OrgsContainer";
import SkeletonForLoading from "../ConfigSteps/SkeletonForLoading";
+import OauthManager from "../../services/oauth-manager";
type GitHubOptionType = {
selectedOption: number;
@@ -161,7 +162,7 @@ const ConfigSteps = () => {
const response = await AppManager.fetchOrgs();
setLoaderForOrgFetching(false);
if (response instanceof AxiosError) {
- showError(modifyError(response, {}, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(response, {}, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
return { success: false, orgs: [] };
} else {
setOrganizations(response.orgs);
@@ -180,7 +181,7 @@ const ConfigSteps = () => {
});
} catch (e) {
setLoaderForLogin(false);
- showError(modifyError(e as AxiosError, {}, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(e as AxiosError, {}, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
reportError(e);
}
break;
@@ -199,6 +200,16 @@ const ConfigSteps = () => {
clearLogin();
};
+ const reLogin = async () => {
+ // Clearing the errors
+ showError(undefined);
+ await OauthManager.clear();
+ // This resets the token validity check in the parent component and resets the UI
+ setIsLoggedIn(false);
+ // Restart the whole auth flow
+ await OauthManager.authenticateInGitHub(() => {});
+ };
+
const clearLogin = () => {
setIsLoggedIn(false);
setLoaderForLogin(false);
@@ -212,7 +223,7 @@ const ConfigSteps = () => {
const connected = await AppManager.connectOrg(gitHubInstallationId);
analyticsClient.sendTrackEvent({ actionSubject: "organisationConnectResponse", action: connected ? "success" : "fail"}, { mode });
if (connected instanceof AxiosError) {
- showError(modifyError(connected, { orgLogin }, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(connected, { orgLogin }, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
} else {
navigate("/spa/connected");
}
@@ -238,7 +249,7 @@ const ConfigSteps = () => {
}
});
} catch (e) {
- showError(modifyError(e as AxiosError, { }, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(e as AxiosError, { }, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
analyticsClient.sendTrackEvent({ actionSubject: "installNewOrgInGithubResponse", action: "fail"}, { mode });
reportError(e);
}
@@ -252,7 +263,7 @@ const ConfigSteps = () => {
const response = await OAuthManager.finishOAuthFlow(event.data?.code, event.data?.state);
setLoaderForLogin(false);
if (response instanceof AxiosError) {
- showError(modifyError(response, {}, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(response, {}, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
analyticsClient.sendTrackEvent({ actionSubject: "finishOAuthFlow", action: "fail" });
return;
} else {
@@ -272,7 +283,7 @@ const ConfigSteps = () => {
const recheckValidity = async () => {
const status: boolean | AxiosError = await OAuthManager.checkValidity();
if (status instanceof AxiosError) {
- showError(modifyError(status, {}, { onClearGitHubToken: clearGitHubToken }));
+ showError(modifyError(status, {}, { onClearGitHubToken: clearGitHubToken, onRelogin: reLogin }));
return;
}
setLoggedInUser(OAuthManager.getUserDetails().username);
diff --git a/spa/src/utils/modifyError.tsx b/spa/src/utils/modifyError.tsx
index 834f4ac929..8491db3472 100644
--- a/spa/src/utils/modifyError.tsx
+++ b/spa/src/utils/modifyError.tsx
@@ -1,9 +1,7 @@
import { AxiosError } from "axios";
import { ErrorType, ApiError, ErrorCode } from "rest-interfaces";
import React, { MouseEvent } from "react";
-import Heading from "@atlaskit/heading";
-import styled from "@emotion/styled";
-import { token } from "@atlaskit/tokens";
+import { ErrorForIPBlocked, ErrorForNonAdmins, ErrorForSSO } from "../components/Error/KnownErrors";
export type ErrorObjType = {
type: ErrorType,
@@ -28,12 +26,8 @@ export const GENERIC_MESSAGE_WITH_LINK = <>
export const modifyError = (
error: AxiosError | SimpleError | ErrorWithErrorCode,
context: { orgLogin?: string; },
- callbacks: { onClearGitHubToken: (e: MouseEvent) => void }
+ callbacks: { onClearGitHubToken: (e: MouseEvent) => void; onRelogin: () => void }
): ErrorObjType => {
-
- const Paragraph = styled.p`
- color: ${token("color.text.subtle")};
- `;
const errorObj = { type: "error" as ErrorType };
const warningObj = { type: "warning" as ErrorType };
let errorCode: ErrorCode = "UNKNOWN";
@@ -47,50 +41,34 @@ export const modifyError = (
// TODO: map all of the remaining backend errors in frontend
if (errorCode === "IP_BLOCKED") {
+ return {
+ ...warningObj,
+ message:
+ };
+ } else if (errorCode === "SSO_LOGIN") {
+ // TODO: Update this to support GHE
+ const accessUrl = `https://github.com/organizations/${context.orgLogin}/settings/profile`;
+
return {
...warningObj,
message: <>
- GitHub for Jira is blocked by your IP allowlist
-
- Your GitHub organization only allows access to some IP addresses. To view
- development work in Jira, you need to add GitHub for Jira’s IP addresses to
- your allowlist.
-
-
- Learn how to add GitHub for Jira to your IP allowlist
+
>
};
} else if (errorCode === "INSUFFICIENT_PERMISSION") {
- return { ...errorObj, message: `You are not Admin of the target org ${context.orgLogin || ""}. Please make sure you are admin of the org and try again.` }; //TODO: Better message
- } else if (errorCode === "TIMEOUT") {
- return { ...errorObj, message: "Request timeout. Please try again later." }; //TODO: Better message
- } else if (errorCode === "RATELIMIT") {
- return { ...errorObj, message: "GitHub rate limit exceeded. Please try again later." }; //TODO: Better message
- } else if (errorCode === "SSO_LOGIN") {
return {
...warningObj,
- message: <>
- SSO Login required
-
- You cannot connect to this organization because you are not currently logged in through your SSO in GitHub.
-
- Please follow the following steps:
-
- -
- Please go to the organization settings page and make sure you have admin access there.
-
- -
- Please click this link to reset your token. This will allow you to connect to this organization.
-
-
-
- >
+ message:
};
+ } else if (errorCode === "TIMEOUT") {
+ return { ...errorObj, message: "Request timeout. Please try again later." };
+ } else if (errorCode === "RATELIMIT") {
+ return { ...errorObj, message: "GitHub rate limit exceeded. Please try again later." };
} else if (errorCode === "INVALID_TOKEN") {
return {
- ...warningObj,
+ ...errorObj,
message: <>
- "The GitHub token seems invalid, please re-authorise and try again."
+ GitHub token seems invalid, please login again.
>
};
} else {