feat(intellij): Add dont-show-again for warnings. Add more online help links. (#823)

release-fix-intellij-update-support-version-range
Zhiming Ma 2023-11-18 16:03:24 +08:00 committed by GitHub
parent 2cc751766f
commit 5e7ca4f569
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 191 additions and 21 deletions

View File

@ -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<ApplicationSettingsState>()
val agentService = service<AgentService>()
agentService.issueNotification?.expire()
@ -24,7 +26,23 @@ class CheckIssueDetail : AnAction() {
if (detail["name"] == "connectionFailed") {
invokeLater {
val messages = "<html>" + (detail["message"] as String?)?.replace("\n", "<br/>") + "</html>"
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<String, Any>,
serverHealthState: Map<String, Any>?,
@ -76,7 +133,7 @@ class CheckIssueDetail : AnAction() {
"""
Your Tabby server is running model <i>$model</i> 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 <a href='https://tabby.tabbyml.com/docs/models/'>model directory</a>.
You can find a list of recommend models in the <a href='https://tabby.tabbyml.com/docs/models/'>model registry</a>.
""".trimIndent()
} else {
""
@ -85,7 +142,7 @@ class CheckIssueDetail : AnAction() {
val host = URL(agentConfig.server?.endpoint).host
if (helpMessageForRunningLargeModelOnCPU.isEmpty()) {
commonHelpMessage += "<li>The running model <i>$model</i> may be performing poorly due to its large parameter size.<br/>"
commonHelpMessage += "Please consider trying smaller models. You can find a list of supported models in the <a href='https://tabby.tabbyml.com/docs/models/'>model directory</a>.</li>"
commonHelpMessage += "Please consider trying smaller models. You can find a list of recommend models in the <a href='https://tabby.tabbyml.com/docs/models/'>model registry</a>.</li>"
}
if (!(host.startsWith("localhost") || host.startsWith("127.0.0.1"))) {
commonHelpMessage += "<li>A poor network connection. Please check your network and proxy settings.</li>"
@ -106,8 +163,13 @@ class CheckIssueDetail : AnAction() {
}
override fun update(e: AnActionEvent) {
val settings = service<ApplicationSettingsState>()
val agentService = service<AgentService>()
e.presentation.isVisible = agentService.currentIssue.value != null
val muted = mutableListOf<String>()
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 {

View File

@ -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")
}
}

View File

@ -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/")
}
}

View File

@ -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/")
}
}

View File

@ -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")
}
}

View File

@ -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

View File

@ -168,6 +168,19 @@ class ApplicationSettingsPanel {
)
.panel
private val resetMutedNotificationsButton = JButton("Reset \"Don't Show Again\" Notifications").apply {
addActionListener {
val settings = service<ApplicationSettingsState>()
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("<html>Node binary<br/>(Requires restart IDE)</html>", nodeBinaryPanel, 5, false)
.addSeparator(5)
.addLabeledComponent("Anonymous usage tracking", isAnonymousUsageTrackingPanel, 5, false)
.apply {
if (service<ApplicationSettingsState>().notificationsMuted.isNotEmpty()) {
addSeparator(5)
addLabeledComponent("Notifications", resetMutedNotificationsPanel, 5, false)
}
}
.addComponentFillVertically(JPanel(), 0)
.panel

View File

@ -56,11 +56,20 @@ class ApplicationSettingsState : PersistentStateComponent<ApplicationSettingsSta
isAnonymousUsageTrackingDisabledFlow.value = value
}
private val notificationsMutedFlow = MutableStateFlow(listOf<String>())
val notificationsMutedState = notificationsMutedFlow.asStateFlow()
var notificationsMuted: List<String> = 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<String>,
)
val data: State
@ -69,6 +78,7 @@ class ApplicationSettingsState : PersistentStateComponent<ApplicationSettingsSta
serverEndpoint = serverEndpoint,
nodeBinary = nodeBinary,
isAnonymousUsageTrackingDisabled = isAnonymousUsageTrackingDisabled,
notificationsMuted = notificationsMuted,
)
val state = combine(
@ -76,12 +86,14 @@ class ApplicationSettingsState : PersistentStateComponent<ApplicationSettingsSta
serverEndpointState,
nodeBinaryState,
isAnonymousUsageTrackingDisabledState,
) { completionTriggerMode, serverEndpoint, nodeBinary, isAnonymousUsageTrackingDisabled ->
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)

View File

@ -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<String>()
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"

View File

@ -93,11 +93,31 @@
text="Open Settings..."
description="Show settings for Tabby.">
</action>
<action id="Tabby.OpenOnlineDocs"
class="com.tabbyml.intellijtabby.actions.OpenOnlineDocs"
text="Open Online Help..."
description="Open the online docs in your web browser.">
</action>
<group id="Tabby.OpenOnlineHelp"
popup="true"
text="Open Online Help"
description="View useful links for online help.">
<action id="Tabby.OpenOnlineHelp.OpenOnlineDocumentation"
class="com.tabbyml.intellijtabby.actions.OpenOnlineDocumentation"
text="Online Documentation..."
description="Open the documentation page in your web browser.">
</action>
<action id="Tabby.OpenOnlineHelp.OpenModelRegistry"
class="com.tabbyml.intellijtabby.actions.OpenModelRegistry"
text="Model Registry..."
description="Explore more recommend models from Tabby's model registry.">
</action>
<action id="Tabby.OpenOnlineHelp.JoinTabbySlackCommunity"
class="com.tabbyml.intellijtabby.actions.JoinTabbySlackCommunity"
text="Tabby Slack Community..."
description="Join Tabby's Slack community to get help or feed back.">
</action>
<action id="Tabby.OpenOnlineHelp.OpenTabbyGithubRepo"
class="com.tabbyml.intellijtabby.actions.OpenTabbyGithubRepo"
text="Tabby GitHub Repository..."
description="View the source code for Tabby, and open issues.">
</action>
</group>
</group>
</actions>
</idea-plugin>