Skip to content

Commit be80566

Browse files
committed
[dashboard,server] switch ide version with one toggle
1 parent ffe6f48 commit be80566

File tree

5 files changed

+92
-119
lines changed

5 files changed

+92
-119
lines changed

chart/templates/server-ide-configmap.yaml

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,22 @@ options:
4646
orderKey: "00"
4747
title: "VS Code"
4848
type: "browser"
49+
label: "Browser"
4950
logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscode.svg"
51+
# latestLogo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscodeInsiders.svg"
5052
image: {{ (include "stable-image-full" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.codeImage)) }}
51-
code-latest:
52-
orderKey: "01"
53-
title: "VS Code"
54-
type: "browser"
55-
logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscodeInsiders.svg"
56-
tooltip: "Early access version, still subject to testing."
57-
label: "Insiders"
58-
image: {{ (include "insider-image-full" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.codeImage)) }}
59-
resolveImageDigest: true
53+
latestImage: {{ (include "insider-image-full" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.codeImage)) }}
6054

6155
# Desktop IDEs
6256
code-desktop:
6357
orderKey: "02"
6458
title: "VS Code"
6559
type: "desktop"
60+
label: "Desktop"
6661
logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscode.svg"
62+
# latestLogo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscodeInsiders.svg"
6763
image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.codeDesktop)) }}
68-
code-desktop-insiders:
69-
orderKey: "03"
70-
title: "VS Code"
71-
type: "desktop"
72-
logo: "https://ide.{{ $.Values.hostname }}/image/ide-logo/vscodeInsiders.svg"
73-
tooltip: "Visual Studio Code Insiders for early adopters."
74-
label: "Insiders"
75-
image: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.codeDesktopInsiders)) }}
64+
latestImage: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.codeDesktopInsiders)) }}
7665
intellij:
7766
orderKey: "04"
7867
title: "IntelliJ IDEA"
@@ -113,8 +102,9 @@ clients:
113102
"If you don't see an open dialog in your browser, make sure you have <a target='_blank' class='gp-link' href='https://code.visualstudio.com/download'>VS Code</a> installed on your machine, and then click <b>${OPEN_LINK_LABEL}</b> below.",
114103
]
115104
vscode-insiders:
116-
defaultDesktopIDE: "code-desktop-insiders"
117-
desktopIDEs: ["code-desktop-insiders"]
105+
# TODO(hw): make useLatestVersion marked?
106+
defaultDesktopIDE: "code-desktop"
107+
desktopIDEs: ["code-desktop"]
118108
installationSteps: [
119109
"If you don't see an open dialog in your browser, make sure you have <a target='_blank' class='gp-link' href='https://code.visualstudio.com/insiders'>VS Code Insiders</a> installed on your machine, and then click <b>${OPEN_LINK_LABEL}</b> below.",
120110
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
export interface SelectableCardSolidProps {
8+
title: string;
9+
selected: boolean;
10+
className?: string;
11+
onClick: () => void;
12+
children?: React.ReactNode;
13+
}
14+
15+
function SelectableCardSolid(props: SelectableCardSolidProps) {
16+
return (
17+
<div
18+
className={`rounded-xl px-3 py-3 flex flex-col cursor-pointer group transition ease-in-out ${
19+
props.selected ? "bg-gray-800" : "bg-gray-100 dark:bg-gray-900 hover:bg-gray-200 dark:hover:bg-gray-800"
20+
} ${props.className || ""}`}
21+
onClick={props.onClick}
22+
>
23+
<div className="flex items-center">
24+
<p
25+
className={`w-full pl-1 text-base font-semibold truncate ${
26+
props.selected ? "text-gray-100 dark:text-gray-100" : "text-gray-800 dark:text-gray-500"
27+
}`}
28+
title={props.title}
29+
>
30+
{props.title}
31+
</p>
32+
<input className="opacity-0" type="radio" checked={props.selected} />
33+
</div>
34+
{props.children}
35+
</div>
36+
);
37+
}
38+
39+
export default SelectableCardSolid;

components/dashboard/src/settings/Preferences.tsx

Lines changed: 29 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,28 @@ import InfoBox from "../components/InfoBox";
1010
import { PageWithSubMenu } from "../components/PageWithSubMenu";
1111
import PillLabel from "../components/PillLabel";
1212
import SelectableCard from "../components/SelectableCard";
13+
import SelectableCardSolid from "../components/SelectableCardSolid";
1314
import Tooltip from "../components/Tooltip";
1415
import { getGitpodService } from "../service/service";
1516
import { ThemeContext } from "../theme-context";
1617
import { UserContext } from "../user-context";
1718
import settingsMenu from "./settings-menu";
18-
import IDENone from "../icons/IDENone.svg";
19-
import IDENoneDark from "../icons/IDENoneDark.svg";
2019
import CheckBox from "../components/CheckBox";
2120
import { trackEvent } from "../Analytics";
2221

2322
type Theme = "light" | "dark" | "system";
2423

25-
const DesktopNoneId = "none";
26-
const DesktopNone: IDEOption = {
27-
image: "",
28-
logo: IDENone,
29-
orderKey: "-1",
30-
title: "None",
31-
type: "desktop",
32-
};
24+
const DefaultBrowserIDE = "code";
3325

3426
export default function Preferences() {
3527
const { user } = useContext(UserContext);
36-
const { setIsDark, isDark } = useContext(ThemeContext);
28+
const { setIsDark } = useContext(ThemeContext);
3729

38-
const updateUserIDEInfo = async (defaultDesktopIde: string, defaultIde: string, useLatestVersion: boolean) => {
39-
const useDesktopIde = defaultDesktopIde !== DesktopNoneId;
40-
const desktopIde = useDesktopIde ? defaultDesktopIde : undefined;
30+
const updateUserIDEInfo = async (selectedIde: string, useLatestVersion: boolean) => {
31+
// Always start vscode browser ide
32+
const defaultIde = DefaultBrowserIDE;
33+
const useDesktopIde = selectedIde !== DefaultBrowserIDE;
34+
const desktopIde = useDesktopIde ? selectedIde : undefined;
4135
const additionalData = user?.additionalData ?? {};
4236
const settings = additionalData.ideSettings ?? {};
4337
settings.useDesktopIde = useDesktopIde;
@@ -61,38 +55,32 @@ export default function Preferences() {
6155
};
6256

6357
const [defaultIde, setDefaultIde] = useState<string>(user?.additionalData?.ideSettings?.defaultIde || "");
64-
const actuallySetDefaultIde = async (value: string) => {
65-
await updateUserIDEInfo(defaultDesktopIde, value, useLatestVersion);
66-
setDefaultIde(value);
67-
};
6858

6959
const [defaultDesktopIde, setDefaultDesktopIde] = useState<string>(
70-
(user?.additionalData?.ideSettings?.useDesktopIde && user?.additionalData?.ideSettings?.defaultDesktopIde) ||
71-
DesktopNoneId,
60+
user?.additionalData?.ideSettings?.defaultDesktopIde || "",
7261
);
7362
const actuallySetDefaultDesktopIde = async (value: string) => {
74-
await updateUserIDEInfo(value, defaultIde, useLatestVersion);
63+
await updateUserIDEInfo(value, useLatestVersion);
7564
setDefaultDesktopIde(value);
7665
};
7766

7867
const [useLatestVersion, setUseLatestVersion] = useState<boolean>(
7968
user?.additionalData?.ideSettings?.useLatestVersion ?? false,
8069
);
8170
const actuallySetUseLatestVersion = async (value: boolean) => {
82-
await updateUserIDEInfo(defaultDesktopIde, defaultIde, value);
71+
await updateUserIDEInfo(defaultDesktopIde, value);
8372
setUseLatestVersion(value);
8473
};
8574

8675
const [ideOptions, setIdeOptions] = useState<IDEOptions | undefined>(undefined);
8776
useEffect(() => {
8877
(async () => {
8978
const ideopts = await getGitpodService().server.getIDEOptions();
90-
ideopts.options[DesktopNoneId] = DesktopNone;
9179
setIdeOptions(ideopts);
92-
if (!defaultIde) {
80+
if (!defaultIde || ideopts.options[defaultIde] == null) {
9381
setDefaultIde(ideopts.defaultIde);
9482
}
95-
if (!defaultDesktopIde) {
83+
if (!defaultDesktopIde || ideopts.options[defaultDesktopIde] == null) {
9684
setDefaultDesktopIde(ideopts.defaultDesktopIde);
9785
}
9886
})();
@@ -112,8 +100,7 @@ export default function Preferences() {
112100
setTheme(theme);
113101
};
114102

115-
const browserIdeOptions = ideOptions && orderedIdeOptions(ideOptions, "browser");
116-
const desktopIdeOptions = ideOptions && orderedIdeOptions(ideOptions, "desktop");
103+
const allIdeOptions = ideOptions && orderedIdeOptions(ideOptions);
117104

118105
const [dotfileRepo, setDotfileRepo] = useState<string>(user?.additionalData?.dotfileRepo || "");
119106
const actuallySetDotfileRepo = async (value: string) => {
@@ -132,48 +119,17 @@ export default function Preferences() {
132119
<PageWithSubMenu subMenu={settingsMenu} title="Preferences" subtitle="Configure user preferences.">
133120
{ideOptions && (
134121
<>
135-
{browserIdeOptions && (
122+
{/* <div>{JSON.stringify(user?.additionalData?.ideSettings, null, 4)}</div> */}
123+
{allIdeOptions && (
136124
<>
137-
<h3>Browser Editor</h3>
125+
<h3>Editor</h3>
138126
<p className="text-base text-gray-500 dark:text-gray-400">
139-
Choose the default editor for opening workspaces in the browser.
140-
</p>
141-
<div className="my-4 gap-4 flex flex-wrap">
142-
{browserIdeOptions.map(([id, option]) => {
143-
const selected = defaultIde === id;
144-
const onSelect = () => actuallySetDefaultIde(id);
145-
return renderIdeOption(option, selected, onSelect);
146-
})}
147-
</div>
148-
{ideOptions.options[defaultIde]?.notes && (
149-
<InfoBox className="my-5 max-w-2xl">
150-
<ul>
151-
{ideOptions.options[defaultIde].notes?.map((x, idx) => (
152-
<li className={idx > 0 ? "mt-2" : ""}>{x}</li>
153-
))}
154-
</ul>
155-
</InfoBox>
156-
)}
157-
</>
158-
)}
159-
{desktopIdeOptions && (
160-
<>
161-
<h3 className="mt-12 flex">
162-
Desktop Editor
163-
<PillLabel type="warn" className="font-semibold py-0.5 px-2 self-center">
164-
Beta
165-
</PillLabel>
166-
</h3>
167-
<p className="text-base text-gray-500 dark:text-gray-400">
168-
Optionally, choose the default desktop editor for opening workspaces.
127+
Choose the editor for opening workspaces.
169128
</p>
170129
<div className="my-4 gap-4 flex flex-wrap max-w-2xl">
171-
{desktopIdeOptions.map(([id, option]) => {
130+
{allIdeOptions.map(([id, option]) => {
172131
const selected = defaultDesktopIde === id;
173132
const onSelect = () => actuallySetDefaultDesktopIde(id);
174-
if (id === DesktopNoneId) {
175-
option.logo = isDark ? IDENoneDark : IDENone;
176-
}
177133
return renderIdeOption(option, selected, onSelect);
178134
})}
179135
</div>
@@ -210,7 +166,7 @@ export default function Preferences() {
210166
)}
211167
<CheckBox
212168
title="Latest Release"
213-
desc="Include the latest Early Access Program (EAP) version for each JetBrains IDE."
169+
desc="Use the latest version for each editor. Insiders for VS Code, EAP for JetBrains IDEs."
214170
checked={useLatestVersion}
215171
onChange={(e) => actuallySetUseLatestVersion(e.target.checked)}
216172
/>
@@ -301,35 +257,33 @@ export default function Preferences() {
301257
);
302258
}
303259

304-
function orderedIdeOptions(ideOptions: IDEOptions, type: "browser" | "desktop") {
260+
function orderedIdeOptions(ideOptions: IDEOptions) {
305261
// TODO: Maybe convert orderKey to number before sort?
306-
return Object.entries(ideOptions.options)
307-
.filter(([_, x]) => x.type === type && !x.hidden)
308-
.sort((a, b) => {
309-
const keyA = a[1].orderKey || a[0];
310-
const keyB = b[1].orderKey || b[0];
311-
return keyA.localeCompare(keyB);
312-
});
262+
return Object.entries(ideOptions.options).sort((a, b) => {
263+
const keyA = a[1].orderKey || a[0];
264+
const keyB = b[1].orderKey || b[0];
265+
return keyA.localeCompare(keyB);
266+
});
313267
}
314268

315269
function renderIdeOption(option: IDEOption, selected: boolean, onSelect: () => void): JSX.Element {
316270
const card = (
317-
<SelectableCard className="w-36 h-40" title={option.title} selected={selected} onClick={onSelect}>
271+
<SelectableCardSolid className="w-36 h-40" title={option.title} selected={selected} onClick={onSelect}>
318272
<div className="flex justify-center mt-3">
319273
<img className="w-16 filter-grayscale self-center" src={option.logo} alt="logo" />
320274
</div>
321275
{option.label ? (
322276
<div
323277
className={`font-semibold text-sm ${
324-
selected ? "text-green-500" : "text-gray-500 dark:text-gray-400"
278+
selected ? "text-gray-100 dark:text-gray-300" : "text-gray-500 dark:text-gray-400"
325279
} uppercase mt-2 px-3 py-1 self-center`}
326280
>
327281
{option.label}
328282
</div>
329283
) : (
330284
<></>
331285
)}
332-
</SelectableCard>
286+
</SelectableCardSolid>
333287
);
334288

335289
if (option.tooltip) {

components/server/src/workspace/workspace-starter.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,18 +530,21 @@ export class WorkspaceStarter {
530530
};
531531

532532
const ideChoice = user.additionalData?.ideSettings?.defaultIde;
533+
const useLatest = !!user.additionalData?.ideSettings?.useLatestVersion;
534+
533535
if (!!ideChoice) {
534536
const mappedImage = ideConfig.ideOptions.options[ideChoice];
535-
if (!!mappedImage && mappedImage.image) {
536-
configuration.ideImage = mappedImage.image;
537+
if (mappedImage.image != null) {
538+
configuration.ideImage = useLatest
539+
? mappedImage?.latestImage ?? mappedImage?.image
540+
: mappedImage?.image;
537541
} else if (this.authService.hasPermission(user, "ide-settings")) {
538542
// if the IDE choice isn't one of the preconfiured choices, we assume its the image name.
539543
// For now, this feature requires special permissions.
540544
configuration.ideImage = ideChoice;
541545
}
542546
}
543547

544-
const useLatest = !!user.additionalData?.ideSettings?.useLatestVersion;
545548
const referrerIde = this.resolveReferrerIDE(workspace, user, ideConfig);
546549
if (referrerIde) {
547550
configuration.desktopIdeImage = useLatest

install/installer/pkg/components/server/ide/configmap.go

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
2525
typeDesktop := "desktop"
2626

2727
codeDesktop := "code-desktop"
28-
codeDesktopInsiders := "code-desktop-insiders"
2928

3029
intellij := "intellij"
3130
goland := "goland"
@@ -43,8 +42,9 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
4342
},
4443
},
4544
"vscode-insiders": {
46-
DefaultDesktopIDE: codeDesktopInsiders,
47-
DesktopIDEs: []string{codeDesktopInsiders},
45+
// TODO(hw): make useLatestVersion marked?
46+
DefaultDesktopIDE: codeDesktop,
47+
DesktopIDEs: []string{codeDesktop},
4848
InstallationSteps: []string{
4949
"If you don't see an open dialog in your browser, make sure you have <a target='_blank' class='gp-link' href='https://code.visualstudio.com/insiders'>VS Code Insiders</a> installed on your machine, and then click <b>${OPEN_LINK_LABEL}</b> below.",
5050
},
@@ -62,34 +62,21 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
6262
OrderKey: pointer.String("00"),
6363
Title: "VS Code",
6464
Type: typeBrowser,
65+
Label: pointer.String("Browser"),
6566
Logo: getIdeLogoPath("vscode"),
6667
Image: common.ImageName(ctx.Config.Repository, ide.CodeIDEImage, ide.CodeIDEImageStableVersion),
67-
},
68-
"code-latest": {
69-
OrderKey: pointer.String("01"),
70-
Title: "VS Code",
71-
Type: typeBrowser,
72-
Logo: getIdeLogoPath("vscodeInsiders"),
73-
Tooltip: pointer.String("Early access version, still subject to testing."),
74-
Label: pointer.String("Insiders"),
75-
Image: common.ImageName(ctx.Config.Repository, ide.CodeIDEImage, ctx.VersionManifest.Components.Workspace.CodeImage.Version),
76-
ResolveImageDigest: pointer.Bool(true),
68+
// LatestLogo: getIdeLogoPath("vscodeInsiders"),
69+
LatestImage: common.ImageName(ctx.Config.Repository, ide.CodeIDEImage, ctx.VersionManifest.Components.Workspace.CodeImage.Version),
7770
},
7871
codeDesktop: {
7972
OrderKey: pointer.String("02"),
8073
Title: "VS Code",
8174
Type: typeDesktop,
75+
Label: pointer.String("Desktop"),
8276
Logo: getIdeLogoPath("vscode"),
8377
Image: common.ImageName(ctx.Config.Repository, ide.CodeDesktopIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.CodeDesktopImage.Version),
84-
},
85-
codeDesktopInsiders: {
86-
OrderKey: pointer.String("03"),
87-
Title: "VS Code",
88-
Type: typeDesktop,
89-
Logo: getIdeLogoPath("vscodeInsiders"),
90-
Tooltip: pointer.String("Visual Studio Code Insiders for early adopters."),
91-
Label: pointer.String("Insiders"),
92-
Image: common.ImageName(ctx.Config.Repository, ide.CodeDesktopInsidersIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.CodeDesktopImageInsiders.Version),
78+
// LatestLogo: getIdeLogoPath("vscodeInsiders"),
79+
LatestImage: common.ImageName(ctx.Config.Repository, ide.CodeDesktopInsidersIDEImage, ctx.VersionManifest.Components.Workspace.DesktopIdeImages.CodeDesktopImageInsiders.Version),
9380
},
9481
intellij: {
9582
OrderKey: pointer.String("04"),

0 commit comments

Comments
 (0)