diff --git a/components/dashboard/src/Analytics.tsx b/components/dashboard/src/Analytics.tsx index 4e7704f8c7f5e4..027718858ce05e 100644 --- a/components/dashboard/src/Analytics.tsx +++ b/components/dashboard/src/Analytics.tsx @@ -10,7 +10,12 @@ import Cookies from "js-cookie"; import { v4 } from "uuid"; import { Experiment } from "./experiments"; -export type Event = "invite_url_requested" | "organisation_authorised" | "dotfile_repo_changed" | "feedback_submitted"; +export type Event = + | "invite_url_requested" + | "organisation_authorised" + | "dotfile_repo_changed" + | "feedback_submitted" + | "workspace_class_changed"; type InternalEvent = Event | "path_changed" | "dashboard_clicked"; export type EventProperties = TrackOrgAuthorised | TrackInviteUrlRequested | TrackDotfileRepo | TrackFeedback; diff --git a/components/dashboard/src/settings/Preferences.tsx b/components/dashboard/src/settings/Preferences.tsx index ce47dd27507769..c85ab8c0db8971 100644 --- a/components/dashboard/src/settings/Preferences.tsx +++ b/components/dashboard/src/settings/Preferences.tsx @@ -14,6 +14,8 @@ import getSettingsMenu from "./settings-menu"; import { trackEvent } from "../Analytics"; import { PaymentContext } from "../payment-context"; import SelectIDE from "./SelectIDE"; +import { getExperimentsClient } from "../experiments/client"; +import SelectWorkspaceClass from "./selectClass"; type Theme = "light" | "dark" | "system"; @@ -50,6 +52,12 @@ export default function Preferences() { } }; + const [isShowWorkspaceClasses, setIsShowWorkspaceClasses] = useState(false); + (async () => { + const showWorkspaceClasses = await getExperimentsClient().getValueAsync("workspace_classes", false, {}); + setIsShowWorkspaceClasses(showWorkspaceClasses); + })(); + return (
-

- Dotfiles{" "} -

+

Dotfiles

Customize workspaces using dotfiles.

Repository URL

@@ -141,6 +147,7 @@ export default function Preferences() {

+ ); diff --git a/components/dashboard/src/settings/selectClass.tsx b/components/dashboard/src/settings/selectClass.tsx new file mode 100644 index 00000000000000..7805f4b661b806 --- /dev/null +++ b/components/dashboard/src/settings/selectClass.tsx @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2022 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 { useContext, useState } from "react"; +import SelectableCardSolid from "../components/SelectableCardSolid"; +import { getGitpodService } from "../service/service"; +import { UserContext } from "../user-context"; +import { trackEvent } from "../Analytics"; +import { WorkspaceClasses } from "@gitpod/gitpod-protocol"; + +interface SelectWorkspaceClassProps { + enabled: boolean; +} + +export default function SelectWorkspaceClass(props: SelectWorkspaceClassProps) { + const { user } = useContext(UserContext); + + const [workspaceClass, setWorkspaceClass] = useState( + user?.additionalData?.workspaceClasses?.regular || "standard", + ); + const actuallySetWorkspaceClass = async (value: string) => { + const additionalData = user?.additionalData || {}; + const prevWorkspaceClass = additionalData?.workspaceClasses?.regular || "standard"; + const workspaceClasses = (additionalData?.workspaceClasses || {}) as WorkspaceClasses; + workspaceClasses.regular = value; + workspaceClasses.prebuild = value; + additionalData.workspaceClasses = workspaceClasses; + if (value !== prevWorkspaceClass) { + await getGitpodService().server.updateLoggedInUser({ additionalData }); + trackEvent("workspace_class_changed", { + previous: prevWorkspaceClass, + current: value, + }); + setWorkspaceClass(value); + } + }; + + if (!props.enabled) { + return
; + } else { + return ( +
+

Workspaces

+

+ Choose the workspace machine type for your workspaces. +

+
+ actuallySetWorkspaceClass("standard")} + > +
+ + + +
+
+ actuallySetWorkspaceClass("XL")} + > +
+ + + + + +
+
+
+
+ ); + } +} diff --git a/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts b/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts index bf4ff4228b7e3c..37bee7904aced9 100644 --- a/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts +++ b/components/ee/payment-endpoint/src/accounting/account-service.spec.db.ts @@ -77,7 +77,7 @@ const end = new Date(Date.UTC(2000, 2, 1)).toISOString(); emailNotificationSettings: { allowsChangelogMail: true, allowsDevXMail: true - } + }, } }); await this.workspaceDb.store({ diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index 7e6d44af7e4615..35d8800564e755 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -157,6 +157,8 @@ export interface AdditionalUserData { dotfileRepo?: string; // Identifies an explicit team or user ID to which all the user's workspace usage should be attributed to (e.g. for billing purposes) usageAttributionId?: string; + // preferred workspace classes + workspaceClasses?: WorkspaceClasses; // additional user profile data profile?: ProfileDetails; } @@ -186,6 +188,11 @@ export type IDESettings = { useLatestVersion?: boolean; }; +export interface WorkspaceClasses { + regular: string; + prebuild: string; +} + export interface UserPlatform { uid: string; userAgent: string;