From 705f6641979edc93a70dd578e3058e786b022cd6 Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Tue, 30 Aug 2022 14:19:45 +0000 Subject: [PATCH] Add Gitpod-related actions to JetBrains IDEs --- .../gitpodprotocol/api/GitpodServer.java | 12 +++ .../gitpodprotocol/api/entities/Error.java | 20 +++++ .../entities/SetWorkspaceTimeoutResult.java | 17 +++++ .../api/entities/TakeSnapshotOptions.java | 46 ++++++++++++ .../entities/WorkspaceTimeoutDuration.java | 22 ++++++ .../gitpod/jetbrains/remote/GitpodManager.kt | 13 +++- .../remote/actions/AccessControlAction.kt | 23 ++++++ .../remote/actions/CommunityChatAction.kt | 18 +++++ .../jetbrains/remote/actions/ContextAction.kt | 20 +++++ .../remote/actions/DashboardAction.kt | 20 +++++ .../remote/actions/DocumentationAction.kt | 18 +++++ .../actions/ExtendWorkspaceTimeoutAction.kt | 47 ++++++++++++ .../remote/actions/FollowUsOnTwitterAction.kt | 18 +++++ .../remote/actions/ReportIssueAction.kt | 18 +++++ .../remote/actions/SettingsAction.kt | 23 ++++++ .../actions/ShareWorkspaceSnapshotAction.kt | 74 ++++++++++++++++++ .../remote/actions/StopWorkspaceAction.kt | 24 ++++++ .../actions/UpgradeSubscriptionAction.kt | 23 ++++++ .../src/main/resources/META-INF/plugin.xml | 75 +++++++++++++++++++ .../gateway/GitpodConnectionProvider.kt | 4 +- .../gateway/GitpodStartWorkspaceView.kt | 2 +- 21 files changed, 533 insertions(+), 4 deletions(-) create mode 100644 components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/Error.java create mode 100644 components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/SetWorkspaceTimeoutResult.java create mode 100644 components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/TakeSnapshotOptions.java create mode 100644 components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/WorkspaceTimeoutDuration.java create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/AccessControlAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/CommunityChatAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ContextAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DashboardAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DocumentationAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ExtendWorkspaceTimeoutAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/FollowUsOnTwitterAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ReportIssueAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/SettingsAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ShareWorkspaceSnapshotAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/StopWorkspaceAction.kt create mode 100644 components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/UpgradeSubscriptionAction.kt diff --git a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/GitpodServer.java b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/GitpodServer.java index 8535c7fcd92f7d..512953960efd67 100644 --- a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/GitpodServer.java +++ b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/GitpodServer.java @@ -37,4 +37,16 @@ public interface GitpodServer { @JsonRequest CompletableFuture openPort(String workspaceId, WorkspaceInstancePort port); + + @JsonRequest + CompletableFuture takeSnapshot(TakeSnapshotOptions options); + + @JsonRequest + CompletableFuture waitForSnapshot(String snapshotId); + + @JsonRequest + CompletableFuture setWorkspaceTimeout(String workspaceId, String duration); + + @JsonRequest + CompletableFuture stopWorkspace(String workspaceId); } diff --git a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/Error.java b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/Error.java new file mode 100644 index 00000000000000..0ec624e7828dc4 --- /dev/null +++ b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/Error.java @@ -0,0 +1,20 @@ +// 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. + +package io.gitpod.gitpodprotocol.api.entities; + +public enum Error { + NOT_FOUND(404), + SNAPSHOT_ERROR(630); + + private int errCode; + + Error(int errCode) { + this.errCode = errCode; + } + + public int getErrCode() { + return errCode; + } +} diff --git a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/SetWorkspaceTimeoutResult.java b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/SetWorkspaceTimeoutResult.java new file mode 100644 index 00000000000000..edf46e9f483777 --- /dev/null +++ b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/SetWorkspaceTimeoutResult.java @@ -0,0 +1,17 @@ +// 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. + +package io.gitpod.gitpodprotocol.api.entities; + +public class SetWorkspaceTimeoutResult { + private String[] resetTimeoutOnWorkspaces; + + public SetWorkspaceTimeoutResult(String[] resetTimeoutOnWorkspaces) { + this.resetTimeoutOnWorkspaces = resetTimeoutOnWorkspaces; + } + + public String[] getResetTimeoutOnWorkspaces() { + return resetTimeoutOnWorkspaces; + } +} diff --git a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/TakeSnapshotOptions.java b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/TakeSnapshotOptions.java new file mode 100644 index 00000000000000..dd11bc2c65f19c --- /dev/null +++ b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/TakeSnapshotOptions.java @@ -0,0 +1,46 @@ +// 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. + +package io.gitpod.gitpodprotocol.api.entities; + +public class TakeSnapshotOptions { + private String workspaceId; + private String layoutData; + private boolean dontWait; + + public TakeSnapshotOptions(final String workspaceId, final String layoutData, final Boolean dontWait) { + this.workspaceId = workspaceId; + this.layoutData = layoutData; + this.dontWait = dontWait; + } + + public TakeSnapshotOptions(final String workspaceId, final Boolean dontWait) { + this.workspaceId = workspaceId; + this.dontWait = dontWait; + } + + public String getLayoutData() { + return layoutData; + } + + public void setLayoutData(String layoutData) { + this.layoutData = layoutData; + } + + public String getWorkspaceId() { + return workspaceId; + } + + public void setWorkspaceId(String workspaceId) { + this.workspaceId = workspaceId; + } + + public boolean isDontWait() { + return dontWait; + } + + public void setDontWait(boolean dontWait) { + this.dontWait = dontWait; + } +} diff --git a/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/WorkspaceTimeoutDuration.java b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/WorkspaceTimeoutDuration.java new file mode 100644 index 00000000000000..c35089626798ec --- /dev/null +++ b/components/gitpod-protocol/java/src/main/java/io/gitpod/gitpodprotocol/api/entities/WorkspaceTimeoutDuration.java @@ -0,0 +1,22 @@ +// 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. + +package io.gitpod.gitpodprotocol.api.entities; + +public enum WorkspaceTimeoutDuration { + DURATION_SHORT("short"), + DURATION_LONG("long"), + DURATION_EXTENDED("extended"), + DURATION_180M("180m"); // for backwards compatibility since the IDE uses this + + private String value; + + WorkspaceTimeoutDuration(String value) { + this.value = value; + } + + public String toString() { + return value; + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt index 4204ba401487ff..59f72ec286f043 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt @@ -4,6 +4,7 @@ package io.gitpod.jetbrains.remote +import com.intellij.ide.BrowserUtil import com.intellij.ide.plugins.PluginManagerCore import com.intellij.notification.NotificationAction import com.intellij.notification.NotificationGroupManager @@ -53,6 +54,7 @@ import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture import javax.websocket.DeploymentException +@Suppress("UnstableApiUsage", "OPT_IN_USAGE") @Service class GitpodManager : Disposable { @@ -258,9 +260,12 @@ class GitpodManager : Disposable { val tokenResponse = retry(3) { val request = Token.GetTokenRequest.newBuilder() .setHost(info.gitpodApi.host) + .addScope("function:openPort") .addScope("function:sendHeartBeat") + .addScope("function:setWorkspaceTimeout") + .addScope("function:stopWorkspace") + .addScope("function:takeSnapshot") .addScope("function:trackEvent") - .addScope("function:openPort") .setKind("gitpod") .build() @@ -393,4 +398,10 @@ class GitpodManager : Disposable { metricsJob.cancel() } } + + /** Opens the give URL in the Browser and records an event indicating it was open from a custom IntelliJ Action. */ + fun openUrlFromAction(url: String) { + trackEvent("jb_perform_action_open_url", mapOf("url" to url)) + BrowserUtil.browse(url) + } } diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/AccessControlAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/AccessControlAction.kt new file mode 100644 index 00000000000000..f7859380b382aa --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/AccessControlAction.kt @@ -0,0 +1,23 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager +import org.apache.http.client.utils.URIBuilder + +class AccessControlAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + URIBuilder(workspaceInfo.gitpodHost).setPath("integrations").build().toString().let { url -> + manager.openUrlFromAction(url) + } + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/CommunityChatAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/CommunityChatAction.kt new file mode 100644 index 00000000000000..0e6566bf5771ee --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/CommunityChatAction.kt @@ -0,0 +1,18 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class CommunityChatAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.openUrlFromAction("https://www.gitpod.io/chat") + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ContextAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ContextAction.kt new file mode 100644 index 00000000000000..2c289ea3f6f079 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ContextAction.kt @@ -0,0 +1,20 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class ContextAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + manager.openUrlFromAction(workspaceInfo.workspaceContextUrl) + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DashboardAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DashboardAction.kt new file mode 100644 index 00000000000000..31d683ece1a9da --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DashboardAction.kt @@ -0,0 +1,20 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class DashboardAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + manager.openUrlFromAction(workspaceInfo.gitpodHost) + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DocumentationAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DocumentationAction.kt new file mode 100644 index 00000000000000..529ca1113f59e5 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/DocumentationAction.kt @@ -0,0 +1,18 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class DocumentationAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.openUrlFromAction("https://www.gitpod.io/docs") + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ExtendWorkspaceTimeoutAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ExtendWorkspaceTimeoutAction.kt new file mode 100644 index 00000000000000..bfbe33185b97f7 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ExtendWorkspaceTimeoutAction.kt @@ -0,0 +1,47 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import com.intellij.openapi.diagnostic.thisLogger +import io.gitpod.gitpodprotocol.api.entities.WorkspaceTimeoutDuration +import io.gitpod.jetbrains.remote.GitpodManager +import com.intellij.notification.NotificationType + +class ExtendWorkspaceTimeoutAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + manager.trackEvent("jb_execute_command_gitpod_workspace", mapOf( + "action" to "extend-timeout" + )) + + manager.client.server.setWorkspaceTimeout(workspaceInfo.workspaceId, WorkspaceTimeoutDuration.DURATION_180M.toString()).whenComplete { result, e -> + var message: String + var notificationType: NotificationType + + if (e != null) { + message = "Cannot extend workspace timeout: ${e.message}" + notificationType = NotificationType.ERROR + thisLogger().error("gitpod: failed to extend workspace timeout", e) + } else { + if (result.resetTimeoutOnWorkspaces.isNotEmpty()) { + message = "Workspace timeout has been extended to three hours. This reset the workspace timeout for other workspaces." + notificationType = NotificationType.WARNING + } else { + message = "Workspace timeout has been extended to three hours." + notificationType = NotificationType.INFORMATION + } + } + + val notification = manager.notificationGroup.createNotification(message, notificationType) + notification.notify(null) + } + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/FollowUsOnTwitterAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/FollowUsOnTwitterAction.kt new file mode 100644 index 00000000000000..2b5733a6605ce4 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/FollowUsOnTwitterAction.kt @@ -0,0 +1,18 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class FollowUsOnTwitterAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.openUrlFromAction("https://twitter.com/gitpod") + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ReportIssueAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ReportIssueAction.kt new file mode 100644 index 00000000000000..16b3f8cf805a6d --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ReportIssueAction.kt @@ -0,0 +1,18 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class ReportIssueAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.openUrlFromAction("https://github.com/gitpod-io/gitpod/issues/new/choose") + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/SettingsAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/SettingsAction.kt new file mode 100644 index 00000000000000..4ec65426aa7848 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/SettingsAction.kt @@ -0,0 +1,23 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager +import org.apache.http.client.utils.URIBuilder + +class SettingsAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + URIBuilder(workspaceInfo.gitpodHost).setPath("settings").build().toString().let { url -> + manager.openUrlFromAction(url) + } + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ShareWorkspaceSnapshotAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ShareWorkspaceSnapshotAction.kt new file mode 100644 index 00000000000000..7aeb0cf6836f5e --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/ShareWorkspaceSnapshotAction.kt @@ -0,0 +1,74 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.notification.NotificationAction +import com.intellij.notification.NotificationType +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.util.ExceptionUtil +import io.gitpod.gitpodprotocol.api.entities.TakeSnapshotOptions +import io.gitpod.gitpodprotocol.api.entities.Error +import io.gitpod.jetbrains.remote.GitpodManager +import org.eclipse.lsp4j.jsonrpc.ResponseErrorException +import java.awt.Toolkit +import java.awt.datatransfer.StringSelection + +class ShareWorkspaceSnapshotAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + manager.trackEvent( + "jb_execute_command_gitpod_workspace", mapOf( + "action" to "snapshot" + ) + ) + + val takeSnapshotOptions = TakeSnapshotOptions(workspaceInfo.workspaceId, true) + + manager.client.server.takeSnapshot(takeSnapshotOptions).whenComplete { snapshotId, t -> + if (t != null) { + val notification = manager.notificationGroup.createNotification( + "Cannot capture workspace snapshot: ${t.message}", + NotificationType.ERROR + ) + notification.notify(null) + thisLogger().error("gitpod: failed to capture workspace snapshot", t) + } else { + thisLogger().warn("gitpod: snapshot started ($snapshotId)") + val notification = manager.notificationGroup.createNotification( + "Capturing workspace snapshot: this might take a moment, you will get a notification when the snapshot is ready", + NotificationType.INFORMATION + ) + notification.notify(null) + + manager.client.server.waitForSnapshot(snapshotId).whenComplete { _, t -> + if (t != null) { + val error = ExceptionUtil.findCause(t, ResponseErrorException::class.java) + if (error.responseError.code == Error.SNAPSHOT_ERROR.errCode || error.responseError.code == Error.NOT_FOUND.errCode) { + // this is indeed an error with snapshot creation itself, break here! + throw t + } + } + val notification = manager.notificationGroup.createNotification( + "The current state is captured in a snapshot. Using this link anybody can create their own copy of this workspace.", + NotificationType.INFORMATION + ) + val copyUrlAction = NotificationAction.createSimple("Copy URL to Clipboard") { + val uri = "${workspaceInfo.gitpodHost}#snapshot/$snapshotId"; + val clipboard = Toolkit.getDefaultToolkit().systemClipboard + clipboard.setContents(StringSelection(uri), null) + } + notification.addAction(copyUrlAction) + notification.notify(null) + } + } + } + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/StopWorkspaceAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/StopWorkspaceAction.kt new file mode 100644 index 00000000000000..5e8c0d97f70ae6 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/StopWorkspaceAction.kt @@ -0,0 +1,24 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager + +class StopWorkspaceAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + manager.trackEvent("jb_execute_command_gitpod_workspace", mapOf( + "action" to "stop" + )) + + manager.client.server.stopWorkspace(workspaceInfo.workspaceId) + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/UpgradeSubscriptionAction.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/UpgradeSubscriptionAction.kt new file mode 100644 index 00000000000000..74cb854b8fa9b2 --- /dev/null +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/actions/UpgradeSubscriptionAction.kt @@ -0,0 +1,23 @@ +// 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. + +package io.gitpod.jetbrains.remote.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import io.gitpod.jetbrains.remote.GitpodManager +import org.apache.http.client.utils.URIBuilder + +class UpgradeSubscriptionAction : AnAction() { + private val manager = service() + + override fun actionPerformed(event: AnActionEvent) { + manager.pendingInfo.thenAccept { workspaceInfo -> + URIBuilder(workspaceInfo.gitpodHost).setPath("plans").build().toString().let { url -> + manager.openUrlFromAction(url) + } + } + } +} diff --git a/components/ide/jetbrains/backend-plugin/src/main/resources/META-INF/plugin.xml b/components/ide/jetbrains/backend-plugin/src/main/resources/META-INF/plugin.xml index 7b4cb9fd5cf5b8..dc813d91f8dc50 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/resources/META-INF/plugin.xml +++ b/components/ide/jetbrains/backend-plugin/src/main/resources/META-INF/plugin.xml @@ -44,4 +44,79 @@ restartRequired="true"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt index 014188c3a69f9a..8b357c1bd102dd 100644 --- a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt +++ b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt @@ -244,9 +244,9 @@ class GitpodConnectionProvider : GatewayConnectionProvider { if (thinClientJob == null && update.status.phase == "running") { thinClientJob = launch { try { - val updatedIdeUrl = URL(update.ideUrl); + val updatedIdeUrl = URL(update.ideUrl) val sshHostUrl = - URL(update.ideUrl.replace(update.workspaceId, "${update.workspaceId}.ssh")); + URL(update.ideUrl.replace(update.workspaceId, "${update.workspaceId}.ssh")) val hostKeys = resolveHostKeys(updatedIdeUrl, connectParams) if (hostKeys.isNullOrEmpty()) { setErrorMessage("${connectParams.gitpodHost} installation does not allow SSH access, public keys cannot be found") diff --git a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodStartWorkspaceView.kt b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodStartWorkspaceView.kt index 4cfe851b7caabe..8809ff33b59e0f 100644 --- a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodStartWorkspaceView.kt +++ b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodStartWorkspaceView.kt @@ -76,7 +76,7 @@ class GitpodStartWorkspaceView( if (contextUrl.component.text.isNotBlank()) { backendsModel.selectedItem?.let { backendToId[it]?.let { backend -> - BrowserUtil.browse("https://${settings.gitpodHost}#referrer:jetbrains-gateway:${backend}/${contextUrl.component.text}") + BrowserUtil.browse("https://${settings.gitpodHost}#referrer:jetbrains-gateway:$backend/${contextUrl.component.text}") } } }