-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[ide] Add IntelliJ desktop IDE support #6270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4c8638c
1398e92
60d510e
911541c
15e9f4b
1d01b3d
c931375
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5,10 +5,13 @@ | |||||
*/ | ||||||
|
||||||
import { useContext, useState } from "react"; | ||||||
import CheckBox from "../components/CheckBox"; | ||||||
import { PageWithSubMenu } from "../components/PageWithSubMenu"; | ||||||
import SelectableCard from "../components/SelectableCard"; | ||||||
import Tooltip from "../components/Tooltip"; | ||||||
import vscode from '../images/vscode.svg'; | ||||||
import ideaLogo from '../images/intellijIdeaLogo.svg'; | ||||||
import golandLogo from '../images/golandLogo.svg'; | ||||||
import { getGitpodService } from "../service/service"; | ||||||
import { ThemeContext } from "../theme-context"; | ||||||
import { UserContext } from "../user-context"; | ||||||
|
@@ -19,6 +22,7 @@ type Theme = 'light' | 'dark' | 'system'; | |||||
export default function Preferences() { | ||||||
const { user } = useContext(UserContext); | ||||||
const { setIsDark } = useContext(ThemeContext); | ||||||
|
||||||
const [defaultIde, setDefaultIde] = useState<string>(user?.additionalData?.ideSettings?.defaultIde || 'code'); | ||||||
const actuallySetDefaultIde = async (value: string) => { | ||||||
const additionalData = user?.additionalData || {}; | ||||||
|
@@ -28,6 +32,31 @@ export default function Preferences() { | |||||
await getGitpodService().server.updateLoggedInUser({ additionalData }); | ||||||
setDefaultIde(value); | ||||||
} | ||||||
|
||||||
const desktopIdeFeatureEnabled = !!user?.rolesOrPermissions?.includes('admin'); | ||||||
|
||||||
const [defaultDesktopIde, setDefaultDesktopIde] = useState<string>(user?.additionalData?.ideSettings?.defaultDesktopIde || 'intellij'); | ||||||
const actuallySetDefaultDesktopIde = async (value: string) => { | ||||||
const additionalData = user?.additionalData || {}; | ||||||
const settings = additionalData.ideSettings || {}; | ||||||
settings.defaultDesktopIde = value; | ||||||
additionalData.ideSettings = settings; | ||||||
await getGitpodService().server.updateLoggedInUser({ additionalData }); | ||||||
setDefaultDesktopIde(value); | ||||||
} | ||||||
|
||||||
const [useDesktopIde, setUseDesktopIde] = useState<boolean>(user?.additionalData?.ideSettings?.useDesktopIde || false); | ||||||
const actuallySetUseDesktopIde = async (value: boolean) => { | ||||||
const additionalData = user?.additionalData || {}; | ||||||
const settings = additionalData.ideSettings || {}; | ||||||
settings.useDesktopIde = value; | ||||||
// Make sure that default desktop IDE is set even when the user did not explicitly select one. | ||||||
settings.defaultDesktopIde = defaultDesktopIde; | ||||||
additionalData.ideSettings = settings; | ||||||
await getGitpodService().server.updateLoggedInUser({ additionalData }); | ||||||
setUseDesktopIde(value); | ||||||
} | ||||||
|
||||||
const [theme, setTheme] = useState<Theme>(localStorage.theme || 'light'); | ||||||
const actuallySetTheme = (theme: Theme) => { | ||||||
if (theme === 'dark' || theme === 'system') { | ||||||
|
@@ -59,6 +88,29 @@ export default function Preferences() { | |||||
</SelectableCard> | ||||||
</Tooltip> | ||||||
</div> | ||||||
{desktopIdeFeatureEnabled && | ||||||
<div className="mt-4 space-x-4 flex"> | ||||||
<CheckBox | ||||||
title="Use Desktop IDE" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: Shall we use the same verb as the action button on the loading page?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to: #6438 |
||||||
desc="Choose whether you would like to open your workspace in a desktop IDE instead." | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a longer conversation regarding this one in: #5641 (comment), let me cross-reference it there, also. |
||||||
checked={useDesktopIde} | ||||||
onChange={(evt) => actuallySetUseDesktopIde(evt.target.checked)} /> | ||||||
</div> | ||||||
} | ||||||
{desktopIdeFeatureEnabled && useDesktopIde && | ||||||
<div className="mt-4 space-x-4 flex"> | ||||||
<SelectableCard className="w-36 h-40" title="IntelliJ IDEA" selected={defaultDesktopIde === 'intellij'} onClick={() => actuallySetDefaultDesktopIde('intellij')}> | ||||||
<div className="flex justify-center mt-3"> | ||||||
<img className="w-16 filter-grayscale self-center" src={ideaLogo} /> | ||||||
</div> | ||||||
</SelectableCard> | ||||||
<SelectableCard className="w-36 h-40" title="GoLand" selected={defaultDesktopIde === 'goland'} onClick={() => actuallySetDefaultDesktopIde('goland')}> | ||||||
<div className="flex justify-center mt-3"> | ||||||
<img className="w-16 filter-grayscale self-center" src={golandLogo} /> | ||||||
</div> | ||||||
</SelectableCard> | ||||||
</div> | ||||||
} | ||||||
<h3 className="mt-12">Theme</h3> | ||||||
<p className="text-base text-gray-500">Early bird or night owl? Choose your side.</p> | ||||||
<div className="mt-4 space-x-4 flex"> | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,8 +13,9 @@ export enum StartPhase { | |||||
Creating = 2, | ||||||
Starting = 3, | ||||||
Running = 4, | ||||||
Stopping = 5, | ||||||
Stopped = 6, | ||||||
IdeReady = 5, | ||||||
Stopping = 6, | ||||||
Stopped = 7, | ||||||
}; | ||||||
|
||||||
function getPhaseTitle(phase?: StartPhase, error?: StartWorkspaceError) { | ||||||
|
@@ -32,6 +33,8 @@ function getPhaseTitle(phase?: StartPhase, error?: StartWorkspaceError) { | |||||
return "Starting"; | ||||||
case StartPhase.Running: | ||||||
return "Starting"; | ||||||
case StartPhase.IdeReady: | ||||||
return "Your Workspace is Ready!"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thought: Wondering if a simpler phase would be better here.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to: #6438 |
||||||
case StartPhase.Stopping: | ||||||
return "Stopping"; | ||||||
case StartPhase.Stopped: | ||||||
|
@@ -84,9 +87,9 @@ export function StartPage(props: StartPageProps) { | |||||
return <div className="w-screen h-screen align-middle"> | ||||||
<div className="flex flex-col mx-auto items-center text-center h-screen"> | ||||||
<div className="h-1/3"></div> | ||||||
<img src={gitpodIcon} alt="Gitpod's logo" className={`h-16 flex-shrink-0 ${(error || phase === StartPhase.Stopped) ? '' : 'animate-bounce'}`} /> | ||||||
<img src={gitpodIcon} alt="Gitpod's logo" className={`h-16 flex-shrink-0 ${(error || phase === StartPhase.Stopped || phase === StartPhase.IdeReady) ? '' : 'animate-bounce'}`} /> | ||||||
<h3 className="mt-8 text-xl">{title}</h3> | ||||||
{typeof(phase) === 'number' && phase < StartPhase.Stopping && <ProgressBar phase={phase} error={!!error} />} | ||||||
{typeof(phase) === 'number' && phase < StartPhase.IdeReady && <ProgressBar phase={phase} error={!!error} />} | ||||||
{error && <StartError error={error} />} | ||||||
{props.children} | ||||||
</div> | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -27,6 +27,10 @@ export interface StartWorkspaceState { | |||||
workspace?: Workspace; | ||||||
hasImageBuildLogs?: boolean; | ||||||
error?: StartWorkspaceError; | ||||||
desktopIde?: { | ||||||
link: string | ||||||
label: string | ||||||
} | ||||||
} | ||||||
|
||||||
export default class StartWorkspace extends React.Component<StartWorkspaceProps, StartWorkspaceState> { | ||||||
|
@@ -46,6 +50,10 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps, | |||||
const error = { message: event.data.state.ideFrontendFailureCause }; | ||||||
this.setState({ error }); | ||||||
} | ||||||
if (event.data.state.desktopIdeLink) { | ||||||
const label = event.data.state.desktopIdeLabel || "Open Desktop IDE"; | ||||||
this.setState({ desktopIde: { link: event.data.state.desktopIdeLink, label } }); | ||||||
} | ||||||
} | ||||||
} | ||||||
window.addEventListener('message', setStateEventListener, false); | ||||||
|
@@ -269,8 +277,26 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps, | |||||
if (isHeadless) { | ||||||
return <HeadlessWorkspaceView instanceId={this.state.workspaceInstance.id} />; | ||||||
} | ||||||
phase = StartPhase.Running; | ||||||
statusMessage = <p className="text-base text-gray-400">Opening IDE …</p>; | ||||||
if (!this.state.desktopIde) { | ||||||
phase = StartPhase.Running; | ||||||
statusMessage = <p className="text-base text-gray-400">Opening IDE …</p>; | ||||||
} else { | ||||||
phase = StartPhase.IdeReady; | ||||||
statusMessage = <div> | ||||||
<div className="flex space-x-3 items-center text-left rounded-xl m-auto px-4 h-16 w-72 mt-4 mb-2 bg-gray-100 dark:bg-gray-800"> | ||||||
<div className="rounded-full w-3 h-3 text-sm bg-green-500"> </div> | ||||||
<div> | ||||||
<p className="text-gray-700 dark:text-gray-200 font-semibold">{this.state.workspaceInstance.workspaceId}</p> | ||||||
<a target="_parent" href={this.state.workspace?.contextURL}><p className="w-56 truncate hover:text-blue-600 dark:hover:text-blue-400" >{this.state.workspace?.contextURL}</p></a> | ||||||
</div> | ||||||
</div> | ||||||
<div className="mt-10 justify-center flex space-x-2"> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thought: Although out of the scope of these changes, here's an early draft on how these actions could be unified, compressed, and always available during workspace loading phase based on a relevant discussion (internal). 🍔
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the heads up! Let's address this in: #5641 |
||||||
<a target="_blank" href={this.state.desktopIde.link}><button>{this.state.desktopIde.label}</button></a> | ||||||
<button className="secondary" onClick={() => window.parent.postMessage({ type: 'openBrowserIde' }, '*')}>Open VS Code in Browser</button> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: What do you think of rephrasing this and associating the browser IDE with the product?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Come across this, and I don't think it's a good idea. The "Open in Gitpod" buttons that exist around the internet in Git repositories will lead to whatever IDE you have configured in your account. This button "Open VS Code in Browser" will lead to VS Code no matter what. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point @atduarte! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to: #6438 |
||||||
</div> | ||||||
</div>; | ||||||
} | ||||||
|
||||||
break; | ||||||
|
||||||
// Interrupted is an exceptional state where the container should be running but is temporarily unavailable. | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -212,4 +212,7 @@ export interface WorkspaceInstanceConfiguration { | |
|
||
// ideImage is the ref of the IDE image this instance uses. | ||
ideImage: string; | ||
|
||
// desktopIdeImage is the ref of the desktop IDE image this instance uses. | ||
desktopIdeImage?: string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to future self: Might be worth having a ordered map of |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
packages: | ||
- name: docker | ||
type: generic | ||
argdeps: | ||
- version | ||
deps: | ||
- :intellij | ||
- :goland | ||
- name: intellij | ||
type: docker | ||
srcs: | ||
- "startup.sh" | ||
- "supervisor-ide-config_intellij.json" | ||
- "status/go.mod" | ||
- "status/main.go" | ||
deps: | ||
- components/ide/jetbrains/backend-plugin:plugin | ||
argdeps: | ||
- imageRepoBase | ||
- INTELLIJ_BACKEND_URL | ||
config: | ||
dockerfile: leeway.Dockerfile | ||
metadata: | ||
helm-component: workspace.desktopIdeImages.intellij | ||
buildArgs: | ||
JETBRAINS_BACKEND_URL: ${INTELLIJ_BACKEND_URL} | ||
SUPERVISOR_IDE_CONFIG: supervisor-ide-config_intellij.json | ||
image: | ||
- ${imageRepoBase}/ide/intellij:${version} | ||
- ${imageRepoBase}/ide/intellij:commit-${__git_commit} | ||
- name: goland | ||
type: docker | ||
srcs: | ||
- "startup.sh" | ||
- "supervisor-ide-config_goland.json" | ||
- "status/go.mod" | ||
- "status/main.go" | ||
deps: | ||
- components/ide/jetbrains/backend-plugin:plugin | ||
argdeps: | ||
- imageRepoBase | ||
- GOLAND_BACKEND_URL | ||
config: | ||
dockerfile: leeway.Dockerfile | ||
metadata: | ||
helm-component: workspace.desktopIdeImages.goland | ||
buildArgs: | ||
JETBRAINS_BACKEND_URL: ${GOLAND_BACKEND_URL} | ||
SUPERVISOR_IDE_CONFIG: supervisor-ide-config_goland.json | ||
image: | ||
- ${imageRepoBase}/ide/goland:${version} | ||
- ${imageRepoBase}/ide/goland:commit-${__git_commit} |
Uh oh!
There was an error while loading. Please reload this page.