mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-233558 hide cc status bar widget by default
GitOrigin-RevId: ebeb50fac824592081d028c185bb4500b4cb2cfc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d9fb8debee
commit
d73d10aa6c
+7
-1
@@ -1 +1,7 @@
|
||||
<idea-plugin/>
|
||||
<idea-plugin>
|
||||
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
|
||||
<dependencies>
|
||||
<module name="intellij.agent.workbench.json"/>
|
||||
</dependencies>
|
||||
<!-- endregion -->
|
||||
</idea-plugin>
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
|
||||
<dependencies>
|
||||
<module name="intellij.agent.workbench.codex.common"/>
|
||||
<module name="intellij.agent.workbench.json"/>
|
||||
<module name="intellij.agent.workbench.sessions"/>
|
||||
</dependencies>
|
||||
<!-- endregion -->
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
### auto-generated section `build intellij.agent.workbench.json` start
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library", "resourcegroup")
|
||||
|
||||
resourcegroup(
|
||||
name = "json_resources",
|
||||
srcs = glob(["resources/**/*"]),
|
||||
strip_prefix = "resources"
|
||||
)
|
||||
|
||||
jvm_library(
|
||||
name = "json",
|
||||
module_name = "intellij.agent.workbench.json",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
|
||||
resources = [":json_resources"],
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//libraries/jackson/jackson",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.agent.workbench.json" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<idea-plugin>
|
||||
</idea-plugin>
|
||||
@@ -16,6 +16,9 @@
|
||||
- name: lib/modules/intellij.agent.workbench.codex.sessions.jar
|
||||
contentModules:
|
||||
- name: intellij.agent.workbench.codex.sessions
|
||||
- name: lib/modules/intellij.agent.workbench.json.jar
|
||||
contentModules:
|
||||
- name: intellij.agent.workbench.json
|
||||
- name: lib/modules/intellij.agent.workbench.sessions.jar
|
||||
contentModules:
|
||||
- name: intellij.agent.workbench.sessions
|
||||
- name: intellij.agent.workbench.sessions
|
||||
@@ -5,6 +5,7 @@
|
||||
<description>Agent Workbench - AI-based developement for IntelliJ</description>
|
||||
<vendor>JetBrains</vendor>
|
||||
<content namespace="jetbrains">
|
||||
<module name="intellij.agent.workbench.json"/>
|
||||
<module name="intellij.agent.workbench.claude.common"/>
|
||||
<module name="intellij.agent.workbench.claude.sessions"/>
|
||||
<module name="intellij.agent.workbench.codex.common"/>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<reference ref="OpenFile"/>
|
||||
<separator/>
|
||||
<action id="AgentWorkbenchSessions.ToggleDedicatedFrame" class="com.intellij.agent.workbench.sessions.AgentSessionsDedicatedFrameToggleAction"/>
|
||||
<action id="AgentWorkbenchSessions.ToggleClaudeQuotaWidget" class="com.intellij.agent.workbench.sessions.AgentSessionsToggleClaudeQuotaWidgetAction"/>
|
||||
<action id="AgentWorkbenchSessions.Refresh" class="com.intellij.agent.workbench.sessions.AgentSessionsRefreshAction"/>
|
||||
</group>
|
||||
<action
|
||||
@@ -46,4 +47,4 @@
|
||||
class="com.intellij.agent.workbench.sessions.AgentSessionsActivateWithProjectShortcutAction"
|
||||
use-shortcut-of="ActivateProjectToolWindow"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
</idea-plugin>
|
||||
@@ -23,6 +23,7 @@ toolwindow.provider.codex=Codex
|
||||
toolwindow.provider.claude=Claude
|
||||
action.AgentWorkbenchSessions.Refresh.text=Refresh
|
||||
action.AgentWorkbenchSessions.ToggleDedicatedFrame.text=Open Chat in Dedicated Frame
|
||||
action.AgentWorkbenchSessions.ToggleClaudeQuotaWidget.text=Show Claude Usage in Status Bar
|
||||
action.AgentWorkbenchSessions.ActivateWithProjectShortcut.text=Agent Threads
|
||||
advanced.settings.agent.workbench=Agent Workbench
|
||||
advanced.setting.agent.workbench.chat.open.in.dedicated.frame=Open Agent chat in dedicated frame
|
||||
@@ -46,3 +47,7 @@ status.bar.claude.quota.display.name=Claude Usage
|
||||
status.bar.claude.quota.text={0}% of {1}
|
||||
status.bar.claude.quota.tooltip.session=Session (5h): {0}% \u2014 resets {1}
|
||||
status.bar.claude.quota.tooltip.weekly=Weekly (7d): {0}% \u2014 resets {1}
|
||||
toolwindow.claude.quota.hint.title=See Claude usage in your status bar
|
||||
toolwindow.claude.quota.hint.body=Track 5h and 7d quota at a glance while you work.
|
||||
toolwindow.claude.quota.hint.enable=Enable
|
||||
toolwindow.claude.quota.hint.dismiss=Dismiss
|
||||
|
||||
@@ -541,6 +541,7 @@ internal class AgentSessionsService private constructor(
|
||||
fun openChatThread(path: String, thread: AgentSessionThread, currentProject: Project? = null) {
|
||||
val normalized = normalizePath(path)
|
||||
val key = buildOpenThreadActionKey(path = normalized, thread = thread)
|
||||
markClaudeQuotaHintEligible(thread.provider)
|
||||
actionGate.launch(
|
||||
scope = serviceScope,
|
||||
key = key,
|
||||
@@ -565,6 +566,7 @@ internal class AgentSessionsService private constructor(
|
||||
fun openChatSubAgent(path: String, thread: AgentSessionThread, subAgent: AgentSubAgent, currentProject: Project? = null) {
|
||||
val normalized = normalizePath(path)
|
||||
val key = buildOpenSubAgentActionKey(path = normalized, thread = thread, subAgent = subAgent)
|
||||
markClaudeQuotaHintEligible(thread.provider)
|
||||
actionGate.launch(
|
||||
scope = serviceScope,
|
||||
key = key,
|
||||
@@ -586,6 +588,7 @@ internal class AgentSessionsService private constructor(
|
||||
) {
|
||||
val normalized = normalizePath(path)
|
||||
val key = buildCreateSessionActionKey(normalized, provider, mode)
|
||||
markClaudeQuotaHintEligible(provider)
|
||||
actionGate.launch(
|
||||
scope = serviceScope,
|
||||
key = key,
|
||||
@@ -899,6 +902,13 @@ internal class AgentSessionsService private constructor(
|
||||
return "$OPEN_PROJECT_ACTION_KEY_PREFIX:$path"
|
||||
}
|
||||
|
||||
private fun markClaudeQuotaHintEligible(provider: AgentSessionProvider) {
|
||||
if (provider != AgentSessionProvider.CLAUDE) {
|
||||
return
|
||||
}
|
||||
service<AgentSessionsTreeUiStateService>().markClaudeQuotaHintEligible()
|
||||
}
|
||||
|
||||
private fun buildCreateSessionActionKey(path: String, provider: AgentSessionProvider, mode: AgentSessionLaunchMode): String {
|
||||
return "$CREATE_SESSION_ACTION_KEY_PREFIX:$path:$provider:mode=$mode"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.agent.workbench.sessions
|
||||
|
||||
import com.intellij.agent.workbench.sessions.claude.ClaudeQuotaStatusBarWidgetSettings
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.project.DumbAwareToggleAction
|
||||
|
||||
internal class AgentSessionsToggleClaudeQuotaWidgetAction : DumbAwareToggleAction() {
|
||||
override fun isSelected(e: AnActionEvent): Boolean = ClaudeQuotaStatusBarWidgetSettings.isEnabled()
|
||||
|
||||
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
||||
ClaudeQuotaStatusBarWidgetSettings.setEnabled(state)
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
}
|
||||
@@ -3,11 +3,14 @@ package com.intellij.agent.workbench.sessions
|
||||
// @spec community/plugins/agent-workbench/spec/agent-sessions.spec.md
|
||||
// @spec community/plugins/agent-workbench/spec/agent-sessions-thread-visibility.spec.md
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -15,12 +18,17 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.intellij.agent.workbench.chat.AgentChatTabSelectionService
|
||||
import com.intellij.agent.workbench.sessions.claude.ClaudeQuotaStatusBarWidgetSettings
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.coroutines.delay
|
||||
import org.jetbrains.jewel.foundation.theme.JewelTheme
|
||||
import org.jetbrains.jewel.ui.component.OutlinedButton
|
||||
import org.jetbrains.jewel.ui.component.Text
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Composable
|
||||
internal fun agentSessionsToolWindow(currentProject: Project) {
|
||||
@@ -30,11 +38,27 @@ internal fun agentSessionsToolWindow(currentProject: Project) {
|
||||
val state by service.state.collectAsState()
|
||||
val selectedChatTab by chatSelectionService.selectedChatTab.collectAsState()
|
||||
val lastUsedProvider by uiStateService.lastUsedProviderFlow.collectAsState()
|
||||
val claudeQuotaHintEligible by uiStateService.claudeQuotaHintEligibleFlow.collectAsState()
|
||||
val claudeQuotaHintAcknowledged by uiStateService.claudeQuotaHintAcknowledgedFlow.collectAsState()
|
||||
val isClaudeQuotaWidgetEnabled by ClaudeQuotaStatusBarWidgetSettings.enabledFlow.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
service.refresh()
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
ClaudeQuotaStatusBarWidgetSettings.syncEnabledState()
|
||||
delay(1.seconds)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(claudeQuotaHintEligible, claudeQuotaHintAcknowledged, isClaudeQuotaWidgetEnabled) {
|
||||
if (claudeQuotaHintEligible && !claudeQuotaHintAcknowledged && isClaudeQuotaWidgetEnabled) {
|
||||
uiStateService.acknowledgeClaudeQuotaHint()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(selectedChatTab, state.projects) {
|
||||
val currentSelection = selectedChatTab ?: return@LaunchedEffect
|
||||
val identity = parseAgentSessionIdentity(currentSelection.threadIdentity) ?: return@LaunchedEffect
|
||||
@@ -66,6 +90,14 @@ internal fun agentSessionsToolWindow(currentProject: Project) {
|
||||
visibleThreadCounts = state.visibleThreadCounts,
|
||||
onShowMoreThreads = { path -> service.showMoreThreads(path) },
|
||||
selectedTreeId = selectedTreeId,
|
||||
showClaudeQuotaHint = claudeQuotaHintEligible && !claudeQuotaHintAcknowledged && !isClaudeQuotaWidgetEnabled,
|
||||
onEnableClaudeQuotaWidget = {
|
||||
ClaudeQuotaStatusBarWidgetSettings.setEnabled(true)
|
||||
uiStateService.acknowledgeClaudeQuotaHint()
|
||||
},
|
||||
onDismissClaudeQuotaHint = {
|
||||
uiStateService.acknowledgeClaudeQuotaHint()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,6 +118,9 @@ internal fun agentSessionsToolWindowContent(
|
||||
visibleThreadCounts: Map<String, Int> = emptyMap(),
|
||||
onShowMoreThreads: (String) -> Unit = {},
|
||||
selectedTreeId: SessionTreeId? = null,
|
||||
showClaudeQuotaHint: Boolean = false,
|
||||
onEnableClaudeQuotaWidget: () -> Unit = {},
|
||||
onDismissClaudeQuotaHint: () -> Unit = {},
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -93,6 +128,13 @@ internal fun agentSessionsToolWindowContent(
|
||||
.padding(horizontal = 10.dp, vertical = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
if (showClaudeQuotaHint) {
|
||||
claudeQuotaHintBanner(
|
||||
onEnableClaudeQuotaWidget = onEnableClaudeQuotaWidget,
|
||||
onDismiss = onDismissClaudeQuotaHint,
|
||||
)
|
||||
}
|
||||
|
||||
when {
|
||||
state.projects.isEmpty() -> emptyState(isLoading = state.lastUpdatedAt == null)
|
||||
else -> sessionTree(
|
||||
@@ -116,6 +158,44 @@ internal fun agentSessionsToolWindowContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun claudeQuotaHintBanner(
|
||||
onEnableClaudeQuotaWidget: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val shape = RoundedCornerShape(8.dp)
|
||||
val borderColor = JewelTheme.globalColors.borders.normal
|
||||
.takeOrElse { JewelTheme.globalColors.text.disabled }
|
||||
.copy(alpha = 0.35f)
|
||||
val bodyColor = JewelTheme.globalColors.text.normal.copy(alpha = 0.84f)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(width = 1.dp, color = borderColor, shape = shape)
|
||||
.padding(10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
) {
|
||||
Text(
|
||||
text = AgentSessionsBundle.message("toolwindow.claude.quota.hint.title"),
|
||||
style = AgentSessionsTextStyles.projectTitle(),
|
||||
)
|
||||
Text(
|
||||
text = AgentSessionsBundle.message("toolwindow.claude.quota.hint.body"),
|
||||
style = AgentSessionsTextStyles.threadTitle(),
|
||||
color = bodyColor,
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
OutlinedButton(onClick = onEnableClaudeQuotaWidget) {
|
||||
Text(AgentSessionsBundle.message("toolwindow.claude.quota.hint.enable"))
|
||||
}
|
||||
OutlinedButton(onClick = onDismiss) {
|
||||
Text(AgentSessionsBundle.message("toolwindow.claude.quota.hint.dismiss"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun emptyState(isLoading: Boolean) {
|
||||
val messageKey = if (isLoading) "toolwindow.loading" else "toolwindow.empty.global"
|
||||
|
||||
@@ -114,6 +114,10 @@ internal class AgentSessionsTreeUiStateService
|
||||
|
||||
private val _lastUsedProviderFlow = MutableStateFlow(getLastUsedProvider())
|
||||
val lastUsedProviderFlow: StateFlow<AgentSessionProvider?> = _lastUsedProviderFlow.asStateFlow()
|
||||
private val _claudeQuotaHintEligibleFlow = MutableStateFlow(state.claudeQuotaHintEligible)
|
||||
val claudeQuotaHintEligibleFlow: StateFlow<Boolean> = _claudeQuotaHintEligibleFlow.asStateFlow()
|
||||
private val _claudeQuotaHintAcknowledgedFlow = MutableStateFlow(state.claudeQuotaHintAcknowledged)
|
||||
val claudeQuotaHintAcknowledgedFlow: StateFlow<Boolean> = _claudeQuotaHintAcknowledgedFlow.asStateFlow()
|
||||
|
||||
override fun isProjectCollapsed(path: String): Boolean {
|
||||
return normalizeSessionsProjectPath(path) in state.collapsedProjectPaths
|
||||
@@ -240,9 +244,23 @@ internal class AgentSessionsTreeUiStateService
|
||||
_lastUsedProviderFlow.value = provider
|
||||
}
|
||||
|
||||
fun markClaudeQuotaHintEligible() {
|
||||
if (state.claudeQuotaHintEligible) return
|
||||
updateState { it.copy(claudeQuotaHintEligible = true) }
|
||||
_claudeQuotaHintEligibleFlow.value = true
|
||||
}
|
||||
|
||||
fun acknowledgeClaudeQuotaHint() {
|
||||
if (state.claudeQuotaHintAcknowledged) return
|
||||
updateState { it.copy(claudeQuotaHintAcknowledged = true) }
|
||||
_claudeQuotaHintAcknowledgedFlow.value = true
|
||||
}
|
||||
|
||||
override fun loadState(state: SessionsTreeUiStateState) {
|
||||
super.loadState(state)
|
||||
_lastUsedProviderFlow.value = state.lastUsedProvider?.let(AgentSessionProvider::fromOrNull)
|
||||
_claudeQuotaHintEligibleFlow.value = state.claudeQuotaHintEligible
|
||||
_claudeQuotaHintAcknowledgedFlow.value = state.claudeQuotaHintAcknowledged
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -251,6 +269,8 @@ internal class AgentSessionsTreeUiStateService
|
||||
@JvmField val visibleThreadCountByProject: Map<String, Int> = emptyMap(),
|
||||
@JvmField val openProjectThreadPreviewsByProject: Map<String, List<ThreadPreviewState>> = emptyMap(),
|
||||
@JvmField val lastUsedProvider: String? = null,
|
||||
@JvmField val claudeQuotaHintEligible: Boolean = false,
|
||||
@JvmField val claudeQuotaHintAcknowledged: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
||||
@@ -26,17 +26,17 @@ import javax.swing.JPanel
|
||||
import javax.swing.JProgressBar
|
||||
import javax.swing.Timer
|
||||
|
||||
private const val WIDGET_ID = "claude.quota"
|
||||
internal const val CLAUDE_QUOTA_WIDGET_ID = "claude.quota"
|
||||
private const val UI_REFRESH_INTERVAL_MS = 5_000
|
||||
private const val UI_REFRESH_INITIAL_DELAY_MS = 1_000
|
||||
private const val WARNING_QUOTA_PERCENT = 80
|
||||
|
||||
internal class ClaudeQuotaStatusBarWidgetFactory : StatusBarWidgetFactory {
|
||||
override fun getId(): String = WIDGET_ID
|
||||
override fun getId(): String = CLAUDE_QUOTA_WIDGET_ID
|
||||
|
||||
override fun getDisplayName(): String = AgentSessionsBundle.message("status.bar.claude.quota.display.name")
|
||||
|
||||
override fun isEnabledByDefault(): Boolean = true
|
||||
override fun isEnabledByDefault(): Boolean = false
|
||||
|
||||
override fun createWidget(project: Project): StatusBarWidget = ClaudeQuotaStatusBarWidget()
|
||||
}
|
||||
@@ -62,7 +62,7 @@ internal class ClaudeQuotaStatusBarWidget : CustomStatusBarWidget, Activatable {
|
||||
|
||||
override fun getPresentation(): StatusBarWidget.WidgetPresentation? = null
|
||||
|
||||
override fun ID(): String = WIDGET_ID
|
||||
override fun ID(): String = CLAUDE_QUOTA_WIDGET_ID
|
||||
|
||||
override fun getComponent(): JComponent = myComponent.get()
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.agent.workbench.sessions.claude
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.wm.StatusBarWidgetFactory
|
||||
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetSettings
|
||||
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
internal object ClaudeQuotaStatusBarWidgetSettings {
|
||||
private val _enabledFlow = MutableStateFlow(readEnabledFromSettings())
|
||||
val enabledFlow: StateFlow<Boolean> = _enabledFlow.asStateFlow()
|
||||
|
||||
fun isEnabled(): Boolean {
|
||||
syncEnabledState()
|
||||
return _enabledFlow.value
|
||||
}
|
||||
|
||||
fun syncEnabledState() {
|
||||
_enabledFlow.value = readEnabledFromSettings()
|
||||
}
|
||||
|
||||
fun setEnabled(enabled: Boolean) {
|
||||
val factory = findFactory() ?: return
|
||||
val settings = StatusBarWidgetSettings.getInstance()
|
||||
if (settings.isEnabled(factory) == enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
settings.setEnabled(factory, enabled)
|
||||
for (project in ProjectManager.getInstance().openProjects) {
|
||||
project.service<StatusBarWidgetsManager>().updateWidget(factory)
|
||||
}
|
||||
_enabledFlow.value = enabled
|
||||
}
|
||||
|
||||
private fun readEnabledFromSettings(): Boolean {
|
||||
val factory = findFactory() ?: return false
|
||||
return StatusBarWidgetSettings.getInstance().isEnabled(factory)
|
||||
}
|
||||
|
||||
private fun findFactory(): StatusBarWidgetFactory? {
|
||||
return StatusBarWidgetFactory.EP_NAME.extensionList.firstOrNull { it.id == CLAUDE_QUOTA_WIDGET_ID }
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.agent.workbench.sessions
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class AgentSessionsClaudeQuotaWidgetActionRegistrationTest {
|
||||
@Test
|
||||
fun gearActionsContainClaudeQuotaWidgetToggle() {
|
||||
val descriptor = checkNotNull(javaClass.classLoader.getResource("intellij.agent.workbench.sessions.xml")) {
|
||||
"Module descriptor intellij.agent.workbench.sessions.xml is missing"
|
||||
}.readText()
|
||||
|
||||
assertThat(descriptor)
|
||||
.contains("<group id=\"AgentWorkbenchSessions.ToolWindow.GearActions\">")
|
||||
.contains("<action id=\"AgentWorkbenchSessions.ToggleClaudeQuotaWidget\"")
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,71 @@ class AgentSessionsToolWindowTest {
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun claudeQuotaHintIsShownWhenRequested() {
|
||||
composeRule.setContentWithTheme {
|
||||
agentSessionsToolWindowContent(
|
||||
state = AgentSessionsState(projects = emptyList(), lastUpdatedAt = 1L),
|
||||
onRefresh = {},
|
||||
onOpenProject = {},
|
||||
showClaudeQuotaHint = true,
|
||||
)
|
||||
}
|
||||
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.title"))
|
||||
.assertIsDisplayed()
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.body"))
|
||||
.assertIsDisplayed()
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.enable"))
|
||||
.assertIsDisplayed()
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.dismiss"))
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun claudeQuotaHintEnableInvokesCallback() {
|
||||
var enabled = false
|
||||
|
||||
composeRule.setContentWithTheme {
|
||||
agentSessionsToolWindowContent(
|
||||
state = AgentSessionsState(projects = emptyList(), lastUpdatedAt = 1L),
|
||||
onRefresh = {},
|
||||
onOpenProject = {},
|
||||
showClaudeQuotaHint = true,
|
||||
onEnableClaudeQuotaWidget = { enabled = true },
|
||||
)
|
||||
}
|
||||
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.enable"))
|
||||
.performClick()
|
||||
|
||||
composeRule.runOnIdle {
|
||||
assertThat(enabled).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun claudeQuotaHintDismissInvokesCallback() {
|
||||
var dismissed = false
|
||||
|
||||
composeRule.setContentWithTheme {
|
||||
agentSessionsToolWindowContent(
|
||||
state = AgentSessionsState(projects = emptyList(), lastUpdatedAt = 1L),
|
||||
onRefresh = {},
|
||||
onOpenProject = {},
|
||||
showClaudeQuotaHint = true,
|
||||
onDismissClaudeQuotaHint = { dismissed = true },
|
||||
)
|
||||
}
|
||||
|
||||
composeRule.onNodeWithText(AgentSessionsBundle.message("toolwindow.claude.quota.hint.dismiss"))
|
||||
.performClick()
|
||||
|
||||
composeRule.runOnIdle {
|
||||
assertThat(dismissed).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun projectsDoNotShowGlobalEmptyStateWhenNoThreadsLoadedYet() {
|
||||
val projects = listOf(
|
||||
|
||||
@@ -67,6 +67,29 @@ class AgentSessionsTreeUiStateServiceTest {
|
||||
assertNull(uiState.getLastUsedProvider())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun claudeQuotaHintDefaultsToDisabledAndUnacknowledged() {
|
||||
val uiState = AgentSessionsTreeUiStateService()
|
||||
|
||||
assertFalse(uiState.state.claudeQuotaHintEligible)
|
||||
assertFalse(uiState.state.claudeQuotaHintAcknowledged)
|
||||
assertFalse(uiState.claudeQuotaHintEligibleFlow.value)
|
||||
assertFalse(uiState.claudeQuotaHintAcknowledgedFlow.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun claudeQuotaHintStateRoundTrip() {
|
||||
val uiState = AgentSessionsTreeUiStateService()
|
||||
|
||||
uiState.markClaudeQuotaHintEligible()
|
||||
assertTrue(uiState.state.claudeQuotaHintEligible)
|
||||
assertTrue(uiState.claudeQuotaHintEligibleFlow.value)
|
||||
|
||||
uiState.acknowledgeClaudeQuotaHint()
|
||||
assertTrue(uiState.state.claudeQuotaHintAcknowledged)
|
||||
assertTrue(uiState.claudeQuotaHintAcknowledgedFlow.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setAndGetLastUsedProvider() {
|
||||
val uiState = AgentSessionsTreeUiStateService()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.agent.workbench.sessions
|
||||
|
||||
import com.intellij.agent.workbench.sessions.claude.ClaudeQuotaInfo
|
||||
import com.intellij.agent.workbench.sessions.claude.ClaudeQuotaStatusBarWidgetFactory
|
||||
import com.intellij.agent.workbench.sessions.claude.dominantPercent
|
||||
import com.intellij.agent.workbench.sessions.claude.formatQuotaResetTime
|
||||
import com.intellij.agent.workbench.sessions.claude.formatWidgetText
|
||||
@@ -11,6 +12,11 @@ import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class ClaudeQuotaStatusBarWidgetTest {
|
||||
@Test
|
||||
fun widgetIsDisabledByDefault() {
|
||||
assertThat(ClaudeQuotaStatusBarWidgetFactory().isEnabledByDefault).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun formatTextShowsSessionWhenHigher() {
|
||||
val info = ClaudeQuotaInfo(fiveHourPercent = 45, fiveHourReset = null, sevenDayPercent = 12, sevenDayReset = null)
|
||||
|
||||
Reference in New Issue
Block a user