fix(settings): reserve skill badges for attention (#11413)
* fix(settings): reserve skill badges for attention * test(settings): cover hidden checking badge
This commit is contained in:
parent
b21f978c6d
commit
5c8013abaa
|
|
@ -1,7 +1,7 @@
|
|||
// @vitest-environment happy-dom
|
||||
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { Bot, Mic, Network, Puzzle } from 'lucide-react'
|
||||
import { Bot, GitBranch, Mic, Network, Puzzle } from 'lucide-react'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { getDefaultSettings } from '../../../../shared/constants'
|
||||
import { SettingsSidebar } from './SettingsSidebar'
|
||||
|
|
@ -71,6 +71,24 @@ function renderSidebar(
|
|||
icon: Bot,
|
||||
installStatus: 'up-to-date'
|
||||
},
|
||||
{
|
||||
id: 'voice-loading',
|
||||
title: 'Voice Loading',
|
||||
icon: Mic,
|
||||
installStatus: 'checking'
|
||||
},
|
||||
{
|
||||
id: 'linear',
|
||||
title: 'Linear',
|
||||
icon: GitBranch,
|
||||
installStatus: 'update-available'
|
||||
},
|
||||
{
|
||||
id: 'ephemeral-vms',
|
||||
title: 'Ephemeral VMs',
|
||||
icon: Bot,
|
||||
installStatus: 'needs-attention'
|
||||
},
|
||||
{
|
||||
id: 'plugins',
|
||||
title: 'Plugins',
|
||||
|
|
@ -126,12 +144,15 @@ describe('SettingsSidebar', () => {
|
|||
expect(markup).toContain('--worktree-sidebar-foreground:#f0f4f8')
|
||||
})
|
||||
|
||||
it('renders install state labels separately from static badges', () => {
|
||||
it('reserves install state labels for actionable skill states', () => {
|
||||
const markup = renderSidebar()
|
||||
|
||||
expect(markup).toContain('Not installed')
|
||||
expect(markup).toContain('Installed')
|
||||
expect(markup).toContain('Up to date')
|
||||
expect(markup).not.toContain('Not installed')
|
||||
expect(markup).not.toContain('Installed')
|
||||
expect(markup).not.toContain('Up to date')
|
||||
expect(markup).not.toContain('Checking...')
|
||||
expect(markup).toContain('Update available')
|
||||
expect(markup).toContain('Review skill')
|
||||
expect(markup).toContain('Optional')
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,17 @@ type SettingsSidebarProps = {
|
|||
) => void
|
||||
}
|
||||
|
||||
type VisibleInstallStatus = Extract<
|
||||
SettingsNavInstallStatus,
|
||||
'update-available' | 'needs-attention'
|
||||
>
|
||||
|
||||
function isVisibleInstallStatus(
|
||||
status: SettingsNavInstallStatus | undefined
|
||||
): status is VisibleInstallStatus {
|
||||
return status === 'update-available' || status === 'needs-attention'
|
||||
}
|
||||
|
||||
type SettingsSetupGuideRowProps = {
|
||||
progress: SettingsSetupGuideProgress
|
||||
setupActive: boolean
|
||||
|
|
@ -146,17 +157,8 @@ export function SettingsSidebar({
|
|||
? 'bg-worktree-sidebar-accent font-medium text-worktree-sidebar-accent-foreground ring-1 ring-worktree-sidebar-ring/25'
|
||||
: 'text-worktree-sidebar-foreground/60 hover:bg-worktree-sidebar-accent/60 hover:text-worktree-sidebar-foreground'
|
||||
)
|
||||
const installStatusLabel = (status: SettingsNavInstallStatus): string => {
|
||||
const installStatusLabel = (status: VisibleInstallStatus): string => {
|
||||
switch (status) {
|
||||
case 'install':
|
||||
return translate(
|
||||
'auto.components.settings.AgentSkillSetupPanel.5289300939',
|
||||
'Not installed'
|
||||
)
|
||||
case 'installed':
|
||||
return translate('auto.components.settings.AgentSkillSetupPanel.9fcebceb2a', 'Installed')
|
||||
case 'up-to-date':
|
||||
return translate('auto.components.skills.SkillFreshnessStatusPill.upToDate', 'Up to date')
|
||||
case 'update-available':
|
||||
return translate(
|
||||
'auto.components.skills.SkillFreshnessStatusPill.updateAvailable',
|
||||
|
|
@ -165,23 +167,12 @@ export function SettingsSidebar({
|
|||
case 'needs-attention':
|
||||
return translate(
|
||||
'auto.components.skills.SkillFreshnessStatusPill.needsAttention',
|
||||
'Needs attention'
|
||||
'Review skill'
|
||||
)
|
||||
case 'checking':
|
||||
return translate('auto.components.settings.AgentSkillSetupPanel.68a468752e', 'Checking...')
|
||||
}
|
||||
}
|
||||
const installStatusClassName = (status: SettingsNavInstallStatus): string =>
|
||||
cn(
|
||||
'ml-auto shrink-0 rounded-full border px-1.5 py-0.5 text-[10px] font-medium leading-none',
|
||||
status === 'installed' || status === 'up-to-date'
|
||||
? 'border-status-success-border bg-status-success-background text-status-success'
|
||||
: status === 'update-available' || status === 'needs-attention'
|
||||
? 'border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-300'
|
||||
: status === 'install'
|
||||
? 'border-foreground/15 bg-foreground/10 text-foreground'
|
||||
: 'border-border/50 bg-muted/30 text-muted-foreground'
|
||||
)
|
||||
const installStatusClassName =
|
||||
'ml-auto shrink-0 rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-medium leading-none text-amber-700 dark:text-amber-300'
|
||||
|
||||
return (
|
||||
<aside
|
||||
|
|
@ -270,8 +261,8 @@ export function SettingsSidebar({
|
|||
>
|
||||
<Icon className="size-4 shrink-0" />
|
||||
<span className="truncate">{section.title}</span>
|
||||
{section.installStatus ? (
|
||||
<span className={installStatusClassName(section.installStatus)}>
|
||||
{isVisibleInstallStatus(section.installStatus) ? (
|
||||
<span className={installStatusClassName}>
|
||||
{installStatusLabel(section.installStatus)}
|
||||
</span>
|
||||
) : section.badge ? (
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ describe('SkillFreshnessStatusPill', () => {
|
|||
|
||||
const rendered = await renderPill('orca-cli')
|
||||
// Why: a green pill over a copy the update cannot reach hides real drift.
|
||||
expect(pillText(rendered)).toBe('Needs attention')
|
||||
expect(pillText(rendered)).toBe('Review skill')
|
||||
expect(detailsButton(rendered)?.textContent).toBe('Details')
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function statusPill(status: SkillFreshnessDisplayStatus): React.JSX.Element {
|
|||
<IntegrationStatusPill tone="attention">
|
||||
{translate(
|
||||
'auto.components.skills.SkillFreshnessStatusPill.needsAttention',
|
||||
'Needs attention'
|
||||
'Review skill'
|
||||
)}
|
||||
</IntegrationStatusPill>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3893,7 +3893,7 @@
|
|||
"upToDate": "Up to date",
|
||||
"installed": "Installed",
|
||||
"details": "Details",
|
||||
"needsAttention": "Needs attention"
|
||||
"needsAttention": "Review skill"
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
|
|
|||
|
|
@ -3863,7 +3863,7 @@
|
|||
"upToDate": "Actualizado",
|
||||
"installed": "Instalado",
|
||||
"details": "Details",
|
||||
"needsAttention": "Needs attention"
|
||||
"needsAttention": "Review skill"
|
||||
},
|
||||
"SkillUpdateResultRows": {
|
||||
"stillOutdated": "Still out of date after the update ran."
|
||||
|
|
|
|||
|
|
@ -3863,7 +3863,7 @@
|
|||
"upToDate": "最新です",
|
||||
"installed": "インストール済み",
|
||||
"details": "Details",
|
||||
"needsAttention": "Needs attention"
|
||||
"needsAttention": "Review skill"
|
||||
},
|
||||
"SkillUpdateResultRows": {
|
||||
"stillOutdated": "Still out of date after the update ran."
|
||||
|
|
|
|||
|
|
@ -3863,7 +3863,7 @@
|
|||
"upToDate": "최신 상태",
|
||||
"installed": "설치됨",
|
||||
"details": "Details",
|
||||
"needsAttention": "Needs attention"
|
||||
"needsAttention": "Review skill"
|
||||
},
|
||||
"SkillUpdateResultRows": {
|
||||
"stillOutdated": "Still out of date after the update ran."
|
||||
|
|
|
|||
|
|
@ -3863,7 +3863,7 @@
|
|||
"upToDate": "已是最新",
|
||||
"installed": "已安装",
|
||||
"details": "Details",
|
||||
"needsAttention": "Needs attention"
|
||||
"needsAttention": "Review skill"
|
||||
},
|
||||
"SkillUpdateResultRows": {
|
||||
"stillOutdated": "Still out of date after the update ran."
|
||||
|
|
|
|||
Loading…
Reference in New Issue