Skip to content

Commit 605092e

Browse files
atrakhConvex, Inc.
authored andcommitted
dashboard: cleanup new log page design (#41688)
GitOrigin-RevId: 9f9222a597e1d1df97729f17b77a8922d696ad2f
1 parent 353fc83 commit 605092e

File tree

16 files changed

+1217
-693
lines changed

16 files changed

+1217
-693
lines changed

npm-packages/@convex-dev/design-system/src/Callout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ type CalloutVariant = "instructions" | "error" | "hint" | "localDev" | "upsell";
55
const classes: Record<CalloutVariant, string> = {
66
error: "bg-background-error text-content-error",
77
instructions: "bg-background-warning text-content-warning",
8-
hint: "bg-util-accent/10",
8+
hint: "bg-util-accent/10 dark:bg-util-accent/30",
99
upsell: "bg-util-accent/10 dark:bg-util-accent/30",
1010
localDev:
1111
"bg-teal-100 border border-teal-500 dark:bg-teal-900 text-content-primary",

npm-packages/dashboard-common/src/features/functions/components/FunctionLogs.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { SearchLogsInput } from "@common/features/logs/components/SearchLogsInpu
66
import { filterLogs } from "@common/features/logs/lib/filterLogs";
77
import { displayNameToIdentifier } from "@common/lib/functions/FunctionsProvider";
88
import { functionIdentifierValue } from "@common/lib/functions/generateFileTree";
9-
import { UdfLog, useLogs } from "@common/lib/useLogs";
9+
import { MAX_LOGS, UdfLog, useLogs } from "@common/lib/useLogs";
1010
import { ModuleFunction } from "@common/lib/functions/types";
1111
import { Nent } from "@common/lib/useNents";
1212
import { Button } from "@ui/Button";
@@ -107,7 +107,7 @@ export function FunctionLogs({
107107
return prev;
108108
}
109109
return [...prev, ...newLogs].slice(
110-
Math.max(prev.length + entries.length - 10000, 0),
110+
Math.max(prev.length + entries.length - MAX_LOGS, 0),
111111
prev.length + entries.length,
112112
);
113113
});

npm-packages/dashboard-common/src/features/logs/components/DeploymentEventListItem.tsx

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useContext, useState, useRef, useEffect } from "react";
1+
import { useContext, useState } from "react";
22
import classNames from "classnames";
33
import { GearIcon } from "@radix-ui/react-icons";
44
import {
@@ -10,6 +10,7 @@ import { formatDateTime } from "@common/lib/format";
1010
import { DeploymentAuditLogEvent } from "@common/lib/useDeploymentAuditLog";
1111
import { DetailPanel } from "@common/elements/DetailPanel";
1212
import { DeploymentInfoContext } from "@common/lib/deploymentContext";
13+
import { useScrollIntoViewAndFocus } from "@common/features/logs/hooks/useScrollIntoViewAndFocus";
1314

1415
export function DeploymentEventListItem({
1516
event,
@@ -31,32 +32,10 @@ export function DeploymentEventListItem({
3132
const { TeamMemberLink } = useContext(DeploymentInfoContext);
3233
const [showDetails, setShowDetails] = useState(false);
3334
const timestamp = formatDateTime(new Date(event._creationTime));
34-
const ref = useRef<HTMLDivElement>(null);
35-
const buttonRef = useRef<HTMLButtonElement>(null);
36-
const prevFocusedRef = useRef(focused);
37-
38-
// Focus the button when focused prop changes to true
39-
useEffect(() => {
40-
if (newLogsPageSidepanel && focused) {
41-
buttonRef.current?.focus();
42-
}
43-
}, [focused, newLogsPageSidepanel]);
44-
45-
// Scroll into view when transitioning to focused (only in side panel mode)
46-
useEffect(() => {
47-
if (
48-
focused &&
49-
!prevFocusedRef.current &&
50-
ref.current &&
51-
newLogsPageSidepanel
52-
) {
53-
ref.current.scrollIntoView({
54-
block: "center",
55-
inline: "nearest",
56-
});
57-
}
58-
prevFocusedRef.current = focused;
59-
}, [focused, ref, newLogsPageSidepanel]);
35+
const { elementRef: ref, buttonRef } = useScrollIntoViewAndFocus({
36+
focused,
37+
enabled: !!newLogsPageSidepanel,
38+
});
6039

6140
// When the button receives focus and setShownLog is available, call it
6241
const handleFocus = () => {
@@ -95,6 +74,7 @@ export function DeploymentEventListItem({
9574
setShownLog && "hover:bg-background-tertiary/70",
9675
setShownLog &&
9776
"focus:outline-none focus:border focus:border-border-selected",
77+
focused && "bg-background-highlight",
9878
)}
9979
style={{
10080
height: ITEM_SIZE,

npm-packages/dashboard-common/src/features/logs/components/FunctionCallTree.stories.tsx

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,29 @@ const meta: Meta<typeof FunctionCallTree> = {
77
parameters: {
88
layout: "padded",
99
},
10+
args: {
11+
currentLog: {
12+
id: "1",
13+
udfType: "Query" as const,
14+
localizedTimestamp: "2023-10-15 10:30:00",
15+
timestamp: 1697365800000,
16+
call: functionIdentifierValue("api/users:list"),
17+
cachedResult: false,
18+
requestId: "req_123",
19+
executionId: "exec_1",
20+
caller: "dashboard",
21+
environment: "production",
22+
identityType: "user",
23+
parentExecutionId: null,
24+
executionTimestamp: 1697365800000,
25+
kind: "outcome" as const,
26+
outcome: {
27+
status: "success" as const,
28+
statusCode: null,
29+
},
30+
executionTimeMs: 3000,
31+
},
32+
},
1033
};
1134

1235
export default meta;
@@ -100,6 +123,27 @@ const mockRunningLogs = [
100123

101124
export const WithSuccessfulFunctions: Story = {
102125
args: {
126+
currentLog: {
127+
id: "1",
128+
udfType: "Query" as const,
129+
localizedTimestamp: "2023-10-15 10:30:00",
130+
timestamp: 1697365800000,
131+
call: functionIdentifierValue("api/users:list"),
132+
cachedResult: false,
133+
requestId: "req_123",
134+
executionId: "exec_1",
135+
caller: "dashboard",
136+
environment: "production",
137+
identityType: "user",
138+
parentExecutionId: null,
139+
executionTimestamp: 1697365800000,
140+
kind: "outcome" as const,
141+
outcome: {
142+
status: "success" as const,
143+
statusCode: null,
144+
},
145+
executionTimeMs: 45,
146+
},
103147
logs: [
104148
// Log messages for exec_1
105149
{
@@ -191,14 +235,33 @@ export const WithSuccessfulFunctions: Story = {
191235
executionTimeMs: 120,
192236
},
193237
],
194-
onFunctionSelect: (executionId: string, functionName: string) => {
195-
alert(`Selected function: ${functionName} (${executionId})`);
196-
},
197238
},
198239
};
199240

200241
export const WithFailedFunction: Story = {
201242
args: {
243+
currentLog: {
244+
id: "1",
245+
udfType: "Query" as const,
246+
localizedTimestamp: "2023-10-15 10:30:00",
247+
timestamp: 1697365800000,
248+
call: functionIdentifierValue("api/users:list"),
249+
cachedResult: false,
250+
requestId: "req_123",
251+
executionId: "exec_1",
252+
caller: "dashboard",
253+
environment: "production",
254+
identityType: "user",
255+
parentExecutionId: null,
256+
executionTimestamp: 1697365800000,
257+
kind: "outcome" as const,
258+
outcome: {
259+
status: "failure" as const,
260+
statusCode: null,
261+
},
262+
executionTimeMs: 1500,
263+
error: "User validation failed",
264+
},
202265
logs: [
203266
{
204267
id: "1",
@@ -245,14 +308,26 @@ export const WithFailedFunction: Story = {
245308
error: "Payment gateway timeout",
246309
},
247310
],
248-
onFunctionSelect: (executionId: string, functionName: string) => {
249-
alert(`Selected function: ${functionName} (${executionId})`);
250-
},
251311
},
252312
};
253313

254314
export const WithRunningFunction: Story = {
255315
args: {
316+
currentLog: {
317+
id: "1",
318+
udfType: "Action" as const,
319+
timestamp: Date.now() - 5000,
320+
call: functionIdentifierValue("api/batch:process"),
321+
executionId: "exec_1",
322+
localizedTimestamp: "2023-10-15 10:30:00",
323+
requestId: "req_123",
324+
kind: "log" as const,
325+
output: {
326+
isTruncated: false,
327+
messages: ["Starting batch processing..."],
328+
level: "INFO" as const,
329+
},
330+
},
256331
logs: [
257332
{
258333
id: "1",
@@ -336,23 +411,39 @@ export const WithRunningFunction: Story = {
336411
},
337412
},
338413
],
339-
onFunctionSelect: (executionId: string, functionName: string) => {
340-
alert(`Selected function: ${functionName} (${executionId})`);
341-
},
342414
},
343415
};
344416

345417
export const WithNestedFunctions: Story = {
346418
args: {
419+
currentLog: mockLogs[0],
347420
logs: mockLogs,
348-
onFunctionSelect: (executionId: string, functionName: string) => {
349-
alert(`Selected function: ${functionName} (${executionId})`);
350-
},
351421
},
352422
};
353423

354424
export const WithComplexNesting: Story = {
355425
args: {
426+
currentLog: {
427+
id: "1",
428+
udfType: "Query" as const,
429+
localizedTimestamp: "2023-10-15 10:30:00",
430+
timestamp: 1697365800000,
431+
call: functionIdentifierValue("api/orders:process"),
432+
cachedResult: false,
433+
requestId: "req_123",
434+
executionId: "exec_1",
435+
caller: "dashboard",
436+
environment: "production",
437+
identityType: "user",
438+
parentExecutionId: null,
439+
executionTimestamp: 1697365800000,
440+
kind: "outcome" as const,
441+
outcome: {
442+
status: "success" as const,
443+
statusCode: null,
444+
},
445+
executionTimeMs: 2500,
446+
},
356447
logs: [
357448
{
358449
id: "1",
@@ -460,8 +551,5 @@ export const WithComplexNesting: Story = {
460551
executionTimeMs: 400,
461552
},
462553
],
463-
onFunctionSelect: (executionId: string, functionName: string) => {
464-
alert(`Selected function: ${functionName} (${executionId})`);
465-
},
466554
},
467555
};

npm-packages/dashboard-common/src/features/logs/components/FunctionCallTree.test.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ describe("createExecutionNodes", () => {
5555
functionName: functionIdentifierValue("api/users:list"),
5656
status: "success",
5757
executionTime: 1000,
58-
logCount: 1,
5958
children: [],
6059
});
6160
});
@@ -102,12 +101,11 @@ describe("createExecutionNodes", () => {
102101
functionName: functionIdentifierValue("api/batch:process"),
103102
status: "running",
104103
executionTime: undefined,
105-
logCount: 2,
106104
children: [],
107105
});
108106
});
109107

110-
it("should correctly count logs per execution", () => {
108+
it("should handle multiple executions", () => {
111109
const logs: UdfLog[] = [
112110
// Execution 1: 3 logs
113111
{
@@ -203,8 +201,8 @@ describe("createExecutionNodes", () => {
203201
const exec1 = result.find((n) => n.executionId === "exec_1");
204202
const exec2 = result.find((n) => n.executionId === "exec_2");
205203

206-
expect(exec1?.logCount).toBe(3);
207-
expect(exec2?.logCount).toBe(1);
204+
expect(exec1?.status).toBe("success");
205+
expect(exec2?.status).toBe("failure");
208206
});
209207

210208
it("should build parent-child relationships correctly", () => {

0 commit comments

Comments
 (0)