fix/changeset-release-server-changes
524 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bb450e608d |
feat(webapp): SSO & Directory Sync settings UI improvements (#4196)
📚 Publish docs / publish (push) Has been cancelled
## Summary UI/layout/copy pass over the org **SSO & Directory Sync** settings page (formerly "Identity & Access"). No logic, gates, flags, or data flow changed — server-side auth (`manage:sso`), Enterprise entitlement, action validation, and data loading are all untouched. - Renamed the nav item, page title, and meta from "Identity & Access" to "SSO & Directory Sync". - Added a reusable `SettingsLayout` component system (container, section, header, row, block, actions) modeled on `/account/security`, and refactored the SSO page onto it (section titles, dividers, left title/subtitle + right action rows). - Tightened all UI copy: concise, active voice, consistent labels, no em-dashes. - `Select` primitive: additive `wrap`, `popoverClassName`, and `placement` props (all default to prior behavior) so role options show a bright title with a wrapping description, right-aligned popover, and no horizontal overflow. - Removed the external-link arrow icon from buttons that open a modal; kept it only on genuinely external actions (Contact us, Open in new tab). - Polished the admin portal link dialog: smaller description, tighter spacing, `ClipboardField` with a permanent copy button, removed the redundant Copy link button, and a provider-aware Open label (e.g. "Open in WorkOS") derived from the link host with a safe fallback. ### SSO page UI <img width="3568" height="2550" alt="CleanShot 2026-07-08 at 18 52 11@2x" src="https://github.com/user-attachments/assets/009d2437-7552-4ff0-a457-64744a9fcd88" /> ### Login with SSO and normal email test (local) https://github.com/user-attachments/assets/b33a4ce9-c1fa-45c9-bd3c-077cb6fc9473 ## Test plan - [ ] Non-Enterprise org: SSO page shows the upsell state - [ ] Enterprise org, non-Owner without `manage:sso`: 403 - [ ] Enterprise Owner: verify domains, configure SSO, connect directory, JIT/default/group role selects, and enforcement toggle all work - [ ] Role select popovers: bright title + wrapping description, right-aligned, no horizontal scroll - [ ] Admin portal dialog: copy button works, "Open in WorkOS" opens the portal in a new tab --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
6e827f1da3 |
chore: Tailwind CSS v4 migration (#4139)
Migrates the webapp from Tailwind CSS 3.4 to 4.x. |
||
|
|
6563793132 |
fix(webapp): dashboard timezone display + preference persistence (#4104)
## Summary
Two related timezone bugs in the dashboard.
1. The date/time tooltip could show a UTC offset label that contradicted
the time it displayed. A viewer whose machine clock differs from their
saved timezone (or when a date falls in the other DST phase) would see
something like `Local (UTC +0)` next to a value that isn't at +0.
2. A user's timezone preference silently failed to save whenever their
browser reported a zone like `UTC`, `Etc/UTC`, or `Asia/Kolkata`,
leaving their timestamps stuck in a previously-saved timezone.
## Offset label
The "Local" row formatted its time using the viewer's configured
timezone but computed the `(UTC +n)` label from `new
Date().getTimezoneOffset()`, the browser's offset at the current moment.
Those are two independent sources, so they disagreed when the configured
timezone differed from the machine, and also when the displayed date was
in the opposite DST phase. The label is now derived from the same date
and timezone used to render the row (via `Intl.DateTimeFormat` with
`timeZoneName: "longOffset"`), so it always matches the displayed time.
## Preference persistence
`/resources/timezone` validated the incoming zone against
`Intl.supportedValuesOf("timeZone")`, which lists only canonical zone
ids. Browsers report zones that aren't in that list via
`resolvedOptions().timeZone`, notably `UTC` (and `Etc/UTC`,
`Asia/Kolkata`, `GMT`), so those requests returned 400 and the
preference was never stored. Validation now checks whether the runtime
can resolve the zone at all, which accepts every real zone and still
rejects invalid input.
Added unit tests for both.
|
||
|
|
c7861be520 |
chore: activate no-unused-vars and import linters (#4096)
Once this is merged, oxlint is at a pretty sensible baseline. **Enable `no-unused-vars`, `typescript/consistent-type-imports`, and `import/no-duplicates` lint rules** Turns on three previously-disabled oxlint rules across the monorepo and fixes all violations: - **`no-unused-vars`** – enabled as an error with standard ignore patterns: unused function arguments are ignored by default (`args: "none"`), variables/caught errors/destructured array elements prefixed with `_` are allowed, and rest siblings are permitted. - **`typescript/consistent-type-imports`** – enforced as an error; all type-only imports now use the `import type` syntax. - **`import/no-duplicates`** – enforced as an error; duplicate import statements from the same module have been merged. The remaining commits clean up the violations found across the codebase: removing unused variables/imports/type aliases, adding `_` prefixes to intentionally unused bindings, fixing duplicate imports, and converting value imports to `import type` where appropriate. |
||
|
|
bfa902bd18 |
chore: enable more linters (#4080)
Re-enables ~15 oxlint rules that were blanket-disabled before. |
||
|
|
b2b4c510e2 |
feat(webapp): improve task and dashboard activity charts (#4064)
## Summary Improves and unifies the run-activity charts by extracting a shared set of chart primitives and adopting them on the three task landing pages (agent, standard, scheduled), with the density and label fixes also carried over to the dashboard and custom query charts. Main changes a reviewer should know about: - **Shared primitives (DRY).** New `ChartCard` (title + maximize/fullscreen), `ChartSyncContext` (cross-chart hover + zoom state), `useXAxisTicks` (width-aware tick selection), `activityTimeAxis`, and `statusColors`, plus a server-side `activitySeries.server.ts` holding `chooseBucketSeconds`, status grouping, and the zero-fill helpers. The three task routes and both presenters were refactored onto these, removing roughly 3x duplicated tick logic, status-color tables, and bucket-ladder code. - **Denser bars on short ranges.** Server-side bucketing now uses `chooseBucketSeconds` (nice-interval ladder, ~72 target, capped at 120 buckets) instead of the hardcoded 1h/6h/1d ladder, so a 5m or 1h range no longer collapses into a single bar. - **Width-aware x-axis labels.** Labels are selected to fit the measured plot width (always first + last, evenly spaced, de-duplicated by rendered text), stay horizontal, and reflow on panel/window resize. Y-axis values default to compact form (8K, 1.2M) in `ChartBar`/`ChartLine`. - **Synced hover line.** Hovering one of the agent page's three charts draws a dashed vertical line at the same bucket on the *other* two, and suppresses it on the hovered chart. It is opt-in via `ChartSyncProvider`, so single-chart pages are unaffected. - **Maximize button.** Each chart gets a fullscreen dialog toggle (reuses the existing dashboard-widget pattern, `v` shortcut while hovered). - **Drag-to-zoom on task pages.** Dragging across a task chart sets the Time/Date filter (`from`/`to` URL params, clearing `period`/`cursor`), with a From/To tooltip shown during the drag. - **Custom query charts.** Long categorical x labels (run IDs, task names) middle-truncate and auto-rotate only when needed, and label thinning is now width-aware for both bar and line variants. Dashboard line-chart label density is also width-aware, tuned by a `TIME_AXIS_LABEL_SPACING_PX` constant. - **Tests.** 46 new unit tests for the pure logic (bucket selection, tick spacing, time-axis formatting, zoom range, truncation). ## Intentionally unchanged - **No click/drag zoom on the dashboard or custom query charts.** Drag-to-zoom is wired up on the task landing pages only; zooming the dashboard and custom charts is deliberately deferred to a separate follow-up PR. A plain click (without a drag) on a task chart is a no-op. - **The 25 mini activity charts on the Task list (`_index`) page are untouched.** They are hand-rolled raw-Recharts sparklines kept deliberately lightweight and do not use these primitives. - **Other raw-Recharts sparklines are untouched** (the usage sparkline, errors and prompts pages). - **No ClickHouse query semantics changed** beyond the bucket-interval parameter (same filters, same FINAL / `_is_deleted` handling). - **Webapp-only.** No public package (`packages/*`) changes, so there is no changeset; the `.server-changes/` entries cover it. --- ## Testing Added 46 unit tests covering server-side bucket selection, width-aware tick spacing, time-axis formatting, zoom-range math, and categorical label truncation (`pnpm --filter webapp run test`), and `pnpm run typecheck --filter webapp` passes. Manually exercised each task landing page (agent, standard, scheduled) plus the dashboard and custom query charts, stepping the Date/Time filter through 5m, 1h, 24h, 7d, and 30d to confirm dense bars on short ranges, non-overlapping labels that reflow on resize, the synced hover line across the agent charts, the maximize button, and drag-to-zoom updating the filter. --- ## Changelog The activity charts on the task landing pages and the dashboard and custom query charts now share one set of reusable primitives. X-axis labels are width-aware so they never overlap and reflow when a panel resizes, y-axis values are abbreviated (8K, 1.2M), and short time ranges render dense bars instead of collapsing into a single bar. Hovering any agent chart mirrors a vertical line on the others, every chart gains a maximize button, and dragging across a task chart zooms the Time/Date filter. Long categorical labels such as run IDs and task names middle-truncate and auto-rotate only when needed. --- https://github.com/user-attachments/assets/6be09e38-3a0e-4947-b6e3-4839daa2fbe0 |
||
|
|
b1987dc090 |
feat(webapp): billing limits — pause, reject, recovery, and settings UI (#3996)
## Summary Adds Billing Limits to the webapp. Customers can set a monthly spend cap. When usage crosses the limit, billable environments enter a grace period. If the limit is not resolved before grace expires, new triggers are rejected until the organization increases or removes the limit. |
||
|
|
4fde283e76 |
chore: format and lint webapp also (#4056)
#3977 added formatting and linting everywhere else. This extends it to the webapp. |
||
|
|
63bbea0d96 |
feat(webapp): move the in-dashboard agent launcher into the page header (#4053)
<img width="2400" height="1794" alt="chat-ui-closed" src="https://github.com/user-attachments/assets/35016a72-c6d2-4b6a-8760-b1da5b4a166c" /> <img width="2400" height="1794" alt="chat-ui-open" src="https://github.com/user-attachments/assets/25b3df60-9aa2-40fd-a1ba-1447eeee4c52" /> ## Summary The in-dashboard agent was launched from a button pinned to the bottom-right of every page, which floated over page controls (for example the run inspector's action bar). It now opens from a compact "Chat" button on the far right of the page header, and the same button toggles to "Collapse" while the panel is open. The panel and launcher are labelled "Chat" in the UI. The launcher only renders on env-scoped pages where the agent is enabled (same feature flag gating), so it stays hidden for everyone who doesn't have it. The existing "Ask AI" support button is untouched; it stays in place until the agent is turned on by default. ## How it works `DashboardAgent` (env layout) shares the open/close state through a small context, and `NavBar` renders a launcher that self-hides whenever that context is absent. No floating overlay, and the launcher can't appear on pages where the agent can't open. |
||
|
|
5740955357 |
feat(webapp): enforce RBAC permissions on run, prompt, member, and billing routes (#3948)
## Summary Several dashboard routes performed actions a restricted role should not be able to do (cancel or replay runs, manage prompt versions, invite and manage members, manage billing) without any permission check. This adds role-based permission enforcement to those routes, and disables the matching UI controls (with a tooltip) when the current role lacks permission. Covered actions: - Runs: cancel and replay (single, bulk create, bulk abort) - Prompts: create or edit override versions, and promote a version to current - Members: invite, resend invite, revoke invite - Billing: change plan, billing alerts, and the customer portal ## How Each affected route now goes through the `dashboardLoader` / `dashboardAction` route builders with an `authorization` block declaring the required permission (or a per-intent check where one route handles several intents). Existing tenancy and data-scoping queries are untouched; this only layers permission checks on top. The UI follows disable-don't-hide: controls stay visible but disabled with a "You don't have permission to ..." tooltip. Two reusable pieces support this: `checkPermissions(ability, checks)` turns a set of checks into a boolean map a loader returns to the client, and `PermissionButton` / `PermissionLink` disable the underlying control and show a tooltip when a permission flag is false. ## Behaviour No change in the default configuration: permissions are permissive, so every control stays enabled and every route behaves as before. The checks only take effect when an RBAC plugin is installed. This also makes role assignment on invite-accept non-fatal, so a failure there cannot block joining an org. Verified with `pnpm run typecheck --filter webapp`; `checkPermissions` has unit tests. |
||
|
|
5f2d437eb5 |
fix(webapp): Fix for task page search bar re-rendering bug (#3971)
## Summary Typing in the search bar on the task page could clear or reset the input mid-keystroke. This fixes the re-render race so the field stays stable while you type. ## Root cause Two things compounded: - `SearchInput`'s sync effect depended on `text`, so it re-ran on every keystroke and could overwrite the input with the URL/controlled value while focused. - Each task row unmounted and remounted its activity chart during the side-panel open/close animation (25 charts at once), forcing heavy re-renders that the search effect raced against. ## Fix - `SearchInput` now tracks the last synced value in a ref instead of comparing against `text`, keeping the effect off the keystroke path. It only writes to state when the incoming URL/controlled value actually changes, and never while the input is focused. - Activity charts are now hidden (`hidden` attribute) instead of unmounted during the panel animation, so the rows don't churn the tree and the resize stays smooth. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
07a0e4ade9 |
feat(webapp): split Models into Your models and Model library tabs (#3958)
## Summary The Models page is now split into two tabs. **Your models** shows the models your project has actually used in the selected time range, with usage charts (cost over time, tokens over time, calls by model), a per-model table of calls / cost / avg TTFC / avg tokens-per-sec, and calls/tokens trend sparklines. **Model library** is the full catalog, reordered from alphabetical to a relevance-based provider order (Anthropic, OpenAI, Google, then the rest), newest models first within each provider, with a "New" badge on models released in the last 7 days. One time-range selector drives the whole Your models tab, so the charts, the table, and the sparklines all share the same window. Opening a model shows its own metrics with an independent range picker and a "View in AI metrics" link that opens the AI metrics dashboard filtered to that model. The active tab is kept in the URL so it survives a refresh and is shareable. ## Prompt caching & cost accuracy Both the Your models tab and the AI metrics dashboard now surface prompt-cache usage: a cache-savings column plus per-model cached-tokens and cache-hit-rate views, and a caching section on the dashboard (hit rate, cached tokens, estimated savings, and hit rate by model). Building this surfaced a cost bug. `input_tokens` is the total prompt count and already includes cache-read and cache-creation tokens, but the cost pipeline charged the full input at the input price and then added a separate cache line, so cached tokens were billed twice (and on Anthropic, cache reads were never discounted because their price is keyed differently). The input price now applies only to the non-cached remainder, with cache prices resolved across the provider-specific keys, so LLM cost and the cache hit-rate metric are accurate. Hit rate is computed as cached reads over total input. ## Notes Also fixes React "invalid DOM property" console warnings from the provider icons (the Llama and DeepSeek SVGs used raw `fill-rule` / `clip-rule` / `clip-path` attributes), which this page surfaces by rendering more provider icons. ## Screenshots **Your models tab:** usage charts and a per-model table with calls/tokens trend sparklines. <img width="2560" height="1267" alt="1-your-models-tab" src="https://github.com/user-attachments/assets/859bd24f-9047-4828-8bbb-83e5882846d6" /> **Model library:** provider-relevance ordering with a "New" badge on models released in the last 7 days. <img width="2560" height="1267" alt="2-model-library-tab" src="https://github.com/user-attachments/assets/46dd54b9-80f9-4922-ade9-5935b08dfebc" /> **Model detail, Metrics tab:** per-model range picker and a "View in AI metrics" link. <img width="2560" height="1267" alt="3-model-detail-metrics" src="https://github.com/user-attachments/assets/0f65d9d0-6142-4918-93f0-110bb277101a" /> **View in AI metrics:** the dashboard deep-linked and filtered to the selected model. <img width="2560" height="1267" alt="4-ai-metrics-filtered" src="https://github.com/user-attachments/assets/821f256c-e305-493c-98c7-eafaf2f57f83" /> |
||
|
|
af526dea18 |
feat(webapp): chat AI UI improvements, new task landing pages and side menu (#3941)
Major dashboard restructure plus the new task landing pages and self-serve schedules add-on integration. ## Side menu - Full restructure: standalone Tasks / Runs / Sessions block at the top; new collapsible sections for AI, Observability, Deployments, Manage - Persisted collapse state per section in `dashboardPreferences` - New / updated icons across the menu - Dashboards section: built-in Run metrics + AI metrics + custom dashboards, with drag-to-reorder via ReactGridLayout (`DashboardList.tsx`) - DevPresence connection indicator in the env selector (DEV + V2) ## Tasks (`_index` — unified Tasks page) - Replaces the separated Agents / Standard / Schedules listing pages with one table - New `UnifiedTaskListPresenter` composes `TaskListPresenter` + `AgentListPresenter` (shared `currentWorker` lookup) - Columns: Type (with kind badge), ID, File, Running (numeric for tasks; running + suspended pills for agents), Activity (24h stacked-by-status), sticky menu - Search + "Task type" multi-select filter (URL-synced) - Client-side pagination at 25/page - Right-hand "useful links" panel (cookie-persisted state) - Live-reload SSE: page revalidates on `WORKER_CREATED` so onboarding `trigger dev` flips the blank state automatically ## Agent landing page (`/agents/$agentParam`) - New per-agent detail page - Top tabs (Sessions / Runs) toggle both the chart panel and the table - Three dashboard-style chart cards: Sessions/Runs activity, LLM spend, Tokens - `AgentDetailPresenter` queries ClickHouse for run activity, session activity (with FINAL on `sessions_v1`), and LLM cost/token activity from `llm_metrics_v1` - TimeFilter at the top drives all three charts - Sticky table header, resizable horizontal handle, sidebar with Test agent button + properties - Docs link → `ai-chat/overview` ## Standard Task landing page (`/tasks/standard/$taskParam`) - New per-task detail page mirroring the Agent layout - `TaskDetailPresenter` for activity + properties - Chart panel wrapped in a Card with "Runs by status" header - Top bar with title, TimeFilter, pagination - Right sidebar: Test task + identifier, queue, machine, retry, TTL, payload schema, etc. ## Scheduled Task landing page (`/tasks/scheduled/$taskParam`) - New per-task detail page mirroring the Agent / Standard layout - Top-bar actions (right → left): pagination, Bulk replay…, View all runs, TimeFilter, Create schedule - Connected schedules mini-table in the sidebar - **Self-serve schedules add-on integration** (reincarnated from the now-removed `/schedules` listing page during the `origin/main` merge): - Bottom usage bar pinned via `grid-rows-[auto_1fr_auto]` — progress ring + "X/Y of your schedules" + Purchase / Upgrade / Request CTA - At-limit "Create schedule" intercept dialog - `PurchaseSchedulesModal` extracted as a shared component (`apps/webapp/app/components/schedules/PurchaseSchedulesModal.tsx`) handling increase / decrease / above-quota / need-to-delete states - New resource action route at `/resources/orgs/$organizationSlug/schedules-addon` ## Sessions - Index page: list, filters, blank state, help tooltip rework - Detail page: combined input/output chronological view (replaces split tabs) - Improved raw-message view layout (full-height) - AI payload UI: `data-*` parts grouped under "AI SDK data parts:" label - `toSafeUrl` helper guards rendered URLs from streamed content - Fix: duplicate assistant content on inspector tab switch ## Playground (Test agent) - Restructured top menu; back button + agent-selector popover - Improved blank state - Recent agent chat history moved into the tabbed menu - Better message-scroll container (full height) ## Dashboards - New Dashboards landing page (`/dashboards`) — Run metrics, AI metrics, Create your own CTAs - `BuiltInDashboards` updated; new `TasksDashboardPresenter` for the tasks overview - Custom dashboards section gains drag-to-reorder; cosmetic fix for active-row drag-handle blending ## PageHeader / shared primitives - `PageTitle` gains an `accessory` prop supporting string (auto-wrapped in tooltip) and ReactNode - Help tooltips on Tasks, Runs, Sessions PageTitles explaining the concept and sub-categories - `Card` primitive used for dashboard-style chart panels throughout ## Code review fixes (last batch on this branch) - ClickHouse activity queries hardened: `FINAL` + `_is_deleted = 0` on `task_runs_v2` (ReplacingMergeTree); `organization_id` + `project_id` filters for sort-key prefix; `inserted_at` partition filter on `llm_metrics_v1` - `UnifiedTaskListPresenter`: shared `currentWorker` lookup; slug-collision guard in `mergeRunningStates`; off-by-one fixed in 24h bucket alignment - `ScheduleListPresenter`: halved platform RPCs by deriving limit from `currentPlan` instead of calling `getLimit` - Sessions detail: stopped IntersectionObserver / scroll listener re-attach on every chunk; `requestAnimationFrame` deferral on auto-scroll to avoid virtualizer race - URL hardening: `?types=` validated against known kinds; new `parseFiniteInt` helper applied to `from`/`to`/`page` params - AgentView: HITL resolution buffer now cleared once parts reach a terminal state (was an unbounded Map on long sessions); subscription effect deps documented with eslint suppression - `PurchaseSchedulesModal`: bundle state resets on each open instead of persisting stale drafts ## Manual testing Manual smoke-test plan is tracked under [TRI-10883](https://linear.app/triggerdotdev/issue/TRI-10883), broken into 20 sub-issues covering onboarding, self-serve schedules, side menu, the four landing pages, sessions, runs, dashboards, regressions and performance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
85d93ffe0e |
perf(webapp): skip queue search count (#3925)
### Summary Queue searches previously executed both a count query and a page query with identical filters. This PR switches filtered searches to `hasMore` pagination, removing the extra count query while preserving existing search behavior. ### Testing cd apps/webapp && pnpm run test ./test/queueListSearch.test.ts --run passes ### Changelog Improve filtered queue search performance. |
||
|
|
187c0476c3 |
perf(webapp): shrink run trace loader payload and add trace span cap controls (#3906)
## Summary The run trace page loader serialized every span's raw OTel events (with full properties) into the response, even though the tree UI only renders the derived `timelineEvents` and the span detail panel refetches what it needs. On event-heavy traces that inflated both the loader payload and the server-side heap copies built per request. This PR keeps raw span events server-side and pairs that with a few related trace-view improvements: - A new optional `TRACE_VIEW_EMERGENCY_SPAN_CAP` env var (unset by default) clamps the trace summary and detailed trace summary span limits on both event store paths, including the public run trace endpoint, so operators can bound trace query sizes in one place without retuning the per-store limits. - The TreeView virtualizer resolved every rendered row with a linear scan over the whole tree (and `getNodeProps` did the same via `findIndex`); rows now resolve through memoized id lookup maps, which matters once traces reach tens of thousands of spans. - The run stream SSE lookup now applies the same organization membership scoping as the rest of the run page presenters, for consistency. Behavior is unchanged by default: the trace tree renders from the same `timelineEvents` it always has, and the new cap only takes effect when set. |
||
|
|
cae3dcb7dd |
Env vars page performance fix (#3829)
## Summary This PR improves performance across the Environment Variables page. ## Changes ### Targeted value loading - load only the non-secret (environmentId, key) pairs required by the page. Secret values continue to be redacted in the UI. ### SSR windowing + virtualization - SSR-render only the first 50 rows - hydrate those rows - virtualize the remaining dataset client-side - search is now URL-driven during SSR, ensuring deep links such as `?search=DATABASE_URL` ### Lightweight 'Create' flow - 'Create' page no longer loads the full Environment Variables dataset. ## Results Large projects no longer render thousands of rows during SSR. Example (~11k rendered rows): Metric | Before | After -- | -- | -- Document size | ~150 MB | ~5 MB SSR rows | ~11k | 50 Browser DOM rows | Thousands | ~26–38 |
||
|
|
4f8cf4cc63 |
feat(webapp): runs live updating
## Summary The Runs list now updates live without requiring a page refresh. Status changes and other run fields are updated in place while runs are executing. When new runs matching the current filters are created, a "New runs created" refresh button appears above the list. Root runs now show a live child-run status breakdown directly in the status tooltip. ### List live update - Visible runs update in place while they are still running. - A "New runs created" refresh button appears when new matching runs are detected. - Polling stops when all visible runs have finished and a refresh button is already shown. - Polling pauses when the browser tab is not visible. - Runs list status updates and new-run detection share a single runs/live polling path. ### Child-status tooltip - Root run tooltips now display a breakdown of child run statuses. - Child statuses are loaded when the tooltip opens (after a 400ms hover delay). - The tooltip stays up to date while child runs are still changing state. - Handles cases where child runs continue running after their parent run has completed, or have not yet been created. ### Supporting changes - Added hidden-tab awareness to polling. - Added safeguards around polling inputs (`runIds` deduping and limits). ## Test plan - [x] pnpm run typecheck --filter webapp passes - [x] cd apps/webapp && pnpm run test ./test/presenters/mapRunToLiveFields.test.ts --run passes - [x] cd apps/webapp && pnpm run test ./test/runsRepository.part2.test.ts --run -t "hasNewRuns" passes ### Manual smoke: - [x] Active runs update without a page refresh. - [x] A new matching run shows the refresh banner and the banner actions work as expected. - [x] Root run tooltips show live child-status updates and stop polling once child runs settle. --------- Co-authored-by: Ekaterina Bulatova <kathiekiwi@Ekaterinas-MacBook-Pro.local> |
||
|
|
e4981d1b11 |
feat(webapp): consolidate auth path + add comprehensive auth tests (#3499)
## Summary
Consolidates the webapp's authentication and authorization into a small
set of route helpers, replacing the ad-hoc `requireUser` /
`requireUserId` / `authenticatedEnvironmentForAuthentication` calls
scattered across routes. Same security model, but the per-request flow
(authenticate → authorize → load) now lives in one place per route
family.
Introduces a plugin seam (`@trigger.dev/plugins`) that lets the cloud
build install a richer RBAC implementation without touching webapp code.
The OSS fallback keeps the pre-RBAC permissive behaviour intact, so
self-hosted deployments work unchanged.
Adds a comprehensive end-to-end auth test suite that didn't exist before
— 193 `it()` blocks (vitest reports ~199 after `it.each` expansion)
covering API key, PAT and JWT auth across the public API surface, plus
dashboard session auth for admin pages.
## Changes
### Plugin contract — `@trigger.dev/plugins`
`RoleBaseAccessController` interface authoritative for both OSS
(fallback) and cloud (enterprise plugin):
- `authenticateBearer(request, { allowJWT? })` — API-key / public-JWT
auth, returns env + ability
- `authenticateSession(request, { userId, organizationId?, projectId?
})` — dashboard auth, caller resolves `userId` from the session cookie
and passes it in (no `helpers.getSessionUserId` callback — decouples the
plugin host from session-cookie code)
- `authenticatePat(request, { organizationId?, projectId? })` — PAT
auth, returns identity + `lastAccessedAt` so the host can throttle the
per-request update
- `authenticateAuthorize*` variants for the auth-and-check-in-one-call
cases
- `isUsingPlugin(): Promise<boolean>` — capability flag for UI /
branching where plugin-present-ness matters; replaces the
sentinel-string coupling that had `personalAccessToken.server` matching
`"RBAC plugin not installed"` literally
### Dashboard auth (started, partial rollout)
Admin and settings pages migrated to a unified `dashboardLoader` /
`dashboardAction` helper that authenticates the session, runs an
authorization check, and exposes the result to the route. Other
dashboard routes still on the old pattern; remaining migration tracked
in TRI-8730.
Migrated routes:
- `admin.*` (14 admin / back-office / feature-flags / LLM-models /
notifications / orgs / concurrency pages)
- `_app.orgs.$organizationSlug.settings.team`
- `_app.orgs.$organizationSlug.settings.roles`
### API / realtime / engine auth (complete for the migrated families)
71 routes migrated to a unified `apiBuilder` that centralizes Bearer /
PAT / Public-JWT authentication and applies the per-route authorization
check before the handler runs. Includes:
- `api.v1.*` and `api.v2.*` and `api.v3.*` — tasks, runs, batches,
queues, prompts, deployments, query, sessions, waitpoints, packets,
workers, idempotency keys
- `realtime.v1.*` — runs, batches, sessions, streams
- `engine.v1.*` — dev / worker-action protocols
29 routes still on the legacy `authenticateApiRequest*` helpers —
tracked as a post-deploy follow-up in TRI-9228.
Multi-resource auth direction is now explicit at the call site via
`anyResource(...)` (OR) and `everyResource(...)` (AND). Bare arrays no
longer typecheck — fixes a class of bug where a JWT scoped to one
resource could implicitly access others under OR semantics.
PAT auth path consolidated: was three DB queries per request (legacy
`authenticateApiRequestWithPersonalAccessToken` findFirst +
`rbac.authenticatePat` join + `lastAccessedAt` update). Now one query in
the steady state — plugin returns `lastAccessedAt`, host smart-skips the
update via JS-side throttle when fresh.
Side effect: action aliases preserved historic JWT scope semantics where
the new model is stricter (e.g. a `write:tasks` JWT now also satisfies
`trigger` / `batchTrigger` / `update` actions on the same resource —
matched at the auth boundary, not in the route handler).
### Backwards-compat fixes
The strict-match model regressed several real-world JWT shapes. Each
preserved via explicit `anyResource(...)` entries in the route's authz
block:
- **Batch retrieve routes** (`api.v1.batches.$batchId`, `api.v2.*`,
`realtime.v1.batches.*`) accept `read:runs` JWTs again (pre-RBAC
literal-match superScope behaviour)
- **Runs list routes** (`api.v1.runs`, `realtime.v1.runs`) accept
type-level `read:tasks` / `read:tags` on unfiltered queries (matched the
legacy `Object.keys` iteration semantic)
- **PAT/OAT auth shape** normalized through `toAuthenticated` so all
auth methods return the same slim `AuthenticatedEnvironment` (was:
API-key returned the slim shape but PAT/OAT returned raw Prisma
`Decimal` / no `orgMember`)
- **Scope `:` preservation** in resource ids — `read:tags:env:staging`
now correctly identifies the tag id as `env:staging`, not `env`
### Slim `AuthenticatedEnvironment`
Extracted to `@trigger.dev/core/v3/auth/environment` — a structural
shape independent of `@trigger.dev/database`. The plugin contract
returns this; webapp consumers import from there; the cloud plugin
(Drizzle) returns the same shape without Prisma's `Decimal` class
leaking into the public surface. Lets internal-packages (run-engine,
etc.) refer to `AuthenticatedEnvironment` without pulling Prisma in.
### Auth test suite (new — `*.e2e.full.test.ts`)
193 e2e tests run against a real spawned webapp + Postgres (no mocks).
Coverage matrix:
- **API key auth** — read / write / trigger / batchTrigger / deploy
actions across runs, batches, deployments, prompts, queues, query,
sessions, input-streams, waitpoints, tasks, idempotency keys; multi-key
resources (a run carries batch / tag / task identifiers — auth must
accept any matching scope)
- **Personal Access Token auth** — comprehensive matrix: scope match,
scope mismatch, missing scope, expired token, malformed token
- **Public JWT auth** — sub-vs-URL environment resolution, expired JWTs,
signature verification, scope checking, otu (one-time-use) token
semantics, branch-environment signing-key fallback
- **Dashboard session auth** — admin-only pages reject non-admins;
per-action gating
- **Cross-cutting edge cases** — revoked API key grace window, JWT
cross-environment isolation, MissingResource branch behaviour
### Hygiene cleanups
- Deleted dead `app/services/authorization.server.ts` (legacy
`checkAuthorization` + types — no live consumers post-migration) and its
orphaned test
- Dropped the never-populated `scopes` field from
`ApiAuthenticationResultSuccess`
- `scheduleEmail` moved out of `email.server.ts` into its own module —
breaks a `commonWorker → marqs/V1` import chain that was poisoning the
auth test graph
- OSS Roles page shows a deployment-aware empty state ("Roles aren't
available in this self-hosted deployment" vs the plan-upsell copy) via
`rbac.isUsingPlugin()`
- Team action handler: explicit per-intent ability gates
(`manage:billing` for purchase-seats, `manage:members` for set-role +
remove-member with self-leave carve-out)
### Cross-repo coordination
All public-package contract changes paired in `triggerdotdev/cloud#763`
(rbac-packages branch) — the enterprise plugin implements the same
`RoleBaseAccessController` interface against Drizzle.
## Test plan
- [x] `pnpm run typecheck --filter webapp` clean
- [x] `pnpm --filter webapp exec vitest run --config
vitest.e2e.full.config.ts` — 193/193 pass (requires Docker for
testcontainers)
- [x] Spot-check an authed API endpoint with a valid + invalid API key
against a local stack
- [x] Spot-check the migrated admin pages render and gate non-admins
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
6cdd8814a3 |
fix(webapp): Fix for resizable side panel getting stuck at its min-size (#3538)
## Summary - Run-view inspector panel was glitching out on Firefox: visual flicker on close, locking up at min size, and intermittent `panelHasSpace` invariant errors. Root cause is the underlying `react-window-splitter` library's collapse animation, which uses `@react-spring/rafz` and interacts poorly with Firefox. - Disabled the library's collapse animation on Firefox only, app-wide (every consumer of `RESIZABLE_PANEL_ANIMATION`). Chromium and Safari behaviour is unchanged. ## Changes - **Firefox animation skip** in `RESIZABLE_PANEL_ANIMATION` — UA-detected at module load, resolves to `undefined` for Firefox so the library's animation actor completes in one frame instead of running its rAF loop. - **Inspector min raised 50px → 250px** so dragging can't shrink the panel into a near-useless width. - **`autosaveId` bumped `v2` → `v3`** to invalidate stale persisted snapshots (the library has a `// TODO` branch that ignores prop changes for already-registered panels, so existing users would otherwise still see the old 50px min). - **`react-window-splitter` pinned** to exact `0.4.1` to protect the patch from drifting if line offsets change in a patch release. - **Two hunks added to the existing `@window-splitter/state` patch:** - Removed the library's auto-collapse-on-drag block entirely. Every collapsible panel in the app is parent-controlled, and that block was triggering state-machine deadlocks when handlers were no-ops. Drag-to-collapse is now disabled across the app; collapse is only triggered explicitly (close button, ESC, URL change, etc.). - In `getDeltaForEvent`, fall back to the panel's `default` before its `min` when expanding — so the first ever click on a span opens the inspector at 500px, not 250px. ## Local testing confirmed - [x] Firefox: open a run, click various spans → panel opens instantly at 500px, drags freely between 250px and max, closes instantly to 0. No console errors. - [x] Chrome/Chromium: same flow, but with smooth open/close animation as before. - [x] Safari: same as Chrome. - [x] Reload mid-session → panel restores cleanly to the dragged size. - [x] Other resizable panels in the app (logs, deployments, schedules, batches, bulk-actions, runs index) still animate on Chromium/Safari. ## Notes - Linear: TRI-8584 - Branch contains intermediate commits exploring an unsuccessful snapshot-validator approach; they're reverted by the final commit. Cumulative diff is 6 files. Squash on merge if you'd prefer a clean history. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f7a2bc7c96 |
Feat(webapp) filters UX update (#3451)
## Lots of filter UX improvements across lots of routes ### General - Promoted important filters out of the "More filters" so they're always visible - SearchInput primitive is now reusable and Esc now clears the field (AI filter input also clears with Esc) - Tooltips + keyboard shortcuts on every primary filter button - Brighter text on selected filter items / queue items - Filter dropdowns reordered for better hierarchy - Removed debounce on Tasks page search for faster filtering ### Tasks page search - Esc now clears the field - ENTER submits a search to improve performance when you have lots of tasks https://github.com/user-attachments/assets/4b30521e-dbc4-4468-b2af-8c85bdfb9002 ### Runs filters - Moves Status and Tasks out of the More filters menu - "Root only" toggle is set to false when you filter for a Task. This state isn't stored and flips back to the stored value if filters are cleared <img width="1690" height="986" alt="CleanShot 2026-04-26 at 19 24 08@2x" src="https://github.com/user-attachments/assets/b07da73c-140e-451f-a7bf-c32129317f63" /> ### Batches filters - General consistency improvements <img width="1429" height="948" alt="CleanShot 2026-05-08 at 09 50 35" src="https://github.com/user-attachments/assets/e5ec267f-2aa3-43ef-991e-93bf01bdaea5" /> ### Schedules - General consistency improvements <img width="1567" height="1141" alt="CleanShot 2026-05-08 at 09 51 11" src="https://github.com/user-attachments/assets/34b7da88-87c6-4e4d-a70f-fe13ea9f87ec" /> ### Queues - General consistency improvements <img width="824" height="416" alt="CleanShot 2026-05-08 at 09 52 02" src="https://github.com/user-attachments/assets/b4adc102-8192-4a68-b199-a175c2645a6c" /> ### Waitpoint tokens - General consistency improvements <img width="941" height="363" alt="CleanShot 2026-05-08 at 09 52 19" src="https://github.com/user-attachments/assets/d43aeb3f-7f80-454d-b183-fd077a4e3ff7" /> ### Models - General consistency improvements <img width="1570" height="509" alt="CleanShot 2026-05-08 at 09 53 17" src="https://github.com/user-attachments/assets/066d7646-4672-4cae-8ec0-e30a82889914" /> ### AI metrics - General consistency improvements <img width="1568" height="624" alt="CleanShot 2026-05-08 at 09 53 43" src="https://github.com/user-attachments/assets/fdfc4806-26fa-458d-a5ed-5c226b3bbc9f" /> ### Logs - General consistency improvements <img width="1267" height="752" alt="CleanShot 2026-05-08 at 09 54 30" src="https://github.com/user-attachments/assets/3e9ba871-b9dd-490e-aded-5d87134fd2bb" /> ### Errors - General consistency improvements <img width="1568" height="670" alt="CleanShot 2026-05-08 at 09 54 50" src="https://github.com/user-attachments/assets/fdda027a-e24f-4804-b4bb-203a6c2db960" /> ### Query - General consistency improvements - History, Scope, Triggered (date) filters all have shortcut tooltips - Scope filter now reuses the metrics ScopeFilter component <img width="1566" height="716" alt="CleanShot 2026-05-08 at 09 55 22" src="https://github.com/user-attachments/assets/0130b4a2-9daf-4edc-bada-3380aff4022a" /> ### Dashboards - General consistency improvements - Scope filter gets nicer icons and a shortcut - Nice icons for the Scope menu items <img width="1567" height="769" alt="CleanShot 2026-05-08 at 09 56 10" src="https://github.com/user-attachments/assets/7bea25f7-6c33-4d4a-a36d-3a1cb56afe09" /> ### Custom dashboard - General consistency improvements - Add chart, Add title, and the kebab menu now have tooltips + shortcuts <img width="1566" height="782" alt="CleanShot 2026-05-08 at 09 58 11" src="https://github.com/user-attachments/assets/9df4db25-b2c0-43a2-b92f-00256337d5a9" /> ### Environment variables - General consistency improvements <img width="1569" height="930" alt="CleanShot 2026-05-08 at 09 58 55" src="https://github.com/user-attachments/assets/26e614b4-88e7-400b-aa6d-a96bad488fb8" /> ### Preview branches - General consistency improvements <img width="1570" height="986" alt="CleanShot 2026-05-08 at 09 59 17" src="https://github.com/user-attachments/assets/57a2b939-3670-4252-ab2c-d6dc65bdda1b" /> |
||
|
|
41434b536b |
feat(webapp): admin Back Office tab with org API rate limit editor (#3434)
## Summary - New **Back office** tab at `/admin`, per-org detail page at `/admin/back-office/orgs/:orgId` designed to host future per-org admin actions (project count, delete account, YC deals). - First action: edit an organization's API rate limit — tokenBucket override (refill rate, interval, max tokens), with a live plain-English preview (e.g. *"1,500 requests per minute · 750 request burst allowance"*). Writes are audit-logged via the server logger. - Cleanup: removed unused `v2?` / `v3?` columns from the admin orgs list (display only — Prisma select untouched). ## Test plan - [ ] Back office tab visible in admin nav and highlighted when on a sub-route - [ ] `/admin/orgs` shows a Back office "Open" link per row; no v2/v3 columns - [ ] Empty state at `/admin/back-office` links back to `/admin/orgs` - [ ] Detail page renders the effective rate limit in view mode; Edit reveals the form - [ ] Save writes `Organization.apiRateLimiterConfig`, returns to view mode, shows "Rate limit saved." banner - [ ] Invalid values surface inline field errors and keep edit mode - [ ] Non-admins hitting any new route are redirected to `/` - [ ] Server logs show `admin.backOffice.rateLimit` info line per mutation |
||
|
|
4f2ff3d9de |
fix(wabapp): Fix for wrapping text on run inspector (#3328)
### Text wrapping fix - Fixes message text not wrapping on the run inspector if there were no spaces in the text - Fixes inspector title truncation - Adds a copy text button for the Message property <img width="468" height="740" alt="CleanShot 2026-04-04 at 10 19 02@2x" src="https://github.com/user-attachments/assets/71e42bf3-d103-44a2-b3b4-937c0b60a4bc" /> |
||
|
|
cf0fdde3c4 |
Feat(webapp): animated resizable panel (#3319)
This is a small improvement mainly with the UI Skills file: - Animate open and close the Resizable panels - Uses the built in animation hooks from react-window-splitter - Includes a global variable for the animation easing and timing for consistency https://github.com/user-attachments/assets/50ed0019-ed12-4e08-b95c-7c6d1fe5bac0 |
||
|
|
e31b03eac2 |
fix(webapp): Responsive improvements for the onboarding screens (#3318)
Simple responsive breakpoint changes to the 3 onboarding screens + the login screen to make it mobile friendlier <img width="523" height="872" alt="CleanShot 2026-04-02 at 17 18 55" src="https://github.com/user-attachments/assets/815d19ca-df9b-4b3e-8f6d-e00c81628679" /> |
||
|
|
bf736a79fc |
Feat(webapp): Models page UI improvements (#3308)
Lots of layout and UI improvements to the new Models page <img width="2282" height="1356" alt="CleanShot 2026-04-01 at 14 14 35" src="https://github.com/user-attachments/assets/4a13a291-5d5b-415f-962f-b9cfb25b887d" /> |
||
|
|
0977c56efe |
Errors (versions) (#3187)
- Added versions filtering on the Errors list and page - Added errors stacked bars to the graph on the individual error page --------- Co-authored-by: James Ritchie <james@trigger.dev> |
||
|
|
21cf8f9965 | fix(webapp): disable resizable panel cookie saves to prevent large cookies causing HTTP 431 errors (#3282) | ||
|
|
2037254a9b |
Feat(webapp) AI screen UI improvements (#3269)
### Lots of UI improvements to the Prompts pages: #### New side menu icons <img width="234" height="110" alt="CleanShot 2026-03-25 at 14 26 33" src="https://github.com/user-attachments/assets/8039ee8f-92a0-477d-ac91-458dfa43020b" /> #### Compact horizontal start finish times so scanning generations list is consistent <img width="618" height="174" alt="CleanShot 2026-03-25 at 14 24 03" src="https://github.com/user-attachments/assets/7eb69475-d539-4e34-b0b5-5cd5119c1aea" /> #### Tidied up the metrics view <img width="1607" height="925" alt="CleanShot 2026-03-25 at 14 23 52" src="https://github.com/user-attachments/assets/d4bf2761-8e09-4d91-bfb8-e10d1508042f" /> #### Copiable metadata <img width="274" height="160" alt="CleanShot 2026-03-25 at 14 23 44" src="https://github.com/user-attachments/assets/487c804d-c000-4cd0-9a19-30c2681712df" /> #### Cleaner versions list <img width="463" height="264" alt="CleanShot 2026-03-25 at 14 23 28" src="https://github.com/user-attachments/assets/a2dfede7-0e7d-4f9c-8b01-00ba13070f70" /> #### Overall consistency improvements, shortcut keys and UI behaviours improvements <img width="2279" height="1349" alt="CleanShot 2026-03-25 at 14 23 02" src="https://github.com/user-attachments/assets/0c29257b-15a0-443c-b872-a9f4a7f6af13" /> --------- Co-authored-by: Eric Allam <eallam@icloud.com> |
||
|
|
54d95ee4b9 |
feat: AI prompt management dashboard and enhanced span inspectors (#3244)
- Full prompt management UI: list, detail, override, and version
management for AI prompts defined with `prompts.define()`
- Rich AI span inspectors for all AI SDK operations with token usage,
messages, and prompt context
- Real-time generation tracking with live polling and filtering
## Prompt management
Define prompts in your code with `prompts.define()`, then manage
versions and overrides from the dashboard without redeploying:
```typescript
import { task, prompts } from "@trigger.dev/sdk";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
const supportPrompt = prompts.define({
id: "customer-support",
model: "gpt-4o",
variables: z.object({
customerName: z.string(),
plan: z.string(),
issue: z.string(),
}),
content: `You are a support agent for Acme SaaS.
Customer: {{customerName}} ({{plan}} plan)
Issue: {{issue}}
Respond with empathy and precision.`,
});
export const supportTask = task({
id: "handle-support",
run: async (payload) => {
const resolved = await supportPrompt.resolve({
customerName: payload.name,
plan: payload.plan,
issue: payload.issue,
});
const result = await generateText({
model: openai(resolved.model ?? "gpt-4o"),
system: resolved.text,
prompt: payload.issue,
...resolved.toAISDKTelemetry(),
});
return { response: result.text };
},
});
```
The prompts list page shows each prompt with its current version, model,
override status, and a usage sparkline over the last 24 hours.
From the prompt detail page you can:
- **Create overrides** to change the prompt template or model without
redeploying. Overrides take priority over the deployed version when
`prompt.resolve()` is called.
- **Promote** any code-deployed version to be the current version
- **Browse generations** across all versions with infinite scroll and
live polling for new results
- **Filter** by version, model, operation type, and provider
- **View metrics** (total generations, avg tokens, avg cost, latency)
broken down by version
## AI span inspectors
Every AI SDK operation now gets a custom inspector in the run trace
view:
- **`ai.generateText` / `ai.streamText`** — Shows model, token usage,
cost, the full message thread (system prompt, user message, assistant
response), and linked prompt details
- **`ai.generateObject` / `ai.streamObject`** — Same as above plus the
JSON schema and structured output
- **`ai.toolCall`** — Shows tool name, call ID, and input arguments
- **`ai.embed`** — Shows model and the text being embedded
For generation spans linked to a prompt, a "Prompt" tab shows the prompt
metadata, the input variables passed to `resolve()`, and the template
content from the prompt version.
All AI span inspectors include a compact timestamp and duration header.
## Other improvements
- Resizable panel sizes now persist across page refreshes (patched
`@window-splitter/state` to fix snapshot restoration)
- Run page panels also persist their sizes
- Fixed `<div>` inside `<p>` DOM nesting warnings in span titles and
chat messages
- Added Operations and Providers filters to the AI metrics dashboard
## Screenshots
<img width="3680" height="2392" alt="CleanShot 2026-03-21 at 10 14
17@2x"
src="https://github.com/user-attachments/assets/f3e59989-a2fa-4990-a9d0-3cacda431868"
/>
<img width="3680" height="2392" alt="CleanShot 2026-03-21 at 10 15
37@2x"
src="https://github.com/user-attachments/assets/2f2d02df-2d2b-44fb-ac6f-9153f6a6c387"
/>
<img width="3680" height="2392" alt="CleanShot 2026-03-21 at 10 15
54@2x"
src="https://github.com/user-attachments/assets/baa161e0-ef91-4fa4-a55f-986b71cccdf0"
/>
|
||
|
|
fea8ae4e53 |
feat(webapp): self serve preview branches and team members (#3201)
## Adds 2 self serve features ### 1. self serve preview branches - Copies the patterns of the self serve concurrency - Self serve only available on Pro plan (otherwise you are linked to the billing plans page) - Global self serve branches limit: 180 (+20 for the Pro plan). It can be overridden per Org - You need to archive branches before reducing the number of extra branches you're paying for - Branches are removed immediately but remain billed until the end of the billing cycle like extra concurrency ### 2. self serve team members - Copies the patterns of the self serve concurrency - Self serve only available on Pro plan (otherwise you are linked to the billing plans page) - Global self serve members is unlimited but can be limited with the same env var quota and overridden per org if needed - You need to remove team members before reducing the number of members you pay for - Team members are removed immediately but remain billed until the end of the billing cycle like extra concurrency |
||
|
|
d1ea8d8f74 |
Fix(webapp) onboarding fixes (#3189)
### Fixes and improvements to the onboarding questions: **This change is worth double checking @matt-aitken** - Update to the Button.tsx file: it now takes `isLoading` that shows a spinner in the middle of the button (replacing the button text and any icons) and sets it to `disabled`. It does this nicely by keeping the button width the same so there's no layout shift. **Other fixes** - Fixes an issue where if you type a custom option in the "What technologies do you use" question, it doesn't check the list to see if it matches. Now it checks the box if you've typed an option from that list. - When we randomize the list of onboarding question options, we now store the position they appeared in the list |
||
|
|
5f359be286 |
feature: Errors page (#3172)
A top-level Errors page that aggregates errors from failed runs with occurrences metrics. https://github.com/user-attachments/assets/8f0ef55e-90dd-4faa-9051-59f4665181e4 Errors are “fingerprinted” so similar errors are grouped together (e.g. has an ID in the error message). You can view an individual error to view a timeline of when it fired, the runs, and bulk replay them. |
||
|
|
a09038b066 |
Feature(webapp): new User and Project onboarding questions (#3109)
- New User onboarding questions added and stored in a new `onboardingData` col - Keeps the same Org creation screen and stores the data in the same format in same DB column - New Org onboarding questions addded and stored in a new `onboardingData` col https://github.com/user-attachments/assets/244e4bae-f74d-4ed4-a545-92c9b927e98b --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
9ba608d2cf |
TRQL function tests and fixes (#3076)
What changed - Fixed some functions like dateAdd, toString, ifNotFinite - Removed all functions that accept lambdas as they're not supported (yet) - Added tests for all TRQL functions that use ClickHouse |
||
|
|
79f8cdef72 |
Fix(webapp): logs button + logs table row link fix (#3107)
Small fixes and improvements to the logs page: - Clicking the Run ID didn't open inspector - Swapped the "open link in tab" icon with Runs icon - Prevent tooltip hovering on Level info <img width="350" height="206" alt="CleanShot 2026-02-20 at 10 00 37@2x" src="https://github.com/user-attachments/assets/3e82f24a-c0a1-4c01-a8e9-9e06a8af982a" /> |
||
|
|
469b039090 |
feat: OTEL metrics pipeline for task workers (#3061)
- Adds an end-to-end OTEL metrics pipeline: task workers collect and export metrics via OpenTelemetry, the webapp ingests them into ClickHouse, and they're queryable through the existing dashboard query engine - Workers emit process CPU/memory metrics (via `@opentelemetry/host-metrics`) and Node.js runtime metrics (event loop utilization, event loop delay, heap usage) - Users can create custom metrics in their tasks via `otel.metrics.getMeter()` from `@trigger.dev/sdk` - Metrics are automatically tagged with run context (run ID, task slug, machine, worker version) so they can be sliced per-run, per-task, or per-machine - The TSQL query engine gains metrics table support with typed attribute columns, `prettyFormat()` for human-readable values, and per-schema time bucket thresholds - Includes reference tasks (`references/hello-world/src/trigger/metrics.ts`) demonstrating CPU-intensive, memory-ramp, bursty workload, and custom metrics patterns ## What changed ### Metrics collection (packages/core, packages/cli-v3) - **Metrics export pipeline** — `TracingSDK` now sets up a `MeterProvider` with a `PeriodicExportingMetricReader` that chains through `TaskContextMetricExporter` (adds run context attributes) and `BufferingMetricExporter` (batches exports to reduce overhead) - **Host metrics** — Enabled `@opentelemetry/host-metrics` for process CPU, memory, and system-level metrics - **Node.js runtime metrics** — New `nodejsRuntimeMetrics.ts` module using `performance.eventLoopUtilization()`, `monitorEventLoopDelay()`, and `process.memoryUsage()` to emit 6 observable gauges - File system and diskio metrics - **Custom metrics** — Exposed `otel.metrics` from `@trigger.dev/sdk` so users can create counters, histograms, and gauges in their tasks - **Machine ID** — Stable per-worker machine identifier for grouping metrics - **Dev worker** — Drops `system.*` metrics to reduce noise, keeps sending metrics between runs in warm workers ### Metrics ingestion (apps/webapp) - **OTEL endpoint** — `otel.v1.metrics.ts` accepts OTEL metric export requests (JSON and protobuf), converts to ClickHouse rows - **ClickHouse schema** — `017_create_metrics_v1.sql` with 10-second aggregation buckets, JSON attributes column, 60-day TTLs ### Query engine (internal-packages/tsql, apps/webapp) - **Metrics query schema** — Typed columns for metric attributes (`task_identifier`, `run_id`, `machine_name`, `worker_version`, etc.) extracted from the JSON attributes column - **`prettyFormat()`** — TSQL function that annotates columns with format hints (`bytes`, `percent`, `durationSeconds`) for frontend rendering without changing the underlying data - **Per-schema time buckets** — Different tables can define their own time bucket thresholds (metrics uses tighter intervals than runs) - **AI query integration** — The AI query service knows about the metrics table and can generate metric queries - **Chart improvements** — Better formatting for byte values, percentages, and durations in charts and tables ### Reference project - **`references/hello-world/src/trigger/metrics.ts`** — 6 example tasks: `cpu-intensive`, `memory-ramp`, `bursty-workload`, `sustained-workload`, `concurrent-load`, `custom-metrics` ## Test plan - [ ] Build all packages and webapp - [ ] Start dev worker with hello-world reference project - [ ] Run `cpu-intensive`, `memory-ramp`, and `custom-metrics` tasks - [ ] Verify metrics in ClickHouse: `SELECT DISTINCT metric_name FROM metrics_v1` - [ ] Query via dashboard AI: "show me CPU utilization over time" - [ ] Verify `prettyFormat` renders correctly in chart tooltips and table cells - [ ] Confirm dev worker drops `system.*` metrics but keeps `process.*` and `nodejs.*` |
||
|
|
eb0f963393 |
feat(metrics): Dashboard charts performance improvements (#3083)
Summary - Only render the top 50 series - Improved rendering performance on bar charts |
||
|
|
b793f33e59 |
Logs: new materialized view and some UI improvements (#3069)
This will prevent internal logs to be added to the task_events_search_table Closes #<issue> ## ✅ Checklist - [x] I have followed every step in the [contributing guide](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md) - [x] The PR title follows the convention. - [x] I ran and tested the code works --- ## Testing Ran the migration, deleted the old invalid rows and ran new tasks. The undesired logs are not added to the table. --- ## Changelog Updated the MATERIALIZED VIEW to also filter for `trace_id != ''` --------- Co-authored-by: Matt Aitken <matt@mattaitken.com> |
||
|
|
b4e08bddec |
Fix(webapp): metrics UI improvements (#3063)
- Lots of small UI improvements - Toggle full screen charts with "V" shortcut <img width="3504" height="2286" alt="CleanShot 2026-02-14 at 20 06 30@2x" src="https://github.com/user-attachments/assets/32403661-06b3-4f6c-a074-243b3f43197d" /> <img width="362" height="222" alt="CleanShot 2026-02-14 at 20 06 58@2x" src="https://github.com/user-attachments/assets/ee4f5859-4b71-482e-9636-5abd78d9f623" /> <img width="434" height="360" alt="CleanShot 2026-02-14 at 20 06 53@2x" src="https://github.com/user-attachments/assets/44339348-f3f3-425b-bbf3-bb41ed6a8e59" /> <img width="460" height="310" alt="CleanShot 2026-02-14 at 20 06 48@2x" src="https://github.com/user-attachments/assets/eb3b6af6-b88a-4677-8a48-acfa6b768770" /> <img width="502" height="332" alt="CleanShot 2026-02-14 at 20 06 45@2x" src="https://github.com/user-attachments/assets/b788d78b-8f4a-4b18-94c8-487673f3ec7b" /> <img width="370" height="257" alt="CleanShot 2026-02-14 at 20 10 29@2x" src="https://github.com/user-attachments/assets/a81e8b14-b2eb-402c-bf3b-affd0d4fde26" /> |
||
|
|
9030e94362 |
Metrics improvements (#3046)
Summary - Remove LIMIT from built-in dashboard queries - Make concurrency configurable per project via environment variables - Fix widget fallback period to Metrics default (1d) instead of 7d - Handle concurrency at the project level - Sort series for graphs so largest is displayed at the bottom (legend shows largest at top) - Use average aggregation for some built-in charts - Improve aggregation handling for the legend - Only render chart points when there is data; render dots on line charts - Truncate legend items and show tooltip on hover - Better preserve chart configuration when the underlying query changes |
||
|
|
bc0d1ff59a |
Metrics dashboards (#3019)
Summary - Implemented metrics dashboards with a built-in dashboard and custom dashboards - Added a "Big number” display type What changed - New data format for metric layouts and saving/editing layouts (editing, saving, cancel revert) - QueryWidget usable on Query page and Metrics dashboards - Time filtering, auto-reloading and timeBucket() auto-bin support - Filters added to metrics; widget popover/improved history and blank states - Side menu: - Metrics/Insights section with icons, colors, padding, collapsible behavior and reordering of custom dashboards - Move action logic into service for reuse and API querying; refactor reordering for reuse <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/3019" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: James Ritchie <james@trigger.dev> |
||
|
|
eaed7d0ba4 |
fix(webapp): UI/UX improvements for logs, query, and shortcuts (#2997)
## ✅ Checklist - [X] I have followed every step in the [contributing guide](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md) - [X] The PR title follows the convention. - [X] I ran and tested the code works --- ## Testing Manually tested each implementation. --- ## Changelog * Updated Logs Page with the new implementation in time filter component * In TRQL editor users can now click on empty/blank spaces in the editor and the cursor will appear * Added CMD + / for line commenting in TRQL * Activated proper undo/redo functionality in CodeMirror (TRQL editor) * Added a check for new logs button, previously once the user got to the end of the logs he could not check for newer logs * Added showing MS in logs page Dates * Removed LOG_INFO internal logs, they are available with Admin Debug flag * Added support for correct timezone render on server side. * Increased CLICKHOUSE_LOGS_LIST_MAX_MEMORY_USAGE to 1GB * Changed Previous run/ Next run to J/K, consistent with previous/next page in Runs list |
||
|
|
f53db6fd16 |
Query: time limits, performance improvements, styling (#2953)
Summary - Query: add time limits, performance improvements, and styling updates Changes - Add ClickHouse output_text and error_text columns with indexes - Automatically use _text columns for JSON based on query pattern; support JSON column data prefixes - Add idempotency key and scope columns - Add enforcedWhereClause for tenant and time restrictions, instead of the old tenant stuff. - Implement basic time filter limiting and set default time period based on plan; show message when results are clipped - UX: resizable code area (including vertical splits), collapsible sidebar, fix table/chart vertical sizing, max height for chart legend in fullscreen - Styling and UI tweaks: improved chart legend styling, more chart colours, thinner line chart stroke, pricing callout color, improved layout for callouts - Features: generate and save AI titles <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/2953"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> |
||
|
|
c0b86efbd3 |
feat(webapp): Add MiddleTruncate component for long task names (#2946)
Closes # ## ✅ Checklist - [ ] I have followed every step in the [contributing guide](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md) - [ ] The PR title follows the convention. - [ ] I ran and tested the code works --- ## Testing Tested the MiddleTruncate component in the TasksDropdown by: 1. Verifying that long task names (e.g., "namespace:category:subcategory:task-name") are truncated in the middle 2. Confirming the full text appears in a tooltip on hover 3. Testing responsive behavior - truncation adjusts when the container is resized 4. Verifying that short task names that fit within the container are displayed in full without truncation --- ## Changelog Added a new `MiddleTruncate` primitive component that intelligently truncates text in the middle while preserving the beginning and end portions. This is particularly useful for long hierarchical identifiers like task slugs. **Key features:** - Truncates text in the middle with an ellipsis (…) when it exceeds available width - Shows full text in a tooltip on hover when truncated - Responsive - recalculates truncation on container resize using ResizeObserver - Maintains minimum character visibility (4 chars minimum on each side for readability) - Integrated into TasksDropdown to handle long task names **Changes:** - Created new `MiddleTruncate.tsx` component with binary search algorithm for optimal character distribution - Updated TasksDropdown to use MiddleTruncate for task slug display - Increased TasksDropdown popover width from 240px to 360px to provide better space for truncated text --- ## Screenshots 💯 https://github.com/user-attachments/assets/a7a2191a-2e36-437e-ab3f-517fe7620b93 <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/2946"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
e29e1c86d9 |
Fix/tri 7032 logs page feedback (#2947)
## ✨ Changes
### UI & UX
- Normalized log level display across table and detail view
- Fixed table header scroll behavior and sidebar positioning
- Improved loading state with taller segment and disabled resizing
- Added "no more logs" message with count
- Enhanced keyboard shortcuts
### Filtering & Search
- Streamlined filters: RunId and Task only (removed run filters)
- Side panel closes when filters change
- Fixed logs from previous search remaining in table
- Fixed table scroll position when changing filters
### Backend
- Added performance indexes on message and attributes
(`014_add_task_runs_v2_search_indexes.sql`)
- Added DEBUG level logging by default
- Removed internal logs from display
- Fixed ServiceValidationError forwarding to frontend
- Removed v1 logs API support
|
||
|
|
49de105862 |
Feat(webapp): collapsible side menu (#2939)
- Better separation between main feature pages and manage pages - Toggle via keyboard shortcut Cmd/Ctrl + B or click collapse button - Collapsed state persisted to database (survives page refresh) - All menu items show tooltips when collapsed - Smooth animations using Framer Motion and CSS transitions - Impersonation-safe (preferences not modified when impersonating) https://github.com/user-attachments/assets/35827922-b80a-418e-8341-eb22c9bb5ed4 <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/2939"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> |
||
|
|
3056a51b82 |
Query improvements (#2905)
What changed - Upgraded recharts to 2.15.2 - Added multiple chart types and components: big number, line, stacked, bar (including zoomable & reference line), big dataset bar, and usage graph - Implemented custom legend with animated values, tooltip showing x-axis data, and hover/highlight behaviors for stacks and legend - Added loading, no-data, and invalid chart states plus loading spinners and improved loading animations/layout - Storybook integration: initial charts setup, separate chart files, alphabetized menu, chart state toggles, and story updates - Interaction & UX improvements: zooming (drag/select), crosshair pointer, show/select dates while zooming, prevent text selection on drag, hide mouse wheel zoom, capped legend items, axis/legend styling tweaks, better spacing, and min-height for charts - Data & state handling: moved date data to route for unified zooming, moved chartState to main Chart component, moved hard-coded/mock data out of components, and set chart data when zooming to start/end dates - Performance & animation: turned off/reduced chart animations, sped up animated numbers, removed hover transitions for bars - New UI primitives and layout: Card component, small card updates, SVG icons, improved segmented control and popover variants, table improvements (resizable columns, filtering, sorting, scrolling fixes) - Various fixes and polish: tooltip style fixes, legend value updates, hover/leave state resets, bar width fixes for small datasets, type/import fixes, and numerous small style/typo tweaks --------- Co-authored-by: James Ritchie <james@trigger.dev> |
||
|
|
a5339a1bac | fix(dashboard): remove span ID to original span ID cache and use a different approach to link to the cached runs (#2886) | ||
|
|
c8686b5f1c |
feat: tri-6738 Create aggregated logs page (#2862)
Closes #<issue> ## ✅ Checklist - [x] I have followed every step in the [contributing guide](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md) - [x] The PR title follows the convention. - [x] I ran and tested the code works --- ## Testing - Verified log detail view displays correctly with message, metadata, and attributes - Tested search highlighting functionality in log messages (escapes special regex characters) - Confirmed tabs (Details/Run) switch properly with keyboard shortcuts (d/r) - Verified run information loads via async fetcher in Run tab - Tested close button and Escape key for dismissing the panel - Verified log details display correct information: level badges, kind badges, timestamps, trace IDs, span IDs - Confirmed links to parent spans and run pages work correctly - Tested with various log levels (ERROR, WARN, INFO, DEBUG, TRACE) and kinds (SPAN, SPAN_EVENT, LOG_*) - Verified admin-only fields display correctly when user has admin access - Tested data loading states and error states (log not found, run not found) --- ## Changelog Created new Logs page. The information shown is gathered from the spans from each run. The feature supports all run filters with two new filters for level and logs text search. --- ## Screenshots <img width="2059" height="1196" alt="Logs page preview" src="https://github.com/user-attachments/assets/70b667b4-98cc-4728-855a-2766dd5c1aa5" /> 💯 --------- Co-authored-by: James Ritchie <james@trigger.dev> |
||
|
|
7a9490893c | fix(webapp): Fix for missing table rows divider lines in safari (#2873) |