Skip to content

Commit 667ee41

Browse files
refactor(site): improve minor queries and visuals on external auth (#11066)
1 parent 8a6bfc9 commit 667ee41

File tree

5 files changed

+102
-109
lines changed

5 files changed

+102
-109
lines changed

site/src/api/queries/externalAuth.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import * as API from "api/api";
2+
import { ExternalAuth } from "api/typesGenerated";
3+
import { QueryClient, UseMutationOptions } from "react-query";
4+
5+
// Returns all configured external auths for a given user.
6+
export const externalAuths = () => {
7+
return {
8+
queryKey: ["external-auth"],
9+
queryFn: () => API.getUserExternalAuthProviders(),
10+
};
11+
};
12+
13+
export const externalAuthProvider = (providerId: string) => {
14+
return {
15+
queryKey: ["external-auth", providerId],
16+
queryFn: () => API.getExternalAuthProvider(providerId),
17+
};
18+
};
19+
20+
export const externalAuthDevice = (providerId: string) => {
21+
return {
22+
queryFn: () => API.getExternalAuthDevice(providerId),
23+
queryKey: ["external-auth", providerId, "device"],
24+
};
25+
};
26+
27+
export const exchangeExternalAuthDevice = (
28+
providerId: string,
29+
deviceCode: string,
30+
queryClient: QueryClient,
31+
) => {
32+
return {
33+
queryFn: () =>
34+
API.exchangeExternalAuthDevice(providerId, {
35+
device_code: deviceCode,
36+
}),
37+
queryKey: ["external-auth", providerId, "device", deviceCode],
38+
onSuccess: async () => {
39+
// Force a refresh of the Git auth status.
40+
await queryClient.invalidateQueries(["external-auth", providerId]);
41+
},
42+
};
43+
};
44+
45+
export const validateExternalAuth = (
46+
queryClient: QueryClient,
47+
): UseMutationOptions<ExternalAuth, unknown, string> => {
48+
return {
49+
mutationFn: API.getExternalAuthProvider,
50+
onSuccess: (data, providerId) => {
51+
queryClient.setQueryData(["external-auth", providerId], data);
52+
},
53+
};
54+
};
55+
56+
export const unlinkExternalAuths = (queryClient: QueryClient) => {
57+
return {
58+
mutationFn: API.unlinkExternalAuthProvider,
59+
onSuccess: async () => {
60+
await queryClient.invalidateQueries(["external-auth"]);
61+
},
62+
};
63+
};

site/src/api/queries/externalauth.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
import { useQuery, useQueryClient } from "react-query";
2-
import {
3-
exchangeExternalAuthDevice,
4-
getExternalAuthDevice,
5-
getExternalAuthProvider,
6-
} from "api/api";
72
import { usePermissions } from "hooks";
83
import { type FC } from "react";
94
import { useParams, useSearchParams } from "react-router-dom";
@@ -13,56 +8,44 @@ import { isAxiosError } from "axios";
138
import Button from "@mui/material/Button";
149
import { SignInLayout } from "components/SignInLayout/SignInLayout";
1510
import { Welcome } from "components/Welcome/Welcome";
11+
import {
12+
externalAuthDevice,
13+
externalAuthProvider,
14+
exchangeExternalAuthDevice,
15+
} from "api/queries/externalAuth";
1616

1717
const ExternalAuthPage: FC = () => {
18-
const { provider } = useParams();
19-
if (!provider) {
20-
throw new Error("provider must exist");
21-
}
18+
const { provider } = useParams() as { provider: string };
2219
const [searchParams] = useSearchParams();
2320
const permissions = usePermissions();
2421
const queryClient = useQueryClient();
25-
const getExternalAuthProviderQuery = useQuery({
26-
queryKey: ["externalauth", provider],
27-
queryFn: () => getExternalAuthProvider(provider),
22+
const externalAuthProviderOpts = externalAuthProvider(provider);
23+
const externalAuthProviderQuery = useQuery({
24+
...externalAuthProviderOpts,
2825
refetchOnWindowFocus: true,
2926
});
3027

31-
const getExternalAuthDeviceQuery = useQuery({
28+
const externalAuthDeviceQuery = useQuery({
29+
...externalAuthDevice(provider),
3230
enabled:
33-
Boolean(!getExternalAuthProviderQuery.data?.authenticated) &&
34-
Boolean(getExternalAuthProviderQuery.data?.device),
35-
queryFn: () => getExternalAuthDevice(provider),
36-
queryKey: ["externalauth", provider, "device"],
31+
Boolean(!externalAuthProviderQuery.data?.authenticated) &&
32+
Boolean(externalAuthProviderQuery.data?.device),
3733
refetchOnMount: false,
3834
});
3935
const exchangeExternalAuthDeviceQuery = useQuery({
40-
queryFn: () =>
41-
exchangeExternalAuthDevice(provider, {
42-
device_code: getExternalAuthDeviceQuery.data?.device_code || "",
43-
}),
44-
queryKey: [
45-
"externalauth",
36+
...exchangeExternalAuthDevice(
4637
provider,
47-
getExternalAuthDeviceQuery.data?.device_code,
48-
],
49-
enabled: Boolean(getExternalAuthDeviceQuery.data),
50-
onSuccess: () => {
51-
// Force a refresh of the Git auth status.
52-
queryClient.invalidateQueries(["externalauth", provider]).catch((ex) => {
53-
console.error("invalidate queries", ex);
54-
});
55-
},
38+
externalAuthDeviceQuery.data?.device_code ?? "",
39+
queryClient,
40+
),
41+
enabled: Boolean(externalAuthDeviceQuery.data),
5642
retry: true,
57-
retryDelay: (getExternalAuthDeviceQuery.data?.interval || 5) * 1000,
43+
retryDelay: (externalAuthDeviceQuery.data?.interval || 5) * 1000,
5844
refetchOnWindowFocus: (query) =>
5945
query.state.status === "success" ? false : "always",
6046
});
6147

62-
if (
63-
getExternalAuthProviderQuery.isLoading ||
64-
!getExternalAuthProviderQuery.data
65-
) {
48+
if (externalAuthProviderQuery.isLoading || !externalAuthProviderQuery.data) {
6649
return null;
6750
}
6851

@@ -73,8 +56,8 @@ const ExternalAuthPage: FC = () => {
7356
}
7457

7558
if (
76-
!getExternalAuthProviderQuery.data.authenticated &&
77-
!getExternalAuthProviderQuery.data.device
59+
!externalAuthProviderQuery.data.authenticated &&
60+
!externalAuthProviderQuery.data.device
7861
) {
7962
const redirectedParam = searchParams?.get("redirected");
8063
if (redirectedParam && redirectedParam.toLowerCase() === "true") {
@@ -111,16 +94,16 @@ const ExternalAuthPage: FC = () => {
11194

11295
return (
11396
<ExternalAuthPageView
114-
externalAuth={getExternalAuthProviderQuery.data}
97+
externalAuth={externalAuthProviderQuery.data}
11598
onReauthenticate={() => {
116-
queryClient.setQueryData(["externalauth", provider], {
117-
...getExternalAuthProviderQuery.data,
99+
queryClient.setQueryData(externalAuthProviderOpts.queryKey, {
100+
...externalAuthProviderQuery.data,
118101
authenticated: false,
119102
});
120103
}}
121104
viewExternalAuthConfig={permissions.viewExternalAuthConfig}
122105
deviceExchangeError={deviceExchangeError}
123-
externalAuthDevice={getExternalAuthDeviceQuery.data}
106+
externalAuthDevice={externalAuthDeviceQuery.data}
124107
/>
125108
);
126109
};

site/src/pages/UserExternalAuthSettingsPage/UserExternalAuthSettingsPage.tsx

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { FC, useState } from "react";
22
import { UserExternalAuthSettingsPageView } from "./UserExternalAuthSettingsPageView";
33
import {
4-
listUserExternalAuths,
4+
externalAuths,
55
unlinkExternalAuths,
66
validateExternalAuth,
7-
} from "api/queries/externalauth";
7+
} from "api/queries/externalAuth";
88
import { Section } from "components/SettingsLayout/Section";
99
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog";
1010
import { useMutation, useQuery, useQueryClient } from "react-query";
@@ -17,30 +17,17 @@ const UserExternalAuthSettingsPage: FC = () => {
1717
// need to be refetched
1818
const [unlinked, setUnlinked] = useState(0);
1919

20-
const {
21-
data: externalAuths,
22-
error,
23-
isLoading,
24-
refetch,
25-
} = useQuery(listUserExternalAuths());
26-
20+
const externalAuthsQuery = useQuery(externalAuths());
2721
const [appToUnlink, setAppToUnlink] = useState<string>();
28-
const mutateParams = unlinkExternalAuths(queryClient);
29-
const unlinkAppMutation = useMutation({
30-
...mutateParams,
31-
onSuccess: async () => {
32-
await mutateParams.onSuccess();
33-
},
34-
});
35-
22+
const unlinkAppMutation = useMutation(unlinkExternalAuths(queryClient));
3623
const validateAppMutation = useMutation(validateExternalAuth(queryClient));
3724

3825
return (
39-
<Section title="External Authentication">
26+
<Section title="External Authentication" layout="fluid">
4027
<UserExternalAuthSettingsPageView
41-
isLoading={isLoading}
42-
getAuthsError={error}
43-
auths={externalAuths}
28+
isLoading={externalAuthsQuery.isLoading}
29+
getAuthsError={externalAuthsQuery.error}
30+
auths={externalAuthsQuery.data}
4431
unlinked={unlinked}
4532
onUnlinkExternalAuth={(providerID: string) => {
4633
setAppToUnlink(providerID);
@@ -81,7 +68,7 @@ const UserExternalAuthSettingsPage: FC = () => {
8168
// setAppToUnlink closes the modal
8269
setAppToUnlink(undefined);
8370
// refetch repopulates the external auth data
84-
await refetch();
71+
await externalAuthsQuery.refetch();
8572
// this tells our child components to refetch their data
8673
// as at least 1 provider was unlinked.
8774
setUnlinked(unlinked + 1);

site/src/pages/UserExternalAuthSettingsPage/UserExternalAuthSettingsPageView.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
import { ExternalAuthPollingState } from "pages/CreateWorkspacePage/CreateWorkspacePage";
2525
import { useState, useCallback, useEffect } from "react";
2626
import { useQuery } from "react-query";
27-
import { userExternalAuth } from "api/queries/externalauth";
27+
import { externalAuthProvider } from "api/queries/externalAuth";
2828
import { FullScreenLoader } from "components/Loader/FullScreenLoader";
2929

3030
export type UserExternalAuthSettingsPageViewProps = {
@@ -61,7 +61,7 @@ export const UserExternalAuthSettingsPageView = ({
6161
<TableRow>
6262
<TableCell>Application</TableCell>
6363
<TableCell>Link</TableCell>
64-
<TableCell></TableCell>
64+
<TableCell width="1%"></TableCell>
6565
</TableRow>
6666
</TableHead>
6767
<TableBody>
@@ -150,7 +150,7 @@ const ExternalAuthRow = ({
150150
message={authenticated ? "Authenticated" : "Click to Login"}
151151
externalAuthPollingState={externalAuthPollingState}
152152
startPollingExternalAuth={startPollingExternalAuth}
153-
></ExternalAuth>
153+
/>
154154
</TableCell>
155155
<TableCell>
156156
{(link || externalAuth?.authenticated) && (
@@ -199,7 +199,7 @@ const useExternalAuth = (providerID: string, unlinked: number) => {
199199
}, []);
200200

201201
const { data: externalAuth, refetch } = useQuery({
202-
...userExternalAuth(providerID),
202+
...externalAuthProvider(providerID),
203203
refetchInterval: externalAuthPollingState === "polling" ? 1000 : false,
204204
});
205205

0 commit comments

Comments
 (0)