From 5e7ca4f56914e50cdf885756ea78a3bbfd3b871e Mon Sep 17 00:00:00 2001 From: Zhiming Ma Date: Sat, 18 Nov 2023 16:03:24 +0800 Subject: [PATCH] feat(intellij): Add dont-show-again for warnings. Add more online help links. (#823) --- .../intellijtabby/actions/CheckIssueDetail.kt | 78 +++++++++++++++++-- .../actions/JoinTabbySlackCommunity.kt | 11 +++ ...OpenOnlineDocs.kt => OpenModelRegistry.kt} | 4 +- .../actions/OpenOnlineDocumentation.kt | 11 +++ .../actions/OpenTabbyGithubRepo.kt | 11 +++ .../intellijtabby/agent/AgentService.kt | 26 ++++++- .../settings/ApplicationSettingsPanel.kt | 19 +++++ .../settings/ApplicationSettingsState.kt | 14 +++- .../status/StatusBarWidgetFactory.kt | 8 +- .../src/main/resources/META-INF/plugin.xml | 30 +++++-- 10 files changed, 191 insertions(+), 21 deletions(-) create mode 100644 clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/JoinTabbySlackCommunity.kt rename clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/{OpenOnlineDocs.kt => OpenModelRegistry.kt} (69%) create mode 100644 clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocumentation.kt create mode 100644 clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenTabbyGithubRepo.kt diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/CheckIssueDetail.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/CheckIssueDetail.kt index 200a62f..f50477b 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/CheckIssueDetail.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/CheckIssueDetail.kt @@ -1,21 +1,23 @@ package com.tabbyml.intellijtabby.actions -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.* import com.intellij.openapi.application.invokeLater import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.ui.Messages +import com.intellij.openapi.ui.popup.JBPopupFactory import com.tabbyml.intellijtabby.agent.Agent import com.tabbyml.intellijtabby.agent.AgentService +import com.tabbyml.intellijtabby.settings.ApplicationSettingsState import kotlinx.coroutines.launch import java.net.URL + class CheckIssueDetail : AnAction() { private val logger = Logger.getInstance(CheckIssueDetail::class.java) override fun actionPerformed(e: AnActionEvent) { + val settings = service() val agentService = service() agentService.issueNotification?.expire() @@ -24,7 +26,23 @@ class CheckIssueDetail : AnAction() { if (detail["name"] == "connectionFailed") { invokeLater { val messages = "" + (detail["message"] as String?)?.replace("\n", "
") + "" - Messages.showErrorDialog(messages, "Cannot Connect to Tabby Server") + val selected = Messages.showDialog( + messages, + "Cannot Connect to Tabby Server", + arrayOf("OK", "Online Help"), + 0, + Messages.getErrorIcon(), + ) + when (selected) { + 0 -> { + // OK + } + + 1 -> { + // Online Help + showOnlineHelp(e) + } + } } return@launch } else { @@ -38,12 +56,51 @@ class CheckIssueDetail : AnAction() { } val message = buildDetailMessage(detail, serverHealthState, agentConfig) invokeLater { - Messages.showInfoMessage(message, title) + val selected = Messages.showDialog( + message, + title, + arrayOf("OK", "Online Help", "Don't Show Again"), + 0, + Messages.getWarningIcon(), + ) + when (selected) { + 0 -> { + // OK + } + + 1 -> { + // Online Help + showOnlineHelp(e) + } + + 2 -> { + // Don't Show Again + settings.notificationsMuted += listOf("completionResponseTimeIssues") + } + } } } } } + private fun showOnlineHelp(e: AnActionEvent) { + e.project?.let { + invokeLater { + val actionManager = ActionManager.getInstance() + val actionGroup = actionManager.getAction("Tabby.OpenOnlineHelp") as? ActionGroup ?: return@invokeLater + val popup = JBPopupFactory.getInstance().createActionGroupPopup( + "Online Help", + actionGroup, + e.dataContext, + false, + null, + 10, + ) + popup.showCenteredInCurrentWindow(it) + } + } + } + private fun buildDetailMessage( detail: Map, serverHealthState: Map?, @@ -76,7 +133,7 @@ class CheckIssueDetail : AnAction() { """ Your Tabby server is running model $model on CPU. This model may be performing poorly due to its large parameter size, please consider trying smaller models or switch to GPU. - You can find a list of supported models in the model directory. + You can find a list of recommend models in the model registry. """.trimIndent() } else { "" @@ -85,7 +142,7 @@ class CheckIssueDetail : AnAction() { val host = URL(agentConfig.server?.endpoint).host if (helpMessageForRunningLargeModelOnCPU.isEmpty()) { commonHelpMessage += "
  • The running model $model may be performing poorly due to its large parameter size.
    " - commonHelpMessage += "Please consider trying smaller models. You can find a list of supported models in the model directory.
  • " + commonHelpMessage += "Please consider trying smaller models. You can find a list of recommend models in the model registry." } if (!(host.startsWith("localhost") || host.startsWith("127.0.0.1"))) { commonHelpMessage += "
  • A poor network connection. Please check your network and proxy settings.
  • " @@ -106,8 +163,13 @@ class CheckIssueDetail : AnAction() { } override fun update(e: AnActionEvent) { + val settings = service() val agentService = service() - e.presentation.isVisible = agentService.currentIssue.value != null + val muted = mutableListOf() + if (settings.notificationsMuted.contains("completionResponseTimeIssues")) { + muted += listOf("slowCompletionResponseTime", "highCompletionTimeoutRate") + } + e.presentation.isVisible = agentService.currentIssue.value != null && agentService.currentIssue.value !in muted } override fun getActionUpdateThread(): ActionUpdateThread { diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/JoinTabbySlackCommunity.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/JoinTabbySlackCommunity.kt new file mode 100644 index 0000000..73dd3e4 --- /dev/null +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/JoinTabbySlackCommunity.kt @@ -0,0 +1,11 @@ +package com.tabbyml.intellijtabby.actions + +import com.intellij.ide.BrowserUtil +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent + +class JoinTabbySlackCommunity: AnAction() { + override fun actionPerformed(e: AnActionEvent) { + BrowserUtil.browse("https://join.slack.com/t/tabbycommunity/shared_invite/zt-1xeiddizp-bciR2RtFTaJ37RBxr8VxpA") + } +} \ No newline at end of file diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocs.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenModelRegistry.kt similarity index 69% rename from clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocs.kt rename to clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenModelRegistry.kt index acfacb5..9c3d433 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocs.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenModelRegistry.kt @@ -4,8 +4,8 @@ import com.intellij.ide.BrowserUtil import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent -class OpenOnlineDocs: AnAction() { +class OpenModelRegistry: AnAction() { override fun actionPerformed(e: AnActionEvent) { - BrowserUtil.browse("https://tabby.tabbyml.com/docs/extensions/") + BrowserUtil.browse("https://tabby.tabbyml.com/docs/models/") } } \ No newline at end of file diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocumentation.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocumentation.kt new file mode 100644 index 0000000..cb794d2 --- /dev/null +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenOnlineDocumentation.kt @@ -0,0 +1,11 @@ +package com.tabbyml.intellijtabby.actions + +import com.intellij.ide.BrowserUtil +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent + +class OpenOnlineDocumentation: AnAction() { + override fun actionPerformed(e: AnActionEvent) { + BrowserUtil.browse("https://tabby.tabbyml.com/") + } +} \ No newline at end of file diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenTabbyGithubRepo.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenTabbyGithubRepo.kt new file mode 100644 index 0000000..60eb49b --- /dev/null +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/actions/OpenTabbyGithubRepo.kt @@ -0,0 +1,11 @@ +package com.tabbyml.intellijtabby.actions + +import com.intellij.ide.BrowserUtil +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent + +class OpenTabbyGithubRepo : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + BrowserUtil.browse("https://github.com/tabbyml/tabby") + } +} \ No newline at end of file diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/agent/AgentService.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/agent/AgentService.kt index 3322a3a..c9f2ae6 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/agent/AgentService.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/agent/AgentService.kt @@ -8,6 +8,8 @@ import com.intellij.notification.NotificationType import com.intellij.notification.Notifications import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.ActionManager +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.ApplicationInfo import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.invokeLater @@ -76,7 +78,13 @@ class AgentService : Disposable { "${e.message}", NotificationType.ERROR, ) - notification.addAction(ActionManager.getInstance().getAction("Tabby.OpenOnlineDocs")) + notification.addAction( + object : AnAction("Open Online Documentation") { + override fun actionPerformed(e: AnActionEvent) { + BrowserUtil.browse("https://tabby.tabbyml.com/docs/extensions/troubleshooting/#tabby-initialization-failed") + } + } + ) invokeLater { initFailedNotification?.expire() initFailedNotification = notification @@ -131,16 +139,18 @@ class AgentService : Disposable { scope.launch { agent.currentIssue.collect { issueName -> + val showCompletionResponseWarnings = !completionResponseWarningShown && + !settings.notificationsMuted.contains("completionResponseTimeIssues") val message = when (issueName) { "connectionFailed" -> "Cannot connect to Tabby server" - "slowCompletionResponseTime" -> if (!completionResponseWarningShown) { + "slowCompletionResponseTime" -> if (showCompletionResponseWarnings) { completionResponseWarningShown = true "Completion requests appear to take too much time" } else { return@collect } - "highCompletionTimeoutRate" -> if (!completionResponseWarningShown) { + "highCompletionTimeoutRate" -> if (showCompletionResponseWarnings) { completionResponseWarningShown = true "Most completion requests timed out" } else { @@ -160,6 +170,16 @@ class AgentService : Disposable { NotificationType.WARNING, ) notification.addAction(ActionManager.getInstance().getAction("Tabby.CheckIssueDetail")) + if (issueName in listOf("slowCompletionResponseTime", "highCompletionTimeoutRate")) { + notification.addAction( + object : AnAction("Don't Show Again") { + override fun actionPerformed(e: AnActionEvent) { + issueNotification?.expire() + settings.notificationsMuted += listOf("completionResponseTimeIssues") + } + } + ) + } invokeLater { issueNotification?.expire() issueNotification = notification diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsPanel.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsPanel.kt index fdd5b50..cf55039 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsPanel.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsPanel.kt @@ -168,6 +168,19 @@ class ApplicationSettingsPanel { ) .panel + private val resetMutedNotificationsButton = JButton("Reset \"Don't Show Again\" Notifications").apply { + addActionListener { + val settings = service() + settings.notificationsMuted = listOf() + invokeLater(ModalityState.stateForComponent(this@ApplicationSettingsPanel.mainPanel)) { + Messages.showInfoMessage("Reset \"Don't Show Again\" notifications successfully.", "Reset Notifications") + } + } + } + private val resetMutedNotificationsPanel: JPanel = FormBuilder.createFormBuilder() + .addComponent(resetMutedNotificationsButton) + .panel + val mainPanel: JPanel = FormBuilder.createFormBuilder() .addLabeledComponent("Server endpoint", serverEndpointPanel, 5, false) .addSeparator(5) @@ -176,6 +189,12 @@ class ApplicationSettingsPanel { .addLabeledComponent("Node binary
    (Requires restart IDE)", nodeBinaryPanel, 5, false) .addSeparator(5) .addLabeledComponent("Anonymous usage tracking", isAnonymousUsageTrackingPanel, 5, false) + .apply { + if (service().notificationsMuted.isNotEmpty()) { + addSeparator(5) + addLabeledComponent("Notifications", resetMutedNotificationsPanel, 5, false) + } + } .addComponentFillVertically(JPanel(), 0) .panel diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsState.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsState.kt index 157b64b..e6d53aa 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsState.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/settings/ApplicationSettingsState.kt @@ -56,11 +56,20 @@ class ApplicationSettingsState : PersistentStateComponent()) + val notificationsMutedState = notificationsMutedFlow.asStateFlow() + var notificationsMuted: List = listOf() + set(value) { + field = value + notificationsMutedFlow.value = value + } + data class State( val completionTriggerMode: TriggerMode, val serverEndpoint: String, val nodeBinary: String, val isAnonymousUsageTrackingDisabled: Boolean, + val notificationsMuted: List, ) val data: State @@ -69,6 +78,7 @@ class ApplicationSettingsState : PersistentStateComponent + notificationsMutedState, + ) { completionTriggerMode, serverEndpoint, nodeBinary, isAnonymousUsageTrackingDisabled, notificationsMuted -> State( completionTriggerMode = completionTriggerMode, serverEndpoint = serverEndpoint, nodeBinary = nodeBinary, isAnonymousUsageTrackingDisabled = isAnonymousUsageTrackingDisabled, + notificationsMuted = notificationsMuted, ) }.stateIn(CoroutineScope(Dispatchers.IO), SharingStarted.Eagerly, this.data) diff --git a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/status/StatusBarWidgetFactory.kt b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/status/StatusBarWidgetFactory.kt index af2aef7..8a621bf 100644 --- a/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/status/StatusBarWidgetFactory.kt +++ b/clients/intellij/src/main/kotlin/com/tabbyml/intellijtabby/status/StatusBarWidgetFactory.kt @@ -87,7 +87,7 @@ class StatusBarWidgetFactory : StatusBarEditorBasedWidgetFactory() { actionManager.getAction("Tabby.CheckIssueDetail"), actionManager.getAction("Tabby.ToggleInlineCompletionTriggerMode"), actionManager.getAction("Tabby.OpenSettings"), - actionManager.getAction("Tabby.OpenOnlineDocs"), + actionManager.getAction("Tabby.OpenOnlineHelp"), ) } }, @@ -109,7 +109,11 @@ class StatusBarWidgetFactory : StatusBarEditorBasedWidgetFactory() { tooltip = "Tabby: Initialization failed" } Agent.Status.READY -> { - if (state.currentIssue != null) { + val muted = mutableListOf() + if (state.settings.notificationsMuted.contains("completionResponseTimeIssues")) { + muted += listOf("slowCompletionResponseTime", "highCompletionTimeoutRate") + } + if (state.currentIssue != null && state.currentIssue !in muted) { icon = AllIcons.General.Warning tooltip = when(state.currentIssue) { "slowCompletionResponseTime" -> "Tabby: Completion requests appear to take too much time" diff --git a/clients/intellij/src/main/resources/META-INF/plugin.xml b/clients/intellij/src/main/resources/META-INF/plugin.xml index e62399b..8d0b427 100644 --- a/clients/intellij/src/main/resources/META-INF/plugin.xml +++ b/clients/intellij/src/main/resources/META-INF/plugin.xml @@ -93,11 +93,31 @@ text="Open Settings..." description="Show settings for Tabby."> - - + + + + + + + + + + \ No newline at end of file