Skip to content

Commit 1eb2afa

Browse files
committed
Add versions filtering to the Errors list page
1 parent 5f359be commit 1eb2afa

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as Ariakit from "@ariakit/react";
2+
import { SelectTrigger } from "~/components/primitives/Select";
3+
import { useSearchParams } from "~/hooks/useSearchParam";
4+
import { appliedSummary, FilterMenuProvider } from "~/components/runs/v3/SharedFilters";
5+
import { filterIcon, VersionsDropdown } from "~/components/runs/v3/RunFilters";
6+
import { AppliedFilter } from "~/components/primitives/AppliedFilter";
7+
8+
const shortcut = { key: "v" };
9+
10+
export function LogsVersionFilter() {
11+
const { values, del } = useSearchParams();
12+
const selectedVersions = values("versions");
13+
14+
if (selectedVersions.length === 0 || selectedVersions.every((v) => v === "")) {
15+
return (
16+
<FilterMenuProvider>
17+
{(search, setSearch) => (
18+
<VersionsDropdown
19+
trigger={
20+
<SelectTrigger
21+
icon={filterIcon("versions")}
22+
variant="secondary/small"
23+
shortcut={shortcut}
24+
tooltipTitle="Filter by version"
25+
>
26+
<span className="ml-0.5">Versions</span>
27+
</SelectTrigger>
28+
}
29+
searchValue={search}
30+
clearSearchValue={() => setSearch("")}
31+
/>
32+
)}
33+
</FilterMenuProvider>
34+
);
35+
}
36+
37+
return (
38+
<FilterMenuProvider>
39+
{(search, setSearch) => (
40+
<VersionsDropdown
41+
trigger={
42+
<Ariakit.Select render={<div className="group cursor-pointer focus-custom" />}>
43+
<AppliedFilter
44+
label="Versions"
45+
icon={filterIcon("versions")}
46+
value={appliedSummary(selectedVersions)}
47+
onRemove={() => del(["versions", "cursor", "direction"])}
48+
variant="secondary/small"
49+
/>
50+
</Ariakit.Select>
51+
}
52+
searchValue={search}
53+
clearSearchValue={() => setSearch("")}
54+
/>
55+
)}
56+
</FilterMenuProvider>
57+
);
58+
}

apps/webapp/app/components/runs/v3/RunFilters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1216,7 +1216,7 @@ function AppliedMachinesFilter() {
12161216
);
12171217
}
12181218

1219-
function VersionsDropdown({
1219+
export function VersionsDropdown({
12201220
trigger,
12211221
clearSearchValue,
12221222
searchValue,

apps/webapp/app/presenters/v3/ErrorsListPresenter.server.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type ErrorsListOptions = {
2222
projectId: string;
2323
// filters
2424
tasks?: string[];
25+
versions?: string[];
2526
period?: string;
2627
from?: number;
2728
to?: number;
@@ -39,6 +40,7 @@ export const ErrorsListOptionsSchema = z.object({
3940
userId: z.string().optional(),
4041
projectId: z.string(),
4142
tasks: z.array(z.string()).optional(),
43+
versions: z.array(z.string()).optional(),
4244
period: z.string().optional(),
4345
from: z.number().int().nonnegative().optional(),
4446
to: z.number().int().nonnegative().optional(),
@@ -123,6 +125,7 @@ export class ErrorsListPresenter extends BasePresenter {
123125
userId,
124126
projectId,
125127
tasks,
128+
versions,
126129
period,
127130
search,
128131
from,
@@ -156,6 +159,7 @@ export class ErrorsListPresenter extends BasePresenter {
156159

157160
const hasFilters =
158161
(tasks !== undefined && tasks.length > 0) ||
162+
(versions !== undefined && versions.length > 0) ||
159163
(search !== undefined && search !== "") ||
160164
!time.isDefault;
161165

@@ -189,6 +193,10 @@ export class ErrorsListPresenter extends BasePresenter {
189193
queryBuilder.where("task_identifier IN {tasks: Array(String)}", { tasks });
190194
}
191195

196+
if (versions && versions.length > 0) {
197+
queryBuilder.where("task_version IN {versions: Array(String)}", { versions });
198+
}
199+
192200
queryBuilder.groupBy("error_fingerprint, task_identifier");
193201

194202
// Text search via HAVING (operates on aggregated values)
@@ -282,6 +290,7 @@ export class ErrorsListPresenter extends BasePresenter {
282290
},
283291
filters: {
284292
tasks,
293+
versions,
285294
search,
286295
period: time,
287296
from: effectiveFrom,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors._index/route.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { TypedAwait, typeddefer, useTypedLoaderData } from "remix-typedjson";
1616
import { PageBody } from "~/components/layout/AppLayout";
1717
import { LogsSearchInput } from "~/components/logs/LogsSearchInput";
1818
import { LogsTaskFilter } from "~/components/logs/LogsTaskFilter";
19+
import { LogsVersionFilter } from "~/components/logs/LogsVersionFilter";
1920
import { Button } from "~/components/primitives/Buttons";
2021
import { Callout } from "~/components/primitives/Callout";
2122
import { formatDateTime, RelativeDateTime } from "~/components/primitives/DateTime";
@@ -80,6 +81,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8081

8182
const url = new URL(request.url);
8283
const tasks = url.searchParams.getAll("tasks").filter((t) => t.length > 0);
84+
const versions = url.searchParams.getAll("versions").filter((v) => v.length > 0);
8385
const search = url.searchParams.get("search") ?? undefined;
8486
const period = url.searchParams.get("period") ?? undefined;
8587
const fromStr = url.searchParams.get("from");
@@ -101,6 +103,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
101103
userId,
102104
projectId: project.id,
103105
tasks: tasks.length > 0 ? tasks : undefined,
106+
versions: versions.length > 0 ? versions : undefined,
104107
search,
105108
period,
106109
from,
@@ -239,6 +242,7 @@ function FiltersBar({
239242
const searchParams = new URLSearchParams(location.search);
240243
const hasFilters =
241244
searchParams.has("tasks") ||
245+
searchParams.has("versions") ||
242246
searchParams.has("search") ||
243247
searchParams.has("period") ||
244248
searchParams.has("from") ||
@@ -250,6 +254,7 @@ function FiltersBar({
250254
{list ? (
251255
<>
252256
<LogsTaskFilter possibleTasks={list.filters.possibleTasks} />
257+
<LogsVersionFilter />
253258
<TimeFilter
254259
defaultPeriod={defaultPeriod}
255260
maxPeriodDays={retentionLimitDays}
@@ -269,6 +274,7 @@ function FiltersBar({
269274
) : (
270275
<>
271276
<LogsTaskFilter possibleTasks={[]} />
277+
<LogsVersionFilter />
272278
<TimeFilter defaultPeriod={defaultPeriod} maxPeriodDays={retentionLimitDays} />
273279
<LogsSearchInput placeholder="Search errors..." />
274280
{hasFilters && (

0 commit comments

Comments
 (0)