Skip to content

Commit f3e0cb8

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/compute-workload-manager
2 parents 5032b7f + 5f359be commit f3e0cb8

File tree

49 files changed

+4750
-75
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4750
-75
lines changed

.changeset/warm-falcons-joke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/build": patch
3+
---
4+
5+
Add syncSupabaseEnvVars to pull database connection strings and save them as trigger.dev environment variables

.server-changes/add-errors-page.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
area: webapp
3+
type: feature
4+
---
5+
6+
A new Errors page for viewing and tracking errors that cause runs to fail
7+
8+
- Errors are grouped using error fingerprinting
9+
- View top errors for a time period, filter by task, or search the text
10+
- View occurrences over time
11+
- View all the runs for an error and bulk replay them

apps/webapp/app/components/BulkActionFilterSummary.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,18 @@ export function BulkActionFilterSummary({
228228
/>
229229
);
230230
}
231+
case "errorId": {
232+
return (
233+
<AppliedFilter
234+
variant="minimal/medium"
235+
key={key}
236+
label={"Error ID"}
237+
icon={filterIcon(key)}
238+
value={value}
239+
removable={false}
240+
/>
241+
);
242+
}
231243
default: {
232244
assertNever(typedKey);
233245
}

apps/webapp/app/components/integrations/VercelBuildSettings.tsx

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Switch } from "~/components/primitives/Switch";
22
import { Label } from "~/components/primitives/Label";
33
import { Hint } from "~/components/primitives/Hint";
44
import { TextLink } from "~/components/primitives/TextLink";
5+
import { SimpleTooltip } from "~/components/primitives/Tooltip";
56
import {
67
EnvironmentIcon,
78
environmentFullTitle,
@@ -18,6 +19,8 @@ type BuildSettingsFieldsProps = {
1819
atomicBuilds: EnvSlug[];
1920
onAtomicBuildsChange: (slugs: EnvSlug[]) => void;
2021
envVarsConfigLink?: string;
22+
/** Slugs that should be forced off and disabled, with tooltip reason. */
23+
disabledEnvSlugs?: Partial<Record<EnvSlug, string>>;
2124
};
2225

2326
export function BuildSettingsFields({
@@ -29,7 +32,11 @@ export function BuildSettingsFields({
2932
atomicBuilds,
3033
onAtomicBuildsChange,
3134
envVarsConfigLink,
35+
disabledEnvSlugs,
3236
}: BuildSettingsFieldsProps) {
37+
const isSlugDisabled = (slug: EnvSlug) => !!disabledEnvSlugs?.[slug];
38+
const enabledSlugs = availableEnvSlugs.filter((s) => !isSlugDisabled(s));
39+
3340
return (
3441
<>
3542
{/* Pull env vars before build */}
@@ -41,11 +48,11 @@ export function BuildSettingsFields({
4148
<Switch
4249
variant="small"
4350
checked={
44-
availableEnvSlugs.length > 0 &&
45-
availableEnvSlugs.every((s) => pullEnvVarsBeforeBuild.includes(s))
51+
enabledSlugs.length > 0 &&
52+
enabledSlugs.every((s) => pullEnvVarsBeforeBuild.includes(s))
4653
}
4754
onCheckedChange={(checked) => {
48-
onPullEnvVarsChange(checked ? [...availableEnvSlugs] : []);
55+
onPullEnvVarsChange(checked ? [...enabledSlugs] : []);
4956
}}
5057
/>
5158
)}
@@ -63,8 +70,13 @@ export function BuildSettingsFields({
6370
<div className="flex flex-col gap-2 rounded border bg-charcoal-800 p-3">
6471
{availableEnvSlugs.map((slug) => {
6572
const envType = envSlugToType(slug);
66-
return (
67-
<div key={slug} className="flex items-center justify-between">
73+
const disabled = isSlugDisabled(slug);
74+
const disabledReason = disabledEnvSlugs?.[slug];
75+
const row = (
76+
<div
77+
key={slug}
78+
className={`flex items-center justify-between ${disabled ? "opacity-50" : ""}`}
79+
>
6880
<div className="flex items-center gap-1.5">
6981
<EnvironmentIcon environment={{ type: envType }} className="size-4" />
7082
<span className={`text-sm ${environmentTextClassName({ type: envType })}`}>
@@ -73,7 +85,8 @@ export function BuildSettingsFields({
7385
</div>
7486
<Switch
7587
variant="small"
76-
checked={pullEnvVarsBeforeBuild.includes(slug)}
88+
checked={disabled ? false : pullEnvVarsBeforeBuild.includes(slug)}
89+
disabled={disabled}
7790
onCheckedChange={(checked) => {
7891
onPullEnvVarsChange(
7992
checked
@@ -84,6 +97,12 @@ export function BuildSettingsFields({
8497
/>
8598
</div>
8699
);
100+
if (disabled && disabledReason) {
101+
return (
102+
<SimpleTooltip key={slug} button={row} content={disabledReason} side="left" />
103+
);
104+
}
105+
return row;
87106
})}
88107
</div>
89108
</div>
@@ -97,17 +116,17 @@ export function BuildSettingsFields({
97116
<Switch
98117
variant="small"
99118
checked={
100-
availableEnvSlugs.length > 0 &&
101-
availableEnvSlugs.every(
119+
enabledSlugs.length > 0 &&
120+
enabledSlugs.every(
102121
(s) => discoverEnvVars.includes(s) || !pullEnvVarsBeforeBuild.includes(s)
103122
) &&
104-
availableEnvSlugs.some((s) => discoverEnvVars.includes(s))
123+
enabledSlugs.some((s) => discoverEnvVars.includes(s))
105124
}
106-
disabled={!availableEnvSlugs.some((s) => pullEnvVarsBeforeBuild.includes(s))}
125+
disabled={!enabledSlugs.some((s) => pullEnvVarsBeforeBuild.includes(s))}
107126
onCheckedChange={(checked) => {
108127
onDiscoverEnvVarsChange(
109128
checked
110-
? availableEnvSlugs.filter((s) => pullEnvVarsBeforeBuild.includes(s))
129+
? enabledSlugs.filter((s) => pullEnvVarsBeforeBuild.includes(s))
111130
: []
112131
);
113132
}}
@@ -122,11 +141,13 @@ export function BuildSettingsFields({
122141
<div className="flex flex-col gap-2 rounded border bg-charcoal-800 p-3">
123142
{availableEnvSlugs.map((slug) => {
124143
const envType = envSlugToType(slug);
144+
const disabled = isSlugDisabled(slug);
145+
const disabledReason = disabledEnvSlugs?.[slug];
125146
const isPullDisabled = !pullEnvVarsBeforeBuild.includes(slug);
126-
return (
147+
const row = (
127148
<div
128149
key={slug}
129-
className={`flex items-center justify-between ${isPullDisabled ? "opacity-50" : ""}`}
150+
className={`flex items-center justify-between ${disabled || isPullDisabled ? "opacity-50" : ""}`}
130151
>
131152
<div className="flex items-center gap-1.5">
132153
<EnvironmentIcon environment={{ type: envType }} className="size-4" />
@@ -136,8 +157,8 @@ export function BuildSettingsFields({
136157
</div>
137158
<Switch
138159
variant="small"
139-
checked={discoverEnvVars.includes(slug)}
140-
disabled={isPullDisabled}
160+
checked={disabled ? false : discoverEnvVars.includes(slug)}
161+
disabled={disabled || isPullDisabled}
141162
onCheckedChange={(checked) => {
142163
onDiscoverEnvVarsChange(
143164
checked
@@ -148,6 +169,12 @@ export function BuildSettingsFields({
148169
/>
149170
</div>
150171
);
172+
if (disabled && disabledReason) {
173+
return (
174+
<SimpleTooltip key={slug} button={row} content={disabledReason} side="left" />
175+
);
176+
}
177+
return row;
151178
})}
152179
</div>
153180
</div>

apps/webapp/app/components/integrations/VercelOnboardingModal.tsx

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { vercelAppInstallPath, v3ProjectSettingsIntegrationsPath, githubAppInsta
4848
import type { loader } from "~/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.vercel";
4949
import { useEffect, useState, useCallback, useRef } from "react";
5050
import { usePostHogTracking } from "~/hooks/usePostHog";
51+
import { TextLink } from "../primitives/TextLink";
5152

5253
function safeRedirectUrl(url: string): string | null {
5354
try {
@@ -224,9 +225,10 @@ export function VercelOnboardingModal({
224225
() => availableEnvSlugsForOnboardingBuildSettings
225226
);
226227

227-
// Sync pullEnvVarsBeforeBuild and discoverEnvVars when hasStagingEnvironment becomes true (once)
228+
// Sync pullEnvVarsBeforeBuild and discoverEnvVars when hasStagingEnvironment becomes true
229+
// AND a custom Vercel environment is mapped (once)
228230
useEffect(() => {
229-
if (hasStagingEnvironment && !hasSyncedStagingRef.current) {
231+
if (hasStagingEnvironment && vercelStagingEnvironment && !hasSyncedStagingRef.current) {
230232
hasSyncedStagingRef.current = true;
231233
setPullEnvVarsBeforeBuild((prev) => {
232234
if (!prev.includes("stg")) {
@@ -241,7 +243,15 @@ export function VercelOnboardingModal({
241243
return prev;
242244
});
243245
}
244-
}, [hasStagingEnvironment]);
246+
}, [hasStagingEnvironment, vercelStagingEnvironment]);
247+
248+
// Strip "stg" from build settings when the staging environment mapping is cleared
249+
useEffect(() => {
250+
if (!vercelStagingEnvironment) {
251+
setPullEnvVarsBeforeBuild((prev) => prev.filter((s) => s !== "stg"));
252+
setDiscoverEnvVars((prev) => prev.filter((s) => s !== "stg"));
253+
}
254+
}, [vercelStagingEnvironment]);
245255

246256
// Sync pullEnvVarsBeforeBuild and discoverEnvVars when hasPreviewEnvironment becomes true (once)
247257
useEffect(() => {
@@ -670,6 +680,11 @@ export function VercelOnboardingModal({
670680
const showBuildSettings = state === "build-settings";
671681
const showGitHubConnection = state === "github-connection";
672682

683+
const disabledEnvSlugsForBuildSettings =
684+
hasStagingEnvironment && !vercelStagingEnvironment
685+
? ({ stg: "Map a custom Vercel environment to Staging to enable this" } as Partial<Record<EnvSlug, string>>)
686+
: undefined;
687+
673688
return (
674689
<Dialog open={isOpen} onOpenChange={(open) => {
675690
if (!open && !fromMarketplaceContext) {
@@ -731,7 +746,7 @@ export function VercelOnboardingModal({
731746
)}
732747

733748
<Hint>
734-
Once connected, your <code className="text-xs">TRIGGER_SECRET_KEY</code> will be
749+
Once connected, your <code className="text-xs rounded bg-charcoal-700 px-1 py-0.5 text-text-bright">TRIGGER_SECRET_KEY</code> will be
735750
automatically synced to Vercel for each environment.
736751
</Hint>
737752

@@ -775,6 +790,10 @@ export function VercelOnboardingModal({
775790
<Paragraph className="text-sm">
776791
Select which custom Vercel environment should map to Trigger.dev's Staging
777792
environment. Production and Preview environments are mapped automatically.
793+
If you skip this step, the{" "}
794+
<code className="rounded bg-charcoal-700 px-1 py-0.5 text-text-bright">TRIGGER_SECRET_KEY</code>{" "}
795+
will not be installed for the staging environment in Vercel. You can configure this later in
796+
project settings.
778797
</Paragraph>
779798

780799
<Select
@@ -800,15 +819,6 @@ export function VercelOnboardingModal({
800819
))}
801820
</Select>
802821

803-
<Callout variant="info">
804-
<p className="text-xs">
805-
If you skip this step, the{" "}
806-
<code className="rounded bg-charcoal-700 px-1 py-0.5 text-text-bright">TRIGGER_SECRET_KEY</code>{" "}
807-
will not be installed for the staging environment in Vercel. You can configure this later in
808-
project settings.
809-
</p>
810-
</Callout>
811-
812822
<Paragraph className="text-xs text-text-dimmed">
813823
Make sure the staging branch in your Vercel project's Git settings matches the staging branch
814824
configured in your GitHub integration.
@@ -845,25 +855,13 @@ export function VercelOnboardingModal({
845855

846856
{showEnvVarSync && (
847857
<div className="flex flex-col gap-4">
848-
<Header3>Pull Environment Variables</Header3>
849-
<Paragraph className="text-sm">
850-
Select which environment variables to pull from Vercel now. This is a one-time pull.
851-
Later on environment variables can be pulled before each build.
852-
</Paragraph>
853-
854-
<div className="flex gap-4 text-sm">
855-
<div className="rounded border bg-charcoal-750 px-3 py-2">
856-
<span className="font-medium text-text-bright">{syncableEnvVars.length}</span>
857-
<span className="text-text-dimmed"> can be pulled</span>
858-
</div>
859-
{secretEnvVars.length > 0 && (
860-
<div className="rounded border bg-charcoal-750 px-3 py-2">
861-
<span className="font-medium text-amber-400">{secretEnvVars.length}</span>
862-
<span className="text-text-dimmed"> secret (cannot pull)</span>
863-
</div>
864-
)}
858+
<div className="flex flex-col gap-1">
859+
<Header3>Pull Environment Variables</Header3>
860+
<Paragraph className="text-sm">
861+
Choose which environment variables to import from Vercel. This runs as a one time pull to prefill your project with the variables it needs. You’ll be able to pull again later, or enable automatic syncing before each build if you prefer.
862+
If you are using Supabase or Neon branching, <TextLink href="https://trigger.dev/docs/vercel-integration#supabase-and-neon-database-branching" target="_blank" rel="noopener noreferrer">read the docs</TextLink> for the recommended setup.
863+
</Paragraph>
865864
</div>
866-
867865
<div className="flex items-center justify-between rounded border bg-charcoal-800 p-3">
868866
<div>
869867
<Label>Pull all environment variables now</Label>
@@ -1052,6 +1050,7 @@ export function VercelOnboardingModal({
10521050
onDiscoverEnvVarsChange={setDiscoverEnvVars}
10531051
atomicBuilds={atomicBuilds}
10541052
onAtomicBuildsChange={setAtomicBuilds}
1053+
disabledEnvSlugs={disabledEnvSlugsForBuildSettings}
10551054
/>
10561055

10571056
<FormButtons

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { motion } from "framer-motion";
33
import { useCallback, useEffect, useRef, useState } from "react";
44
import { Input } from "~/components/primitives/Input";
55
import { ShortcutKey } from "~/components/primitives/ShortcutKey";
6-
import { cn } from "~/utils/cn";
7-
import { useOptimisticLocation } from "~/hooks/useOptimisticLocation";
86
import { useSearchParams } from "~/hooks/useSearchParam";
7+
import { cn } from "~/utils/cn";
8+
9+
export type LogsSearchInputProps = {
10+
placeholder?: string;
11+
};
912

10-
export function LogsSearchInput() {
11-
const location = useOptimisticLocation();
13+
export function LogsSearchInput({ placeholder = "Search logs…" }: LogsSearchInputProps) {
1214
const inputRef = useRef<HTMLInputElement>(null);
1315

1416
const { value, replace, del } = useSearchParams();
@@ -61,7 +63,7 @@ export function LogsSearchInput() {
6163
type="text"
6264
ref={inputRef}
6365
variant="secondary-small"
64-
placeholder="Search logs…"
66+
placeholder={placeholder}
6567
value={text}
6668
onChange={(e) => setText(e.target.value)}
6769
fullWidth

apps/webapp/app/components/navigation/SideMenu.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
Squares2X2Icon,
2525
TableCellsIcon,
2626
UsersIcon,
27+
BugAntIcon,
2728
} from "@heroicons/react/20/solid";
2829
import { Link, useFetcher, useNavigation } from "@remix-run/react";
2930
import { LayoutGroup, motion } from "framer-motion";
@@ -73,6 +74,7 @@ import {
7374
v3EnvironmentPath,
7475
v3EnvironmentVariablesPath,
7576
v3LogsPath,
77+
v3ErrorsPath,
7678
v3ProjectAlertsPath,
7779
v3ProjectPath,
7880
v3ProjectSettingsGeneralPath,
@@ -112,6 +114,7 @@ import { SideMenuHeader } from "./SideMenuHeader";
112114
import { SideMenuItem } from "./SideMenuItem";
113115
import { SideMenuSection } from "./SideMenuSection";
114116
import { type SideMenuSectionId } from "./sideMenuTypes";
117+
import { IconBugFilled } from "@tabler/icons-react";
115118

116119
/** Get the collapsed state for a specific side menu section from user preferences */
117120
function getSectionCollapsed(
@@ -474,6 +477,17 @@ export function SideMenu({
474477
isCollapsed={isCollapsed}
475478
/>
476479
)}
480+
{(user.admin || user.isImpersonating) && (
481+
<SideMenuItem
482+
name="Errors"
483+
icon={IconBugFilled}
484+
activeIconColor="text-amber-500"
485+
inactiveIconColor="text-amber-500"
486+
to={v3ErrorsPath(organization, project, environment)}
487+
data-action="errors"
488+
isCollapsed={isCollapsed}
489+
/>
490+
)}
477491
<SideMenuItem
478492
name="Query"
479493
icon={TableCellsIcon}

0 commit comments

Comments
 (0)