Skip to content

Commit 443f2a1

Browse files
committed
code review fixes
1 parent 5350dfe commit 443f2a1

File tree

4 files changed

+166
-71
lines changed

4 files changed

+166
-71
lines changed

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

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ type CodeBlockProps = {
7272
const dimAmount = 0.5;
7373
const extraLinesWhenClipping = 0.35;
7474

75+
const SEARCH_HIGHLIGHT_STYLES = {
76+
backgroundColor: "#facc15",
77+
color: "#000000",
78+
fontWeight: "500",
79+
} as const;
80+
7581
const defaultTheme: PrismTheme = {
7682
plain: {
7783
color: "#9C9AF2",
@@ -365,7 +371,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
365371
)}
366372
dir="ltr"
367373
>
368-
{code}
374+
{highlightSearchInText(code, searchTerm)}
369375
</pre>
370376
</div>
371377
)}
@@ -407,7 +413,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
407413
className="overflow-auto px-3 py-3 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
408414
>
409415
<pre className="relative mr-2 p-2 font-mono text-base leading-relaxed" dir="ltr">
410-
{code}
416+
{highlightSearchInText(code, searchTerm)}
411417
</pre>
412418
</div>
413419
)}
@@ -420,6 +426,42 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
420426

421427
CodeBlock.displayName = "CodeBlock";
422428

429+
/**
430+
* Highlights search term matches in plain text
431+
*/
432+
function highlightSearchInText(text: string, searchTerm: string | undefined): React.ReactNode {
433+
if (!searchTerm || searchTerm.trim() === "") {
434+
return text;
435+
}
436+
437+
const escapedSearch = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
438+
const regex = new RegExp(escapedSearch, "gi");
439+
440+
const parts: React.ReactNode[] = [];
441+
let lastIndex = 0;
442+
let match;
443+
let matchCount = 0;
444+
445+
while ((match = regex.exec(text)) !== null) {
446+
if (match.index > lastIndex) {
447+
parts.push(text.substring(lastIndex, match.index));
448+
}
449+
parts.push(
450+
<span key={`match-${matchCount}`} style={SEARCH_HIGHLIGHT_STYLES}>
451+
{match[0]}
452+
</span>
453+
);
454+
lastIndex = regex.lastIndex;
455+
matchCount++;
456+
}
457+
458+
if (lastIndex < text.length) {
459+
parts.push(text.substring(lastIndex));
460+
}
461+
462+
return parts.length > 0 ? parts : text;
463+
}
464+
423465
function Chrome({ title }: { title?: string }) {
424466
return (
425467
<div className="grid h-7 grid-cols-[100px_auto_100px] border-b border-charcoal-800 bg-charcoal-900">
@@ -582,11 +624,7 @@ function HighlightCode({
582624
parts.push(
583625
<span
584626
key={`match-${matchCount}`}
585-
style={{
586-
backgroundColor: "#facc15",
587-
color: "#000000",
588-
fontWeight: "500",
589-
}}
627+
style={SEARCH_HIGHLIGHT_STYLES}
590628
>
591629
{match[0]}
592630
</span>

apps/webapp/app/components/logs/LogDetailView.tsx

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,31 +31,10 @@ import { RunTag } from "~/components/runs/v3/RunTag";
3131
import { formatCurrencyAccurate } from "~/utils/numberFormatter";
3232
import type { TaskRunStatus } from "@trigger.dev/database";
3333
import { PacketDisplay } from "~/components/runs/v3/PacketDisplay";
34+
import type { RunContext } from "~/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs.$logId.run";
3435

35-
// Types for the run context endpoint response
3636
type RunContextData = {
37-
run: {
38-
id: string;
39-
friendlyId: string;
40-
taskIdentifier: string;
41-
status: string;
42-
createdAt: string;
43-
startedAt?: string;
44-
completedAt?: string;
45-
isTest: boolean;
46-
tags: string[];
47-
queue: string;
48-
concurrencyKey: string | null;
49-
usageDurationMs: number;
50-
costInCents: number;
51-
baseCostInCents: number;
52-
machinePreset: string | null;
53-
version?: string;
54-
rootRun: { friendlyId: string; taskIdentifier: string } | null;
55-
parentRun: { friendlyId: string; taskIdentifier: string } | null;
56-
batch: { friendlyId: string } | null;
57-
schedule: { friendlyId: string } | null;
58-
} | null;
37+
run: RunContext | null;
5938
};
6039

6140

@@ -308,10 +287,12 @@ function DetailsTab({ log, runPath, searchTerm }: { log: LogEntry; runPath: stri
308287
const showAttributes = beautifiedAttributes && beautifiedAttributes !== "{}";
309288

310289
// Determine message to show
311-
let message = log.message;
312-
313-
if (log.status === 'ERROR'){
314-
message = (logWithExtras?.attributes?.error as any)?.message;
290+
let message = log.message ?? "";
291+
if (log.level === "ERROR") {
292+
const maybeErrorMessage = (logWithExtras.attributes as any)?.error?.message;
293+
if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
294+
message = maybeErrorMessage;
295+
}
315296
}
316297

317298
return (
@@ -354,17 +335,19 @@ function RunTab({ log, runPath }: { log: LogEntry; runPath: string }) {
354335
const project = useProject();
355336
const environment = useEnvironment();
356337
const fetcher = useTypedFetcher<RunContextData>();
338+
const [requested, setRequested] = useState(false);
357339

358340
// Fetch run details when tab is active
359341
useEffect(() => {
360342
if (!log.runId) return;
361343

344+
setRequested(true);
362345
fetcher.load(
363346
`/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/logs/${encodeURIComponent(log.id)}/run?runId=${encodeURIComponent(log.runId)}`
364347
);
365348
}, [organization.slug, project.slug, environment.slug, log.id, log.runId]);
366349

367-
const isLoading = fetcher.state === "loading";
350+
const isLoading = !requested || fetcher.state === "loading";
368351
const runData = fetcher.data?.run;
369352

370353
if (isLoading) {
@@ -522,7 +505,11 @@ function RunTab({ log, runPath }: { log: LogEntry; runPath: string }) {
522505
<Property.Item>
523506
<Property.Label>Machine</Property.Label>
524507
<Property.Value className="-ml-0.5">
525-
<MachineLabelCombo preset={runData.machinePreset as MachinePresetName} />
508+
{runData.machinePreset ? (
509+
<MachineLabelCombo preset={runData.machinePreset as MachinePresetName} />
510+
) : (
511+
"–"
512+
)}
526513
</Property.Value>
527514
</Property.Item>
528515

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs.$logId.run.tsx

Lines changed: 100 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,73 @@
11
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
22
import { json } from "@remix-run/node";
3+
import { z } from "zod";
4+
import { MachinePresetName } from "@trigger.dev/core/v3";
35
import { requireUserId } from "~/services/session.server";
46
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
57
import { findProjectBySlug } from "~/models/project.server";
68
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
79
import { $replica } from "~/db.server";
10+
import type { TaskRunStatus } from "@trigger.dev/database";
11+
12+
// Valid TaskRunStatus values
13+
const VALID_TASK_RUN_STATUSES = [
14+
"PENDING",
15+
"QUEUED",
16+
"EXECUTING",
17+
"WAITING_FOR_EXECUTION",
18+
"WAITING",
19+
"COMPLETED_SUCCESSFULLY",
20+
"COMPLETED_WITH_ERRORS",
21+
"SYSTEM_FAILURE",
22+
"FAILURE",
23+
"CANCELED",
24+
] as const;
25+
26+
// Schema for validating run context data
27+
export const RunContextSchema = z.object({
28+
id: z.string(),
29+
friendlyId: z.string(),
30+
taskIdentifier: z.string(),
31+
status: z.enum(VALID_TASK_RUN_STATUSES).catch((ctx) => {
32+
throw new Error(`Invalid TaskRunStatus: ${ctx.input}`);
33+
}),
34+
createdAt: z.string().datetime(),
35+
startedAt: z.string().datetime().optional(),
36+
completedAt: z.string().datetime().optional(),
37+
isTest: z.boolean(),
38+
tags: z.array(z.string()),
39+
queue: z.string(),
40+
concurrencyKey: z.string().nullable(),
41+
usageDurationMs: z.number(),
42+
costInCents: z.number(),
43+
baseCostInCents: z.number(),
44+
machinePreset: MachinePresetName.nullable(),
45+
version: z.string().optional(),
46+
rootRun: z
47+
.object({
48+
friendlyId: z.string(),
49+
taskIdentifier: z.string(),
50+
})
51+
.nullable(),
52+
parentRun: z
53+
.object({
54+
friendlyId: z.string(),
55+
taskIdentifier: z.string(),
56+
})
57+
.nullable(),
58+
batch: z
59+
.object({
60+
friendlyId: z.string(),
61+
})
62+
.nullable(),
63+
schedule: z
64+
.object({
65+
friendlyId: z.string(),
66+
})
67+
.nullable(),
68+
});
69+
70+
export type RunContext = z.infer<typeof RunContextSchema>;
871

972
// Fetch run context for a log entry
1073
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
@@ -99,38 +162,43 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
99162
schedule = scheduleData;
100163
}
101164

165+
const runData = {
166+
id: run.id,
167+
friendlyId: run.friendlyId,
168+
taskIdentifier: run.taskIdentifier,
169+
status: run.status,
170+
createdAt: run.createdAt.toISOString(),
171+
startedAt: run.startedAt?.toISOString(),
172+
completedAt: run.completedAt?.toISOString(),
173+
isTest: run.isTest,
174+
tags: run.runTags,
175+
queue: run.queue,
176+
concurrencyKey: run.concurrencyKey,
177+
usageDurationMs: run.usageDurationMs,
178+
costInCents: run.costInCents,
179+
baseCostInCents: run.baseCostInCents,
180+
machinePreset: run.machinePreset,
181+
version: run.lockedToVersion?.version,
182+
rootRun: run.rootTaskRun
183+
? {
184+
friendlyId: run.rootTaskRun.friendlyId,
185+
taskIdentifier: run.rootTaskRun.taskIdentifier,
186+
}
187+
: null,
188+
parentRun: run.parentTaskRun
189+
? {
190+
friendlyId: run.parentTaskRun.friendlyId,
191+
taskIdentifier: run.parentTaskRun.taskIdentifier,
192+
}
193+
: null,
194+
batch: run.batch ? { friendlyId: run.batch.friendlyId } : null,
195+
schedule: schedule,
196+
};
197+
198+
// Validate the run data
199+
const validatedRun = RunContextSchema.parse(runData);
200+
102201
return json({
103-
run: {
104-
id: run.id,
105-
friendlyId: run.friendlyId,
106-
taskIdentifier: run.taskIdentifier,
107-
status: run.status,
108-
createdAt: run.createdAt.toISOString(),
109-
startedAt: run.startedAt?.toISOString(),
110-
completedAt: run.completedAt?.toISOString(),
111-
isTest: run.isTest,
112-
tags: run.runTags,
113-
queue: run.queue,
114-
concurrencyKey: run.concurrencyKey,
115-
usageDurationMs: run.usageDurationMs,
116-
costInCents: run.costInCents,
117-
baseCostInCents: run.baseCostInCents,
118-
machinePreset: run.machinePreset,
119-
version: run.lockedToVersion?.version,
120-
rootRun: run.rootTaskRun
121-
? {
122-
friendlyId: run.rootTaskRun.friendlyId,
123-
taskIdentifier: run.rootTaskRun.taskIdentifier,
124-
}
125-
: null,
126-
parentRun: run.parentTaskRun
127-
? {
128-
friendlyId: run.parentTaskRun.friendlyId,
129-
taskIdentifier: run.parentTaskRun.taskIdentifier,
130-
}
131-
: null,
132-
batch: run.batch ? { friendlyId: run.batch.friendlyId } : null,
133-
schedule: schedule,
134-
},
202+
run: validatedRun,
135203
});
136204
};

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,11 @@ function RunBody({
573573
<Property.Value>
574574
<div className="flex items-start justify-between gap-2">
575575
<div className="flex-1">
576-
<div className="break-all">
577-
{run.idempotencyKey ? run.idempotencyKey : "–"}
578-
</div>
576+
{run.idempotencyKey ? (
577+
<CopyableText value={run.idempotencyKey} copyValue={run.idempotencyKey} asChild />
578+
) : (
579+
<div className="break-all"></div>
580+
)}
579581
{run.idempotencyKey && (
580582
<div>
581583
Expires:{" "}

0 commit comments

Comments
 (0)