feat(dashboard): add agent status search board (#11042)

* feat(dashboard): add agent status search board

* fix(dashboard): keep idle controls reachable

* chore: drop merge-only formatting drift

* fix(dashboard): compare sparse subagent snapshots safely

* fix(dashboard): satisfy settings handler lint

* fix(dashboard): address review feedback

* fix(dashboard): complete search and localized status copy

* fix(dashboard): pad active filter row

* fix(dashboard): keep idle control in board settings

* fix(dashboard): source filters from workspace state

* fix(dashboard): clarify PR and MR status filter

* fix(dashboard): preserve review and board parity
This commit is contained in:
Brennan Benson
2026-07-28 15:51:43 -07:00
committed by GitHub
parent 5753cf6c5c
commit 13c193a00a
33 changed files with 1894 additions and 155 deletions
@@ -20,13 +20,24 @@ const SNAPSHOT = {
leafId: 'leaf-1',
repoName: 'Orca',
worktreeName: 'Dashboard',
workspaceStatusId: 'in-review',
workspaceStatusLabel: 'In review',
workspaceStatusColor: 'emerald',
hasReview: true,
review: { number: 11012, state: 'open' },
subagents: [{ id: 'child-1', name: 'Review loop', dotState: 'working' }],
startedAt: 1_699_999_000_000,
finishedAt: null,
stateChangedAt: 1_699_999_500_000,
unseen: true,
askSummary: '{"question":"Proceed?"}'
}
]
],
showIdle: false,
filterOptions: {
projects: [{ id: 'repo-1', label: 'Orca' }],
workspaceStatuses: [{ id: 'in-review', label: 'In review', color: 'emerald' }]
}
} satisfies DashboardSnapshot
describe('dashboard payload validation', () => {
@@ -48,6 +59,18 @@ describe('dashboard payload validation', () => {
cards: [{ ...SNAPSHOT.cards[0], lastAgentMessage: 'x'.repeat(8_001) }]
})
).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], review: { number: 0, state: 'open' } }]
})
).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], subagents: [{ id: '', name: 'bad', dotState: 'idle' }] }]
})
).toBe(false)
})
it('accepts repo icons a pop-out can safely render, and rejects the rest', () => {
@@ -85,6 +108,29 @@ describe('dashboard payload validation', () => {
expect(isDashboardSnapshot({ ...SNAPSHOT, repoIconsByRepoId: [] })).toBe(false)
})
it('accepts bounded filter options independently of cards', () => {
expect(isDashboardSnapshot({ ...SNAPSHOT, cards: [] })).toBe(true)
expect(isDashboardSnapshot({ ...SNAPSHOT, filterOptions: undefined })).toBe(true)
expect(
isDashboardSnapshot({
...SNAPSHOT,
filterOptions: {
...SNAPSHOT.filterOptions,
projects: [{ id: '', label: 'Invalid' }]
}
})
).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
filterOptions: {
...SNAPSHOT.filterOptions,
workspaceStatuses: [{ id: 'todo', label: 'x'.repeat(1_025) }]
}
})
).toBe(false)
})
it('bounds the conversation name', () => {
expect(
isDashboardSnapshot({
+82 -1
View File
@@ -8,11 +8,14 @@ import {
} from '../../shared/agent-status-types'
const MAX_DASHBOARD_CARDS = 1_000
const MAX_DASHBOARD_SUBAGENTS = 100
const MAX_DASHBOARD_REPO_ICONS = 500
const MAX_DASHBOARD_FILTER_OPTIONS = 500
const MAX_ID_LENGTH = 4_096
const MAX_LABEL_LENGTH = 1_024
const DASHBOARD_BUCKETS = new Set(['attention', 'working', 'idle'])
const DASHBOARD_BUCKETS = new Set(['attention', 'working', 'done', 'idle'])
const DASHBOARD_DOT_STATES = new Set(['working', 'blocked', 'waiting', 'done', 'idle'])
const DASHBOARD_REVIEW_STATES = new Set(['open', 'closed', 'merged', 'draft'])
function isBoundedString(value: unknown, maxLength: number, allowEmpty = false): value is string {
return typeof value === 'string' && value.length <= maxLength && (allowEmpty || value.length > 0)
@@ -53,10 +56,44 @@ export function isDashboardSnapshot(value: unknown): value is DashboardSnapshot
Array.isArray(snapshot.cards) &&
snapshot.cards.length <= MAX_DASHBOARD_CARDS &&
snapshot.cards.every(isDashboardCard) &&
(snapshot.showIdle === undefined || typeof snapshot.showIdle === 'boolean') &&
isDashboardFilterOptions(snapshot.filterOptions) &&
isDashboardRepoIcons(snapshot.repoIconsByRepoId)
)
}
function isDashboardFilterOptions(value: unknown): boolean {
if (value === undefined) {
return true
}
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return false
}
const options = value as Record<string, unknown>
return (
isDashboardFilterOptionList(options.projects) &&
isDashboardFilterOptionList(options.workspaceStatuses)
)
}
function isDashboardFilterOptionList(value: unknown): boolean {
return (
Array.isArray(value) &&
value.length <= MAX_DASHBOARD_FILTER_OPTIONS &&
value.every((entry) => {
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
return false
}
const option = entry as Record<string, unknown>
return (
isBoundedString(option.id, MAX_ID_LENGTH) &&
isBoundedString(option.label, MAX_LABEL_LENGTH, true) &&
isOptionalBoundedString(option.color, MAX_ID_LENGTH)
)
})
)
}
/** Repo icons reach the pop-out's `<img src>`, so each one must survive the
* same sanitizer the settings picker writes through. */
function isDashboardRepoIcons(value: unknown): boolean {
@@ -77,6 +114,44 @@ function isDashboardRepoIcons(value: unknown): boolean {
)
}
function isDashboardReview(value: unknown): boolean {
if (value === undefined) {
return true
}
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return false
}
const review = value as Record<string, unknown>
return (
isFiniteNumber(review.number) &&
review.number > 0 &&
typeof review.state === 'string' &&
DASHBOARD_REVIEW_STATES.has(review.state)
)
}
function isDashboardSubagents(value: unknown): boolean {
if (value === undefined) {
return true
}
return (
Array.isArray(value) &&
value.length <= MAX_DASHBOARD_SUBAGENTS &&
value.every((entry) => {
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
return false
}
const subagent = entry as Record<string, unknown>
return (
isBoundedString(subagent.id, MAX_ID_LENGTH) &&
isBoundedString(subagent.name, MAX_LABEL_LENGTH, true) &&
typeof subagent.dotState === 'string' &&
DASHBOARD_DOT_STATES.has(subagent.dotState)
)
})
)
}
function isDashboardCard(value: unknown): boolean {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return false
@@ -99,6 +174,12 @@ function isDashboardCard(value: unknown): boolean {
(card.leafId === null || isBoundedString(card.leafId, MAX_ID_LENGTH)) &&
isBoundedString(card.repoName, MAX_LABEL_LENGTH, true) &&
isBoundedString(card.worktreeName, MAX_LABEL_LENGTH, true) &&
isOptionalBoundedString(card.workspaceStatusId, MAX_ID_LENGTH) &&
isOptionalBoundedString(card.workspaceStatusLabel, MAX_LABEL_LENGTH) &&
isOptionalBoundedString(card.workspaceStatusColor, MAX_ID_LENGTH) &&
(card.hasReview === undefined || typeof card.hasReview === 'boolean') &&
isDashboardReview(card.review) &&
isDashboardSubagents(card.subagents) &&
isFiniteNumber(card.startedAt) &&
(card.finishedAt === null || isFiniteNumber(card.finishedAt)) &&
isFiniteNumber(card.stateChangedAt) &&