Skip to content

Commit ab6731c

Browse files
committed
Improved layout
1 parent 6bfb56b commit ab6731c

File tree

1 file changed

+110
-98
lines changed
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors

1 file changed

+110
-98
lines changed

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

Lines changed: 110 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
2-
import { type MetaFunction, Form, Link } from "@remix-run/react";
2+
import { type MetaFunction, Form, Link, Outlet } from "@remix-run/react";
33
import { XMarkIcon } from "@heroicons/react/20/solid";
44
import { ServiceValidationError } from "~/v3/services/baseService.server";
55
import {
@@ -31,6 +31,18 @@ import { Badge } from "~/components/primitives/Badge";
3131
import { Header1, Header3 } from "~/components/primitives/Headers";
3232
import { formatDistanceToNow } from "date-fns";
3333
import { cn } from "~/utils/cn";
34+
import {
35+
CopyableTableCell,
36+
Table,
37+
TableBlankRow,
38+
TableBody,
39+
TableCell,
40+
TableCellChevron,
41+
TableCellMenu,
42+
TableHeader,
43+
TableHeaderCell,
44+
TableRow,
45+
} from "~/components/primitives/Table";
3446

3547
export const meta: MetaFunction = () => {
3648
return [
@@ -106,75 +118,81 @@ export default function Page() {
106118
useTypedLoaderData<typeof loader>();
107119

108120
return (
109-
<PageContainer>
110-
<NavBar>
111-
<PageTitle title="Errors" />
112-
</NavBar>
121+
<>
122+
<PageContainer>
123+
<NavBar>
124+
<PageTitle title="Errors" />
125+
</NavBar>
113126

114-
<PageBody scrollable={false}>
115-
<Suspense
116-
fallback={
117-
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto] overflow-hidden">
118-
<div className="border-b border-grid-bright" />
119-
<div className="my-2 flex items-center justify-center">
120-
<div className="mx-auto flex items-center gap-2">
121-
<Spinner />
122-
<Paragraph variant="small">Loading errors…</Paragraph>
123-
</div>
124-
</div>
125-
</div>
126-
}
127-
>
128-
<TypedAwait
129-
resolve={data}
130-
errorElement={
131-
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
132-
<FiltersBar defaultPeriod={defaultPeriod} retentionLimitDays={retentionLimitDays} />
133-
<div className="flex items-center justify-center px-3 py-12">
134-
<Callout variant="error" className="max-w-fit">
135-
Unable to load errors. Please refresh the page or try again in a moment.
136-
</Callout>
127+
<PageBody scrollable={false}>
128+
<Suspense
129+
fallback={
130+
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto] overflow-hidden">
131+
<div className="border-b border-grid-bright" />
132+
<div className="my-2 flex items-center justify-center">
133+
<div className="mx-auto flex items-center gap-2">
134+
<Spinner />
135+
<Paragraph variant="small">Loading errors…</Paragraph>
136+
</div>
137137
</div>
138138
</div>
139139
}
140140
>
141-
{(result) => {
142-
// Check if result contains an error
143-
if ("error" in result) {
141+
<TypedAwait
142+
resolve={data}
143+
errorElement={
144+
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
145+
<FiltersBar
146+
defaultPeriod={defaultPeriod}
147+
retentionLimitDays={retentionLimitDays}
148+
/>
149+
<div className="flex items-center justify-center px-3 py-12">
150+
<Callout variant="error" className="max-w-fit">
151+
Unable to load errors. Please refresh the page or try again in a moment.
152+
</Callout>
153+
</div>
154+
</div>
155+
}
156+
>
157+
{(result) => {
158+
// Check if result contains an error
159+
if ("error" in result) {
160+
return (
161+
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
162+
<FiltersBar
163+
defaultPeriod={defaultPeriod}
164+
retentionLimitDays={retentionLimitDays}
165+
/>
166+
<div className="flex items-center justify-center px-3 py-12">
167+
<Callout variant="error" className="max-w-fit">
168+
{result.error}
169+
</Callout>
170+
</div>
171+
</div>
172+
);
173+
}
144174
return (
145-
<div className="grid h-full max-h-full grid-rows-[2.5rem_auto_1fr] overflow-hidden">
175+
<div className="grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden">
146176
<FiltersBar
177+
list={result}
147178
defaultPeriod={defaultPeriod}
148179
retentionLimitDays={retentionLimitDays}
149180
/>
150-
<div className="flex items-center justify-center px-3 py-12">
151-
<Callout variant="error" className="max-w-fit">
152-
{result.error}
153-
</Callout>
154-
</div>
181+
<ErrorsList
182+
errorGroups={result.errorGroups}
183+
organizationSlug={organizationSlug}
184+
projectParam={projectParam}
185+
envParam={envParam}
186+
/>
155187
</div>
156188
);
157-
}
158-
return (
159-
<div className="grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden">
160-
<FiltersBar
161-
list={result}
162-
defaultPeriod={defaultPeriod}
163-
retentionLimitDays={retentionLimitDays}
164-
/>
165-
<ErrorsList
166-
errorGroups={result.errorGroups}
167-
organizationSlug={organizationSlug}
168-
projectParam={projectParam}
169-
envParam={envParam}
170-
/>
171-
</div>
172-
);
173-
}}
174-
</TypedAwait>
175-
</Suspense>
176-
</PageBody>
177-
</PageContainer>
189+
}}
190+
</TypedAwait>
191+
</Suspense>
192+
</PageBody>
193+
</PageContainer>
194+
<Outlet />
195+
</>
178196
);
179197
}
180198

@@ -260,8 +278,19 @@ function ErrorsList({
260278
}
261279

262280
return (
263-
<div className="overflow-y-auto">
264-
<div className="divide-y divide-grid-dimmed">
281+
<Table containerClassName="max-h-full pb-[2.5rem]">
282+
<TableHeader>
283+
<TableRow>
284+
<TableHeaderCell>ID</TableHeaderCell>
285+
<TableHeaderCell>Error</TableHeaderCell>
286+
<TableHeaderCell>Occurrences</TableHeaderCell>
287+
<TableHeaderCell>Tasks</TableHeaderCell>
288+
<TableHeaderCell>First seen</TableHeaderCell>
289+
<TableHeaderCell>Last seen</TableHeaderCell>
290+
<TableHeaderCell hiddenLabel>Go to page</TableHeaderCell>
291+
</TableRow>
292+
</TableHeader>
293+
<TableBody>
265294
{errorGroups.map((errorGroup) => (
266295
<ErrorGroupRow
267296
key={errorGroup.fingerprint}
@@ -271,8 +300,8 @@ function ErrorsList({
271300
envParam={envParam}
272301
/>
273302
))}
274-
</div>
275-
</div>
303+
</TableBody>
304+
</Table>
276305
);
277306
}
278307

@@ -294,42 +323,25 @@ function ErrorGroupRow({
294323
{ fingerprint: errorGroup.fingerprint }
295324
);
296325

326+
const errorMessage = `${errorGroup.errorType}: ${errorGroup.errorMessage}`;
327+
297328
return (
298-
<Link
299-
to={errorPath}
300-
className={cn(
301-
"block px-4 py-3 transition hover:bg-charcoal-800",
302-
"border-l-4 border-transparent hover:border-rose-500"
303-
)}
304-
>
305-
<div className="flex items-start justify-between gap-4">
306-
<div className="min-w-0 flex-1">
307-
<div className="mb-1 flex items-center gap-2">
308-
<Badge variant="default">{errorGroup.errorType}</Badge>
309-
<Paragraph variant="extra-small" className="text-text-dimmed">
310-
{errorGroup.affectedTasks} task{errorGroup.affectedTasks !== 1 ? "s" : ""}
311-
</Paragraph>
312-
</div>
313-
<Paragraph className="mb-2 truncate font-medium">{errorGroup.errorMessage}</Paragraph>
314-
<div className="flex items-center gap-3 text-xs text-text-dimmed">
315-
<span>
316-
First seen: {formatDistanceToNow(errorGroup.firstSeen, { addSuffix: true })}
317-
</span>
318-
<span></span>
319-
<span>Last seen: {formatDistanceToNow(errorGroup.lastSeen, { addSuffix: true })}</span>
320-
<span></span>
321-
<span>Sample: {errorGroup.sampleTaskIdentifier}</span>
322-
</div>
323-
</div>
324-
<div className="flex flex-col items-end gap-1">
325-
<Badge variant="outline-rounded" className="font-mono">
326-
{errorGroup.count.toLocaleString()}
327-
</Badge>
328-
<Paragraph variant="extra-small" className="text-text-dimmed">
329-
occurrences
330-
</Paragraph>
331-
</div>
332-
</div>
333-
</Link>
329+
<TableRow>
330+
<CopyableTableCell to={errorPath} value={errorGroup.fingerprint}>
331+
{errorGroup.fingerprint.slice(-8)}
332+
</CopyableTableCell>
333+
<CopyableTableCell to={errorPath} className="font-mono" value={errorMessage}>
334+
{errorMessage}
335+
</CopyableTableCell>
336+
<TableCell to={errorPath}>{errorGroup.count.toLocaleString()}</TableCell>
337+
<TableCell to={errorPath}>{errorGroup.affectedTasks}</TableCell>
338+
<TableCell to={errorPath}>
339+
{formatDistanceToNow(errorGroup.firstSeen, { addSuffix: true })}
340+
</TableCell>
341+
<TableCell to={errorPath}>
342+
{formatDistanceToNow(errorGroup.lastSeen, { addSuffix: true })}
343+
</TableCell>
344+
<TableCellChevron to={errorPath} isSticky />
345+
</TableRow>
334346
);
335347
}

0 commit comments

Comments
 (0)