Skip to content

Commit ba2e20f

Browse files
kathiekiwiTrigger.dev RepoOps
authored andcommitted
feat(alerts): Errors alerts V1 on the query binding
Error alerts: get notified about new errors or when a specific error occurs again. Mono-RevId: b52375263891c777aeecb7aa23446af1acd42c66
1 parent 4e7dee6 commit ba2e20f

14 files changed

Lines changed: 3303 additions & 147 deletions

File tree

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

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { Button, LinkButton } from "~/components/primitives/Buttons";
4040
import { Callout } from "~/components/primitives/Callout";
4141
import { formatDateTime, RelativeDateTime } from "~/components/primitives/DateTime";
4242
import { Header3 } from "~/components/primitives/Headers";
43-
import { NavBar, PageTitle } from "~/components/primitives/PageHeader";
43+
import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/PageHeader";
4444
import { Paragraph } from "~/components/primitives/Paragraph";
4545
import { PopoverSectionHeader } from "~/components/primitives/Popover";
4646
import { SearchInput } from "~/components/primitives/SearchInput";
@@ -67,10 +67,15 @@ import { SimpleTooltip } from "~/components/primitives/Tooltip";
6767
import TooltipPortal from "~/components/primitives/TooltipPortal";
6868
import { appliedSummary, FilterMenuProvider, TimeFilter } from "~/components/runs/v3/SharedFilters";
6969
import { $replica } from "~/db.server";
70+
import { useEnvironment } from "~/hooks/useEnvironment";
71+
import { useOrganization } from "~/hooks/useOrganizations";
72+
import { useProject } from "~/hooks/useProject";
73+
import { CreateAlertButton } from "~/components/alerts/CreateAlertButton";
74+
import { NEW_ERROR_ALERT_PREFILL } from "~/components/alerts/errorAlertPrefill";
7075
import { useInterval } from "~/hooks/useInterval";
7176
import { useOptimisticLocation } from "~/hooks/useOptimisticLocation";
7277
import { useSearchParams } from "~/hooks/useSearchParam";
73-
import { findProjectBySlug } from "~/models/project.server";
78+
import { findProjectWithOrgFlagsBySlug } from "~/models/project.server";
7479
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
7580
import {
7681
ErrorsListPresenter,
@@ -84,6 +89,7 @@ import { getCurrentPlan } from "~/services/platform.v3.server";
8489
import { requireUser } from "~/services/session.server";
8590
import { formatNumberCompact } from "~/utils/numberFormatter";
8691
import { EnvironmentParamSchema, v3ErrorPath } from "~/utils/pathBuilder";
92+
import { canUseAlertsList } from "~/v3/canUseAlertsList.server";
8793
import { ServiceValidationError } from "~/v3/services/baseService.server";
8894
import { errorsAgentPageContext } from "~/components/dashboard-agent/suggested-prompts";
8995
import type { Handle } from "~/utils/handle";
@@ -101,7 +107,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
101107

102108
const { projectParam, organizationSlug, envParam } = EnvironmentParamSchema.parse(params);
103109

104-
const project = await findProjectBySlug(organizationSlug, projectParam, userId);
110+
const project = await findProjectWithOrgFlagsBySlug(organizationSlug, projectParam, userId);
105111
if (!project) {
106112
throw new Response("Project not found", { status: 404 });
107113
}
@@ -130,6 +136,11 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
130136
const direction =
131137
directionRaw === "forward" || directionRaw === "backward" ? directionRaw : undefined;
132138

139+
const alertsEnabled = await canUseAlertsList({
140+
orgFeatureFlags: (project.organization.featureFlags as Record<string, unknown>) ?? {},
141+
userId,
142+
});
143+
133144
const plan = await getCurrentPlan(project.organizationId);
134145
const retentionLimitDays = plan?.v3Subscription?.plan?.limits.logRetentionDays.number ?? 30;
135146

@@ -181,6 +192,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
181192
occurrences: occurrencesPromise,
182193
defaultPeriod: "1d",
183194
retentionLimitDays,
195+
alertsEnabled,
184196
organizationSlug,
185197
projectParam,
186198
envParam,
@@ -193,6 +205,7 @@ export default function Page() {
193205
occurrences,
194206
defaultPeriod,
195207
retentionLimitDays,
208+
alertsEnabled,
196209
organizationSlug,
197210
projectParam,
198211
envParam,
@@ -209,17 +222,31 @@ export default function Page() {
209222
}, [revalidator]),
210223
});
211224

225+
const organization = useOrganization();
226+
const project = useProject();
227+
const environment = useEnvironment();
212228
const location = useOptimisticLocation();
213229
const alertsHref = useMemo(() => {
230+
if (alertsEnabled) return undefined;
214231
const params = new URLSearchParams(location.search);
215232
params.set("alerts", "true");
216233
return `?${params.toString()}`;
217-
}, [location.search]);
234+
}, [alertsEnabled, location.search]);
218235

219236
return (
220237
<>
221238
<NavBar>
222239
<PageTitle title="Errors" />
240+
{alertsEnabled ? (
241+
<PageAccessories>
242+
<CreateAlertButton
243+
organization={organization}
244+
project={project}
245+
environment={environment}
246+
prefill={NEW_ERROR_ALERT_PREFILL}
247+
/>
248+
</PageAccessories>
249+
) : null}
223250
</NavBar>
224251

225252
<PageBody scrollable={false}>
@@ -417,7 +444,7 @@ function FiltersBar({
417444
list?: ErrorsListData;
418445
defaultPeriod?: string;
419446
retentionLimitDays: number;
420-
alertsHref: string;
447+
alertsHref?: string;
421448
}) {
422449
const location = useOptimisticLocation();
423450
const searchParams = new URLSearchParams(location.search);
@@ -483,16 +510,18 @@ function FiltersBar({
483510
)}
484511
</div>
485512
<div className="flex shrink-0 items-center gap-1.5">
486-
<LinkButton
487-
to={alertsHref}
488-
variant="secondary/small"
489-
LeadingIcon={BellAlertIcon}
490-
leadingIconClassName="text-alerts"
491-
shortcut={alertsShortcut}
492-
tooltip="Configure alerts"
493-
>
494-
Configure alerts…
495-
</LinkButton>
513+
{alertsHref ? (
514+
<LinkButton
515+
to={alertsHref}
516+
variant="secondary/small"
517+
LeadingIcon={BellAlertIcon}
518+
leadingIconClassName="text-alerts"
519+
shortcut={alertsShortcut}
520+
tooltip="Configure alerts"
521+
>
522+
Configure alerts…
523+
</LinkButton>
524+
) : null}
496525
{list && <ListPagination list={list} />}
497526
</div>
498527
</div>

0 commit comments

Comments
 (0)