Skip to content

Commit c05fc0d

Browse files
committed
Major rendering performance improvements
1 parent e4d86dd commit c05fc0d

File tree

5 files changed

+180
-105
lines changed

5 files changed

+180
-105
lines changed

apps/webapp/app/components/code/AIQueryInput.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ interface AIQueryInputProps {
3232
onQueryGenerated: (query: string) => void;
3333
/** Set this to a prompt to auto-populate and immediately submit */
3434
autoSubmitPrompt?: string;
35-
/** The current query in the editor (used for edit mode) */
36-
currentQuery?: string;
35+
/** Get the current query in the editor (used for edit mode) */
36+
getCurrentQuery?: () => string;
3737
}
3838

3939
export function AIQueryInput({
4040
onQueryGenerated,
4141
autoSubmitPrompt,
42-
currentQuery,
42+
getCurrentQuery,
4343
}: AIQueryInputProps) {
4444
const [prompt, setPrompt] = useState("");
4545
const [mode, setMode] = useState<AIQueryMode>("new");
@@ -59,7 +59,7 @@ export function AIQueryInput({
5959
const resourcePath = `/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/query/ai-generate`;
6060

6161
// Can only use edit mode if there's a current query
62-
const canEdit = Boolean(currentQuery?.trim());
62+
const canEdit = Boolean(getCurrentQuery?.()?.trim());
6363

6464
// If mode is edit but there's no current query, switch to new
6565
useEffect(() => {
@@ -71,6 +71,7 @@ export function AIQueryInput({
7171
const submitQuery = useCallback(
7272
async (queryPrompt: string, submitMode: AIQueryMode = mode) => {
7373
if (!queryPrompt.trim() || isLoading) return;
74+
const currentQuery = getCurrentQuery?.();
7475
if (submitMode === "edit" && !currentQuery?.trim()) return;
7576

7677
setIsLoading(true);
@@ -160,7 +161,7 @@ export function AIQueryInput({
160161
setIsLoading(false);
161162
}
162163
},
163-
[isLoading, resourcePath, mode, currentQuery]
164+
[isLoading, resourcePath, mode, getCurrentQuery]
164165
);
165166

166167
const processStreamEvent = useCallback(

apps/webapp/app/components/code/QueryResultsChart.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { OutputColumnMetadata } from "@internal/clickhouse";
2-
import { useMemo } from "react";
2+
import { memo, useMemo } from "react";
33
import {
44
Area,
55
AreaChart,
@@ -331,7 +331,11 @@ function sortData(
331331
});
332332
}
333333

334-
export function QueryResultsChart({ rows, columns, config }: QueryResultsChartProps) {
334+
export const QueryResultsChart = memo(function QueryResultsChart({
335+
rows,
336+
columns,
337+
config,
338+
}: QueryResultsChartProps) {
335339
const {
336340
xAxisColumn,
337341
yAxisColumns,
@@ -505,7 +509,7 @@ export function QueryResultsChart({ rows, columns, config }: QueryResultsChartPr
505509
)}
506510
</ChartContainer>
507511
);
508-
}
512+
});
509513

510514
/**
511515
* Creates a Y-axis value formatter based on the data range

apps/webapp/app/components/code/TSQLResultsTable.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { OutputColumnMetadata } from "@internal/clickhouse";
22
import { formatDurationMilliseconds, MachinePresetName } from "@trigger.dev/core/v3";
3-
import { useState } from "react";
3+
import { memo, useState } from "react";
44
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
55
import { MachineLabelCombo } from "~/components/MachineLabelCombo";
66
import { DateTimeAccurate } from "~/components/primitives/DateTime";
@@ -399,7 +399,7 @@ function isRightAlignedColumn(column: OutputColumnMetadata): boolean {
399399
return isNumericType(column.type);
400400
}
401401

402-
export function TSQLResultsTable({
402+
export const TSQLResultsTable = memo(function TSQLResultsTable({
403403
rows,
404404
columns,
405405
prettyFormatting = true,
@@ -456,4 +456,4 @@ export function TSQLResultsTable({
456456
</TableBody>
457457
</Table>
458458
);
459-
}
459+
});

apps/webapp/app/components/primitives/DateTime.tsx

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { GlobeAltIcon, GlobeAmericasIcon } from "@heroicons/react/20/solid";
22
import { Laptop } from "lucide-react";
3-
import { Fragment, type ReactNode, useSyncExternalStore } from "react";
3+
import { Fragment, memo, type ReactNode, useMemo, useSyncExternalStore } from "react";
44
import { CopyButton } from "./CopyButton";
55
import { useLocales } from "./LocaleProvider";
66
import { Paragraph } from "./Paragraph";
@@ -63,16 +63,7 @@ export const DateTime = ({
6363
const locales = useLocales();
6464
const localTimeZone = useLocalTimeZone();
6565

66-
const realDate = typeof date === "string" ? new Date(date) : date;
67-
68-
const tooltipContent = (
69-
<TooltipContent
70-
realDate={realDate}
71-
timeZone={timeZone}
72-
localTimeZone={localTimeZone}
73-
locales={locales}
74-
/>
75-
);
66+
const realDate = useMemo(() => (typeof date === "string" ? new Date(date) : date), [date]);
7667

7768
const formattedDateTime = (
7869
<Fragment>
@@ -90,7 +81,20 @@ export const DateTime = ({
9081

9182
if (!showTooltip) return formattedDateTime;
9283

93-
return <SimpleTooltip button={formattedDateTime} content={tooltipContent} side="right" />;
84+
return (
85+
<SimpleTooltip
86+
button={formattedDateTime}
87+
content={
88+
<TooltipContent
89+
realDate={realDate}
90+
timeZone={timeZone}
91+
localTimeZone={localTimeZone}
92+
locales={locales}
93+
/>
94+
}
95+
side="right"
96+
/>
97+
);
9498
};
9599

96100
export function formatDateTime(
@@ -224,7 +228,7 @@ function formatTimeOnly(
224228
}).format(date);
225229
}
226230

227-
export const DateTimeAccurate = ({
231+
const DateTimeAccurateInner = ({
228232
date,
229233
timeZone = "UTC",
230234
previousDate = null,
@@ -242,13 +246,15 @@ export const DateTimeAccurate = ({
242246
: null;
243247

244248
// Smart formatting based on whether date changed
245-
const formattedDateTime = hideDate
246-
? formatTimeOnly(realDate, localTimeZone, locales, hour12)
247-
: realPrevDate
248-
? isSameDay(realDate, realPrevDate)
249+
const formattedDateTime = useMemo(() => {
250+
return hideDate
249251
? formatTimeOnly(realDate, localTimeZone, locales, hour12)
250-
: formatDateTimeAccurate(realDate, localTimeZone, locales, hour12)
251-
: formatDateTimeAccurate(realDate, localTimeZone, locales, hour12);
252+
: realPrevDate
253+
? isSameDay(realDate, realPrevDate)
254+
? formatTimeOnly(realDate, localTimeZone, locales, hour12)
255+
: formatDateTimeAccurate(realDate, localTimeZone, locales, hour12)
256+
: formatDateTimeAccurate(realDate, localTimeZone, locales, hour12);
257+
}, [realDate, localTimeZone, locales, hour12, hideDate, previousDate]);
252258

253259
if (!showTooltip)
254260
return <Fragment>{formattedDateTime.replace(/\s/g, String.fromCharCode(32))}</Fragment>;
@@ -271,6 +277,28 @@ export const DateTimeAccurate = ({
271277
);
272278
};
273279

280+
function areDateTimePropsEqual(prev: DateTimeProps, next: DateTimeProps): boolean {
281+
// Compare Date objects by timestamp value, not reference
282+
const prevTime = prev.date instanceof Date ? prev.date.getTime() : prev.date;
283+
const nextTime = next.date instanceof Date ? next.date.getTime() : next.date;
284+
if (prevTime !== nextTime) return false;
285+
286+
const prevPrevTime =
287+
prev.previousDate instanceof Date ? prev.previousDate.getTime() : prev.previousDate;
288+
const nextPrevTime =
289+
next.previousDate instanceof Date ? next.previousDate.getTime() : next.previousDate;
290+
if (prevPrevTime !== nextPrevTime) return false;
291+
292+
return (
293+
prev.timeZone === next.timeZone &&
294+
prev.showTooltip === next.showTooltip &&
295+
prev.hideDate === next.hideDate &&
296+
prev.hour12 === next.hour12
297+
);
298+
}
299+
300+
export const DateTimeAccurate = memo(DateTimeAccurateInner, areDateTimePropsEqual);
301+
274302
function formatDateTimeAccurate(
275303
date: Date,
276304
timeZone: string,
@@ -333,14 +361,17 @@ function DateTimeTooltipContent({
333361
isoDateTime,
334362
icon,
335363
}: DateTimeTooltipContentProps) {
336-
const getUtcOffset = () => {
337-
if (title !== "Local") return "";
338-
const offset = -new Date().getTimezoneOffset();
339-
const sign = offset >= 0 ? "+" : "-";
340-
const hours = Math.abs(Math.floor(offset / 60));
341-
const minutes = Math.abs(offset % 60);
342-
return `(UTC ${sign}${hours}${minutes ? `:${minutes.toString().padStart(2, "0")}` : ""})`;
343-
};
364+
const getUtcOffset = useMemo(
365+
() => () => {
366+
if (title !== "Local") return "";
367+
const offset = -new Date().getTimezoneOffset();
368+
const sign = offset >= 0 ? "+" : "-";
369+
const hours = Math.abs(Math.floor(offset / 60));
370+
const minutes = Math.abs(offset % 60);
371+
return `(UTC ${sign}${hours}${minutes ? `:${minutes.toString().padStart(2, "0")}` : ""})`;
372+
},
373+
[title]
374+
);
344375

345376
return (
346377
<div className="flex flex-col gap-1">

0 commit comments

Comments
 (0)