- The following information will be used to set up Git configuration. You can override Git author name
- and email per project by using the default environment variables{" "}
- GIT_AUTHOR_NAME, GIT_COMMITTER_NAME,{" "}
- GIT_AUTHOR_EMAIL and GIT_COMMITTER_EMAIL.
-
-
-
-
-
-
Avatar
-

+
-
+
+
Delete Account
This action will remove all the data associated with your account in Gitpod.
diff --git a/components/dashboard/src/settings/ProfileInformation.tsx b/components/dashboard/src/settings/ProfileInformation.tsx
new file mode 100644
index 00000000000000..2f2eadfc113e33
--- /dev/null
+++ b/components/dashboard/src/settings/ProfileInformation.tsx
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2021 Gitpod GmbH. All rights reserved.
+ * Licensed under the GNU Affero General Public License (AGPL).
+ * See License-AGPL.txt in the project root for license information.
+ */
+
+import { User } from "@gitpod/gitpod-protocol";
+import { hoursBefore, isDateSmaller } from "@gitpod/gitpod-protocol/lib/util/timeutil";
+import React, { useContext, useState } from "react";
+import Alert from "../components/Alert";
+import CodeText from "../components/CodeText";
+import Modal from "../components/Modal";
+import { getGitpodService } from "../service/service";
+import { UserContext } from "../user-context";
+import { isGitpodIo } from "../utils";
+
+export namespace ProfileState {
+ export interface ProfileState {
+ name: string;
+ email: string;
+ company?: string;
+ avatarURL?: string;
+ }
+
+ export function getProfileState(user: User): ProfileState {
+ return {
+ name: User.getName(user!) || "",
+ email: User.getPrimaryEmail(user!) || "",
+ company: user?.additionalData?.profile?.companyName,
+ avatarURL: user?.avatarUrl,
+ };
+ }
+
+ export function setProfileState(user: User, profileState: ProfileState): User {
+ user.fullName = profileState.name;
+ user.avatarUrl = profileState.avatarURL;
+
+ if (!user.additionalData) {
+ user.additionalData = {};
+ }
+ if (!user.additionalData.profile) {
+ user.additionalData.profile = {};
+ }
+ user.additionalData.profile.emailAddress = profileState.email;
+ user.additionalData.profile.companyName = profileState.company;
+ user.additionalData.profile.lastUpdatedDetailsNudge = new Date().toISOString();
+
+ return user;
+ }
+
+ export function hasChanges(before: ProfileState, after: ProfileState) {
+ return (
+ before.name !== after.name ||
+ before.email !== after.email ||
+ before.company !== after.company ||
+ before.avatarURL !== after.avatarURL
+ );
+ }
+
+ function shouldNudgeForUpdate(user: User): boolean {
+ if (!isGitpodIo()) {
+ return false;
+ }
+ if (!user.additionalData?.profile) {
+ // never updated profile information and account is older than 24 hours (i.e. ask on second day).
+ return !isDateSmaller(hoursBefore(new Date().toISOString(), 24), user.creationDate);
+ }
+ // if the profile wasn't updated for 12 months ask again.
+ return !(
+ !!user.additionalData.profile.lastUpdatedDetailsNudge &&
+ isDateSmaller(
+ hoursBefore(new Date().toISOString(), 24 * 365),
+ user.additionalData.profile.lastUpdatedDetailsNudge,
+ )
+ );
+ }
+
+ /**
+ * @param state
+ * @returns error message or empty string when valid
+ */
+ export function validate(state: ProfileState): string {
+ if (state.name.trim() === "") {
+ return "Name must not be empty.";
+ }
+ if (state.email.trim() === "") {
+ return "Email must not be empty.";
+ }
+ if (
+ !/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
+ state.email.trim(),
+ )
+ ) {
+ return "Please enter a valid email.";
+ }
+ return "";
+ }
+
+ export function NudgeForProfileUpdateModal() {
+ const { user, setUser } = useContext(UserContext);
+ const original = ProfileState.getProfileState(user!);
+ const [profileState, setProfileState] = useState(original);
+ const [errorMessage, setErrorMessage] = useState("");
+ const [visible, setVisible] = useState(shouldNudgeForUpdate(user!));
+
+ const saveProfileState = () => {
+ const error = ProfileState.validate(profileState);
+ setErrorMessage(error);
+ if (error) {
+ return;
+ }
+ const updatedUser = ProfileState.setProfileState(user!, profileState);
+ setUser(updatedUser);
+ getGitpodService().server.updateLoggedInUser(updatedUser);
+ setVisible(shouldNudgeForUpdate(updatedUser!));
+ };
+
+ const cancelProfileUpdate = () => {
+ setProfileState(original);
+ saveProfileState();
+ };
+
+ return (
+
+
+
+
+ }
+ >
+
+
+ The following information will be used to set up Git configuration. You can override Git author name and
+ email per project by using the default environment variables GIT_AUTHOR_NAME,{" "}
+ GIT_COMMITTER_NAME, GIT_AUTHOR_EMAIL and{" "}
+ GIT_COMMITTER_EMAIL.
+
+ {props.errorMessage.length > 0 && (
+
+ {props.errorMessage}
+
+ )}
+ {props.updated && (
+
+ Profile information has been updated.
+
+ )}
+
+
+
+
+
Avatar
+

+
+
+
+ {props.children || null}
+
+ );
+}
diff --git a/components/dashboard/src/workspaces/Workspaces.tsx b/components/dashboard/src/workspaces/Workspaces.tsx
index c3cfd8a1bd2931..6dd530fce94b6d 100644
--- a/components/dashboard/src/workspaces/Workspaces.tsx
+++ b/components/dashboard/src/workspaces/Workspaces.tsx
@@ -20,6 +20,7 @@ import { StartWorkspaceModalContext, StartWorkspaceModalKeyBinding } from "./sta
import SelectIDEModal from "../settings/SelectIDEModal";
import Arrow from "../components/Arrow";
import ConfirmationModal from "../components/ConfirmationModal";
+import { ProfileState } from "../settings/ProfileInformation";
export interface WorkspacesProps {}
@@ -68,7 +69,12 @@ export default function () {
}}
>
- {isOnboardingUser &&