taskchef 7.26.0 → 7.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/src/dashboard/dist/app.js +11 -11
- package/src/dashboard/dist/app.js.map +1 -1
- package/src/dashboard/dist/styles.css +1 -1
- package/src/dashboard/react/components/ActivityTimeline.tsx +14 -8
- package/src/dashboard/react/components/TaskDetail.test.tsx +12 -6
- package/src/dashboard/react/styles.css +5 -1
|
@@ -31,7 +31,10 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
|
|
|
31
31
|
<Stack gap={7}>
|
|
32
32
|
<Box className="taskchef-turn-heading">
|
|
33
33
|
<StatusBadge status={presentation.status} />
|
|
34
|
-
<
|
|
34
|
+
<Box className="taskchef-turn-timing">
|
|
35
|
+
<RelativeTime label="Turn update time" value={presentation.updatedAt} />
|
|
36
|
+
<TurnReportedWork turn={turn} />
|
|
37
|
+
</Box>
|
|
35
38
|
</Box>
|
|
36
39
|
{presentation.sourceLabel && <Text c="dimmed" size="xs">{presentation.sourceLabel}</Text>}
|
|
37
40
|
<Box>
|
|
@@ -63,7 +66,6 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
|
|
|
63
66
|
title={usage.title}
|
|
64
67
|
value={usage.cost.value}
|
|
65
68
|
/>
|
|
66
|
-
<TurnReportedWorkMetric turn={turn} />
|
|
67
69
|
</Box>
|
|
68
70
|
{usage.note && <Text c="dimmed" size="xs">{usage.note}</Text>}
|
|
69
71
|
<Text c="dimmed" className="taskchef-mono" size="xs">Turn ref: {identity ?? "—"}</Text>
|
|
@@ -75,16 +77,20 @@ export function ActivityTimeline({ highlightTurnRef, task }: { highlightTurnRef:
|
|
|
75
77
|
);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
function
|
|
80
|
+
function TurnReportedWork({ turn }: { turn: TaskTurn }) {
|
|
79
81
|
const now = useLiveNow(turn.result === null);
|
|
80
82
|
const elapsed = turnReportedWorkView(turn, now);
|
|
81
83
|
return (
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
<Text
|
|
85
|
+
aria-label={elapsed.accessibleLabel}
|
|
86
|
+
c="dimmed"
|
|
87
|
+
className="taskchef-turn-duration"
|
|
88
|
+
size="xs"
|
|
85
89
|
title={elapsed.title}
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
>
|
|
91
|
+
<span className="taskchef-field-label">{elapsed.label}</span>
|
|
92
|
+
<span>{elapsed.value}</span>
|
|
93
|
+
</Text>
|
|
88
94
|
);
|
|
89
95
|
}
|
|
90
96
|
|
|
@@ -70,11 +70,15 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
|
|
|
70
70
|
<MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>,
|
|
71
71
|
);
|
|
72
72
|
const metrics = container.querySelector(".taskchef-turn-metrics") as HTMLElement;
|
|
73
|
+
const timing = container.querySelector(".taskchef-turn-timing") as HTMLElement;
|
|
73
74
|
expect(metrics).not.toBeNull();
|
|
75
|
+
expect(timing).not.toBeNull();
|
|
74
76
|
expect(within(metrics).getByText("Tokens").nextSibling).toHaveTextContent("330");
|
|
75
77
|
expect(within(metrics).getByText("Estimated cost").nextSibling).toHaveTextContent("$0.12");
|
|
76
|
-
expect(within(metrics).
|
|
77
|
-
expect(within(
|
|
78
|
+
expect(within(metrics).queryByText("Elapsed")).not.toBeInTheDocument();
|
|
79
|
+
expect(within(timing).getByLabelText(/^Turn update time:/i)).toBeVisible();
|
|
80
|
+
expect(within(timing).getByLabelText(/completed turn reported wall-clock elapsed time/i))
|
|
81
|
+
.toHaveTextContent("Elapsed18m 32s");
|
|
78
82
|
cleanup();
|
|
79
83
|
}
|
|
80
84
|
|
|
@@ -89,7 +93,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
|
|
|
89
93
|
vi.spyOn(window, "clearInterval").mockImplementation(() => undefined);
|
|
90
94
|
const task = fixtureTask();
|
|
91
95
|
render(<MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>);
|
|
92
|
-
expect(screen.
|
|
96
|
+
expect(screen.getByLabelText(/current turn reported wall-clock elapsed time/i))
|
|
97
|
+
.toHaveTextContent("Elapsed so far18m 32s");
|
|
93
98
|
expect(screen.getByText("Tokens").nextSibling).toHaveTextContent("Pending");
|
|
94
99
|
expect(screen.getByText("Estimated cost").nextSibling).toHaveTextContent("Pending");
|
|
95
100
|
|
|
@@ -98,7 +103,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
|
|
|
98
103
|
tick?.();
|
|
99
104
|
});
|
|
100
105
|
|
|
101
|
-
expect(screen.
|
|
106
|
+
expect(screen.getByLabelText(/current turn reported wall-clock elapsed time/i))
|
|
107
|
+
.toHaveTextContent("Elapsed so far18m 34s");
|
|
102
108
|
cleanup();
|
|
103
109
|
vi.restoreAllMocks();
|
|
104
110
|
}
|
|
@@ -126,8 +132,8 @@ test("covers terminal, active, and unavailable timeline metrics", () => {
|
|
|
126
132
|
},
|
|
127
133
|
});
|
|
128
134
|
render(<MantineProvider><ActivityTimeline highlightTurnRef={null} task={task} /></MantineProvider>);
|
|
129
|
-
expect(screen.
|
|
130
|
-
|
|
135
|
+
expect(screen.getByLabelText(/elapsed unavailable.*reported wall-clock/i))
|
|
136
|
+
.toHaveTextContent("ElapsedUnavailable");
|
|
131
137
|
expect(screen.getByText("Manual dashboard turns do not have usage boundaries.")).toBeVisible();
|
|
132
138
|
expect(screen.getByLabelText(/tokens unavailable: manual dashboard turns/i)).toBeVisible();
|
|
133
139
|
}
|
|
@@ -81,7 +81,9 @@ body {
|
|
|
81
81
|
.taskchef-turn { background: var(--taskchef-surface-muted); }
|
|
82
82
|
.taskchef-turn-highlighted { border-color: var(--mantine-color-teal-6); box-shadow: inset 3px 0 var(--mantine-color-teal-6); outline: 3px solid color-mix(in srgb, var(--mantine-color-teal-6) 22%, transparent); }
|
|
83
83
|
.taskchef-turn-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
84
|
-
.taskchef-turn-
|
|
84
|
+
.taskchef-turn-timing { display: flex; align-items: center; justify-content: flex-end; gap: var(--mantine-spacing-sm); min-width: 0; }
|
|
85
|
+
.taskchef-turn-duration { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; }
|
|
86
|
+
.taskchef-turn-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mantine-spacing-xs); }
|
|
85
87
|
.taskchef-turn-metric { min-width: 0; overflow-wrap: anywhere; }
|
|
86
88
|
.taskchef-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; overflow-wrap: anywhere; }
|
|
87
89
|
.taskchef-code-panel { max-height: 280px; margin: 0; padding: 12px; overflow: auto; border-radius: var(--mantine-radius-md); background: var(--taskchef-surface-muted); white-space: pre-wrap; overflow-wrap: anywhere; font: 0.78rem/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
@@ -123,6 +125,8 @@ body {
|
|
|
123
125
|
.taskchef-metadata { grid-template-columns: 1fr; }
|
|
124
126
|
.taskchef-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
125
127
|
.taskchef-turn-metrics { grid-template-columns: 1fr; }
|
|
128
|
+
.taskchef-turn-heading { align-items: flex-start; flex-direction: column; gap: 6px; }
|
|
129
|
+
.taskchef-turn-timing { flex-wrap: wrap; justify-content: flex-start; }
|
|
126
130
|
.taskchef-metadata dt { padding-bottom: 0; border-bottom: 0; }
|
|
127
131
|
}
|
|
128
132
|
|