diff --git a/platform/diagnostic/freezeInPluginNotifier/intellij.platform.diagnostic.freezes.iml b/platform/diagnostic/freezeInPluginNotifier/intellij.platform.diagnostic.freezes.iml index 924234c1e094..036046cb7b9e 100644 --- a/platform/diagnostic/freezeInPluginNotifier/intellij.platform.diagnostic.freezes.iml +++ b/platform/diagnostic/freezeInPluginNotifier/intellij.platform.diagnostic.freezes.iml @@ -1,5 +1,26 @@ + + + + + + + + + + + + + + $KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar + + + + + + diff --git a/platform/diagnostic/freezeInPluginNotifier/resources/messages/PluginFreezeBundle.properties b/platform/diagnostic/freezeInPluginNotifier/resources/messages/PluginFreezeBundle.properties index d3a3ff1f6567..9b408e98e114 100644 --- a/platform/diagnostic/freezeInPluginNotifier/resources/messages/PluginFreezeBundle.properties +++ b/platform/diagnostic/freezeInPluginNotifier/resources/messages/PluginFreezeBundle.properties @@ -1,4 +1,6 @@ action.disable.plugin.text=Disable plugin action.close.panel.text=Dismiss action.ignore.plugin.text=Ignore freezes in plugin -notification.content.plugin.caused.freeze.detected=Plugin ''{0}'' might be slowing things down \ No newline at end of file +notification.content.plugin.caused.freeze.detected=Plugin ''{0}'' might be slowing things down +action.open.issue.tracker.text=Open issue tracker +progress.title.opening.issue.tracker=Opening plugin issue tracker \ No newline at end of file diff --git a/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginFreezeNotifier.kt b/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginFreezeNotifier.kt index b86ca8dd5d80..0e9558fd76bd 100644 --- a/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginFreezeNotifier.kt +++ b/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginFreezeNotifier.kt @@ -2,6 +2,8 @@ package com.intellij.platform.diagnostic.plugin.freeze import com.intellij.featureStatistics.fusCollectors.LifecycleUsageTriggerCollector +import com.intellij.ide.BrowserUtil +import com.intellij.ide.plugins.IdeaPluginDescriptor import com.intellij.ide.plugins.PluginManagerCore import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.impl.ApplicationInfoImpl @@ -10,6 +12,7 @@ import com.intellij.openapi.fileEditor.FileEditor import com.intellij.openapi.project.Project import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFile +import com.intellij.platform.ide.progress.runWithModalProgressBlocking import com.intellij.ui.EditorNotificationPanel import com.intellij.ui.EditorNotificationProvider import com.intellij.ui.EditorNotifications @@ -45,6 +48,11 @@ internal class PluginFreezeNotifier : EditorNotificationProvider { closePanel(project) } + createActionLabel(PluginFreezeBundle.message("action.open.issue.tracker.text")) { + openIssueTracker(project, pluginDescriptor) + + LifecycleUsageTriggerCollector.pluginIssueTrackerOpened() + } createActionLabel(PluginFreezeBundle.message("action.close.panel.text")) { closePanel(project) } @@ -60,6 +68,14 @@ internal class PluginFreezeNotifier : EditorNotificationProvider { } } + private fun openIssueTracker(project: Project, pluginDescriptor: IdeaPluginDescriptor) { + runWithModalProgressBlocking(project, PluginFreezeBundle.message("progress.title.opening.issue.tracker")) { + PluginIssueTrackerResolver.getMarketplaceBugTrackerUrl(pluginDescriptor)?.let { + BrowserUtil.open(it) + } + } + } + private fun closePanel(project: Project) { freezeWatcher.reset() EditorNotifications.getInstance(project).updateAllNotifications() diff --git a/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginIssueTrackerResolver.kt b/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginIssueTrackerResolver.kt new file mode 100644 index 000000000000..df6b6c558eee --- /dev/null +++ b/platform/diagnostic/freezeInPluginNotifier/src/com/intellij/platform/diagnostic/plugin/freeze/PluginIssueTrackerResolver.kt @@ -0,0 +1,41 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.diagnostic.plugin.freeze + +import com.intellij.ide.plugins.marketplace.utils.MarketplaceUrls +import com.intellij.openapi.extensions.PluginDescriptor +import com.intellij.util.io.HttpRequests +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import java.util.concurrent.TimeUnit + +@Serializable +private data class MarketplacePluginInfo( + val urls: PluginUrls, + val icon: String, +) + +@Serializable +private data class PluginUrls( + val url: String, + val bugtrackerUrl: String, +) + +internal object PluginIssueTrackerResolver { + private val json = Json { ignoreUnknownKeys = true } + + suspend fun getMarketplaceBugTrackerUrl(pluginDescriptor: PluginDescriptor): String? { + val url = pluginDescriptor.url?.replace("/plugin/", "/api/plugins/") + if (url == null) return MarketplaceUrls.getPluginHomepage(pluginDescriptor.pluginId) + + val timeoutMillis = TimeUnit.SECONDS.toMillis(5) + return withContext(Dispatchers.IO) { + runCatching { + val response = HttpRequests.request(url).connectTimeout(timeoutMillis.toInt()).readTimeout(timeoutMillis.toInt()).readString() + val pluginInfo: MarketplacePluginInfo = json.decodeFromString(response) + pluginInfo.urls.bugtrackerUrl + }.getOrDefault(MarketplaceUrls.getPluginHomepage(pluginDescriptor.pluginId)) + } + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java index 8e7b62d3bc02..039c349ce21c 100644 --- a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java +++ b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java @@ -28,7 +28,7 @@ import static com.intellij.internal.statistic.utils.PluginInfoDetectorKt.getPlug public final class LifecycleUsageTriggerCollector extends CounterUsagesCollector { private static final Logger LOG = Logger.getInstance(LifecycleUsageTriggerCollector.class); - private static final EventLogGroup LIFECYCLE = new EventLogGroup("lifecycle", 71); + private static final EventLogGroup LIFECYCLE = new EventLogGroup("lifecycle", 72); private static final EventField eapField = EventFields.Boolean("eap"); private static final EventField testField = EventFields.Boolean("test"); @@ -72,6 +72,8 @@ public final class LifecycleUsageTriggerCollector extends CounterUsagesCollector LIFECYCLE.registerEvent("ide.freeze.disabled.plugin", EventFields.PluginInfo); private static final EventId1 IDE_FREEZE_PLUGIN_IGNORED = LIFECYCLE.registerEvent("ide.freeze.ignored.plugin", EventFields.PluginInfo); + private static final EventId IDE_FREEZE_PLUGIN_ISSUE_TRACKER_OPENED = + LIFECYCLE.registerEvent("ide.freeze.issue.tracker.opened"); private static final ClassEventField errorField = EventFields.Class("error"); private static final EventField memoryErrorKindField = @@ -240,4 +242,8 @@ public final class LifecycleUsageTriggerCollector extends CounterUsagesCollector public static void pluginFreezeIgnored(@NotNull PluginId id) { IDE_FREEZE_PLUGIN_IGNORED.log(getPluginInfoById(id)); } + + public static void pluginIssueTrackerOpened() { + IDE_FREEZE_PLUGIN_ISSUE_TRACKER_OPENED.log(); + } }