fix(ui-trajectory): distinguish overlapping request markers
This commit is contained in:
@@ -100,17 +100,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table tbody tr[data-request-only='true'] td {
|
.table tbody tr[data-request-only='true'] td {
|
||||||
height: 1px;
|
height: 0;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
border-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 {
|
.table tbody tr[data-request-only='true']:last-child td {
|
||||||
/* Retain the lower half of the 16px boundary marker at the table's end. */
|
/* Retain the lower half of the 16px boundary marker at the table's end. */
|
||||||
height: 9px;
|
height: 9px;
|
||||||
@@ -130,10 +125,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.requestBoundaryControl {
|
.requestBoundaryControl {
|
||||||
|
--request-boundary-base-left: 12px;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 6;
|
z-index: 6;
|
||||||
top: -8px;
|
top: -8px;
|
||||||
left: 12px;
|
left: calc(var(--request-boundary-base-left) + var(--request-boundary-offset, 0px));
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -198,6 +195,12 @@
|
|||||||
box-shadow: 0 0 0 1.5px var(--dsw-alias-brand-primary-new-colorprimary-new-color);
|
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:hover::after,
|
||||||
.requestBoundaryControl:focus-visible::after {
|
.requestBoundaryControl:focus-visible::after {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -402,7 +405,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.requestBoundaryControl {
|
.requestBoundaryControl {
|
||||||
left: 6px;
|
--request-boundary-base-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kindSlot {
|
.kindSlot {
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ type TrajectorySplitStyle = CSSProperties & {
|
|||||||
'--trajectory-tool-request-width': string
|
'--trajectory-tool-request-width': string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RequestBoundaryStyle = CSSProperties & {
|
||||||
|
'--request-boundary-offset': string
|
||||||
|
}
|
||||||
|
|
||||||
function clampDetailsWidth(width: number, splitWidth: number): number {
|
function clampDetailsWidth(width: number, splitWidth: number): number {
|
||||||
const maxWidth = Math.max(
|
const maxWidth = Math.max(
|
||||||
DETAILS_MIN_WIDTH,
|
DETAILS_MIN_WIDTH,
|
||||||
@@ -453,6 +457,23 @@ function indexRequestNumbers(
|
|||||||
return numbers
|
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 {
|
function summarizeTurn(records: readonly TableRecord[]): string {
|
||||||
const steps = new Set(
|
const steps = new Set(
|
||||||
records
|
records
|
||||||
@@ -1545,6 +1566,7 @@ export function TrajectoryTable({
|
|||||||
collapsedAssistants,
|
collapsedAssistants,
|
||||||
)
|
)
|
||||||
: filterRecords(allRecords, searchMatchIndexes)
|
: filterRecords(allRecords, searchMatchIndexes)
|
||||||
|
const requestBoundaryRuns = indexRequestBoundaryRuns(records)
|
||||||
const selected = allRecords.find(record => record.cell.index === selectedIndex)
|
const selected = allRecords.find(record => record.cell.index === selectedIndex)
|
||||||
const selectedPrompt = selected?.cell.kind === 'system'
|
const selectedPrompt = selected?.cell.kind === 'system'
|
||||||
? selected.cell.promptDetail
|
? selected.cell.promptDetail
|
||||||
@@ -1791,6 +1813,12 @@ export function TrajectoryTable({
|
|||||||
const requestInfo = request === undefined
|
const requestInfo = request === undefined
|
||||||
? undefined
|
? undefined
|
||||||
: sessionRequestNumbers?.find(candidate => candidate.number === request)
|
: 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
|
const requestLabel = request === undefined
|
||||||
? undefined
|
? undefined
|
||||||
: `Request #${request}${requestInfo?.purpose === 'compaction' ? ' · Compaction' : ''}`
|
: `Request #${request}${requestInfo?.purpose === 'compaction' ? ' · Compaction' : ''}`
|
||||||
@@ -1882,6 +1910,9 @@ export function TrajectoryTable({
|
|||||||
aria-label={requestLabel}
|
aria-label={requestLabel}
|
||||||
aria-pressed={requestSelected}
|
aria-pressed={requestSelected}
|
||||||
data-label={requestLabel}
|
data-label={requestLabel}
|
||||||
|
data-request-run-index={requestRunIndex}
|
||||||
|
data-request-status={requestStatus}
|
||||||
|
style={requestBoundaryStyle}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
selectRequest({
|
selectRequest({
|
||||||
|
|||||||
@@ -222,6 +222,47 @@ describe('TrajectoryTable', () => {
|
|||||||
expect(errorResult.closest('[class*="errorPayload"]')).toBeTruthy()
|
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', () => {
|
it('renders responsive role icons with a custom tooltip', () => {
|
||||||
const view = render(<TrajectoryTable turns={TURNS} {...FOLD_PROPS} />)
|
const view = render(<TrajectoryTable turns={TURNS} {...FOLD_PROPS} />)
|
||||||
const toolTag = view.container.querySelector<HTMLElement>('[data-role-kind="tool"]')
|
const toolTag = view.container.querySelector<HTMLElement>('[data-role-kind="tool"]')
|
||||||
|
|||||||
Reference in New Issue
Block a user