diff --git a/shell/plugins/agents/Panel.qml b/shell/plugins/agents/Panel.qml index 67563f62..60677e91 100644 --- a/shell/plugins/agents/Panel.qml +++ b/shell/plugins/agents/Panel.qml @@ -422,6 +422,10 @@ Panel { return status !== "" && status !== "Limits paused" && !needsSignIn(item) ? status : "" } + function pausedWithoutLimits(item) { + return !!item && item.usageStatusText === "Limits paused" && limitWindows(item).length === 0 + } + // Sign an account that's already here in again, following along in the // add view just like adding one. function signInAgain(p, account) { @@ -1343,6 +1347,12 @@ Panel { wrapMode: Text.WordWrap } + UnavailableUsage { + visible: !section.multi && root.pausedWithoutLimits(section.provider) + width: parent.width + record: section.provider + } + Column { visible: !section.multi && section.windows.length > 0 width: parent.width @@ -1449,6 +1459,11 @@ Panel { width: parent.width spacing: Style.space(12) + UnavailableUsage { + width: parent.width + record: accountBlock.modelData + } + Repeater { model: root.displayWindows({ limits: accountBlock.modelData.limits || [] }) @@ -1833,6 +1848,29 @@ Panel { } } + // With no measured windows, leave a place to discover how to get usage. + component UnavailableUsage: Item { + id: unavailable + property var record: null + visible: root.pausedWithoutLimits(record) + implicitHeight: unavailableLabel.implicitHeight + + Text { + id: unavailableLabel + text: "Usage unavailable" + color: root.dim + font.family: root.fontFamily + font.pixelSize: Style.font.bodySmall + } + + HoverHandler { id: unavailableHover } + + PanelToolTip { + visible: unavailableHover.hovered && unavailable.visible + text: unavailable.record ? String(unavailable.record.authHelpText || "Usage has not been updated yet.") : "" + } + } + // One line per limit window: title, meter, percentage, and reset. A // model-scoped allowance on the same clock ("Fable" on Weekly) is a marker // on this row's meter, named in the row's tooltip. diff --git a/test/shell.d/agent-usage-claude-limits-test.sh b/test/shell.d/agent-usage-claude-limits-test.sh index 5372075a..df39f9d8 100644 --- a/test/shell.d/agent-usage-claude-limits-test.sh +++ b/test/shell.d/agent-usage-claude-limits-test.sh @@ -328,6 +328,14 @@ const start = source.indexOf('function windowIsLong') const end = source.indexOf('// The window that decides') assert(start > 0 && end > start, 'agents panel exposes its limit-window helpers') eval(source.slice(start, end).replaceAll('root.nowMs', 'panelRoot.nowMs')) +eval(source.slice(source.indexOf('function needsSignIn'), source.indexOf('// Sign an account'))) + +const paused = { usageStatusText: 'Limits paused', limits: [] } +assertEqual(pausedWithoutLimits(paused), true, 'paused usage without a cache shows a recovery placeholder') +assertEqual(otherTrouble(paused), '', 'paused usage never puts the confusing status in the header') +assertEqual(pausedWithoutLimits({ ...paused, limits: [{ label: 'Session (5-hour)', percent: 0, resetsAt: '' }] }), false, 'cached usage replaces the recovery placeholder') +assertEqual(pausedWithoutLimits({ usageStatusText: 'Sign-in expired', limits: [] }), false, 'expired sign-ins retain their sign-in action') +assertEqual(pausedWithoutLimits(null), false, 'missing records do not show a paused-usage placeholder') assertDeepEqual( limitWindows({ limits: [