diff --git a/platform/platform-impl/api-dump-unreviewed.txt b/platform/platform-impl/api-dump-unreviewed.txt index 615ecd29cbcd..2da4fb63dd3d 100644 --- a/platform/platform-impl/api-dump-unreviewed.txt +++ b/platform/platform-impl/api-dump-unreviewed.txt @@ -3264,15 +3264,10 @@ f:com.intellij.ide.plugins.PluginHostsConfigurable - isModified():Z - reset():V f:com.intellij.ide.plugins.PluginInstallCallbackData -- (java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z):V - f:component1():java.nio.file.Path -- f:component2():com.intellij.ide.plugins.IdeaPluginDescriptorImpl - f:component3():Z -- f:copy(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z):com.intellij.ide.plugins.PluginInstallCallbackData -- bs:copy$default(com.intellij.ide.plugins.PluginInstallCallbackData,java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z,I,java.lang.Object):com.intellij.ide.plugins.PluginInstallCallbackData - equals(java.lang.Object):Z - f:getFile():java.nio.file.Path -- f:getPluginDescriptor():com.intellij.ide.plugins.IdeaPluginDescriptorImpl - f:getRestartNeeded():Z - hashCode():I f:com.intellij.ide.plugins.PluginInstaller @@ -3699,19 +3694,6 @@ c:com.intellij.ide.plugins.newui.SearchQueryParser$Marketplace - p:handleAttribute(java.lang.String,java.lang.String):V com.intellij.ide.plugins.newui.TabHeaderListener - a:selectionChanged(I):V -f:com.intellij.ide.plugins.newui.TabbedPaneHeaderComponent -- javax.swing.JPanel -- (com.intellij.openapi.actionSystem.DefaultActionGroup,com.intellij.ide.plugins.newui.TabHeaderListener):V -- addNotify():V -- addTab(java.lang.String,javax.swing.Icon):V -- getSelectionTab():I -- setBounds(I,I,I,I):V -- setListener():V -- setSelection(I):V -- setSelectionWithEvents(I):V -- setTabTooltip(I,java.lang.String):V -- update():V -- updateUI():V f:com.intellij.ide.plugins.newui.TagComponent - com.intellij.ide.plugins.newui.LinkComponent - ():V diff --git a/platform/platform-impl/api-dump.txt b/platform/platform-impl/api-dump.txt index 9c2a055080dd..54352a04d08e 100644 --- a/platform/platform-impl/api-dump.txt +++ b/platform/platform-impl/api-dump.txt @@ -218,6 +218,12 @@ f:com.intellij.ide.plugins.InstalledPluginsState - getInstalledWithoutRestartPlugins():java.util.Collection com.intellij.ide.plugins.PluginEnableStateChangedListener - a:stateChanged(java.util.Collection,Z):V +f:com.intellij.ide.plugins.PluginInstallCallbackData +- (java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z):V +- f:component2():com.intellij.ide.plugins.IdeaPluginDescriptor +- f:copy(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z):com.intellij.ide.plugins.PluginInstallCallbackData +- bs:copy$default(com.intellij.ide.plugins.PluginInstallCallbackData,java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z,I,java.lang.Object):com.intellij.ide.plugins.PluginInstallCallbackData +- f:getPluginDescriptor():com.intellij.ide.plugins.IdeaPluginDescriptor com.intellij.ide.plugins.PluginManagerMain$PluginEnabler - com.intellij.ide.plugins.PluginEnabler - disable(java.util.Collection):Z diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstallFromDiskAction.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstallFromDiskAction.java index 405dc235c3f1..9015578fa68d 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstallFromDiskAction.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstallFromDiskAction.java @@ -16,6 +16,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.annotations.RequiresEdt; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,6 +26,7 @@ import java.util.Locale; import java.util.Set; import java.util.function.Consumer; +@ApiStatus.Internal public class InstallFromDiskAction extends DumbAwareAction { private static final String PLUGINS_PRESELECTION_PATH = "plugins.preselection.path"; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstallCallbackData.kt b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstallCallbackData.kt index c8241b066c31..2168424839a1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstallCallbackData.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstallCallbackData.kt @@ -4,8 +4,8 @@ package com.intellij.ide.plugins import java.nio.file.Path data class PluginInstallCallbackData( - val file: Path, - val pluginDescriptor: IdeaPluginDescriptorImpl, + val file: Path?, + val pluginDescriptor: IdeaPluginDescriptor, val restartNeeded: Boolean, ) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java index 7fbc61d47be4..a1c430edddcb 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginInstaller.java @@ -251,7 +251,8 @@ public final class PluginInstaller { }, IdeBundle.message("action.InstallFromDiskAction.progress.text"), true, project); if (pluginDescriptor == null) { - MessagesEx.showErrorDialog(parent, IdeBundle.message("dialog.message.fail.to.load.plugin.descriptor.from.file", file.getFileName()), CommonBundle.getErrorTitle()); + MessagesEx.showErrorDialog(parent, IdeBundle.message("dialog.message.fail.to.load.plugin.descriptor.from.file", file.getFileName()), + CommonBundle.getErrorTitle()); return; } @@ -278,7 +279,8 @@ public final class PluginInstaller { return; } if (isBrokenPlugin(pluginDescriptor)) { - var message = CoreBundle.message("plugin.loading.error.long.marked.as.broken", pluginDescriptor.getName(), pluginDescriptor.getVersion()); + var message = + CoreBundle.message("plugin.loading.error.long.marked.as.broken", pluginDescriptor.getName(), pluginDescriptor.getVersion()); MessagesEx.showErrorDialog(parent, message, CommonBundle.getErrorTitle()); return; } @@ -452,15 +454,16 @@ public final class PluginInstaller { @RequiresEdt static void installPluginFromCallbackData(@NotNull PluginInstallCallbackData callbackData) { - var descriptor = callbackData.getPluginDescriptor(); - if (callbackData.getRestartNeeded()) { - shutdownOrRestartAppAfterInstall(descriptor); - } - else { - var loaded = installAndLoadDynamicPlugin(callbackData.getFile(), descriptor); - if (!loaded) { + if (callbackData.getPluginDescriptor() instanceof IdeaPluginDescriptorImpl descriptor && callbackData.getFile() != null) { + if (callbackData.getRestartNeeded()) { shutdownOrRestartAppAfterInstall(descriptor); } + else { + var loaded = installAndLoadDynamicPlugin(callbackData.getFile(), descriptor); + if (!loaded) { + shutdownOrRestartAppAfterInstall(descriptor); + } + } } } @@ -468,9 +471,9 @@ public final class PluginInstaller { PluginManagerConfigurable.shutdownOrRestartAppAfterInstall( PluginManagerConfigurable.getUpdatesDialogTitle(), action -> IdeBundle.message("plugin.installed.ide.restart.required.message", - descriptor.getName(), - action, - ApplicationNamesInfo.getInstance() - .getFullProductName())); + descriptor.getName(), + action, + ApplicationNamesInfo.getInstance() + .getFullProductName())); } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurable.java index e145c144681d..e21ffe89aaa8 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurable.java @@ -95,6 +95,8 @@ public final class PluginManagerConfigurable public static final String ID = "preferences.pluginManager"; public static final String SELECTION_TAB_KEY = "PluginConfigurable.selectionTab"; + public static final DataKey> PLUGIN_INSTALL_CALLBACK_DATA_KEY = + DataKey.create("PLUGIN_INSTALL_CALLBACK_DATA_KEY"); @SuppressWarnings("UseJBColor") public static final Color MAIN_BG_COLOR = JBColor.namedColor("Plugins.background", JBColor.lazy(() -> JBColor.isBright() ? UIUtil.getListBackground() : new Color(0x313335))); @@ -204,7 +206,12 @@ public final class PluginManagerConfigurable String query = (index == MARKETPLACE_TAB ? myInstalledTab : myMarketplaceTab).getSearchQuery(); (index == MARKETPLACE_TAB ? myMarketplaceTab : myInstalledTab).setSearchQuery(query); - }); + }){ + @Override + public void uiDataSnapshot(@NotNull DataSink sink) { + sink.set(PLUGIN_INSTALL_CALLBACK_DATA_KEY, PluginManagerConfigurable.this::onPluginInstalledFromDisk); + } + }; createGearGotIt(); myUpdateAll.setVisible(false); @@ -281,7 +288,9 @@ public final class PluginManagerConfigurable } getPluginsViewCustomizer().processConfigurable(this); - + if (myPluginManagerCustomizer != null) { + myPluginManagerCustomizer.initCustomizer(myCardPanel); + } return myCardPanel; } @@ -355,6 +364,9 @@ public final class PluginManagerConfigurable PluginManagerConfigurable.this.onPluginInstalledFromDisk(callbackData); } }); + if (myPluginManagerCustomizer != null) { + actions.addAll(myPluginManagerCustomizer.getExtraPluginsActions()); + } actions.addSeparator(); actions.add(new ChangePluginStateAction(false)); actions.add(new ChangePluginStateAction(true)); @@ -491,7 +503,7 @@ public final class PluginManagerConfigurable } private void doCreateMarketplaceTab(@NotNull Consumer selectionListener, Project project) { - PluginManagerPanelFactory.INSTANCE.createMarketplacePanel(myCoroutineScope, myPluginModelFacade.getModel(), project, model -> { + PluginManagerPanelFactory.INSTANCE.createMarketplacePanel(myCoroutineScope, myPluginModelFacade.getModel(), project, model -> { List groups = new ArrayList<>(); try { Map> customRepositoriesMap = UiPluginManager.getInstance().getCustomRepositoryPluginMap(); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/PluginInstalledFromDiskResult.kt b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/PluginInstalledFromDiskResult.kt new file mode 100644 index 000000000000..c4faa6d05f24 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/PluginInstalledFromDiskResult.kt @@ -0,0 +1,10 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.ide.plugins.marketplace + +import com.intellij.ide.plugins.api.PluginDto +import kotlinx.serialization.Serializable +import org.jetbrains.annotations.ApiStatus + +@Serializable +@ApiStatus.Internal +data class PluginInstalledFromDiskResult(val pluginDto: PluginDto?, val restartNeeded: Boolean) \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/MyPluginModel.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/MyPluginModel.java index 2ef91eaf99c7..f20f83dba0ca 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/MyPluginModel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/MyPluginModel.java @@ -155,13 +155,13 @@ public class MyPluginModel extends InstalledPluginsTableModel implements PluginE } public void pluginInstalledFromDisk(@NotNull PluginInstallCallbackData callbackData) { - IdeaPluginDescriptorImpl descriptor = callbackData.getPluginDescriptor(); + IdeaPluginDescriptor descriptor = callbackData.getPluginDescriptor(); CheckErrorsResult errors = UiPluginManager.getInstance().getErrors(sessionId.toString(), descriptor.getPluginId()); appendOrUpdateDescriptor(new PluginUiModelAdapter(descriptor), callbackData.getRestartNeeded(), getErrors(errors)); - if (!callbackData.getRestartNeeded()) { + if (!callbackData.getRestartNeeded() && callbackData.getFile() != null && descriptor instanceof IdeaPluginDescriptorImpl) { mySession.getDynamicPluginsToInstall().put(descriptor.getPluginId(), new PendingDynamicPluginInstall(callbackData.getFile(), - descriptor)); + (IdeaPluginDescriptorImpl)descriptor)); } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginManagerCustomizer.kt b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginManagerCustomizer.kt index f96ae5f85dea..86f836010422 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginManagerCustomizer.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginManagerCustomizer.kt @@ -9,9 +9,12 @@ import com.intellij.openapi.util.registry.Registry import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.Nls import javax.swing.Action +import javax.swing.JComponent @ApiStatus.Internal interface PluginManagerCustomizer { + fun initCustomizer(parentComponent: JComponent) + fun getInstallButonCustomizationModel( pluginModelFacade: PluginModelFacade, pluginToInstallModel: PluginUiModel, @@ -33,6 +36,8 @@ interface PluginManagerCustomizer { fun updateAfterModification(updateUi: () -> Unit) + fun getExtraPluginsActions(): List + @Nls fun getAdditionalTitleText(pluginModel: PluginUiModel): String? diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/TabbedPaneHeaderComponent.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/TabbedPaneHeaderComponent.java index 7e7ec569ff05..04d6b56bb80a 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/TabbedPaneHeaderComponent.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/TabbedPaneHeaderComponent.java @@ -19,6 +19,7 @@ import com.intellij.util.ui.AbstractLayoutManager; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.JBValue; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,7 +33,8 @@ import java.awt.event.ComponentEvent; /** * @author Alexander Lobas */ -public final class TabbedPaneHeaderComponent extends JPanel { +@ApiStatus.Internal +public class TabbedPaneHeaderComponent extends JPanel implements UiDataProvider { private final JBValue myHeight = new JBValue.Float(30); private final JBValue myGap = new JBValue.Float(10); @@ -92,6 +94,11 @@ public final class TabbedPaneHeaderComponent extends JPanel { add(createToolbar(actions, IdeBundle.message("plugin.manager.tooltip"), AllIcons.General.GearPlain), BorderLayout.EAST); } + @Override + public void uiDataSnapshot(@NotNull DataSink sink) { + + } + static @NotNull JComponent createToolbar(@NotNull DefaultActionGroup actions, @Nullable @NlsActions.ActionText String tooltip, @NotNull Icon icon) { diff --git a/platform/pluginManager/backend/BUILD.bazel b/platform/pluginManager/backend/BUILD.bazel index 652f753a3335..bf07a3d87bea 100644 --- a/platform/pluginManager/backend/BUILD.bazel +++ b/platform/pluginManager/backend/BUILD.bazel @@ -18,6 +18,7 @@ jvm_library( "//platform/kernel/shared:kernel", "//platform/kernel/rpc.backend", "//platform/platform-impl:ide-impl", + "//platform/editor-ui-api:editor-ui", "//platform/util", "//platform/plugins/parser/impl", "//platform/core-impl", diff --git a/platform/pluginManager/backend/intellij.platform.pluginManager.backend.iml b/platform/pluginManager/backend/intellij.platform.pluginManager.backend.iml index 417e17c87b2c..a0e60324d4f2 100644 --- a/platform/pluginManager/backend/intellij.platform.pluginManager.backend.iml +++ b/platform/pluginManager/backend/intellij.platform.pluginManager.backend.iml @@ -38,6 +38,7 @@ + diff --git a/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/BackendPluginInstallerApi.kt b/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/BackendPluginInstallerApi.kt index d6adb153097d..9dc768334113 100644 --- a/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/BackendPluginInstallerApi.kt +++ b/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/BackendPluginInstallerApi.kt @@ -2,14 +2,13 @@ package com.intellij.platform.pluginManager.backend.rpc import com.intellij.ide.plugins.DynamicPlugins +import com.intellij.ide.plugins.InstallFromDiskAction import com.intellij.ide.plugins.InstallPluginRequest +import com.intellij.ide.plugins.InstalledPluginsTableModel +import com.intellij.ide.plugins.PluginEnabler import com.intellij.ide.plugins.PluginInstaller import com.intellij.ide.plugins.PluginManagerCore -import com.intellij.ide.plugins.marketplace.ApplyPluginsStateResult -import com.intellij.ide.plugins.marketplace.CheckErrorsResult -import com.intellij.ide.plugins.marketplace.InstallPluginResult -import com.intellij.ide.plugins.marketplace.PrepareToUninstallResult -import com.intellij.ide.plugins.marketplace.SetEnabledStateResult +import com.intellij.ide.plugins.marketplace.* import com.intellij.ide.plugins.newui.BgProgressIndicator import com.intellij.ide.plugins.newui.DefaultUiPluginManagerController import com.intellij.ide.plugins.newui.PluginManagerSessionService @@ -46,6 +45,18 @@ class BackendPluginInstallerApi : PluginInstallerApi { return DefaultUiPluginManagerController.setEnableStateForDependencies(sessionId, descriptorIds, enable) } + override suspend fun installPluginFromDisk(projectId: ProjectId?): PluginInstalledFromDiskResult { + return withContext(Dispatchers.EDT) { + val project = projectId?.findProjectOrNull() + val deferred = CompletableDeferred() + + InstallFromDiskAction.installPluginFromDisk(null, project, InstalledPluginsTableModel(project), PluginEnabler.HEADLESS, null) { + deferred.complete(PluginInstalledFromDiskResult(PluginDescriptorConverter.toPluginDto(it.pluginDescriptor), it.restartNeeded)) + } + deferred.await() + } + } + override suspend fun prepareToUninstall(pluginsToUninstall: List): PrepareToUninstallResult { return DefaultUiPluginManagerController.prepareToUninstall(pluginsToUninstall) } diff --git a/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/PluginDescriptorConverter.kt b/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/PluginDescriptorConverter.kt index 486b5f88f5b4..6c4dd6f2618d 100644 --- a/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/PluginDescriptorConverter.kt +++ b/platform/pluginManager/backend/src/com/intellij/platform/pluginManager/backend/rpc/PluginDescriptorConverter.kt @@ -33,6 +33,7 @@ object PluginDescriptorConverter { isLicenseOptional = descriptor.isLicenseOptional releaseVersion = descriptor.releaseVersion displayCategory = descriptor.displayCategory + releaseDate = descriptor.releaseDate?.toInstant()?.toEpochMilli() descriptor.dependencies.forEach { dependency -> addDependency(dependency.pluginId, dependency.isOptional) diff --git a/platform/pluginManager/shared/src/com/intellij/platform/pluginManager/shared/rpc/PluginInstallerApi.kt b/platform/pluginManager/shared/src/com/intellij/platform/pluginManager/shared/rpc/PluginInstallerApi.kt index a53287fefae3..c7835246a303 100644 --- a/platform/pluginManager/shared/src/com/intellij/platform/pluginManager/shared/rpc/PluginInstallerApi.kt +++ b/platform/pluginManager/shared/src/com/intellij/platform/pluginManager/shared/rpc/PluginInstallerApi.kt @@ -6,6 +6,7 @@ import com.intellij.ide.plugins.marketplace.ApplyPluginsStateResult import com.intellij.ide.plugins.marketplace.CheckErrorsResult import com.intellij.openapi.extensions.PluginId import com.intellij.ide.plugins.marketplace.InstallPluginResult +import com.intellij.ide.plugins.marketplace.PluginInstalledFromDiskResult import com.intellij.ide.plugins.marketplace.PrepareToUninstallResult import com.intellij.ide.plugins.marketplace.SetEnabledStateResult import com.intellij.platform.project.ProjectId @@ -33,6 +34,7 @@ interface PluginInstallerApi : RemoteApi { suspend fun prepareToUninstall(pluginsToUninstall: List): PrepareToUninstallResult suspend fun getErrors(sessionId: String, pluginId: PluginId): CheckErrorsResult suspend fun setEnableStateForDependencies(sessionId: String, descriptorIds: Set, enable: Boolean, ): SetEnabledStateResult + suspend fun installPluginFromDisk(projectId: ProjectId?): PluginInstalledFromDiskResult companion object { suspend fun getInstance(): PluginInstallerApi {