From 586e6f9295557932aeacb6d7129aaafc590dc341 Mon Sep 17 00:00:00 2001 From: Joshua Israel <65822698+joshri@users.noreply.github.com> Date: Wed, 15 Dec 2021 14:47:27 -0500 Subject: [PATCH] Add GitLab auth flow to application detail and remove (#1221) * GitLab auth flow works in app detail commits table alert * gitlab auth works on remove app page * removed unnecessary imports * updated commits table tests with provider prop --- ui/components/CommitsTable.tsx | 13 +- ui/components/__tests__/CommitsTable.test.tsx | 20 ++- ui/lib/storage.ts | 2 +- ui/pages/ApplicationDetail.tsx | 132 ++++++++++-------- ui/pages/ApplicationRemove.tsx | 85 ++++++----- 5 files changed, 152 insertions(+), 100 deletions(-) diff --git a/ui/components/CommitsTable.tsx b/ui/components/CommitsTable.tsx index ca8377dabd..906abb7057 100644 --- a/ui/components/CommitsTable.tsx +++ b/ui/components/CommitsTable.tsx @@ -20,6 +20,7 @@ type Props = { app: Application; authSuccess: boolean; onAuthClick?: () => void; + provider: string; }; const timestamp = (isoStr: string) => { @@ -30,7 +31,13 @@ const timestamp = (isoStr: string) => { return DateTime.fromISO(isoStr).toRelative(); }; -function CommitsTable({ className, app, authSuccess, onAuthClick }: Props) { +function CommitsTable({ + className, + app, + authSuccess, + onAuthClick, + provider, +}: Props) { const [commits, loading, error, req] = useListCommits(); React.useEffect(() => { @@ -38,7 +45,7 @@ function CommitsTable({ className, app, authSuccess, onAuthClick }: Props) { return; } - req(GitProvider.GitHub, { + req(GitProvider[provider], { name: app.name, namespace: app.namespace, pageSize: 10, @@ -48,7 +55,7 @@ function CommitsTable({ className, app, authSuccess, onAuthClick }: Props) { if (error) { return error.code === GrpcErrorCodes.Unauthenticated ? ( diff --git a/ui/components/__tests__/CommitsTable.test.tsx b/ui/components/__tests__/CommitsTable.test.tsx index 4f7c7ecb2c..1863a1a3af 100644 --- a/ui/components/__tests__/CommitsTable.test.tsx +++ b/ui/components/__tests__/CommitsTable.test.tsx @@ -39,9 +39,13 @@ describe("CommitsTable", () => { await act(async () => { const { container: div } = render( withTheme( - withContext(, "/", { - applicationsClient: createMockClient(ovr), - }) + withContext( + , + "/", + { + applicationsClient: createMockClient(ovr), + } + ) ), container ); @@ -65,9 +69,13 @@ describe("CommitsTable", () => { await act(async () => { render( withTheme( - withContext(, "/", { - applicationsClient: createMockClient(ovr), - }) + withContext( + , + "/", + { + applicationsClient: createMockClient(ovr), + } + ) ), container ); diff --git a/ui/lib/storage.ts b/ui/lib/storage.ts index 43216547a7..6d4d148de3 100644 --- a/ui/lib/storage.ts +++ b/ui/lib/storage.ts @@ -24,7 +24,7 @@ export function getProviderToken(providerName: GitProvider): string { const CALLBACK_STATE_KEY = "oauth_callback_state"; -export type CallbackSessionState = { page: PageRoute; state: any }; +export type CallbackSessionState = { page: PageRoute | string; state: any }; export function storeCallbackState(value: CallbackSessionState) { if (!window.sessionStorage) { diff --git a/ui/pages/ApplicationDetail.tsx b/ui/pages/ApplicationDetail.tsx index 7c8ec8a00a..27bada803d 100644 --- a/ui/pages/ApplicationDetail.tsx +++ b/ui/pages/ApplicationDetail.tsx @@ -14,6 +14,7 @@ import Page from "../components/Page"; import ReconciliationGraph from "../components/ReconciliationGraph"; import Spacer from "../components/Spacer"; import { AppContext } from "../contexts/AppContext"; +import CallbackStateContextProvider from "../contexts/CallbackStateContext"; import { useRequestState } from "../hooks/common"; import { AutomationKind, @@ -23,6 +24,7 @@ import { } from "../lib/api/applications/applications.pb"; import { getChildren } from "../lib/graph"; import { PageRoute } from "../lib/types"; +import { formatURL } from "../lib/utils"; type Props = { className?: string; @@ -34,14 +36,21 @@ function ApplicationDetail({ className, name }: Props) { React.useContext(AppContext); const [authSuccess, setAuthSuccess] = React.useState(false); const [githubAuthModalOpen, setGithubAuthModalOpen] = React.useState(false); - const [reconciledObjects, setReconciledObjects] = React.useState< UnstructuredObject[] >([]); + const [provider, setProvider] = React.useState(""); const [res, loading, error, req] = useRequestState(); - const [syncRes, syncLoading, syncError, syncRequest] = useRequestState(); + const { getCallbackState, clearCallbackState } = React.useContext(AppContext); + + const callbackState = getCallbackState(); + + if (callbackState) { + setAuthSuccess(true); + clearCallbackState(); + } React.useEffect(() => { const p = async () => { @@ -53,6 +62,7 @@ function ApplicationDetail({ className, name }: Props) { const { provider } = await applicationsClient.ParseRepoURL({ url: res.application.url, }); + setProvider(provider); return { ...res, provider }; }; @@ -99,14 +109,14 @@ function ApplicationDetail({ className, name }: Props) { return ( { syncRequest( applicationsClient.SyncApplication({ @@ -130,60 +140,70 @@ function ApplicationDetail({ className, name }: Props) { } > - {syncError ? ( - + {syncError ? ( + + ) : ( + authSuccess && ( + + ) + )} + + + Source Conditions + + Automation Conditions + - ) : ( - authSuccess && ( - - ) - )} - - - Source Conditions - - Automation Conditions - - Commits - setGithubAuthModalOpen(true)} - /> - { - setAuthSuccess(true); - }} - repoName={application.url} - onClose={() => { - setGithubAuthModalOpen(false); - }} - open={githubAuthModalOpen} - /> + Commits + { + if (provider === "Github") setGithubAuthModalOpen(true); + }} + provider={provider} + /> + { + setAuthSuccess(true); + }} + repoName={application.url} + onClose={() => { + setGithubAuthModalOpen(false); + }} + open={githubAuthModalOpen} + /> + ); } diff --git a/ui/pages/ApplicationRemove.tsx b/ui/pages/ApplicationRemove.tsx index 8ac6069a4c..bedf978bc3 100644 --- a/ui/pages/ApplicationRemove.tsx +++ b/ui/pages/ApplicationRemove.tsx @@ -10,9 +10,10 @@ import Page from "../components/Page"; import Spacer from "../components/Spacer"; import Text from "../components/Text"; import { AppContext } from "../contexts/AppContext"; +import CallbackStateContextProvider from "../contexts/CallbackStateContext"; import { useAppRemove } from "../hooks/applications"; -import { GrpcErrorCodes } from "../lib/types"; -import { poller } from "../lib/utils"; +import { GrpcErrorCodes, PageRoute } from "../lib/types"; +import { formatURL, poller } from "../lib/utils"; type Props = { className?: string; @@ -78,6 +79,14 @@ function ApplicationRemove({ className, name }: Props) { const [authOpen, setAuthOpen] = React.useState(false); const [authSuccess, setAuthSuccess] = React.useState(false); const [appError, setAppError] = React.useState(null); + const { getCallbackState, clearCallbackState } = React.useContext(AppContext); + + const callbackState = getCallbackState(); + + if (callbackState) { + setAuthSuccess(true); + clearCallbackState(); + } React.useEffect(() => { (async () => { @@ -138,40 +147,48 @@ function ApplicationRemove({ className, name }: Props) { ); } + return ( - {!authSuccess && - error && - (error.code === GrpcErrorCodes.Unauthenticated ? ( - setAuthOpen(true)} - /> - ) : ( - - ))} - {repoRemoving && ( - - - - Remove operation in progress... - - )} - {!repoRemoveRes && !repoRemoving && !removedFromCluster && ( - - )} - {(repoRemoving || repoRemoveRes) && ( - - )} - - {repoRemoveRes && } - setAuthOpen(false)} - open={authOpen} - repoName={name} - /> + + {!authSuccess && + error && + (error.code === GrpcErrorCodes.Unauthenticated ? ( + setAuthOpen(true)} + /> + ) : ( + + ))} + {repoRemoving && ( + + + + Remove operation in progress... + + )} + {!repoRemoveRes && !repoRemoving && !removedFromCluster && ( + + )} + {(repoRemoving || repoRemoveRes) && ( + + )} + + {repoRemoveRes && } + setAuthOpen(false)} + open={authOpen} + repoName={name} + /> + ); }