Oskar Otwinowski 4c16387426 fix(webapp): project integrations page — Staging gating, unreachable code, and follow-ups (#4784)
Three bugs on the project integrations page, one commit each for the two
reported ones and four for the follow-ups found while fixing them.

## `chore`: remove unreachable code on the integrations page (TRI-12645)

Two notification panels in `VercelSettingsPanel` could never render:

1. The **"Failed to load Vercel settings"** panel was gated on a
`hasError` state whose setter is never called anywhere, so it was
permanently `false`.
2. The **"connection expired"** banner *inside* the `connectedProject`
branch was unreachable: `VercelSettingsPresenter` only populates
`connectedProject` on its success exit, which hardcodes `authInvalid:
false`, while both `authInvalid: true` exits return `connectedProject:
undefined`.

Removing them makes the surrounding `!showAuthInvalid` guards vacuous,
and the `onboardingData?.authInvalid` disjunct redundant — the loader
already folds onboarding auth state into `authInvalid` before it reaches
the component.

**No behaviour change.** An org with a connected project and an expired
token still gets the banner, from the branch below (untouched).

## `fix`: gate Staging settings on plans without a Staging environment
(TRI-12646)

The ticket's premise was inverted, and I've corrected it there. In Git
settings, **Preview** is the row that's correctly gated; **Staging** is
the one with no gate at all:

- Preview swaps its switch for an Upgrade button, and
`projectSettings.server.ts` neutralises a forged
`previewDeploymentsEnabled=on`.
- Staging was a plain always-editable `Input`, and
`validateStagingBranch` only checked the branch existed on GitHub. An
org without a staging environment could type a tracking branch, hit
Save, get a success toast, and have it silently do nothing.

Staging and Preview environments are created together for projects on a
plan that includes them, so gating one and not the other was an
oversight.

The Staging row now mirrors the Preview row. Server-side it ignores the
submitted branch when there's no staging environment, but **preserves
the stored branch rather than clearing it** — deliberately different
from the Preview handling. Forcing a boolean off is harmless; forcing a
*string* off would wipe a tracking branch the org had already configured
the first time they saved after losing the environment.

The Vercel write path had the same gap: `update-config` /
`complete-onboarding` / `update-env-mapping` never re-derived available
env slugs server-side, so `["stg","preview"]` could be persisted for a
project with neither environment, and
`createDefaultVercelIntegrationData` turned preview on unconditionally.
Both now filter against the project's actual environments, via a pure
`restrictConfigToAvailableEnvSlugs` helper that only touches keys
present on the input.

## `fix`: show build settings when the GitHub app is disabled
(TRI-13488)

The page wrapped Git settings, the Vercel section **and** build settings
in one `githubAppEnabled` guard, so with the GitHub app off it rendered
an empty container.

The Vercel section genuinely depends on GitHub — it can't sync
environment variables or link deployments without a connected repo — so
it stays gated. Build settings don't: they also apply to CLI deploys run
with `--native-build-server`, exactly as the section's own description
states. They now render regardless.

## `fix`: stop the Vercel onboarding modal spinning forever (TRI-13488)

`computeInitialState` starts in `loading-projects` whenever the org has
a Vercel integration but no onboarding data yet, and the effect that
escapes it waits for `availableProjects !== undefined`. When
`getOnboardingData` returns `null` — it does that on any thrown error,
and when the org integration row is missing — nothing ever arrives.

The empty-array case self-resolves (`[] !== undefined`), so this is
specifically the null case. The route can tell "still loading" from
"loaded nothing" because its fetcher always requests
`?vercelOnboarding=true`; it now passes that down and the modal explains
the failure with a retry and a link to check the integration's access on
Vercel.

## `fix`: match staging and preview environments consistently
(TRI-13488)

The four places that ask "does this project have a staging / preview
environment?" disagreed. `VercelSettingsPresenter` matched on type with
no parent filter, so any preview *branch* row satisfied it — branches
are `PREVIEW` rows too. `GitHubSettingsPresenter` and
`ProjectSettingsService` matched on slug instead.

Slug is the weaker key: it's derived at creation time and legacy rows
can carry something else, which is why
`memberDevelopmentEnvironmentWhere` deliberately avoids it. All four now
match on `type` plus `parentEnvironmentId: null`, which excludes
branches without depending on the slug being canonical.

## `fix`: explain when no Vercel environment can be mapped to Staging
(TRI-13488)

Reported while reviewing the branch. The Staging build settings show
*"Set a Vercel environment for Staging first."* whenever the project has
a staging environment and no mapping — but the control that sets the
mapping only rendered when the Vercel project had at least one custom
environment:

```
hint:     hasStagingEnvironment && !configValues.vercelStagingEnvironment
control:  hasStagingEnvironment && customEnvironments.length > 0
```

So a Vercel project with no custom environments, or one whose custom
environments failed to fetch (the presenter swallows that error to
`[]`), got an instruction with nothing to act on. Both conditions
predate this PR.

The mapping row now always renders alongside the hint and explains what
to do when there's nothing to choose from, and the build-settings hint
says the same thing.

## `chore`: remove the remaining dead code (TRI-13488)

- The `"installing"` `OnboardingState` is unproducible — no `setState`
call yields it — so its redirect effect, switch arm, `isLoadingState`
conjunct and the `vercelAppInstallPath` import it was the only user of
are all dead.
- `(state as string) !== "completed"` sits in a branch where TypeScript
has already narrowed `"completed"` out; the cast is what let it compile.
- `hideSectionToggles` was only ever passed alongside
`layout="settings"` but only read inside `layout="card"` blocks, so it
could never take effect. Removed the prop entirely.
- Unused bindings and the helpers only they referenced: `envSlugLabel`,
`_formatSelectedEnvs`, `_CompleteOnboardingForm`,
`_handleFinishOnboarding`, and the rest.

No behaviour change in that commit.

## Not included

The three overlapping modal-open effects in
`settings.integrations/route.tsx` are left alone — they're defensive
against a close-then-reopen race, and untangling them is a behavioural
risk with no user-visible payoff.

## Verification

`pnpm run typecheck --filter webapp`, `pnpm run lint` and `pnpm run
knip` are clean. New `apps/webapp/test/vercelIntegrationConfig.test.ts`
covers the slug restriction and the default-config seeding (both pure
functions); 39 tests pass across it and the three existing
Vercel/project-settings files.

The new `projectId` + `slug` query is served by the existing
`@@unique([projectId, slug, orgMemberId])` prefix — same access pattern
as the preview check it mirrors.

refs TRI-12645, TRI-12646, TRI-13488
2026-08-26 13:26:44 +00:00
2025-08-27 16:52:58 +01:00
2026-08-18 14:59:46 +01:00
2025-12-23 18:37:19 +00:00
2026-07-08 17:23:18 +01:00

Trigger.dev logo

Build and deploy fullymanaged AI agents and workflows

Website | Docs | Issues | Example projects | Feature requests | Public roadmap | Self-hosting

Open Source License npm SDK downloads

Twitter Follow Discord Ask DeepWiki GitHub stars

About Trigger.dev

Trigger.dev is the open-source platform for building AI workflows in TypeScript. Long-running tasks with retries, queues, observability, and elastic scaling.

The platform designed for building AI agents

Build AI agents using all the frameworks, services and LLMs you're used to, deploy them to Trigger.dev and get durable, long-running tasks with retries, queues, observability, and elastic scaling out of the box.

  • Long-running without timeouts: Execute your tasks with absolutely no timeouts, unlike AWS Lambda, Vercel, and other serverless platforms.

  • Durability, retries & queues: Build rock solid agents and AI applications using our durable tasks, retries, queues and idempotency.

  • True runtime freedom: Customize your deployed tasks with system packages run browsers, Python scripts, FFmpeg and more.

  • Human-in-the-loop: Programmatically pause your tasks until a human can approve, reject or give feedback.

  • Realtime apps & streaming: Move your background jobs to the foreground by subscribing to runs or streaming AI responses to your app.

  • Observability & monitoring: Each run has full tracing and logs. Configure error alerts to catch bugs fast.

Key features:

  • JavaScript and TypeScript SDK - Build background tasks using familiar programming models
  • Long-running tasks - Handle resource-heavy tasks without timeouts
  • Durable cron schedules - Create and attach recurring schedules of up to a year
  • Trigger.dev Realtime - Trigger, subscribe to, and get real-time updates for runs, with LLM streaming support
  • Build extensions - Hook directly into the build system and customize the build process. Run Python scripts, FFmpeg, browsers, and more.
  • React hooks - Interact with the Trigger.dev API on your frontend using our React hooks package
  • Batch triggering - Use batchTrigger() to initiate multiple runs of a task with custom payloads and options
  • Structured inputs / outputs - Define precise data schemas for your tasks with runtime payload validation
  • Waits - Add waits to your tasks to pause execution for a specified duration
  • Preview branches - Create isolated environments for testing and development. Integrates with Vercel and git workflows
  • Waitpoints - Add human-in-the-loop judgment at critical decision points without disrupting workflow
  • Concurrency & queues - Set concurrency rules to manage how multiple tasks execute
  • Multiple environments - Support for DEV, PREVIEW, STAGING, and PROD environments
  • No infrastructure to manage - Auto-scaling infrastructure that eliminates timeouts and server management
  • Automatic retries - If your task encounters an uncaught error, we automatically attempt to run it again
  • Checkpointing - Tasks are inherently durable, thanks to our checkpointing feature
  • Versioning - Atomic versioning allows you to deploy new versions without affecting running tasks
  • Machines - Configure the number of vCPUs and GBs of RAM you want the task to use
  • Observability & monitoring - Monitor every aspect of your tasks' performance with comprehensive logging and visualization tools
  • Logging & tracing - Comprehensive logging and tracing for all your tasks
  • Tags - Attach up to ten tags to each run, allowing you to filter via the dashboard, realtime, and the SDK
  • Run metadata - Attach metadata to runs which updates as the run progresses and is available to use in your frontend for live updates
  • Bulk actions - Perform actions on multiple runs simultaneously, including replaying and cancelling
  • Real-time alerts - Choose your preferred notification method for run failures and deployments

Write tasks in your codebase

Create tasks where they belong: in your codebase. Version control, localhost, test and review like you're already used to.

import { task } from "@trigger.dev/sdk";

//1. You need to export each task
export const helloWorld = task({
  //2. Use a unique id for each task
  id: "hello-world",
  //3. The run function is the main function of the task
  run: async (payload: { message: string }) => {
    //4. You can write code that runs for a long time here, there are no timeouts
    console.log(payload.message);
  },
});

Deployment

Use our SDK to write tasks in your codebase. There's no infrastructure to manage, your tasks automatically scale and connect to our cloud. Or you can always self-host.

Environments

We support Development, Staging, Preview, and Production environments, allowing you to test your tasks before deploying them to production.

Full visibility of every job run

View every task in every run so you can tell exactly what happened. We provide a full trace view of every task run so you can see what happened at every step.

Trace view image

Getting started

The quickest way to get started is to create an account and project in our web app, and follow the instructions in the onboarding. Build and deploy your first task in minutes.

Self-hosting

If you prefer to self-host Trigger.dev, you can follow our self-hosting guides:

Support and community

We have a large active community in our official Discord server for support, including a dedicated channel for self-hosting.

Development

To setup and develop locally or contribute to the open source project, follow our development guide.

Meet the Amazing People Behind This Project:

S
Description
Trigger.dev 支持构建和部署完全托管的 AI Agent 与工作流。|GitHub 镜像 16.2k · 🍴 1.4k
https://github.com/triggerdotdev/trigger.dev Readme Apache-2.0 196 MiB
Languages
TypeScript 99.1%
JavaScript 0.4%
Shell 0.2%
CSS 0.1%