chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:32:57 +08:00
commit cd420f9332
4811 changed files with 884702 additions and 0 deletions
@@ -0,0 +1,369 @@
import { getFormProps, getInputProps, useForm } from "@conform-to/react";
import { parseWithZod } from "@conform-to/zod";
import {
EnvelopeIcon,
GlobeAltIcon,
HashtagIcon,
LockClosedIcon,
XMarkIcon,
} from "@heroicons/react/20/solid";
import { BellAlertIcon } from "@heroicons/react/24/solid";
import { useFetcher, useNavigate } from "@remix-run/react";
import { SlackIcon } from "@trigger.dev/companyicons";
import { Fragment, useEffect, useRef, useState } from "react";
import { z } from "zod";
import { ExitIcon } from "~/assets/icons/ExitIcon";
import { InlineCode } from "~/components/code/InlineCode";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Callout, variantClasses } from "~/components/primitives/Callout";
import { Fieldset } from "~/components/primitives/Fieldset";
import { FormError } from "~/components/primitives/FormError";
import { Header2, Header3 } from "~/components/primitives/Headers";
import { Hint } from "~/components/primitives/Hint";
import { Input } from "~/components/primitives/Input";
import { InputGroup } from "~/components/primitives/InputGroup";
import { Select, SelectItem } from "~/components/primitives/Select";
import { TextLink } from "~/components/primitives/TextLink";
import { useToast } from "~/components/primitives/Toast";
import { UnorderedList } from "~/components/primitives/UnorderedList";
import { useOptimisticLocation } from "~/hooks/useOptimisticLocation";
import { useOrganization } from "~/hooks/useOrganizations";
import type { ErrorAlertChannelData } from "~/presenters/v3/ErrorAlertChannelPresenter.server";
import { cn } from "~/utils/cn";
import { organizationSlackIntegrationPath } from "~/utils/pathBuilder";
export const ErrorAlertsFormSchema = z.object({
emails: z.preprocess((i) => {
if (typeof i === "string") return i === "" ? [] : [i];
if (Array.isArray(i)) return i.filter((v) => typeof v === "string" && v !== "");
return [];
}, z.string().email().array()),
slackChannel: z.string().optional(),
slackIntegrationId: z.string().optional(),
webhooks: z.preprocess((i) => {
if (typeof i === "string") return i === "" ? [] : [i];
if (Array.isArray(i)) return i.filter((v) => typeof v === "string" && v !== "");
return [];
}, z.string().url().array()),
});
type ConfigureErrorAlertsProps = ErrorAlertChannelData & {
connectToSlackHref?: string;
formAction: string;
};
export function ConfigureErrorAlerts({
emails: existingEmails,
webhooks: existingWebhooks,
slackChannel: existingSlackChannel,
slack,
emailAlertsEnabled,
connectToSlackHref,
formAction,
}: ConfigureErrorAlertsProps) {
const organization = useOrganization();
const fetcher = useFetcher<{ ok?: boolean }>();
const navigate = useNavigate();
const toast = useToast();
const location = useOptimisticLocation();
const isSubmitting = fetcher.state !== "idle";
const [selectedSlackChannelValue, setSelectedSlackChannelValue] = useState<string | undefined>(
existingSlackChannel
? `${existingSlackChannel.channelId}/${existingSlackChannel.channelName}`
: undefined
);
const selectedSlackChannel =
slack.status === "READY"
? slack.channels?.find((s) => selectedSlackChannelValue === `${s.id}/${s.name}`)
: undefined;
const closeHref = (() => {
const params = new URLSearchParams(location.search);
params.delete("alerts");
const qs = params.toString();
return qs ? `?${qs}` : location.pathname;
})();
const hasHandledSuccess = useRef(false);
useEffect(() => {
if (fetcher.state === "idle" && fetcher.data?.ok && !hasHandledSuccess.current) {
hasHandledSuccess.current = true;
toast.success("Alert settings saved");
navigate(closeHref, { replace: true });
}
}, [fetcher.state, fetcher.data, closeHref, navigate, toast]);
const emailFieldValues = useRef<string[]>(
existingEmails.length > 0 ? [...existingEmails.map((e) => e.email), ""] : [""]
);
const webhookFieldValues = useRef<string[]>(
existingWebhooks.length > 0 ? [...existingWebhooks.map((w) => w.url), ""] : [""]
);
const [form, fields] = useForm<z.infer<typeof ErrorAlertsFormSchema>>({
id: "configure-error-alerts",
onValidate({ formData }) {
return parseWithZod(formData, { schema: ErrorAlertsFormSchema });
},
shouldRevalidate: "onSubmit",
defaultValue: {
emails: emailFieldValues.current,
webhooks: webhookFieldValues.current,
},
});
const { emails, webhooks, slackChannel, slackIntegrationId } = fields;
const emailFields = emails.getFieldList();
const webhookFields = webhooks.getFieldList();
return (
<div className="grid h-full grid-rows-[auto_1fr_auto] overflow-hidden">
<div className="flex items-center justify-between border-b border-grid-bright px-3 py-2">
<Header2 className="flex items-center gap-2">
<BellAlertIcon className="size-5 text-alerts" /> Configure alerts
</Header2>
<LinkButton
to={closeHref}
variant="minimal/small"
TrailingIcon={ExitIcon}
shortcut={{ key: "esc" }}
shortcutPosition="before-trailing-icon"
className="pl-1"
/>
</div>
<fetcher.Form method="post" action={formAction} {...getFormProps(form)} className="contents">
<div className="flex-1 overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
<Fieldset className="flex flex-col gap-4 p-4">
<div className="flex flex-col">
<Header3>Receive alerts when</Header3>
<UnorderedList variant="small/dimmed" className="mt-1">
<li>An error is seen for the first time</li>
<li>A resolved error re-occurs</li>
<li>An ignored error re-occurs based on settings you configured</li>
</UnorderedList>
</div>
{/* Email section */}
<div>
<Header3 className="mb-1">Email</Header3>
{emailAlertsEnabled ? (
<InputGroup>
{emailFields.map((emailField, index) => (
<Fragment key={emailField.key}>
<Input
{...getInputProps(emailField, { type: "email" })}
placeholder={index === 0 ? "Enter an email address" : "Add another email"}
icon={EnvelopeIcon}
onChange={(e) => {
emailFieldValues.current[index] = e.target.value;
if (
emailFields.length === emailFieldValues.current.length &&
emailFieldValues.current.every((v) => v !== "")
) {
form.insert({ name: emails.name });
}
}}
/>
<FormError id={emailField.errorId}>{emailField.errors}</FormError>
</Fragment>
))}
</InputGroup>
) : (
<Callout variant="warning">
Email integration is not available. Please contact your organization
administrator.
</Callout>
)}
</div>
{/* Slack section */}
<div>
<Header3 className="mb-1">Slack</Header3>
<InputGroup fullWidth>
{slack.status === "READY" ? (
<>
<Select
name={slackChannel.name}
placeholder={<span className="text-text-dimmed">Select a Slack channel</span>}
heading="Filter channels…"
value={selectedSlackChannelValue ?? ""}
dropdownIcon
variant="tertiary/medium"
items={slack.channels}
setValue={(value) => {
typeof value === "string" && setSelectedSlackChannelValue(value);
}}
filter={(channel, search) =>
channel.name?.toLowerCase().includes(search.toLowerCase()) ?? false
}
text={(value) => {
const channel = slack.channels.find((s) => value === `${s.id}/${s.name}`);
if (!channel) return;
return (
<span className="text-text-bright">
<SlackChannelTitle {...channel} />
</span>
);
}}
>
{(matches) => (
<>
<SelectItem
value=""
className="border-b border-grid-bright text-text-dimmed"
>
<div className="flex items-center gap-1.5">
<XMarkIcon className="size-4" />
<span>No channel</span>
</div>
</SelectItem>
{matches?.map((channel) => (
<SelectItem
key={channel.id}
value={`${channel.id}/${channel.name}`}
className="text-text-bright"
>
<SlackChannelTitle {...channel} />
</SelectItem>
))}
</>
)}
</Select>
{selectedSlackChannel && selectedSlackChannel.is_private && (
<Callout
variant="warning"
className={cn("text-sm", variantClasses.warning.textColor)}
>
To receive alerts in the{" "}
<InlineCode variant="extra-small">{selectedSlackChannel.name}</InlineCode>{" "}
channel, you need to invite the @Trigger.dev Slack Bot. Go to the channel in
Slack and type:{" "}
<InlineCode variant="extra-small">/invite @Trigger.dev</InlineCode>.
</Callout>
)}
<Hint>
<TextLink to={organizationSlackIntegrationPath(organization)}>
Manage Slack connection
</TextLink>
</Hint>
<input
type="hidden"
name={slackIntegrationId.name}
value={slack.integrationId}
/>
</>
) : slack.status === "NOT_CONFIGURED" ? (
connectToSlackHref ? (
<LinkButton variant="tertiary/medium" to={connectToSlackHref} fullWidth>
<span className="flex items-center gap-2 text-text-bright">
<SlackIcon className="size-5" /> Connect to Slack
</span>
</LinkButton>
) : (
<Callout variant="info">
Slack is not connected. Connect Slack from the{" "}
<span className="font-medium text-text-bright">Alerts</span> page to enable
Slack notifications.
</Callout>
)
) : slack.status === "TOKEN_REVOKED" || slack.status === "TOKEN_EXPIRED" ? (
connectToSlackHref ? (
<div className="flex flex-col gap-4">
<Callout variant="info">
The Slack integration in your workspace has been revoked or has expired.
Please re-connect your Slack workspace.
</Callout>
<LinkButton
variant="tertiary/large"
to={`${connectToSlackHref}?reinstall=true`}
fullWidth
>
<span className="flex items-center gap-2 text-text-bright">
<SlackIcon className="size-5" /> Connect to Slack
</span>
</LinkButton>
</div>
) : (
<Callout variant="info">
The Slack integration in your workspace has been revoked or expired. Please
re-connect from the{" "}
<span className="font-medium text-text-bright">Alerts</span> page.
</Callout>
)
) : slack.status === "FAILED_FETCHING_CHANNELS" ? (
<Callout variant="warning">
Failed loading channels from Slack. Please try again later.
</Callout>
) : (
<Callout variant="warning">
Slack integration is not available. Please contact your organization
administrator.
</Callout>
)}
</InputGroup>
</div>
{/* Webhook section */}
<div>
<Header3 className="mb-1">Webhook</Header3>
<InputGroup>
{webhookFields.map((webhookField, index) => (
<Fragment key={webhookField.key}>
<Input
{...getInputProps(webhookField, { type: "url" })}
placeholder={
index === 0 ? "https://example.com/webhook" : "Add another webhook URL"
}
icon={GlobeAltIcon}
onChange={(e) => {
webhookFieldValues.current[index] = e.target.value;
if (
webhookFields.length === webhookFieldValues.current.length &&
webhookFieldValues.current.every((v) => v !== "")
) {
form.insert({ name: webhooks.name });
}
}}
/>
<FormError id={webhookField.errorId}>{webhookField.errors}</FormError>
</Fragment>
))}
<Hint>We'll issue POST requests to these URLs with a JSON payload.</Hint>
</InputGroup>
</div>
<FormError>{form.errors}</FormError>
</Fieldset>
</div>
<div className="flex items-center justify-between border-t border-grid-bright px-3 py-3">
<LinkButton variant="secondary/medium" to={closeHref}>
Cancel
</LinkButton>
<Button
variant="primary/medium"
type="submit"
disabled={isSubmitting}
isLoading={isSubmitting}
>
{isSubmitting ? "Saving…" : "Save"}
</Button>
</div>
</fetcher.Form>
</div>
);
}
function SlackChannelTitle({ name, is_private }: { name?: string; is_private?: boolean }) {
return (
<div className="flex items-center gap-1.5">
{is_private ? <LockClosedIcon className="size-4" /> : <HashtagIcon className="size-4" />}
<span>{name}</span>
</div>
);
}
@@ -0,0 +1,34 @@
import { type ErrorGroupStatus } from "@trigger.dev/database";
import { cn } from "~/utils/cn";
const styles: Record<ErrorGroupStatus, string> = {
UNRESOLVED: "bg-error/10 text-error",
RESOLVED: "bg-success/10 text-success",
IGNORED: "bg-blue-500/10 text-blue-400",
};
const labels: Record<ErrorGroupStatus, string> = {
UNRESOLVED: "Unresolved",
RESOLVED: "Resolved",
IGNORED: "Ignored",
};
export function ErrorStatusBadge({
status,
className,
}: {
status: ErrorGroupStatus;
className?: string;
}) {
return (
<span
className={cn(
"inline-flex items-center rounded px-2 py-0.5 text-xs font-medium",
styles[status],
className
)}
>
{labels[status]}
</span>
);
}
@@ -0,0 +1,250 @@
import { CheckIcon } from "@heroicons/react/20/solid";
import {
IconAlarmSnooze as IconAlarmSnoozeBase,
IconArrowBackUp as IconArrowBackUpBase,
IconBugOff as IconBugOffBase,
} from "@tabler/icons-react";
import { useEffect, useRef, useState } from "react";
import { type ErrorGroupStatus } from "@trigger.dev/database";
import { useFetcher } from "@remix-run/react";
import { Button } from "~/components/primitives/Buttons";
import { useToast } from "~/components/primitives/Toast";
import { FormError } from "~/components/primitives/FormError";
import { Input } from "~/components/primitives/Input";
import { InputGroup } from "~/components/primitives/InputGroup";
import { Label } from "~/components/primitives/Label";
import { PopoverMenuItem } from "~/components/primitives/Popover";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from "~/components/primitives/Dialog";
const AlarmSnoozeIcon = ({ className }: { className?: string }) => (
<IconAlarmSnoozeBase className={className} size={18} />
);
const ArrowBackUpIcon = ({ className }: { className?: string }) => (
<IconArrowBackUpBase className={className} size={18} />
);
const BugOffIcon = ({ className }: { className?: string }) => (
<IconBugOffBase className={className} size={18} />
);
export function statusActionToastMessage(data: Record<string, string>): string {
switch (data.action) {
case "resolve":
return "Error marked as resolved";
case "unresolve":
return "Error marked as unresolved";
case "ignore": {
const duration = data.duration ? Number(data.duration) : undefined;
if (!duration) return "Error ignored indefinitely";
const hours = duration / (60 * 60 * 1000);
if (hours < 24) return `Error ignored for ${hours} ${hours === 1 ? "hour" : "hours"}`;
const days = hours / 24;
return `Error ignored for ${days} ${days === 1 ? "day" : "days"}`;
}
default:
return "Error status updated";
}
}
export function ErrorStatusMenuItems({
status,
taskIdentifier,
onAction,
onCustomIgnore,
}: {
status: ErrorGroupStatus;
taskIdentifier: string;
onAction: (data: Record<string, string>) => void;
onCustomIgnore: () => void;
}) {
return (
<>
{status === "UNRESOLVED" && (
<>
<PopoverMenuItem
icon={CheckIcon}
leadingIconClassName="text-success"
title="Resolved"
onClick={() => onAction({ taskIdentifier, action: "resolve" })}
/>
<PopoverMenuItem
icon={AlarmSnoozeIcon}
leadingIconClassName="text-blue-500"
title="Ignored for 1 hour"
onClick={() =>
onAction({
taskIdentifier,
action: "ignore",
duration: String(60 * 60 * 1000),
})
}
/>
<PopoverMenuItem
icon={AlarmSnoozeIcon}
leadingIconClassName="text-blue-500"
title="Ignored for 24 hours"
onClick={() =>
onAction({
taskIdentifier,
action: "ignore",
duration: String(24 * 60 * 60 * 1000),
})
}
/>
<PopoverMenuItem
icon={BugOffIcon}
leadingIconClassName="text-blue-500"
title="Ignored forever"
onClick={() => onAction({ taskIdentifier, action: "ignore" })}
/>
<PopoverMenuItem
icon={AlarmSnoozeIcon}
leadingIconClassName="text-blue-500"
title="Ignored with custom condition…"
onClick={onCustomIgnore}
/>
</>
)}
{status === "IGNORED" && (
<>
<PopoverMenuItem
icon={CheckIcon}
leadingIconClassName="text-success"
title="Resolved"
onClick={() => onAction({ taskIdentifier, action: "resolve" })}
/>
<PopoverMenuItem
icon={ArrowBackUpIcon}
leadingIconClassName="text-error"
title="Unresolved"
onClick={() => onAction({ taskIdentifier, action: "unresolve" })}
/>
</>
)}
{status === "RESOLVED" && (
<PopoverMenuItem
icon={ArrowBackUpIcon}
leadingIconClassName="text-error"
title="Unresolved"
onClick={() => onAction({ taskIdentifier, action: "unresolve" })}
/>
)}
</>
);
}
export function CustomIgnoreDialog({
open,
onOpenChange,
taskIdentifier,
formAction,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
taskIdentifier: string;
formAction?: string;
}) {
const fetcher = useFetcher<{ ok?: boolean }>();
const isSubmitting = fetcher.state !== "idle";
const [conditionError, setConditionError] = useState<string | null>(null);
const toast = useToast();
const hasHandledSuccess = useRef(false);
useEffect(() => {
if (fetcher.state === "idle" && fetcher.data?.ok && !hasHandledSuccess.current) {
hasHandledSuccess.current = true;
toast.success("Error ignored with custom condition");
onOpenChange(false);
}
}, [fetcher.state, fetcher.data, onOpenChange, toast]);
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-1.5">
<IconAlarmSnoozeBase className="-ml-1.5 size-6 text-blue-500" />
Custom ignore condition
</DialogTitle>
</DialogHeader>
<fetcher.Form
method="post"
action={formAction}
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const rate = formData.get("occurrenceRate")?.toString().trim();
const total = formData.get("totalOccurrences")?.toString().trim();
if (!rate && !total) {
setConditionError("At least one unignore condition is required");
return;
}
setConditionError(null);
hasHandledSuccess.current = false;
fetcher.submit(e.currentTarget, { method: "post", action: formAction });
}}
>
<input type="hidden" name="action" value="ignore" />
<input type="hidden" name="taskIdentifier" value={taskIdentifier} />
<div className="flex flex-col gap-4 py-4">
<InputGroup fullWidth>
<Label htmlFor="occurrenceRate" variant="small">
Unignore when occurrence rate exceeds (per minute)
</Label>
<Input
id="occurrenceRate"
name="occurrenceRate"
type="number"
min={1}
placeholder="e.g. 10"
onChange={() => conditionError && setConditionError(null)}
/>
</InputGroup>
<InputGroup fullWidth>
<Label htmlFor="totalOccurrences" variant="small">
Unignore when total occurrences exceed
</Label>
<Input
id="totalOccurrences"
name="totalOccurrences"
type="number"
min={1}
placeholder="e.g. 100"
onChange={() => conditionError && setConditionError(null)}
/>
</InputGroup>
{conditionError && <FormError>{conditionError}</FormError>}
<InputGroup fullWidth>
<Label htmlFor="reason" variant="small" required={false}>
Reason
</Label>
<Input id="reason" name="reason" type="text" placeholder="e.g. Known flaky test" />
</InputGroup>
</div>
<DialogFooter>
<Button variant="tertiary/medium" type="button" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button variant="primary/medium" type="submit" disabled={isSubmitting}>
{isSubmitting ? "Ignoring…" : "Ignore error"}
</Button>
</DialogFooter>
</fetcher.Form>
</DialogContent>
</Dialog>
);
}