Skip to content

Commit 8d870bf

Browse files
committed
[dashboard] use GetAuthenticatedUser instead of getLoggedInUser
1 parent 7d36eda commit 8d870bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+775
-649
lines changed

components/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"countries-list": "^2.6.1",
3131
"crypto-browserify": "3.12.0",
3232
"dayjs": "^1.11.5",
33+
"deepmerge": "^4.2.2",
3334
"file-saver": "^2.0.5",
3435
"idb-keyval": "^6.2.0",
3536
"js-cookie": "^3.0.1",

components/dashboard/src/AppNotifications.tsx

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
*/
66

77
import dayjs from "dayjs";
8-
import deepMerge from "deepmerge";
98
import { useCallback, useEffect, useState } from "react";
109
import Alert, { AlertType } from "./components/Alert";
1110
import { useUserLoader } from "./hooks/use-user-loader";
12-
import { getGitpodService } from "./service/service";
1311
import { isGitpodIo } from "./utils";
1412
import { trackEvent } from "./Analytics";
13+
import { useUpdateCurrentUserMutation } from "./data/current-user/update-mutation";
14+
import { User as UserProtocol } from "@gitpod/gitpod-protocol";
15+
import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
1516

1617
const KEY_APP_DISMISSED_NOTIFICATIONS = "gitpod-app-notifications-dismissed";
1718
const PRIVACY_POLICY_LAST_UPDATED = "2023-10-17";
@@ -24,59 +25,60 @@ interface Notification {
2425
onClose?: () => void;
2526
}
2627

27-
const UPDATED_PRIVACY_POLICY: Notification = {
28-
id: "privacy-policy-update",
29-
type: "info",
30-
preventDismiss: true,
31-
onClose: async () => {
32-
let dismissSuccess = false;
33-
try {
34-
const userUpdates = { additionalData: { profile: { acceptedPrivacyPolicyDate: dayjs().toISOString() } } };
35-
const previousUser = await getGitpodService().server.getLoggedInUser();
36-
const updatedUser = await getGitpodService().server.updateLoggedInUser(
37-
deepMerge(previousUser, userUpdates),
38-
);
39-
dismissSuccess = !!updatedUser;
40-
} catch (err) {
41-
console.error("Failed to update user's privacy policy acceptance date", err);
42-
dismissSuccess = false;
43-
} finally {
44-
trackEvent("privacy_policy_update_accepted", {
45-
path: window.location.pathname,
46-
success: dismissSuccess,
47-
});
48-
}
49-
},
50-
message: (
51-
<span className="text-md">
52-
We've updated our Privacy Policy. You can review it{" "}
53-
<a className="gp-link" href="https://www.gitpod.io/privacy" target="_blank" rel="noreferrer">
54-
here
55-
</a>
56-
.
57-
</span>
58-
),
28+
const UPDATED_PRIVACY_POLICY = (updateUser: (user: Partial<UserProtocol>) => Promise<User>) => {
29+
return {
30+
id: "privacy-policy-update",
31+
type: "info",
32+
preventDismiss: true,
33+
onClose: async () => {
34+
let dismissSuccess = false;
35+
try {
36+
const updatedUser = await updateUser({
37+
additionalData: { profile: { acceptedPrivacyPolicyDate: dayjs().toISOString() } },
38+
});
39+
dismissSuccess = !!updatedUser;
40+
} catch (err) {
41+
console.error("Failed to update user's privacy policy acceptance date", err);
42+
dismissSuccess = false;
43+
} finally {
44+
trackEvent("privacy_policy_update_accepted", {
45+
path: window.location.pathname,
46+
success: dismissSuccess,
47+
});
48+
}
49+
},
50+
message: (
51+
<span className="text-md">
52+
We've updated our Privacy Policy. You can review it{" "}
53+
<a className="gp-link" href="https://www.gitpod.io/privacy" target="_blank" rel="noreferrer">
54+
here
55+
</a>
56+
.
57+
</span>
58+
),
59+
} as Notification;
5960
};
6061

6162
export function AppNotifications() {
6263
const [topNotification, setTopNotification] = useState<Notification | undefined>(undefined);
6364
const { user, loading } = useUserLoader();
65+
const updateUser = useUpdateCurrentUserMutation();
6466

6567
useEffect(() => {
6668
const notifications = [];
6769
if (!loading && isGitpodIo()) {
6870
if (
69-
!user?.additionalData?.profile?.acceptedPrivacyPolicyDate ||
70-
new Date(PRIVACY_POLICY_LAST_UPDATED) > new Date(user.additionalData.profile.acceptedPrivacyPolicyDate)
71+
!user?.profile?.acceptedPrivacyPolicyDate ||
72+
new Date(PRIVACY_POLICY_LAST_UPDATED) > new Date(user.profile.acceptedPrivacyPolicyDate)
7173
) {
72-
notifications.push(UPDATED_PRIVACY_POLICY);
74+
notifications.push(UPDATED_PRIVACY_POLICY((u: Partial<UserProtocol>) => updateUser.mutateAsync(u)));
7375
}
7476
}
7577

7678
const dismissedNotifications = getDismissedNotifications();
7779
const topNotification = notifications.find((n) => !dismissedNotifications.includes(n.id));
7880
setTopNotification(topNotification);
79-
}, [loading, setTopNotification, user]);
81+
}, [loading, updateUser, setTopNotification, user]);
8082

8183
const dismissNotification = useCallback(() => {
8284
if (!topNotification) {

components/dashboard/src/Login.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { useNeedsSetup } from "./dedicated-setup/use-needs-setup";
2323
import { AuthProviderDescription } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
2424
import { Button, ButtonProps } from "@podkit/buttons/Button";
2525
import { cn } from "@podkit/lib/cn";
26+
import { userClient } from "./service/public-api";
2627

2728
export function markLoggedIn() {
2829
document.cookie = GitpodCookie.generateCookie(window.location.hostname);
@@ -67,9 +68,11 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
6768

6869
const updateUser = useCallback(async () => {
6970
await getGitpodService().reconnect();
70-
const user = await getGitpodService().server.getLoggedInUser();
71-
setUser(user);
72-
markLoggedIn();
71+
const { user } = await userClient.getAuthenticatedUser({});
72+
if (user) {
73+
setUser(user);
74+
markLoggedIn();
75+
}
7376
}, [setUser]);
7477

7578
const authorizeSuccessful = useCallback(async () => {

components/dashboard/src/app/AdminRoute.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { useContext } from "react";
88
import { Redirect, Route } from "react-router";
99
import { UserContext } from "../user-context";
10+
import { User_RoleOrPermission } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
1011

1112
// A wrapper for <Route> that redirects to the workspaces screen if the user isn't a admin.
1213
// This wrapper only accepts the component property
@@ -15,7 +16,7 @@ export function AdminRoute({ component }: any) {
1516
return (
1617
<Route
1718
render={({ location }: any) =>
18-
user?.rolesOrPermissions?.includes("admin") ? (
19+
user?.rolesOrPermissions?.includes(User_RoleOrPermission.ADMIN) ? (
1920
<Route component={component}></Route>
2021
) : (
2122
<Redirect

components/dashboard/src/app/AppBlockingFlows.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import { FC, lazy } from "react";
88
import { useShowDedicatedSetup } from "../dedicated-setup/use-show-dedicated-setup";
99
import { useCurrentUser } from "../user-context";
10-
import { MigrationPage, useShouldSeeMigrationPage } from "../whatsnew/MigrationPage";
1110
import { useShowUserOnboarding } from "../onboarding/use-show-user-onboarding";
1211
import { useHistory } from "react-router";
1312
import { useCurrentOrg } from "../data/organizations/orgs-query";
@@ -22,7 +21,6 @@ export const AppBlockingFlows: FC = ({ children }) => {
2221
const history = useHistory();
2322
const user = useCurrentUser();
2423
const org = useCurrentOrg();
25-
const shouldSeeMigrationPage = useShouldSeeMigrationPage();
2624
const showDedicatedSetup = useShowDedicatedSetup();
2725
const showUserOnboarding = useShowUserOnboarding();
2826

@@ -31,11 +29,6 @@ export const AppBlockingFlows: FC = ({ children }) => {
3129
return <></>;
3230
}
3331

34-
// If orgOnlyAttribution is enabled and the user hasn't been migrated, yet, we need to show the migration page
35-
if (shouldSeeMigrationPage) {
36-
return <MigrationPage />;
37-
}
38-
3932
// Handle dedicated setup if necessary
4033
if (showDedicatedSetup.showSetup) {
4134
return (

components/dashboard/src/app/AppRoutes.tsx

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

7-
import React, { useState } from "react";
7+
import React from "react";
88
import { Redirect, Route, Switch, useLocation } from "react-router";
99
import OAuthClientApproval from "../OauthClientApproval";
1010
import Menu from "../menu/Menu";
@@ -25,15 +25,13 @@ import {
2525
usagePathMain,
2626
} from "../user-settings/settings.routes";
2727
import { getURLHash, isGitpodIo } from "../utils";
28-
import { WhatsNew, shouldSeeWhatsNew } from "../whatsnew/WhatsNew";
2928
import { workspacesPathMain } from "../workspaces/workspaces.routes";
3029
import { AdminRoute } from "./AdminRoute";
3130
import { Blocked } from "./Blocked";
3231

3332
// TODO: Can we bundle-split/lazy load these like other pages?
3433
import { BlockedRepositories } from "../admin/BlockedRepositories";
3534
import { Heading1, Subheading } from "../components/typography/headings";
36-
import { useCurrentUser } from "../user-context";
3735
import PersonalAccessTokenCreateView from "../user-settings/PersonalAccessTokensCreateView";
3836
import { CreateWorkspacePage } from "../workspaces/CreateWorkspacePage";
3937
import { WebsocketClients } from "./WebsocketClients";
@@ -84,8 +82,6 @@ const ConfigurationDetailPage = React.lazy(
8482

8583
export const AppRoutes = () => {
8684
const hash = getURLHash();
87-
const user = useCurrentUser();
88-
const [isWhatsNewShown, setWhatsNewShown] = useState(user && shouldSeeWhatsNew(user));
8985
const location = useLocation();
9086
const repoConfigListAndDetail = useFeatureFlag("repoConfigListAndDetail");
9187

@@ -99,10 +95,6 @@ export const AppRoutes = () => {
9995
return <OAuthClientApproval />;
10096
}
10197

102-
if (isWhatsNewShown) {
103-
return <WhatsNew onClose={() => setWhatsNewShown(false)} />;
104-
}
105-
10698
// TODO: Try and encapsulate this in a route for "/" (check for hash in route component, render or redirect accordingly)
10799
const isCreation = location.pathname === "/" && hash !== "";
108100
if (isCreation) {

components/dashboard/src/components/AuthorizeGit.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { FC, useCallback, useContext } from "react";
88
import { Link } from "react-router-dom";
99
import { useAuthProviderDescriptions } from "../data/auth-providers/auth-provider-descriptions-query";
1010
import { openAuthorizeWindow } from "../provider-utils";
11-
import { getGitpodService } from "../service/service";
11+
import { userClient } from "../service/public-api";
1212
import { UserContext, useCurrentUser } from "../user-context";
1313
import { Button } from "./Button";
1414
import { Heading2, Heading3, Subheading } from "./typography/headings";
@@ -18,20 +18,23 @@ import { useIsOwner } from "../data/organizations/members-query";
1818
import { AuthProviderDescription } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
1919

2020
export function useNeedsGitAuthorization() {
21-
const authProviders = useAuthProviderDescriptions();
21+
const { data: authProviders } = useAuthProviderDescriptions();
2222
const user = useCurrentUser();
23-
if (!user || !authProviders.data) {
23+
if (!user || !authProviders) {
2424
return false;
2525
}
26-
return !authProviders.data.some((ap) => user.identities.some((i) => ap.id === i.authProviderId));
26+
return !authProviders.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();
3232
const { data: authProviders } = useAuthProviderDescriptions();
33-
const updateUser = useCallback(() => {
34-
getGitpodService().server.getLoggedInUser().then(setUser);
33+
const updateUser = useCallback(async () => {
34+
const response = await userClient.getAuthenticatedUser({});
35+
if (response.user) {
36+
setUser(response.user);
37+
}
3538
}, [setUser]);
3639

3740
const connect = useCallback(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 { userClient } from "../../service/public-api";
9+
import { GetAuthenticatedUserRequest, User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
10+
11+
export const useAuthenticatedUser = () => {
12+
const query = useQuery<User>({
13+
queryKey: getAuthenticatedUserQueryKey(),
14+
queryFn: async () => {
15+
const params = new GetAuthenticatedUserRequest();
16+
const response = await userClient.getAuthenticatedUser(params);
17+
return response.user!;
18+
},
19+
});
20+
return query;
21+
};
22+
23+
export const getAuthenticatedUserQueryKey = () => ["authenticated-user", {}];

components/dashboard/src/data/current-user/update-mutation.ts

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

7-
import { User } from "@gitpod/gitpod-protocol";
7+
import { AdditionalUserData, User as UserProtocol } from "@gitpod/gitpod-protocol";
88
import { useMutation } from "@tanstack/react-query";
99
import { trackEvent } from "../../Analytics";
1010
import { getGitpodService } from "../../service/service";
1111
import { useCurrentUser } from "../../user-context";
12+
import { converter } from "../../service/public-api";
13+
import deepmerge from "deepmerge";
1214

13-
type UpdateCurrentUserArgs = Partial<User>;
15+
type UpdateCurrentUserArgs = Partial<UserProtocol>;
1416

1517
export const useUpdateCurrentUserMutation = () => {
1618
return useMutation({
1719
mutationFn: async (partialUser: UpdateCurrentUserArgs) => {
18-
return await getGitpodService().server.updateLoggedInUser(partialUser);
20+
const current = await getGitpodService().server.getLoggedInUser();
21+
const update: UpdateCurrentUserArgs = {
22+
id: current.id,
23+
fullName: partialUser.fullName || current.fullName,
24+
additionalData: deepmerge<AdditionalUserData>(
25+
current.additionalData || {},
26+
partialUser.additionalData || {},
27+
),
28+
};
29+
const user = await getGitpodService().server.updateLoggedInUser(update);
30+
return converter.toUser(user);
1931
},
2032
});
2133
};
@@ -31,7 +43,6 @@ export const useUpdateCurrentUserDotfileRepoMutation = () => {
3143
}
3244

3345
const additionalData = {
34-
...(user.additionalData || {}),
3546
dotfileRepo,
3647
};
3748
const updatedUser = await updateUser.mutateAsync({ additionalData });
@@ -40,14 +51,14 @@ export const useUpdateCurrentUserDotfileRepoMutation = () => {
4051
},
4152
onMutate: async () => {
4253
return {
43-
previousDotfileRepo: user?.additionalData?.dotfileRepo || "",
54+
previousDotfileRepo: user?.dotfileRepo || "",
4455
};
4556
},
4657
onSuccess: (updatedUser, _, context) => {
47-
if (updatedUser?.additionalData?.dotfileRepo !== context?.previousDotfileRepo) {
58+
if (updatedUser?.dotfileRepo !== context?.previousDotfileRepo) {
4859
trackEvent("dotfile_repo_changed", {
4960
previous: context?.previousDotfileRepo ?? "",
50-
current: updatedUser?.additionalData?.dotfileRepo ?? "",
61+
current: updatedUser?.dotfileRepo ?? "",
5162
});
5263
}
5364
},

components/dashboard/src/data/organizations/orgs-query.ts

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

7-
import { User } from "@gitpod/gitpod-protocol";
7+
import { User } from "@gitpod/public-api/lib/gitpod/v1/user_pb";
88
import { useQuery, useQueryClient } from "@tanstack/react-query";
99
import { useCallback } from "react";
1010
import { useLocation } from "react-router";

components/dashboard/src/data/setup.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ import * as VerificationClasses from "@gitpod/public-api/lib/gitpod/v1/verificat
2828
import * as InstallationClasses from "@gitpod/public-api/lib/gitpod/v1/installation_pb";
2929
import * as SCMClasses from "@gitpod/public-api/lib/gitpod/v1/scm_pb";
3030
import * as SSHClasses from "@gitpod/public-api/lib/gitpod/v1/ssh_pb";
31+
import * as UserClasses from "@gitpod/public-api/lib/gitpod/v1/user_pb";
3132

3233
// This is used to version the cache
3334
// If data we cache changes in a non-backwards compatible way, increment this version
3435
// That will bust any previous cache versions a client may have stored
35-
const CACHE_VERSION = "14";
36+
const CACHE_VERSION = "15";
3637

3738
export function noPersistence(queryKey: QueryKey): QueryKey {
3839
return [...queryKey, "no-persistence"];
@@ -158,6 +159,7 @@ function initializeMessages() {
158159
...Object.values(InstallationClasses),
159160
...Object.values(SCMClasses),
160161
...Object.values(SSHClasses),
162+
...Object.values(UserClasses),
161163
];
162164
for (const c of constr) {
163165
if ((c as any).prototype instanceof Message) {

0 commit comments

Comments
 (0)