Skip to content

Commit 9d9c553

Browse files
atrakhConvex, Inc.
authored andcommitted
dashboard: use query param for selected log (#41583)
GitOrigin-RevId: 71f0c0fafb7fbca1e995b46b0a46dfdc8ff83ac6
1 parent eaed0d7 commit 9d9c553

File tree

4 files changed

+59
-21
lines changed

4 files changed

+59
-21
lines changed

npm-packages/dashboard-common/src/elements/LogOutput.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ import { LogLevel } from "@common/elements/LogLevel";
55
export function LogOutput({
66
output,
77
wrap,
8+
secondary,
89
}: {
910
output: Output;
1011
wrap?: boolean;
12+
secondary?: boolean;
1113
}) {
1214
return (
1315
<div
1416
className={classNames(
15-
"text-xs overflow-y-auto text-content-secondary",
17+
"text-xs overflow-y-auto",
1618
wrap ? "whitespace-pre-wrap break-all" : "truncate",
19+
secondary && "text-content-secondary",
1720
)}
1821
>
1922
{output.messages &&

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

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
InfoCircledIcon,
77
QuestionMarkCircledIcon,
88
} from "@radix-ui/react-icons";
9-
import { Fragment, memo, useCallback, useRef, useState } from "react";
9+
import { Fragment, memo, useCallback, useMemo, useRef, useState } from "react";
1010
import { FixedSizeList, ListOnScrollProps, areEqual } from "react-window";
1111
import { useDebounce, useMeasure } from "react-use";
1212
import { Transition, Dialog } from "@headlessui/react";
@@ -35,6 +35,8 @@ import { CopyTextButton } from "@common/elements/CopyTextButton";
3535
import { TextInput } from "@ui/TextInput";
3636
import { MultiSelectValue } from "@ui/MultiSelectCombobox";
3737
import { LogListResources } from "@common/features/logs/components/LogListResources";
38+
import { shallowNavigate } from "@common/lib/useTableMetadata";
39+
import { useRouter } from "next/router";
3840

3941
export type LogListProps = {
4042
logs?: UdfLog[];
@@ -60,6 +62,8 @@ export function LogList({
6062
setPaused,
6163
setManuallyPaused,
6264
}: LogListProps) {
65+
const router = useRouter();
66+
6367
const interleavedLogs = interleaveLogs(
6468
filteredLogs ?? [],
6569
deploymentAuditLogs ?? [],
@@ -69,7 +73,31 @@ export function LogList({
6973
const [sheetRef, { height: heightOfListContainer }] =
7074
useMeasure<HTMLDivElement>();
7175

72-
const [shownLog, setShownLog] = useState<UdfLog>();
76+
// Derive shownLog from URL query parameters
77+
const shownLog = useMemo(() => {
78+
const logTs = router.query.logTs as string | undefined;
79+
80+
if (logTs && filteredLogs) {
81+
// Find the log with this timestamp in filtered logs
82+
const matchingLog = filteredLogs.find(
83+
(log) => log.timestamp === Number(logTs),
84+
);
85+
return matchingLog;
86+
}
87+
88+
return undefined;
89+
}, [router.query.logTs, filteredLogs]);
90+
91+
// Update URL when log selection changesAdd a comment on lines R88 to R90Add diff commentMarkdown input: edit mode selected.WritePreviewAdd a suggestionHeadingBoldItalicQuoteCodeLinkUnordered listNumbered listTask listMentionReferenceSaved repliesAdd FilesPaste, drop, or click to add filesCancelCommentStart a reviewReturn to code
92+
const setShownLog = useCallback(
93+
(log: UdfLog | undefined) => {
94+
void shallowNavigate(router, {
95+
...router.query,
96+
logTs: log ? log.timestamp.toString() : undefined,
97+
});
98+
},
99+
[router],
100+
);
73101

74102
const hasFilters =
75103
!!logs && !!filteredLogs && filteredLogs.length !== logs.length;
@@ -126,6 +154,7 @@ function WindowedLogList({
126154
hasFilters,
127155
paused,
128156
setManuallyPaused,
157+
shownLog,
129158
}: {
130159
interleavedLogs: InterleavedLog[];
131160
setClearedLogs: (clearedLogs: number[]) => void;
@@ -135,6 +164,7 @@ function WindowedLogList({
135164
hasFilters: boolean;
136165
paused: boolean;
137166
setManuallyPaused(paused: boolean): void;
167+
shownLog?: UdfLog;
138168
}) {
139169
const listRef = useRef<FixedSizeList>(null);
140170
const outerRef = useRef<HTMLDivElement>(null);
@@ -189,6 +219,7 @@ configure a log stream."
189219
setClearedLogs,
190220
clearedLogs,
191221
setShownLog,
222+
selectedLogTimestamp: shownLog?.timestamp,
192223
}}
193224
RowOrLoading={LogListRow}
194225
/>
@@ -221,6 +252,7 @@ type LogItemProps = {
221252
setClearedLogs: (clearedLogs: number[]) => void;
222253
setShownLog(shown: UdfLog | undefined): void;
223254
clearedLogs: number[];
255+
selectedLogTimestamp?: number;
224256
};
225257
index: number;
226258
style: any;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export function LogListItem({
114114
<LogLevel level={log.output.level} />
115115
)}
116116
{log.kind === "log" && (
117-
<LogOutput output={log.output} wrap={!setShownLog} />
117+
<LogOutput output={log.output} wrap={!setShownLog} secondary />
118118
)}
119119
{log.kind === "outcome" && log.error && (
120120
<LogOutput
@@ -123,6 +123,7 @@ export function LogListItem({
123123
messages: [log.error],
124124
level: "FAILURE",
125125
}}
126+
secondary
126127
wrap={!setShownLog}
127128
/>
128129
)}

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

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ export function Logs({
187187
: latestAuditLog?._creationTime;
188188

189189
return (
190-
<div className="flex h-full w-full min-w-[48rem] flex-col gap-2 p-6 py-4">
191-
<div className="flex flex-col gap-4">
190+
<div className="flex h-full w-full min-w-[48rem] flex-col overflow-hidden p-6 py-4">
191+
<div className="flex shrink-0 flex-col gap-4">
192192
<LogToolbar
193193
firstItem={<LogsHeader />}
194194
selectedLevels={levels}
@@ -236,21 +236,23 @@ export function Logs({
236236
</Button>
237237
</div>
238238
</div>
239-
<LogList
240-
nents={nents}
241-
logs={logs}
242-
filteredLogs={filteredLogs}
243-
deploymentAuditLogs={deploymentAuditLogs}
244-
filter={filter}
245-
clearedLogs={clearedLogs}
246-
setClearedLogs={setClearedLogs}
247-
paused={paused > 0 || manuallyPaused}
248-
setPaused={onPause}
249-
setManuallyPaused={(p) => {
250-
onPause(p);
251-
setManuallyPaused(p);
252-
}}
253-
/>
239+
<div className="flex-1 overflow-hidden">
240+
<LogList
241+
nents={nents}
242+
logs={logs}
243+
filteredLogs={filteredLogs}
244+
deploymentAuditLogs={deploymentAuditLogs}
245+
filter={filter}
246+
clearedLogs={clearedLogs}
247+
setClearedLogs={setClearedLogs}
248+
paused={paused > 0 || manuallyPaused}
249+
setPaused={onPause}
250+
setManuallyPaused={(p) => {
251+
onPause(p);
252+
setManuallyPaused(p);
253+
}}
254+
/>
255+
</div>
254256
</div>
255257
);
256258
}

0 commit comments

Comments
 (0)