Skip to content

Commit 21bb3c1

Browse files
Use AuthProviderService API in Dashboard – EXP-847 (#19057)
* convert Login.ts * extract auth provider utils into protocol * complete migration from useAuthProviders to useAuthProviderDescriptions * fixup import of scopes util * revert rename * migrate useDeleteOrgAuthProviderMutation * migrate Org Git Integrations * fix label for authprovider types * wip migration user-level git integrations * WIP updateProviderEntry * wip migration * fixup: label of auth provider types * fixup: dont render Unknown type * fix label * fix this undefined * bump CACHE_VERSION * fixup allow to change the `clientId` only * fixup add AuthProviderClasses to supported messages --------- Co-authored-by: Huiwen <[email protected]>
1 parent bde844b commit 21bb3c1

33 files changed

+827
-304
lines changed

components/dashboard/src/Login.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { AuthProviderInfo } from "@gitpod/gitpod-protocol";
87
import * as GitpodCookie from "@gitpod/gitpod-protocol/lib/util/gitpod-cookie";
98
import { useContext, useEffect, useState, useMemo, useCallback, FC } from "react";
109
import { UserContext } from "./user-context";
@@ -18,9 +17,10 @@ import { getURLHash } from "./utils";
1817
import ErrorMessage from "./components/ErrorMessage";
1918
import { Heading1, Heading2, Subheading } from "./components/typography/headings";
2019
import { SSOLoginForm } from "./login/SSOLoginForm";
21-
import { useAuthProviders } from "./data/auth-providers/auth-provider-query";
20+
import { useAuthProviderDescriptions } from "./data/auth-providers/auth-provider-descriptions-query";
2221
import { SetupPending } from "./login/SetupPending";
2322
import { useNeedsSetup } from "./dedicated-setup/use-needs-setup";
23+
import { AuthProviderDescription } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
2424

2525
export function markLoggedIn() {
2626
document.cookie = GitpodCookie.generateCookie(window.location.hostname);
@@ -38,7 +38,7 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
3838

3939
const urlHash = useMemo(() => getURLHash(), []);
4040

41-
const authProviders = useAuthProviders();
41+
const authProviders = useAuthProviderDescriptions();
4242
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
4343
const [hostFromContext, setHostFromContext] = useState<string | undefined>();
4444
const [repoPathname, setRepoPathname] = useState<string | undefined>();
@@ -58,7 +58,7 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
5858
}
5959
}, [urlHash]);
6060

61-
let providerFromContext: AuthProviderInfo | undefined;
61+
let providerFromContext: AuthProviderDescription | undefined;
6262
if (hostFromContext && authProviders.data) {
6363
providerFromContext = authProviders.data.find((provider) => provider.host === hostFromContext);
6464
}
@@ -158,7 +158,7 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
158158
className="btn-login flex-none w-56 h-10 p-0 inline-flex rounded-xl"
159159
onClick={() => openLogin(providerFromContext!.host)}
160160
>
161-
{iconForAuthProvider(providerFromContext.authProviderType)}
161+
{iconForAuthProvider(providerFromContext.type)}
162162
<span className="pt-2 pb-2 mr-3 text-sm my-auto font-medium truncate overflow-ellipsis">
163163
Continue with {simplifyProviderName(providerFromContext.host)}
164164
</span>
@@ -170,7 +170,7 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
170170
className="btn-login flex-none w-56 h-10 p-0 inline-flex rounded-xl"
171171
onClick={() => openLogin(ap.host)}
172172
>
173-
{iconForAuthProvider(ap.authProviderType)}
173+
{iconForAuthProvider(ap.type)}
174174
<span className="pt-2 pb-2 mr-3 text-sm my-auto font-medium truncate overflow-ellipsis">
175175
Continue with {simplifyProviderName(ap.host)}
176176
</span>

components/dashboard/src/components/AuthorizeGit.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { AuthProviderInfo } from "@gitpod/gitpod-protocol";
87
import { FC, useCallback, useContext } from "react";
98
import { Link } from "react-router-dom";
10-
import { useAuthProviders } from "../data/auth-providers/auth-provider-query";
9+
import { useAuthProviderDescriptions } from "../data/auth-providers/auth-provider-descriptions-query";
1110
import { openAuthorizeWindow } from "../provider-utils";
1211
import { getGitpodService } from "../service/service";
1312
import { UserContext, useCurrentUser } from "../user-context";
@@ -16,45 +15,43 @@ import { Heading2, Heading3, Subheading } from "./typography/headings";
1615
import classNames from "classnames";
1716
import { iconForAuthProvider, simplifyProviderName } from "../provider-utils";
1817
import { useIsOwner } from "../data/organizations/members-query";
18+
import { AuthProviderDescription } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
1919

2020
export function useNeedsGitAuthorization() {
21-
const authProviders = useAuthProviders();
21+
const authProviders = useAuthProviderDescriptions();
2222
const user = useCurrentUser();
2323
if (!user || !authProviders.data) {
2424
return false;
2525
}
26-
return !authProviders.data.some((ap) => user.identities.some((i) => ap.authProviderId === i.authProviderId));
26+
return !authProviders.data.some((ap) => user.identities.some((i) => ap.id === i.authProviderId));
2727
}
2828

2929
export const AuthorizeGit: FC<{ className?: string }> = ({ className }) => {
3030
const { setUser } = useContext(UserContext);
3131
const owner = useIsOwner();
32-
const authProviders = useAuthProviders();
32+
const { data: authProviders } = useAuthProviderDescriptions();
3333
const updateUser = useCallback(() => {
3434
getGitpodService().server.getLoggedInUser().then(setUser);
3535
}, [setUser]);
3636

3737
const connect = useCallback(
38-
(ap: AuthProviderInfo) => {
38+
(ap: AuthProviderDescription) => {
3939
openAuthorizeWindow({
4040
host: ap.host,
41-
scopes: ap.requirements?.default,
4241
overrideScopes: true,
4342
onSuccess: updateUser,
4443
});
4544
},
4645
[updateUser],
4746
);
4847

49-
if (authProviders.data === undefined) {
48+
if (authProviders === undefined) {
5049
return <></>;
5150
}
5251

53-
const verifiedProviders = authProviders.data.filter((ap) => ap.verified);
54-
5552
return (
5653
<div className={classNames("text-center p-4 m-4 py-10", className)}>
57-
{verifiedProviders.length === 0 ? (
54+
{authProviders.length === 0 ? (
5855
<>
5956
<Heading3 className="pb-2">No Git integrations</Heading3>
6057
{!!owner ? (
@@ -82,7 +79,7 @@ export const AuthorizeGit: FC<{ className?: string }> = ({ className }) => {
8279
Select one of the following available providers to access repositories for your account.
8380
</Subheading>
8481
<div className="flex flex-col items-center">
85-
{verifiedProviders.map((ap) => {
82+
{authProviders.map((ap) => {
8683
return (
8784
<Button
8885
onClick={() => connect(ap)}
@@ -91,7 +88,7 @@ export const AuthorizeGit: FC<{ className?: string }> = ({ className }) => {
9188
className="mt-3 btn-login flex-none w-56 px-0 py-0.5 inline-flex"
9289
>
9390
<div className="flex relative -left-4 w-56">
94-
{iconForAuthProvider(ap.authProviderType)}
91+
{iconForAuthProvider(ap.type)}
9592
<span className="pt-2 pb-2 mr-3 text-sm my-auto font-medium truncate overflow-ellipsis">
9693
Continue with {simplifyProviderName(ap.host)}
9794
</span>

components/dashboard/src/components/RepositoryFinder.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import { ReactComponent as RepositoryIcon } from "../icons/RepositoryWithColor.s
1111
import { SuggestedRepository } from "@gitpod/gitpod-protocol";
1212
import { MiddleDot } from "./typography/MiddleDot";
1313
import { useUnifiedRepositorySearch } from "../data/git-providers/unified-repositories-search-query";
14-
import { useAuthProviders } from "../data/auth-providers/auth-provider-query";
14+
import { useAuthProviderDescriptions } from "../data/auth-providers/auth-provider-descriptions-query";
1515
import { ReactComponent as Exclamation2 } from "../images/exclamation2.svg";
16+
import { AuthProviderType } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
1617

1718
interface RepositoryFinderProps {
1819
selectedContextURL?: string;
@@ -39,7 +40,7 @@ export default function RepositoryFinder({
3940
hasMore,
4041
} = useUnifiedRepositorySearch({ searchString, excludeProjects });
4142

42-
const authProviders = useAuthProviders();
43+
const authProviders = useAuthProviderDescriptions();
4344

4445
const handleSelectionChange = useCallback(
4546
(selectedID: string) => {
@@ -115,7 +116,10 @@ export default function RepositoryFinder({
115116
isSelectable: false,
116117
} as ComboboxElement);
117118
}
118-
if (searchString.length >= 3 && authProviders.data?.some((p) => p.authProviderType === "BitbucketServer")) {
119+
if (
120+
searchString.length >= 3 &&
121+
authProviders.data?.some((p) => p.type === AuthProviderType.BITBUCKET_SERVER)
122+
) {
119123
// add an element that tells the user that the Bitbucket Server does only support prefix search
120124
result.push({
121125
id: "bitbucket-server",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useQuery } from "@tanstack/react-query";
8+
import { authProviderClient } from "../../service/public-api";
9+
import { useCurrentUser } from "../../user-context";
10+
import {
11+
AuthProviderDescription,
12+
ListAuthProviderDescriptionsRequest,
13+
} from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
14+
15+
export const useAuthProviderDescriptions = () => {
16+
const user = useCurrentUser();
17+
const query = useQuery<AuthProviderDescription[]>({
18+
queryKey: getAuthProviderDescriptionsQueryKey(),
19+
queryFn: async () => {
20+
const params = new ListAuthProviderDescriptionsRequest();
21+
if (user) {
22+
params.id = {
23+
case: "userId",
24+
value: user.id,
25+
};
26+
}
27+
const response = await authProviderClient.listAuthProviderDescriptions(params);
28+
return response.descriptions;
29+
},
30+
});
31+
return query;
32+
};
33+
34+
export const getAuthProviderDescriptionsQueryKey = () => ["auth-provider-descriptions", {}];

components/dashboard/src/data/auth-providers/auth-provider-query.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useMutation, useQueryClient } from "@tanstack/react-query";
8+
import { getOrgAuthProvidersQueryKey } from "./org-auth-providers-query";
9+
import { CreateAuthProviderRequest } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
10+
import { authProviderClient } from "../../service/public-api";
11+
12+
type CreateAuthProviderArgs = {
13+
provider: Pick<CreateAuthProviderRequest, "host" | "type"> & {
14+
clientId: string;
15+
clientSecret: string;
16+
orgId: string;
17+
};
18+
};
19+
export const useCreateOrgAuthProviderMutation = () => {
20+
const queryClient = useQueryClient();
21+
22+
return useMutation({
23+
mutationFn: async ({ provider }: CreateAuthProviderArgs) => {
24+
const response = await authProviderClient.createAuthProvider(
25+
new CreateAuthProviderRequest({
26+
owner: { case: "organizationId", value: provider.orgId },
27+
host: provider.host,
28+
oauth2Config: {
29+
clientId: provider.clientId,
30+
clientSecret: provider.clientSecret,
31+
},
32+
type: provider.type,
33+
}),
34+
);
35+
return response.authProvider!;
36+
},
37+
onSuccess(provider) {
38+
const orgId = provider?.owner?.value;
39+
if (!orgId) {
40+
return;
41+
}
42+
43+
queryClient.invalidateQueries({ queryKey: getOrgAuthProvidersQueryKey(orgId) });
44+
},
45+
});
46+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useMutation, useQueryClient } from "@tanstack/react-query";
8+
import { CreateAuthProviderRequest } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
9+
import { authProviderClient } from "../../service/public-api";
10+
import { getUserAuthProvidersQueryKey } from "./user-auth-providers-query";
11+
12+
type CreateAuthProviderArgs = {
13+
provider: Pick<CreateAuthProviderRequest, "host" | "type"> & {
14+
clientId: string;
15+
clientSecret: string;
16+
userId: string;
17+
};
18+
};
19+
export const useCreateUserAuthProviderMutation = () => {
20+
const queryClient = useQueryClient();
21+
22+
return useMutation({
23+
mutationFn: async ({ provider }: CreateAuthProviderArgs) => {
24+
const response = await authProviderClient.createAuthProvider(
25+
new CreateAuthProviderRequest({
26+
owner: { case: "ownerId", value: provider.userId },
27+
host: provider.host,
28+
oauth2Config: {
29+
clientId: provider.clientId,
30+
clientSecret: provider.clientSecret,
31+
},
32+
type: provider.type,
33+
}),
34+
);
35+
return response.authProvider!;
36+
},
37+
onSuccess(provider) {
38+
const userId = provider?.owner?.value;
39+
if (!userId) {
40+
return;
41+
}
42+
43+
queryClient.invalidateQueries({ queryKey: getUserAuthProvidersQueryKey(userId) });
44+
},
45+
});
46+
};

components/dashboard/src/data/auth-providers/delete-org-auth-provider-mutation.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
*/
66

77
import { useMutation, useQueryClient } from "@tanstack/react-query";
8-
import { getGitpodService } from "../../service/service";
98
import { useCurrentOrg } from "../organizations/orgs-query";
10-
import { getOrgAuthProvidersQueryKey, OrgAuthProvidersQueryResult } from "./org-auth-providers-query";
9+
import { getOrgAuthProvidersQueryKey } from "./org-auth-providers-query";
10+
import { authProviderClient } from "../../service/public-api";
11+
import { AuthProvider, DeleteAuthProviderRequest } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
1112

1213
type DeleteAuthProviderArgs = {
1314
providerId: string;
@@ -22,18 +23,21 @@ export const useDeleteOrgAuthProviderMutation = () => {
2223
throw new Error("No current organization selected");
2324
}
2425

25-
return await getGitpodService().server.deleteOrgAuthProvider({
26-
id: providerId,
27-
organizationId: organization.id,
28-
});
26+
const response = await authProviderClient.deleteAuthProvider(
27+
new DeleteAuthProviderRequest({
28+
authProviderId: providerId,
29+
}),
30+
);
31+
32+
return response;
2933
},
3034
onSuccess: (_, { providerId }) => {
3135
if (!organization) {
3236
throw new Error("No current organization selected");
3337
}
3438

3539
const queryKey = getOrgAuthProvidersQueryKey(organization.id);
36-
queryClient.setQueryData<OrgAuthProvidersQueryResult>(queryKey, (providers) => {
40+
queryClient.setQueryData<AuthProvider[]>(queryKey, (providers) => {
3741
return providers?.filter((p) => p.id !== providerId);
3842
});
3943

0 commit comments

Comments
 (0)