Skip to content

Commit eda0f85

Browse files
committed
[dashboard] allow editing user information
fixes #10999
1 parent ba78bd4 commit eda0f85

File tree

4 files changed

+104
-30
lines changed

4 files changed

+104
-30
lines changed

components/dashboard/src/settings/Account.tsx

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,17 @@ import { getGitpodService, gitpodHostUrl } from "../service/service";
1111
import { UserContext } from "../user-context";
1212
import getSettingsMenu from "./settings-menu";
1313
import ConfirmationModal from "../components/ConfirmationModal";
14-
import CodeText from "../components/CodeText";
1514
import { PaymentContext } from "../payment-context";
15+
import ProfileInformation from "./ProfileInformation";
1616

1717
export default function Account() {
1818
const { user } = useContext(UserContext);
1919
const { showPaymentUI, showUsageBasedUI } = useContext(PaymentContext);
2020

2121
const [modal, setModal] = useState(false);
22+
const primaryEmail = User.getPrimaryEmail(user!) || "";
2223
const [typedEmail, setTypedEmail] = useState("");
2324

24-
const primaryEmail = User.getPrimaryEmail(user!) || "---";
25-
2625
const deleteAccount = async () => {
2726
await getGitpodService().server.deleteAccount();
2827
document.location.href = gitpodHostUrl.asApiLogout().toString();
@@ -60,31 +59,7 @@ export default function Account() {
6059
title="Account"
6160
subtitle="Manage account and Git configuration."
6261
>
63-
<h3>Profile</h3>
64-
<p className="text-base text-gray-500 pb-4 max-w-2xl">
65-
The following information will be used to set up Git configuration. You can override Git author name
66-
and email per project by using the default environment variables{" "}
67-
<CodeText>GIT_AUTHOR_NAME</CodeText>, <CodeText>GIT_COMMITTER_NAME</CodeText>,{" "}
68-
<CodeText>GIT_AUTHOR_EMAIL</CodeText> and <CodeText>GIT_COMMITTER_EMAIL</CodeText>.
69-
</p>
70-
<div className="flex flex-col lg:flex-row">
71-
<div>
72-
<div className="mt-4">
73-
<h4>Name</h4>
74-
<input type="text" disabled={true} value={user?.fullName || user?.name} />
75-
</div>
76-
<div className="mt-4">
77-
<h4>Email</h4>
78-
<input type="text" disabled={true} value={primaryEmail} />
79-
</div>
80-
</div>
81-
<div className="lg:pl-14">
82-
<div className="mt-4">
83-
<h4>Avatar</h4>
84-
<img className="rounded-full w-24 h-24" src={user!.avatarUrl} alt={user!.name} />
85-
</div>
86-
</div>
87-
</div>
62+
<ProfileInformation />
8863
<h3 className="mt-12">Delete Account</h3>
8964
<p className="text-base text-gray-500 pb-4">
9065
This action will remove all the data associated with your account in Gitpod.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* Copyright (c) 2021 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 { User } from "@gitpod/gitpod-protocol";
8+
import { useContext, useState } from "react";
9+
import { UserContext } from "../user-context";
10+
import CodeText from "../components/CodeText";
11+
import { getGitpodService } from "../service/service";
12+
13+
export default function ProfileInformation() {
14+
const { user, setUser } = useContext(UserContext);
15+
16+
const originalName = User.getName(user!) || "";
17+
const originalEmail = User.getPrimaryEmail(user!) || "";
18+
const originalCompany = User.getPrimaryEmail(user!) || "";
19+
20+
const [name, setName] = useState(originalName);
21+
const [email, setEmail] = useState(originalEmail);
22+
const [company, setCompany] = useState(originalCompany);
23+
24+
const hasChanges = () => {
25+
return originalName !== name || originalEmail !== email || originalCompany !== company;
26+
};
27+
28+
const safe = () => {
29+
if (!user) return;
30+
user.fullName = name;
31+
if (!user.additionalData) {
32+
user.additionalData = {};
33+
}
34+
user.additionalData.emailAddress = email;
35+
user.additionalData.companyName = company;
36+
user.additionalData.lastUpdatedDetailsNudge = new Date().toISOString();
37+
38+
getGitpodService()
39+
.server.updateLoggedInUser(user)
40+
.then((u) => setUser(u));
41+
};
42+
43+
const cancel = () => {
44+
setName(originalName);
45+
setEmail(originalEmail);
46+
setCompany(originalCompany);
47+
};
48+
49+
return (
50+
<div>
51+
<h3>Profile</h3>
52+
<p className="text-base text-gray-500 pb-4 max-w-2xl">
53+
The following information will be used to set up Git configuration. You can override Git author name and
54+
email per project by using the default environment variables <CodeText>GIT_AUTHOR_NAME</CodeText>,{" "}
55+
<CodeText>GIT_COMMITTER_NAME</CodeText>, <CodeText>GIT_AUTHOR_EMAIL</CodeText> and{" "}
56+
<CodeText>GIT_COMMITTER_EMAIL</CodeText>.
57+
</p>
58+
<div className="flex flex-col lg:flex-row">
59+
<div>
60+
<div className="mt-4">
61+
<h4>Name</h4>
62+
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
63+
</div>
64+
<div className="mt-4">
65+
<h4>Email</h4>
66+
<input type="text" value={email} onChange={(e) => setEmail(e.target.value)} />
67+
</div>
68+
<div className="mt-4">
69+
<h4>Company</h4>
70+
<input type="text" value={company} onChange={(e) => setCompany(e.target.value)} />
71+
</div>
72+
</div>
73+
<div className="lg:pl-14">
74+
<div className="mt-4">
75+
<h4>Avatar</h4>
76+
<img className="rounded-full w-24 h-24" src={user!.avatarUrl} alt={user!.name} />
77+
</div>
78+
</div>
79+
</div>
80+
<div className="flex flex-row">
81+
<button className="primary" disabled={!hasChanges()} onClick={safe}>
82+
Safe
83+
</button>
84+
<button className="secondary" disabled={!hasChanges()} onClick={cancel}>
85+
Cancel
86+
</button>
87+
</div>
88+
</div>
89+
);
90+
}

components/gitpod-protocol/src/protocol.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,14 @@ export namespace User {
7070
}
7171

7272
/**
73-
* Tries to return the primaryEmail of the first identity this user signed up with.
73+
* Returns the stored email or if it doesn't exist returns the primaryEmail of the first identity this user signed up with.
7474
* @param user
7575
* @returns A primaryEmail, or undefined if there is none.
7676
*/
7777
export function getPrimaryEmail(user: User): string | undefined {
78+
if (user.additionalData?.emailAddress) {
79+
return user.additionalData?.emailAddress;
80+
}
7881
const identities = user.identities.filter((i) => !!i.primaryEmail);
7982
if (identities.length <= 0) {
8083
return undefined;
@@ -154,6 +157,12 @@ export interface AdditionalUserData {
154157
dotfileRepo?: string;
155158
// Identifies an explicit team or user ID to which all the user's workspace usage should be attributed to (e.g. for billing purposes)
156159
usageAttributionId?: string;
160+
// when was the last time the user updated their profile information or has been nudged to do so.
161+
lastUpdatedDetailsNudge?: string;
162+
// the user's company name
163+
companyName?: string;
164+
// the user's email
165+
emailAddress?: string;
157166
}
158167

159168
export interface EmailNotificationSettings {

components/licensor/typescript/ee/src/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface LicensePayload {
2929
level: LicenseLevel
3030
validUntil: string
3131
seats: number
32-
customerID: string
32+
customerID?: string
3333
}
3434

3535
export enum LicenseSubscriptionLevel {

0 commit comments

Comments
 (0)