Skip to content

Commit f281fd8

Browse files
committed
added migration for indexes
added debug level (logger.debug) by default fixed issue where when changing filters the table would not scroll up removed internal logs from list fixed ServiceValidationError not being sent to FE Removed run filters removed v1 support for logs
1 parent 2705dd0 commit f281fd8

File tree

11 files changed

+403
-389
lines changed

11 files changed

+403
-389
lines changed

apps/webapp/app/components/LogLevelTooltipInfo.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ export function LogLevelTooltipInfo() {
1212
Structured logging helps you debug and monitor your tasks.
1313
</Paragraph>
1414
</div>
15-
<div>
16-
<div className="mb-0.5">
17-
<Header3 className="text-blue-400">Debug</Header3>
18-
</div>
19-
<Paragraph variant="small" className="text-text-dimmed">
20-
Detailed diagnostic information for development and debugging.
21-
</Paragraph>
22-
</div>
2315
<div>
2416
<div className="mb-0.5">
2517
<Header3 className="text-blue-400">Info</Header3>
@@ -46,17 +38,17 @@ export function LogLevelTooltipInfo() {
4638
</div>
4739
<div>
4840
<div className="mb-0.5">
49-
<Header3 className="text-charcoal-400">Cancelled</Header3>
41+
<Header3 className="text-charcoal-400">Debug</Header3>
5042
</div>
5143
<Paragraph variant="small" className="text-text-dimmed">
52-
Messages logged when a task run is cancelled before completion.
44+
Detailed diagnostic information for development and debugging.
5345
</Paragraph>
5446
</div>
5547
<div className="border-t border-charcoal-700 pt-4">
5648
<Header3>Tracing & Spans</Header3>
5749
<Paragraph variant="small" className="text-text-dimmed">
58-
Automatically track the flow of your code through task triggers, attempts, and HTTP requests.
59-
Create custom traces to monitor specific operations.
50+
Automatically track the flow of your code through task triggers, attempts, and HTTP
51+
requests. Create custom traces to monitor specific operations.
6052
</Paragraph>
6153
</div>
6254
<LinkButton

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,26 @@ export function LogDetailView({ logId, initialLog, onClose, searchTerm }: LogDet
9494
const isLoading = fetcher.state === "loading";
9595
const log = fetcher.data ?? initialLog;
9696

97-
// Handle Escape key to close panel
97+
const runPath = v3RunSpanPath(
98+
organization,
99+
project,
100+
environment,
101+
{ friendlyId: log?.runId ?? "" },
102+
{ spanId: log?.spanId ?? "" }
103+
);
104+
105+
// Handle keyboard shortcuts
98106
useEffect(() => {
99107
const handleKeyDown = (e: KeyboardEvent) => {
100108
if (e.key === "Escape") {
101109
onClose();
110+
} else if ((e.key === "v" || e.key === "V") && !e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey && !isLoading && log) {
111+
window.open(runPath, "_blank");
102112
}
103113
};
104114
window.addEventListener("keydown", handleKeyDown);
105115
return () => window.removeEventListener("keydown", handleKeyDown);
106-
}, [onClose]);
116+
}, [onClose, log, runPath, isLoading]);
107117

108118
if (isLoading && !log) {
109119
return (
@@ -129,14 +139,6 @@ export function LogDetailView({ logId, initialLog, onClose, searchTerm }: LogDet
129139
);
130140
}
131141

132-
const runPath = v3RunSpanPath(
133-
organization,
134-
project,
135-
environment,
136-
{ friendlyId: log.runId },
137-
{ spanId: log.spanId }
138-
);
139-
140142
return (
141143
<div className="flex h-full flex-col overflow-hidden">
142144
{/* Header */}
@@ -175,7 +177,7 @@ export function LogDetailView({ logId, initialLog, onClose, searchTerm }: LogDet
175177
</TabButton>
176178
</TabContainer>
177179
<Link to={runPath} target="_blank" rel="noopener noreferrer">
178-
<Button variant="minimal/small" LeadingIcon={ArrowTopRightOnSquareIcon}>
180+
<Button variant="minimal/small" LeadingIcon={ArrowTopRightOnSquareIcon} shortcut={{ key: "v" }}>
179181
View full run
180182
</Button>
181183
</Link>

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

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,15 @@ import type { LogLevel } from "~/presenters/v3/LogsListPresenter.server";
1616
import { cn } from "~/utils/cn";
1717

1818
const allLogLevels: { level: LogLevel; label: string; color: string }[] = [
19-
{ level: "ERROR", label: "Error", color: "text-error" },
20-
{ level: "WARN", label: "Warning", color: "text-warning" },
2119
{ level: "INFO", label: "Info", color: "text-blue-400" },
22-
{ level: "CANCELLED", label: "Cancelled", color: "text-charcoal-400" },
20+
{ level: "WARN", label: "Warning", color: "text-warning" },
21+
{ level: "ERROR", label: "Error", color: "text-error" },
2322
{ level: "DEBUG", label: "Debug", color: "text-charcoal-400" },
24-
{ level: "TRACE", label: "Trace", color: "text-charcoal-500" },
2523
];
2624

27-
function getAvailableLevels(showDebug: boolean): typeof allLogLevels {
28-
if (showDebug) {
29-
return allLogLevels;
30-
}
31-
return allLogLevels.filter((level) => level.level !== "DEBUG");
25+
// In the future we might add other levels or change which are available
26+
function getAvailableLevels(): typeof allLogLevels {
27+
return allLogLevels;
3228
}
3329

3430
function getLevelBadgeColor(level: LogLevel): string {
@@ -41,24 +37,20 @@ function getLevelBadgeColor(level: LogLevel): string {
4137
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
4238
case "INFO":
4339
return "text-blue-400 bg-blue-500/10 border-blue-500/20";
44-
case "TRACE":
45-
return "text-charcoal-500 bg-charcoal-800 border-charcoal-700";
46-
case "CANCELLED":
47-
return "text-charcoal-400 bg-charcoal-700 border-charcoal-600";
4840
default:
4941
return "text-text-dimmed bg-charcoal-750 border-charcoal-700";
5042
}
5143
}
5244

5345
const shortcut = { key: "l" };
5446

55-
export function LogsLevelFilter({ showDebug = false }: { showDebug?: boolean }) {
47+
export function LogsLevelFilter() {
5648
const { values } = useSearchParams();
5749
const selectedLevels = values("levels");
5850
const hasLevels = selectedLevels.length > 0 && selectedLevels.some((v) => v !== "");
5951

6052
if (hasLevels) {
61-
return <AppliedLevelFilter showDebug={showDebug} />;
53+
return <AppliedLevelFilter/>;
6254
}
6355

6456
return (
@@ -73,25 +65,22 @@ export function LogsLevelFilter({ showDebug = false }: { showDebug?: boolean })
7365
Level
7466
</SelectTrigger>
7567
}
76-
showDebug={showDebug}
7768
/>
7869
);
7970
}
8071

8172
function LevelDropdown({
8273
trigger,
83-
showDebug = false,
8474
}: {
8575
trigger: ReactNode;
86-
showDebug?: boolean;
8776
}) {
8877
const { values, replace } = useSearchParams();
8978

9079
const handleChange = (values: string[]) => {
9180
replace({ levels: values, cursor: undefined, direction: undefined });
9281
};
9382

94-
const availableLevels = getAvailableLevels(showDebug);
83+
const availableLevels = getAvailableLevels();
9584

9685
return (
9786
<SelectProvider value={values("levels")} setValue={handleChange} virtualFocus={true}>
@@ -120,7 +109,7 @@ function LevelDropdown({
120109
);
121110
}
122111

123-
function AppliedLevelFilter({ showDebug = false }: { showDebug?: boolean }) {
112+
function AppliedLevelFilter() {
124113
const { values, del } = useSearchParams();
125114
const levels = values("levels");
126115

@@ -141,7 +130,6 @@ function AppliedLevelFilter({ showDebug = false }: { showDebug?: boolean }) {
141130
/>
142131
</Ariakit.Select>
143132
}
144-
showDebug={showDebug}
145133
/>
146134
);
147135
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import type { TaskTriggerSource } from "@trigger.dev/database";
2+
import type { ReactNode } from "react";
3+
import { useMemo } from "react";
4+
import * as Ariakit from "@ariakit/react";
5+
import {
6+
ComboBox,
7+
SelectItem,
8+
SelectList,
9+
SelectPopover,
10+
SelectProvider,
11+
SelectTrigger,
12+
} from "~/components/primitives/Select";
13+
import { useSearchParams } from "~/hooks/useSearchParam";
14+
import { TaskTriggerSourceIcon } from "~/components/runs/v3/TaskTriggerSource";
15+
import { appliedSummary, FilterMenuProvider } from "~/components/runs/v3/SharedFilters";
16+
import { AppliedFilter } from "~/components/primitives/AppliedFilter";
17+
18+
const shortcut = { key: "t" };
19+
20+
type TaskOption = {
21+
slug: string;
22+
triggerSource: TaskTriggerSource;
23+
};
24+
25+
interface LogsTaskFilterProps {
26+
possibleTasks: TaskOption[];
27+
}
28+
29+
export function LogsTaskFilter({ possibleTasks }: LogsTaskFilterProps) {
30+
const { values, replace, del } = useSearchParams();
31+
const selectedTasks = values("tasks");
32+
33+
if (selectedTasks.length === 0 || selectedTasks.every((v) => v === "")) {
34+
return (
35+
<FilterMenuProvider>
36+
{(search, setSearch) => (
37+
<TasksDropdown
38+
trigger={
39+
<SelectTrigger
40+
icon={<TaskTriggerSourceIcon source="STANDARD" className="size-4" />}
41+
variant="secondary/small"
42+
shortcut={shortcut}
43+
tooltipTitle="Filter by task"
44+
>
45+
Tasks
46+
</SelectTrigger>
47+
}
48+
searchValue={search}
49+
clearSearchValue={() => setSearch("")}
50+
possibleTasks={possibleTasks}
51+
/>
52+
)}
53+
</FilterMenuProvider>
54+
);
55+
}
56+
57+
return (
58+
<FilterMenuProvider>
59+
{(search, setSearch) => (
60+
<TasksDropdown
61+
trigger={
62+
<Ariakit.Select render={<div className="group cursor-pointer focus-custom" />}>
63+
<AppliedFilter
64+
label="Task"
65+
icon={<TaskTriggerSourceIcon source="STANDARD" className="size-4" />}
66+
value={appliedSummary(
67+
selectedTasks.map((v) => {
68+
const task = possibleTasks.find((task) => task.slug === v);
69+
return task ? task.slug : v;
70+
})
71+
)}
72+
onRemove={() => del(["tasks", "cursor", "direction"])}
73+
variant="secondary/small"
74+
/>
75+
</Ariakit.Select>
76+
}
77+
searchValue={search}
78+
clearSearchValue={() => setSearch("")}
79+
possibleTasks={possibleTasks}
80+
/>
81+
)}
82+
</FilterMenuProvider>
83+
);
84+
}
85+
86+
function TasksDropdown({
87+
trigger,
88+
clearSearchValue,
89+
searchValue,
90+
onClose,
91+
possibleTasks,
92+
}: {
93+
trigger: ReactNode;
94+
clearSearchValue: () => void;
95+
searchValue: string;
96+
onClose?: () => void;
97+
possibleTasks: TaskOption[];
98+
}) {
99+
const { values, replace } = useSearchParams();
100+
101+
const handleChange = (values: string[]) => {
102+
clearSearchValue();
103+
replace({ tasks: values, cursor: undefined, direction: undefined });
104+
};
105+
106+
const filtered = useMemo(() => {
107+
return possibleTasks.filter((item) => {
108+
return item.slug.toLowerCase().includes(searchValue.toLowerCase());
109+
});
110+
}, [searchValue, possibleTasks]);
111+
112+
return (
113+
<SelectProvider value={values("tasks")} setValue={handleChange} virtualFocus={true}>
114+
{trigger}
115+
<SelectPopover
116+
className="min-w-0 max-w-[min(240px,var(--popover-available-width))]"
117+
hideOnEscape={() => {
118+
if (onClose) {
119+
onClose();
120+
return false;
121+
}
122+
123+
return true;
124+
}}
125+
>
126+
<ComboBox placeholder={"Filter by task..."} value={searchValue} />
127+
<SelectList>
128+
{filtered.map((item, index) => (
129+
<SelectItem
130+
key={`${item.triggerSource}-${item.slug}`}
131+
value={item.slug}
132+
icon={
133+
<TaskTriggerSourceIcon source={item.triggerSource} className="size-4 flex-none" />
134+
}
135+
>
136+
{item.slug}
137+
</SelectItem>
138+
))}
139+
</SelectList>
140+
</SelectPopover>
141+
</SelectProvider>
142+
);
143+
}

0 commit comments

Comments
 (0)