From 1392775940a8da2e35a2a4857cdf3ed0910f3848 Mon Sep 17 00:00:00 2001 From: Carl-Robert Linnupuu Date: Sat, 2 Dec 2023 00:54:57 +0200 Subject: [PATCH] feat: display notification on plugin updates --- .../ee/carlrobert/codegpt/CodeGPTPlugin.java | 20 +++++- .../codegpt/CodeGPTUpdateStartupActivity.java | 68 +++++++++++++++++++ .../configuration/ConfigurationComponent.java | 13 ++++ .../ConfigurationConfigurable.java | 4 ++ .../configuration/ConfigurationState.java | 9 +++ .../carlrobert/codegpt/util/OverlayUtil.java | 7 +- src/main/resources/META-INF/plugin.xml | 1 + .../resources/messages/codegpt.properties | 7 +- 8 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 src/main/java/ee/carlrobert/codegpt/CodeGPTUpdateStartupActivity.java diff --git a/src/main/java/ee/carlrobert/codegpt/CodeGPTPlugin.java b/src/main/java/ee/carlrobert/codegpt/CodeGPTPlugin.java index 65a8b21b..43649035 100644 --- a/src/main/java/ee/carlrobert/codegpt/CodeGPTPlugin.java +++ b/src/main/java/ee/carlrobert/codegpt/CodeGPTPlugin.java @@ -5,11 +5,15 @@ import static java.util.Objects.requireNonNull; import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import ee.carlrobert.codegpt.telemetry.core.util.Directories; +import com.intellij.openapi.updateSettings.impl.PluginDownloader; +import com.intellij.openapi.updateSettings.impl.UpdateChecker; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collection; +import java.util.Optional; import org.jetbrains.annotations.NotNull; public final class CodeGPTPlugin { @@ -46,4 +50,18 @@ public final class CodeGPTPlugin { public static @NotNull String getProjectIndexStorePath(@NotNull Project project) { return getIndexStorePath() + File.separator + project.getName(); } + + public static Optional tryFindAvailableUpdate( + @NotNull ProgressIndicator indicator) { + return findAvailableUpdates(indicator).stream() + .filter((update) -> CODEGPT_ID.equals(update.getId())) + .findFirst(); + } + + private static @NotNull Collection findAvailableUpdates( + @NotNull ProgressIndicator indicator) { + return UpdateChecker.getInternalPluginUpdates(null, indicator) + .getPluginUpdates() + .getAllEnabled(); + } } diff --git a/src/main/java/ee/carlrobert/codegpt/CodeGPTUpdateStartupActivity.java b/src/main/java/ee/carlrobert/codegpt/CodeGPTUpdateStartupActivity.java new file mode 100644 index 00000000..7563f918 --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/CodeGPTUpdateStartupActivity.java @@ -0,0 +1,68 @@ +package ee.carlrobert.codegpt; + +import com.intellij.notification.NotificationAction; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; +import com.intellij.openapi.updateSettings.impl.UpdateChecker; +import com.intellij.openapi.updateSettings.impl.UpdateSettings; +import com.intellij.util.concurrency.AppExecutorUtil; +import ee.carlrobert.codegpt.settings.configuration.ConfigurationState; +import ee.carlrobert.codegpt.util.OverlayUtil; +import java.util.concurrent.TimeUnit; +import org.jetbrains.annotations.NotNull; + +public class CodeGPTUpdateStartupActivity implements StartupActivity.Background { + + @Override + public void runActivity(@NotNull Project project) { + schedulePluginUpdateChecks(project); + } + + private void schedulePluginUpdateChecks(Project project) { + AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> { + if (project != null && ConfigurationState.getInstance().isCheckForPluginUpdates()) { + new CheckForUpdatesTask(project).queue(); + } + + }, 0, 4L, TimeUnit.HOURS); + } + + private static class CheckForUpdatesTask extends Task.Backgroundable { + + public CheckForUpdatesTask(@NotNull Project project) { + super(project, CodeGPTBundle.get("checkForUpdatesTask.title"), true); + } + + private static void installCodeGPTUpdate(Project project) { + var settingsCopy = new UpdateSettings(); + var settingsState = settingsCopy.getState(); + settingsState.copyFrom(UpdateSettings.getInstance().getState()); + settingsState.setCheckNeeded(true); + settingsState.setPluginsCheckNeeded(true); + settingsState.setShowWhatsNewEditor(true); + settingsState.setThirdPartyPluginsAllowed(true); + UpdateChecker.updateAndShowResult(project, settingsCopy); + } + + public void run(@NotNull ProgressIndicator indicator) { + if (!myProject.isDisposed()) { + CodeGPTPlugin.tryFindAvailableUpdate(indicator) + .ifPresent((update) -> OverlayUtil.getDefaultNotification( + CodeGPTBundle.get("checkForUpdatesTask.notification.message"), + NotificationType.IDE_UPDATE) + .addAction(NotificationAction.createSimpleExpiring( + CodeGPTBundle.get("checkForUpdatesTask.notification.installButton"), + () -> ApplicationManager.getApplication() + .executeOnPooledThread(() -> installCodeGPTUpdate(myProject)))) + .addAction(NotificationAction.createSimpleExpiring( + CodeGPTBundle.get("checkForUpdatesTask.notification.hideButton"), + () -> ConfigurationState.getInstance().setCheckForPluginUpdates(false))) + .notify(myProject)); + } + } + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java index 4816f209..5a768789 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationComponent.java @@ -41,6 +41,7 @@ public class ConfigurationComponent { private final JPanel mainPanel; private final JBTable table; + private final JBCheckBox checkForPluginUpdatesCheckBox; private final JBCheckBox openNewTabCheckBox; private final JBCheckBox methodNameGenerationCheckBox; private final JBCheckBox autoFormattingCheckBox; @@ -99,6 +100,9 @@ public class ConfigurationComponent { systemPromptTextArea.setColumns(60); systemPromptTextArea.setRows(3); + checkForPluginUpdatesCheckBox = new JBCheckBox( + CodeGPTBundle.get("configurationConfigurable.checkForPluginUpdates.label"), + configuration.isCheckForPluginUpdates()); openNewTabCheckBox = new JBCheckBox( CodeGPTBundle.get("configurationConfigurable.openNewTabCheckBox.label"), configuration.isCreateNewChatOnEachAction()); @@ -112,6 +116,7 @@ public class ConfigurationComponent { mainPanel = FormBuilder.createFormBuilder() .addComponent(tablePanel) .addVerticalGap(4) + .addComponent(checkForPluginUpdatesCheckBox) .addComponent(openNewTabCheckBox) .addComponent(methodNameGenerationCheckBox) .addComponent(autoFormattingCheckBox) @@ -256,6 +261,14 @@ public class ConfigurationComponent { maxTokensField.setValue(maxTokens); } + public boolean isCheckForPluginUpdates() { + return checkForPluginUpdatesCheckBox.isSelected(); + } + + public void setCheckForPluginUpdates(boolean checkForUpdates) { + checkForPluginUpdatesCheckBox.setSelected(checkForUpdates); + } + public boolean isCreateNewChatOnEachAction() { return openNewTabCheckBox.isSelected(); } diff --git a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java index 364c66ee..27f71fc8 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationConfigurable.java @@ -37,6 +37,8 @@ public class ConfigurationConfigurable implements Configurable { || configurationComponent.getMaxTokens() != configuration.getMaxTokens() || configurationComponent.getTemperature() != configuration.getTemperature() || !configurationComponent.getSystemPrompt().equals(configuration.getSystemPrompt()) + || configurationComponent.isCheckForPluginUpdates() + != configuration.isCheckForPluginUpdates() || configurationComponent.isCreateNewChatOnEachAction() != configuration.isCreateNewChatOnEachAction() || configurationComponent.isMethodNameGenerationEnabled() @@ -52,6 +54,7 @@ public class ConfigurationConfigurable implements Configurable { configuration.setMaxTokens(configurationComponent.getMaxTokens()); configuration.setTemperature(configurationComponent.getTemperature()); configuration.setSystemPrompt(configurationComponent.getSystemPrompt()); + configuration.setCheckForPluginUpdates(configurationComponent.isCheckForPluginUpdates()); configuration.setCreateNewChatOnEachAction( configurationComponent.isCreateNewChatOnEachAction()); configuration.setMethodNameGenerationEnabled( @@ -67,6 +70,7 @@ public class ConfigurationConfigurable implements Configurable { configurationComponent.setMaxTokens(configuration.getMaxTokens()); configurationComponent.setTemperature(configuration.getTemperature()); configurationComponent.setSystemPrompt(configuration.getSystemPrompt()); + configurationComponent.setCheckForPluginUpdates(configuration.isCheckForPluginUpdates()); configurationComponent.setCreateNewChatOnEachAction( configuration.isCreateNewChatOnEachAction()); configurationComponent.setDisableMethodNameGeneration( diff --git a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java index b3d2d190..e38e410a 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/configuration/ConfigurationState.java @@ -20,6 +20,7 @@ public class ConfigurationState implements PersistentStateComponent + diff --git a/src/main/resources/messages/codegpt.properties b/src/main/resources/messages/codegpt.properties index ff06f19b..03a6b3ac 100644 --- a/src/main/resources/messages/codegpt.properties +++ b/src/main/resources/messages/codegpt.properties @@ -66,6 +66,7 @@ configurationConfigurable.table.header.actionColumnLabel=Action configurationConfigurable.table.header.promptColumnLabel=Prompt configurationConfigurable.table.action.revertToDefaults.text=Revert to Defaults configurationConfigurable.table.action.addKeymap.text=Add Shortcut +configurationConfigurable.checkForPluginUpdates.label=Check for plugin updates automatically configurationConfigurable.openNewTabCheckBox.label=Open a new chat on each action configurationConfigurable.enableMethodNameGeneration.label=Enable method name lookup suggestions configurationConfigurable.autoFormatting.label=Enable automatic code formatting @@ -128,4 +129,8 @@ service.llama.title=LLaMA C/C++ Port (Free, Local) validation.error.fieldRequired=This field is required. validation.error.invalidEmail=The email you entered is invalid. validation.error.mustBeNumber=Value must be number. -validation.error.mustBeBetweenZeroAndOne=Value must be between 0 and 1. \ No newline at end of file +validation.error.mustBeBetweenZeroAndOne=Value must be between 0 and 1. +checkForUpdatesTask.title=Checking for CodeGPT update... +checkForUpdatesTask.notification.message=An update for CodeGPT is available. +checkForUpdatesTask.notification.installButton=Install update +checkForUpdatesTask.notification.hideButton=Do not show again