mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(ui-trajectory): distinguish overlapping request markers
This commit is contained in:
@@ -100,17 +100,12 @@
|
||||
}
|
||||
|
||||
.table tbody tr[data-request-only='true'] td {
|
||||
height: 1px;
|
||||
height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.table tbody tr[data-request-only='true']:has(+ tr[data-request-only='true']) td {
|
||||
/* Keep consecutive boundary markers from painting their halos over one another. */
|
||||
height: 9px;
|
||||
}
|
||||
|
||||
.table tbody tr[data-request-only='true']:last-child td {
|
||||
/* Retain the lower half of the 16px boundary marker at the table's end. */
|
||||
height: 9px;
|
||||
@@ -130,10 +125,12 @@
|
||||
}
|
||||
|
||||
.requestBoundaryControl {
|
||||
--request-boundary-base-left: 12px;
|
||||
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
top: -8px;
|
||||
left: 12px;
|
||||
left: calc(var(--request-boundary-base-left) + var(--request-boundary-offset, 0px));
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
@@ -198,6 +195,12 @@
|
||||
box-shadow: 0 0 0 1.5px var(--dsw-alias-brand-primary-new-colorprimary-new-color);
|
||||
}
|
||||
|
||||
.requestBoundaryControl[data-request-status='error']::before,
|
||||
.requestBoundaryControl[data-request-status='error']:hover::before,
|
||||
.requestBoundaryControl[data-request-status='error']:focus-visible::before {
|
||||
background: var(--dsw-alias-state-error-primary);
|
||||
}
|
||||
|
||||
.requestBoundaryControl:hover::after,
|
||||
.requestBoundaryControl:focus-visible::after {
|
||||
opacity: 1;
|
||||
@@ -402,7 +405,7 @@
|
||||
}
|
||||
|
||||
.requestBoundaryControl {
|
||||
left: 6px;
|
||||
--request-boundary-base-left: 6px;
|
||||
}
|
||||
|
||||
.kindSlot {
|
||||
|
||||
@@ -191,6 +191,10 @@ type TrajectorySplitStyle = CSSProperties & {
|
||||
'--trajectory-tool-request-width': string
|
||||
}
|
||||
|
||||
type RequestBoundaryStyle = CSSProperties & {
|
||||
'--request-boundary-offset': string
|
||||
}
|
||||
|
||||
function clampDetailsWidth(width: number, splitWidth: number): number {
|
||||
const maxWidth = Math.max(
|
||||
DETAILS_MIN_WIDTH,
|
||||
@@ -453,6 +457,23 @@ function indexRequestNumbers(
|
||||
return numbers
|
||||
}
|
||||
|
||||
function indexRequestBoundaryRuns(records: readonly TableRecord[]): ReadonlyMap<number, number> {
|
||||
const indexes = new Map<number, number>()
|
||||
let previous: TableRecord | undefined
|
||||
let runIndex = 0
|
||||
for (const record of records) {
|
||||
if (record.cell.requestOnly !== true) {
|
||||
previous = record
|
||||
runIndex = 0
|
||||
continue
|
||||
}
|
||||
runIndex = previous?.cell.requestOnly === true ? runIndex + 1 : 0
|
||||
indexes.set(record.cell.index, runIndex)
|
||||
previous = record
|
||||
}
|
||||
return indexes
|
||||
}
|
||||
|
||||
function summarizeTurn(records: readonly TableRecord[]): string {
|
||||
const steps = new Set(
|
||||
records
|
||||
@@ -1545,6 +1566,7 @@ export function TrajectoryTable({
|
||||
collapsedAssistants,
|
||||
)
|
||||
: filterRecords(allRecords, searchMatchIndexes)
|
||||
const requestBoundaryRuns = indexRequestBoundaryRuns(records)
|
||||
const selected = allRecords.find(record => record.cell.index === selectedIndex)
|
||||
const selectedPrompt = selected?.cell.kind === 'system'
|
||||
? selected.cell.promptDetail
|
||||
@@ -1791,6 +1813,12 @@ export function TrajectoryTable({
|
||||
const requestInfo = request === undefined
|
||||
? undefined
|
||||
: sessionRequestNumbers?.find(candidate => candidate.number === request)
|
||||
const requestStatus = requestInfo?.status
|
||||
?? (record.cell.isError === true ? 'error' : undefined)
|
||||
const requestRunIndex = requestBoundaryRuns.get(record.cell.index) ?? 0
|
||||
const requestBoundaryStyle: RequestBoundaryStyle = {
|
||||
'--request-boundary-offset': `${requestRunIndex * 8}px`,
|
||||
}
|
||||
const requestLabel = request === undefined
|
||||
? undefined
|
||||
: `Request #${request}${requestInfo?.purpose === 'compaction' ? ' · Compaction' : ''}`
|
||||
@@ -1882,6 +1910,9 @@ export function TrajectoryTable({
|
||||
aria-label={requestLabel}
|
||||
aria-pressed={requestSelected}
|
||||
data-label={requestLabel}
|
||||
data-request-run-index={requestRunIndex}
|
||||
data-request-status={requestStatus}
|
||||
style={requestBoundaryStyle}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation()
|
||||
selectRequest({
|
||||
|
||||
@@ -222,6 +222,47 @@ describe('TrajectoryTable', () => {
|
||||
expect(errorResult.closest('[class*="errorPayload"]')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('marks failed requests and lays coincident request markers left to right', () => {
|
||||
const turns: readonly TrajectoryTurnModel[] = [
|
||||
{
|
||||
turn: null,
|
||||
groups: [{
|
||||
title: 'Step 1',
|
||||
cells: [{
|
||||
index: 1,
|
||||
kind: 'message',
|
||||
text: '',
|
||||
requestOnly: true,
|
||||
isError: true,
|
||||
timeSeconds: 0.1,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
{
|
||||
turn: null,
|
||||
groups: [{
|
||||
title: 'Step 2',
|
||||
cells: [{
|
||||
index: 2,
|
||||
kind: 'message',
|
||||
text: '',
|
||||
requestOnly: true,
|
||||
timeSeconds: 0.1,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
]
|
||||
render(<TrajectoryTable turns={turns} {...FOLD_PROPS} />)
|
||||
|
||||
const failed = screen.getByRole('button', { name: 'Request #1' })
|
||||
const retry = screen.getByRole('button', { name: 'Request #2' })
|
||||
expect(failed.getAttribute('data-request-status')).toBe('error')
|
||||
expect(failed.getAttribute('data-request-run-index')).toBe('0')
|
||||
expect(failed.style.getPropertyValue('--request-boundary-offset')).toBe('0px')
|
||||
expect(retry.getAttribute('data-request-run-index')).toBe('1')
|
||||
expect(retry.style.getPropertyValue('--request-boundary-offset')).toBe('8px')
|
||||
})
|
||||
|
||||
it('renders responsive role icons with a custom tooltip', () => {
|
||||
const view = render(<TrajectoryTable turns={TURNS} {...FOLD_PROPS} />)
|
||||
const toolTag = view.container.querySelector<HTMLElement>('[data-role-kind="tool"]')
|
||||
|
||||
Reference in New Issue
Block a user