Compare commits

...

338 Commits

Author SHA1 Message Date
Eric Allam 0687ce722c Release 3.3.11 (#1621)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 4s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2025-01-17 12:06:41 +00:00
github-actions[bot] d627fa718e chore: Update version for release (#1611)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-17 12:05:15 +00:00
Matt Aitken 5798024a5b Require max duration in trigger.config. Validate TRIGGER_ACCESS_TOKEN is a PAT. (#1620)
* Show a good error if TRIGGER_ACCESS_TOKEN isn’t a PAT

* Require maxDuration in trigger.config from now on

* Changeset

* Update the trigger.config templates copy, and set the default to 1hr

* Set the maxDuration in the trigger.config files inside the repo

* Fixed the e2e tests by setting the package to 0.0.0-prerelease-20250116195421
2025-01-17 11:32:55 +00:00
Eric Allam 5750f35add Shared queue consumer telemetry improvements and perf changes (#1619)
* Shared queue consumer telemetry improvements

* findUnique -> findFirst to stop the prisma dataloader issue on api key auth

* Added action stats, audited all actions and improved reasons

* Better debug logging filtering
2025-01-17 09:15:21 +00:00
Matt Aitken 11f2832ae5 Fix for detecting internal errors 2025-01-16 17:03:39 +00:00
Matt Aitken fd04ed50ef Prevent multiple waits callback delayed by one tick
To ensure the first wait doesn't checkpoint before the second is called
2025-01-16 16:23:56 +00:00
Matt Aitken 6d17443e16 Changeset: Detect parallel waits and show a useful error message 2025-01-16 15:48:55 +00:00
Matt Aitken dd321e3616 Throw an error for concurrent waits (with nice docs link) (#1618)
* WIP preventing concurrent waits, throw an error

* Added ConcurrentWaitError (not retryable)

* Move preventMultipleWaits out of the RuntimeAPI

* Added preventMultipleWaits to the devRuntimeManager

* Added throwable InternalError. Plus new TASK_DID_CONCURRENT_WAIT code

* Docs link for troubleshooting concurrent waits

* Docs for troubleshooting concurrent waits

* preventMultipleWaits function

* Added TASK_DID_CONCURRENT_WAIT code

* Deal with InternalErrors that skipRetrying

* Added preventMultipleWaits to prod
2025-01-16 14:33:14 +00:00
Gabe O'Leary 2ad664d17d Add note about prisma-json-types-generator (#1617) 2025-01-15 23:18:42 +00:00
Matt Aitken 5eb30d026d Improve worker deployment queries (#1616)
* workerDeployment change findUnique to findFirst

* Changed the worker deployment queries to only select what they need, some of the columns are huge

* Only get the bare minimum data for tasks too
2025-01-15 20:34:28 +00:00
nicktrn 719ae83057 Add support for specifying machine preset at trigger time (#1608)
* add machine preset trigger option

* add changeset

* add examples to changeset

* machinePreset -> machine

* task options now also accept machine as simple string

* update openapi spec
2025-01-15 13:47:13 +00:00
Eric Allam 7eda22851e Prevent v2 batches from being resumed before all items have been created (#1614) 2025-01-14 14:37:04 +00:00
Eric Allam b3aa87ee26 Add custom telemetry exporter support (#1602)
* WIP langsmith & AI SDK integration

* Add changeset

* Add exporter support to deployed tasks

* Better support for external exporters and group exporters and instrumentations under the telemetry config property

* Missing changes
2025-01-13 22:43:34 +00:00
Eric Allam 14ce599218 Add reason to MarQS acknowledgeMessage to track why it's called (#1607) 2025-01-13 17:29:09 +00:00
Eric Allam 0a18e1d919 Additional dev queue consumer logging (#1606) 2025-01-13 16:37:19 +00:00
Eric Allam ca51f65394 Truncate ingested log messages to 4096, and truncate message to 256 in the summary tree view (#1604) 2025-01-13 11:35:39 +00:00
Eric Allam 46a37fdc49 Release 3.3.10 (#1601)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 4s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2025-01-10 19:52:30 +00:00
github-actions[bot] 24383dc65d chore: Update version for release (#1600)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-10 19:50:41 +00:00
Eric Allam e13edd3a20 Handle errors thrown by requests in Realtime react hooks (#1599) 2025-01-10 19:40:34 +00:00
Eric Allam 9e0f03623d Support ignoring test/spec files inside trigger dirs (fixes #1593) (#1596)
* Support ignoring test/spec files inside trigger dirs (fixes #1593)

* Add changeset
2025-01-10 19:40:08 +00:00
Eric Allam 914ceaf3c5 dev CLI: cleanup deprecated background worker files (fixes #1572) (#1595)
* dev CLI: cleanup deprecated background worker files (fixes #1572)

* Add changeset
2025-01-10 19:39:34 +00:00
nicktrn 472e5f93e1 Fix: Prevent failed resumes for very large batches (#1598)
* findUnique -> findFirst

* remove tx

* make query more legible

* cut resume payload queries in half

* remove the additional status checks

* tweak the catalog batch parent task

* fix error message
2025-01-10 18:33:25 +00:00
D-K-P 51a054f534 Added Realtime CSV importer to the docs 2025-01-09 17:13:55 +00:00
Eric Allam efd61f1374 Release 3.3.9 (#1591)
🚀 Publish Trigger.dev Docker / units (push) Failing after 3s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 10s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2025-01-09 11:35:16 +00:00
github-actions[bot] 2c7f7b1d5e chore: Update version for release (#1586)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-09 11:34:03 +00:00
Eric Allam c92edd61af New metadata system doc updates (#1590) 2025-01-09 11:13:48 +00:00
Eric Allam ab69b60348 New metadata deployed task fix (#1588)
* Add more logging around new metadata system

* Make the authenticated env optional when updating run metadata
2025-01-08 22:42:34 +00:00
Dan d52e3d7d57 Added LLM evaluator to example projects (#1589)
* Added repo links

* Added links to remix / nextjs webhooks examples

* Added a Realtime learn more snippet

* Added the batch llm evaluator docs

* Improved snippet

* Updated intro
2025-01-08 21:16:56 +00:00
Eric Allam 3ca0c15161 Add ability to disable metadata flushing and logging (#1587) 2025-01-08 12:37:43 +00:00
James Ritchie 0aa597104c Shortcut improvements (#1573)
* Added shortcuts (with tooltip) to the pagination

* WIP fixing the disabled hover state

* Styled the tooltip

* Added a shortcuts panel to the help menu

* Adds new shortcut to list

* Changes “meta” for “mod”

* Adds more shortcuts to the list

* Adding shortcut to open the shortcuts panel

* tweak gap between shortcut letters

* button component now has icon spacing adjustment (for lucide icons)

* Fixed some ilegal markup

* Pagination uses disabled prop rather than a disabled wrapper

* Improved the Switch styles

* Makes the shortcut modifier optional

* Added new icon based shortcut keys for mac and win

* Updated PC modifier shortcuts

* Adds a new windows key icon

* Allows variants and react nodes to be used as the modifier key

* Adds more shortcuts to the storybook

* Adds missing focus-visible styles to the pagination

* Removed test modifier keys

* number style is tabular

* Update apps/webapp/app/components/primitives/ShortcutKey.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Tooltip now just 1 prop on the button component

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-01-08 11:58:18 +00:00
Eric Allam 34f8bd588e Add ability to update parent and root run metadata from children (#1563)
* Increase the number of active streams from 2 to 5

* WIP parent metadata updates

* Fix noop metadata manager

* Implement run metadata updates from ancestor tasks

* Add changeset

* Add ability to stream into parent and root task runs

* Don't duplicate exporting run metadata types

* Add ability to fetch streams through metadata

* Couple of fixes from CodeRabbit

* Fix metadata tests

* Make sure streams are subscribed in the "background"

* Move the stream subscription stuff to the API client, expose it through `runs.fetchStream`

* Fixed run stream tests
2025-01-08 11:29:24 +00:00
Eric Allam 4243cb2451 Release 3.3.8
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2025-01-08 10:29:06 +00:00
github-actions[bot] 7e8a0d96d2 chore: Update version for release (#1570)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-08 10:26:37 +00:00
Willow (GHOST) 4d19dec71a fix: add user-agent to the websocket request (#1584) 2025-01-07 22:21:32 +00:00
Eric Allam 76a5ac293e Realtime fixes: safari, timezones, and TIMED_OUT status (#1585)
* Fix realtime safari bug because of missing ReadableStream async iterable support
Limit to only safari

* Fix missing TIMED_OUT run status

* When coercing realtime date strings, make sure they are set to UTC
2025-01-07 20:47:49 +00:00
Dan 668b34d25e Adding example projects (#1564)
* Added new side menu section and updated intro

* Updated the fal ai realtime project

* Copy update

* Added example project

* Swapped walkthrough and repo

* Restore original fal task page

* Added links back to the intro
2025-01-03 20:00:40 +00:00
James Ritchie 6a2d033f32 Project setup improvements (#1579)
* Adds ‘an existing project’ to step 1

* When you click pnpm or yarn, the other tabs change too
2024-12-30 18:07:07 +00:00
James Ritchie e71df640a9 Adds more org names to the alert emails (#1561)
Co-authored-by: Matt Aitken <matt@mattaitken.com>
2024-12-30 17:54:38 +00:00
James Ritchie 330f6c548e Softened the language in the Pro upgrade modal (#1574) 2024-12-30 17:49:00 +00:00
Erin Allison 4d2412a0fe Add Support for Alternate Email Transports (#1580)
* Add support for AWS SES and SMTP email transports

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Correct environment variable names for new email settings

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Correct option names being passed to nodemailer for SMTP

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Remove use of AWS SDK synthetic default export

It apparently causes issues when transpiled/bundled

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Add documentation for new email settings

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Move nodemailer types to devDependencies

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Adjust mail transport error handling

Gotta keep the linter happy :)

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Fix typecheck error on MailTransportOptions

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

* Correct environment variable usage for SMTP email transport

Signed-off-by: Erin Allison <eallison@andrettikarting.com>

---------

Signed-off-by: Erin Allison <eallison@andrettikarting.com>
2024-12-30 17:38:17 +00:00
Matt Aitken 21a4fabc28 Docs update batch limits to 5MB 2024-12-18 11:47:50 +00:00
Eric Allam 3418aa614b Don't expire enqueued runs if they have lockedAt set (#1571) 2024-12-16 19:00:18 +00:00
Eric Allam 88a0754ae0 Support scopes packages in externals when found in a transitive dep #1552 (#1569)
* Support scopes packages in externals when found in a transitive dep

* fixed typescript errro

* Add changeset
2024-12-16 17:55:44 +00:00
Eric Allam f3e4597ef4 Update scrape-hacker-news.mdx 2024-12-14 21:11:37 +00:00
Eric Allam 2bf04ece54 Release 3.3.7 (#1562)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-13 15:49:52 +00:00
github-actions[bot] 295b2eb3b6 chore: Update version for release (#1558)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-13 15:48:04 +00:00
James Ritchie f0182abc83 Alert emails now contain the Org name (#1555)
* Alert emails now contain the Org name

* Adds org title to the alert parameters
2024-12-13 13:32:34 +00:00
James Ritchie 1105b9b71a 3 small improvements (#1560)
* Updated login page logos

* Adds an isSelected state to the Table

* Toast style now matches the design

* Adds a space between the upgrade panel and the list of users
2024-12-13 13:32:19 +00:00
Eric Allam 7077dbf65e @trigger.dev/react-hooks now works with React 19 (#1559) 2024-12-13 13:31:47 +00:00
Eric Allam 6b355ab9ad Upgrades and fixes to Realtime and Realtime streams (#1549)
* Fix streaming splits in realtime streams v2

* Add changeset

* Skip all flaky tests 😡

* Improve the way we stream from tasks to the server

* Improve the v1 realtime streams (Redis)

* Turn on the relay realtime stream service

* Improved the relay realtime cleanup

* Fixed consuming realtime runs w/streams after the run is already finished

* Remove some logs

* Update changeset

* Fixed runStream tests
2024-12-13 11:42:50 +00:00
Niloy 68d7139ebe Update deploy-environment-variables.mdx (#1509)
base64 with -i for input file
2024-12-13 11:16:47 +00:00
James Ritchie c58f6f7a68 Upgrading from Hobby to Pro displays a dialog to confirm (#1545)
* Upgrading from Hobby to Pro displays a dialog to confirm

* Improved the logic for upgrading to pro

* Added the spinner component to storybook

* Improved the dark style spinner
2024-12-13 11:14:47 +00:00
James Ritchie 6516e15bd8 Changes frozen to waiting (#1551)
* Offset the tooltip in more

* The Select component’s shortcut has a better hover state

* “Frozen” changed to “Waiting”
2024-12-13 11:13:34 +00:00
James Ritchie 7f2365f4e0 Adds a tooltip to the Status header showing deployment status descriptions (#1554) 2024-12-13 11:11:14 +00:00
James Ritchie f560594610 Tabs horizontally overflow scroll in the side panel inspectors (#1556) 2024-12-13 11:08:04 +00:00
Matt Aitken ebd9767926 When replaying, using the concurrencyLimit from the original run’s queue 2024-12-12 16:48:22 +00:00
Matt Aitken 1c631a1b6f Skip the RealtimeClient tests for now in CI… flaky 2024-12-12 14:39:35 +00:00
Matt Aitken 110a8ea48c Added queue updating logging. For Triggering changed the concurrency limit calculation to match deploying 2024-12-12 13:49:20 +00:00
James Ritchie 10f0ef3301 Adds v2 countdown eol text in side menu (#1546) 2024-12-11 12:24:23 +00:00
nicktrn 2e4a6307b4 Fix: Prevent some attempt creation retries from causing system failures (#1550) 2024-12-11 12:01:18 +00:00
Eric Allam 30ea5eb13a Release 3.3.6 (#1544)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 19s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-10 15:53:45 +00:00
github-actions[bot] 5846f30228 chore: Update version for release (#1537)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-10 15:52:05 +00:00
Eric Allam 3afa42c209 Make TRIGGER_REALTIME_STREAM_VERSION overridable by the project env vars (#1543) 2024-12-10 14:54:50 +00:00
Eric Allam 86b1628953 Add run metadata to runs.list endpoint (#1542) 2024-12-10 12:52:42 +00:00
Matt Aitken ea23dbd297 Throw an error if Resend responds with an error (#1540) 2024-12-10 12:37:36 +00:00
Matt Aitken 9065e64be8 Added logging when we remove a queue’s concurrency limit 2024-12-10 09:57:41 +00:00
Eric Allam 9970b9b68e Realtime streams now powered by electric (#1541)
* Realtime streams now powered by electric, and fix the streaming update duplicate issues by converting the electric Shape materialized view into a ReadableStream of changes

* Ensure realtime subscription stops when runs are finished, and add an onComplete handle to use realtime hooks

* Fix tests
2024-12-09 22:09:30 +00:00
Matt Aitken b4113134ad Fix: test form: update the callback when the task changes 2024-12-08 22:07:42 +00:00
Eric Allam 2a07ea42f1 Optionally trigger batched items sequentially to preserve order (#1536)
* Optionally trigger batched items sequentially to preserve order

* Fix infinite v3.processBatchTaskRun enqueuings by checking the attemptCount
2024-12-05 15:16:06 +00:00
Eric Allam 91afa5ebbf Release 3.3.5 (#1535)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 3s
🚀 Publish Trigger.dev Docker / units (push) Failing after 5s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-03 18:13:54 +00:00
github-actions[bot] 65262dc3d7 chore: Update version for release (#1534)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-03 18:12:28 +00:00
Eric Allam 9105701ae0 Fix cancelled runs breaking realtime subscriptions (#1533) 2024-12-03 16:55:27 +00:00
nicktrn 9b35cc484b Release 3.3.4
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 5s
🚀 Publish Trigger.dev Docker / units (push) Failing after 20s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-03 12:16:56 +00:00
github-actions[bot] 30a04a5a06 chore: Update version for release (#1531)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-03 12:16:08 +00:00
nicktrn 493315af48 Hide batch actions for dev runs 2024-12-03 11:18:40 +00:00
Eric Allam 8db1da69e9 Triggering docs and adding options to all trigger hooks (#1528) 2024-12-03 10:15:49 +00:00
nicktrn cd7a45101e Fix: Extract the correct SDK version during build (#1530)
* fix build manifest sdk version

* new cli version prop in deployment tab

* changeset
2024-12-03 10:00:55 +00:00
nicktrn 29d107dc0a Feat: Add button to try and resume pending batches (#1529)
* add try and resume action for in-progress batches

* don't reinvent the wheel
2024-12-03 09:50:55 +00:00
Eric Allam cf7dc8d719 Release 3.3.3 (#1527)
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 20s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-02 20:02:34 +00:00
github-actions[bot] 9ced599b19 chore: Update version for release (#1526)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-02 20:01:09 +00:00
Eric Allam 67592ec2b4 Multiple streams can now be consumed at the same time (#1522)
* Mutliple streams can be now consumed simultaneously

* Update prerelease script

* Add changeset

* Make it core

* Handle API error responses when streaming
2024-12-02 17:58:10 +00:00
Eric Allam f7bf7bc268 Release 3.3.2 (#1521)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 3s
🚀 Publish Trigger.dev Docker / units (push) Failing after 21s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-12-02 14:14:14 +00:00
github-actions[bot] bb57426a0d chore: Update version for release (#1516)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-02 14:12:27 +00:00
Eric Allam 3ab7eb9c7a Add unique indexes for the oneTimeUseToken columns (#1517) 2024-12-02 13:45:38 +00:00
Eric Allam 2892efad04 Fix: actually wait for realtime streams to finished (#1520)
* Realtime streams fix waiting for streams to finished

* Add changeset
2024-12-02 13:40:18 +00:00
nicktrn 979ba51d2f Feat: configurable deploy timeouts (#1519)
* make deploy timeout configurable

* increase default deploy timeout to 8 minutes
2024-12-02 11:02:16 +00:00
Eric Allam 364ea565ed Use one-time use tokens when triggering or batch triggering from the frontend (#1515)
* Use one-time use tokens when triggering or batch triggering from the frontend

* Add changeset
2024-11-29 20:16:37 +00:00
Eric Allam 58252728f6 Release 3.3.1 (#1513)
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 4s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-29 13:00:10 +00:00
github-actions[bot] 5eaad0577e chore: Update version for release (#1508)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-29 12:56:50 +00:00
Matt Aitken 00f1103deb Show "root" runs by default, save the preference to a cookie (#1512)
* “Root only” toggle, off by default. Disabled when filtering by tasks

* Remove text transition on Switch because it didn’t match the container
2024-11-29 12:40:15 +00:00
Eric Allam c37622e7b6 Realtime: improve scope access to runs with tags and batches (#1511)
* JWT scopes for tags and batches can now access runs that have the tag or are in the batch

- useTaskTrigger can now submit options
- auto-generated batch trigger public access tokens no longer need each individual run ID scope

* Add changeset

* Added task scopes to work like tags and batches

Also removed scopes for tags when auto-generating a public access token as that could be dangerous.
2024-11-29 11:37:11 +00:00
Eric Allam d67023aa8f Fixed the missing icons in trigger spans (#1506) 2024-11-28 19:09:33 +00:00
Matt Aitken d9bfe55a8c Run filters: fix for “Batch ID” that should say “Schedule ID” 2024-11-28 17:00:17 +00:00
Eric Allam f4a18feca0 Docs: Batch Trigger upgrades (#1505)
* WIP batch docs

* More batch trigger v2 docs
2024-11-28 15:55:45 +00:00
Matt Aitken 0acd052061 Release 3.3.0
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 4s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-28 15:27:20 +00:00
github-actions[bot] 6bf3bbcfd7 chore: Update version for release (#1504)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-28 15:26:11 +00:00
James Ritchie 1077709e15 Side help panel (#1488)
* WIP adding a side help panel to the tasks page

* Optionally display the shortcut before the trailing icon in the button

* Updated the close icon

* WIP adding a new side help panel

* WIP adding content to the side help panel

* WIP new side help panel content

* Removed images as not needed any more

* Added content to the side help menu

* Help panel open/closed state stored as cookie

* Removed the icons from the docs and examples links
2024-11-28 11:49:52 +00:00
Willow (GHOST) 54017cbffa feat: always show alerts tab and lock email alerts when keys are missing (#1478) 2024-11-28 11:43:34 +00:00
James Ritchie 39ef733a34 Deploy page table rows stay selected when the side menu is open (#1492) 2024-11-28 11:35:08 +00:00
Fernando Coelho 736f577c25 Update Infisical instructions to new SDK (#1493)
* Update Infisical instructions to new SDK

Current documentation is using old Infisical SDK implementation.

New SDK has a different name, and authenticates on a method, not in the class constructor.

* Fix import and client secret env
2024-11-28 11:34:27 +00:00
James Ritchie b7de02ec14 Improved the text selection style (#1497) 2024-11-28 11:33:27 +00:00
James Ritchie 90db0f6e01 Adds realtime limits to the billing page pricing tiers (#1500) 2024-11-28 11:32:46 +00:00
Eric Allam 6df8069c0e Batch Trigger upgrades (#1502)
* WIP batch trigger v2

* Fix for the DateField being one month out… getUTCMonth() is zero indexed 🤦‍♂️

* Added a custom date range filter

* Deal with closing the custom date range

* Child runs filter

* Fix for the clear button untoggling the child runs

* WIP batchTriggerV2

* Finished removing rate limit from the webapp

* Added an index TaskRun to make useRealtimeBatch performant

* Renamed the period filter labels to be “Last X mins”

* Denormalize background worker columns into TaskRun

* Use the runTags column on TaskRun

* Add TaskRun ("projectId", "id" DESC) index

* Improved the v2 batch trigger endpoint to process items in parallel and also added a threshold, below which the processing of items is async

* Added a runId filter, and WIP for batchId filter

* WIP triggerAll

* Add new batch methods for triggering multiple different tasks in a single batch

* Disabled switch styling

* Batch filtering, force child runs to show if filtering by batch/run

* Added schedule ID filtering

* Force child runs to show when filtering by scheduleId, for consistency

* realtime: allow setting enabled: false on useApiClient

* Batches page

* Always complete batches, not only batchTriggerAndWait in deployed tasks

* Add batch.retrieve and allow filtering by batch in runs.list

* Renamed pending to “In progress”

* Tidied up the table a bit

* Deal with old batches: “Legacy batch”

* Added the Batch to the run inspector

* Fixed the migration that created the new idempotency key index on BatchTaskRun

* Fixed the name of the idempotencyKeyExpiresAt option and now default idempotency key TTL is 30 days, not 24 hours

* Timezone fix: wrong month in Usage page dropdown

* The DateField now defaults to local time, but can be overriden to use utc with an option

* Don’t allow the task icon to get squished

* BatchFilters removed unused imports

* In the batch filtering, use `id` instead of `batchId` in the URL

* BatchFilters: we don’t need a child tasks hidden input field

* Creates some common filter components/functions

* Fix for batchVersion check when filtering by batch status

* Add additional logging around telemetry and more attributes for trigger spans

* Show clear button for specific id filters

* Batch list: only allow environments that are part of this project

* Unnecessary optional chain

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Add JSDocs

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-28 11:25:00 +00:00
nicktrn b714d6fabf Release 3.2.2
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-27 16:31:01 +00:00
github-actions[bot] 576715374e chore: Update version for release (#1503)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-27 16:29:30 +00:00
nicktrn 9046ea4f23 Fix: Prevent hung worker process on flush exceptions (#1501)
* deprecate cli logger warn and error methods

* replace broken error logger in deployed workers

* changeset
2024-11-27 16:22:26 +00:00
Eric Allam 7e209e0771 Stop using Response errors when validating API Keys (#1498)
* Stop using Response errors when validating API Keys, instead introduce a new "Result" type that has success and failure conditions. Adding in a way to progressively adopt because this touches everything.

* Make sure authenticateApiRequestWithFailure always returns a result
2024-11-25 15:19:05 +00:00
Eric Allam 3792394e5c Always await wrapResponse since it returns a Promise, to protect against UnhandledRejection errors (#1494) 2024-11-22 22:16:50 +00:00
Eric Allam 4305a23668 Fix: trigger queue updates (#1491)
* Fixed task trigger queue update logic to only update an existing queue if the concurrency limit changes, instead of on every single trigger task call

* Fix bad update from another branch
2024-11-22 10:39:34 +00:00
James Ritchie e7fc592cd9 Reinstate pagination on schedules page 2024-11-21 09:53:39 +00:00
James Ritchie cb12a73db6 Fix for the last task in a long list wasn’t on screen 2024-11-20 18:10:05 +00:00
James Ritchie 31fc9e12b7 Show the delete alerts button in the popover 2024-11-20 17:40:37 +00:00
James Ritchie 2bdbedcdd8 Fixed layout bug in the alerts page if you don’t have any alerts set 2024-11-20 14:55:22 +00:00
Eric Allam 332166a098 Release 3.2.1
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 3s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-20 14:14:56 +00:00
github-actions[bot] 14f19066b5 chore: Update version for release (#1481)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-20 14:13:53 +00:00
Eric Allam af7a7681cf Update realtime docs for streaming and a couple tweaks to the SDK (#1486) 2024-11-20 14:10:38 +00:00
James Ritchie c044cb125e Fixed the scrolling on the JSON editor on the test page 2024-11-19 16:06:51 +00:00
Eric Allam 8ba226b99a Add TRIGGER_STREAMS_URL to auto-populated dev env vars (#1485) 2024-11-19 16:06:41 +00:00
Eric Allam 7d4708839f Upgrade zod to 3.23.8 (#1484)
* Upgrade to zod 3.23.8

* Add changeset
2024-11-19 15:51:37 +00:00
James Ritchie 532fdcad47 Fix to keep the Alerts progress bar at the bottom of the screen when you have reached the max 2024-11-19 13:34:29 +00:00
Eric Allam 186942de5d minor update should be a patch (#1483) 2024-11-19 13:16:13 +00:00
Eric Allam 23b43be952 feat/realtime-streams (#1470)
* WIP realtime streams

* Handle realtime with large payloads or outputs #1451

* feat: optimize Redis stream handling with batching

Add STREAM_ORIGIN to environment schema. Improve performance in
RealtimeStreams by using TextDecoderStream for simpler text
decoding and implementing batching of XADD commands for Redis
streams. Limit stream size using MAXLEN option. Update
environment variable repository with new variable type. Adjust
import statements for Redis key and value types.

* 🔧 chore: add dev dependencies for bundle analysis

* add metadata tests and a few more utilties

* Add stream tests and improve streaming

* Added AI tool tasks, descriptions to tasks

* Use the config file path to determine the workingDir, then the package.json path

* Remove stream test files

* useTaskTrigger react hook that allows triggering a task from the client

* Add streaming support for the realtime react hooks

* Add ability to stream results after useTaskTrigger

* Improve the stream throttling

* Use the runId as the ID key to bust the cache after triggering

* Upgrade to to the latest electric sql client and server

* Make realtime server backwards compat with 3.1.2 release

* Pass the runId into useRealtimeRun

* Fix scopes when specifiying reading all runs

* WIP @trigger.dev/rsc package

* Various fixes and accepted recommendations by CodeRabbit

* Regenerate pnpm lock file

* A couple tweaks to rsc and give up on rendering react in tasks for now

* Add changeset

* Remove triggerRequest from the useEffect deps

* Improve realtime & frontend authentication errors

* Fixed authorization tests

* Remove unnecessary log

* Add metadata.stream limits and improve the metadata streams structure

* Streams can now have up to 2500 entries

* Various coderabbit fixes

* additional react-hooks jsdocs
2024-11-19 13:14:25 +00:00
James Ritchie ea0956464b Added an ellipsis to the tooltip text 2024-11-19 13:07:11 +00:00
James Ritchie eca79afced Added some padding around the Setup Your Dev callout on Task page 2024-11-19 13:03:20 +00:00
James Ritchie 58861a0983 Added the new Help & Feedback popover to the account side menu (#1482) 2024-11-19 10:08:12 +00:00
James Ritchie 1b3a2f2e5b Full width tables (#1474)
* Updated styling

* Updated the main Table component styles to the new design

* Run page table layout style updates

* Updated row styling and new scrolling behaviour

* Fixed bulk action bar no appearing

* Improved table component styles

* Pagination arrows now chevrons

* Added link to Runs docs page

* Small popover tweak

* Moved the extra Test button out of Tables and into the RunsTable

* WIP refactoring the sticky table cell

* Support for the existing way we have menus in the sticky table cells

* Created a specific Docs style button

* Improved dialog trigger button styles

* Improved docs button styles

* Updated Docs buttons to the new style in the tooltips

* Adding a Test button on hover

* Removed the page padding and made table scroll

* Fixed table scrolling

* cleaned up imports

* WIP adding a test button that links to the test page

* added a docs button to the header

* Much nicer display bar for showing how many schedules you have (and it works with the updated table)

* Fixed the button types in the schedules info panel

* Fixed button icon colour

* Removed the pagination as it’s not being used

* Delete modal button position updated

* Fixed padding on recent payloads panel

* Fixed button icon colours

* Better style for active table row

* Table scrolling now behaves properly

* environment buttons now have a hover state

* Bigger Run test bar to match the Run page

* Small layout fixes to the schedule side panel

* Test page now has link to docs

* fixed text alignment with table headers

* API keys page now has full width tables

* Fix typo and modal layout

* Table uses new sticky button type

* Tidy imports

* Env var table now full width

* Form buttons have a border top

* Updated button styles

* Updated blank state message style to be consistent

* Removed unnecessary form button border

* Alerts page tables now full width

* Allowing the Detail cell to be styled

* Updated the page structure to be the same as the scheduled page – with better progress indicator

* Concurrency limits page now full width

* Fixed function name label extending too far

* Improved the button sizes on the replay modal

* Added a minimal style to the info panels

* Make sure you can always see the info and unlock staging info when the table scrolls

* Info panel style updated to match the others

* Removed the duplicate header

* Usage page tables now full width

* Personal access token page using full width tables

* Small CSS fixes

* Deployments page table now full width

* Deploy page scrolls properly and pagination stays on screen if table is scrollable

* TableCellMenu using the correct popover

* Added missing button variant

* Button group is now named so it doesn’t cause conflicts

* Added docs link to the Run page

* Typo

* Added a link to the test page if you have no runs

* Make the table sticky cell buttons more obvious

* Env var page now using the new popover menu

* Improved the menu items

* Copy tweak

* Made the icons bright on hover

* Updated the cancel run dialog

* Improved the API keys sticky menu behaviour

* Alerts table menu using the new popover

* Correct sized buttons in the Env Var page table menu

* Fixed weird Dialog text styling

* Schedules page blank state using correct docs button style

* Copy tweak

* Menu buttons styled correctly

* Added close buttons to the deploy dialogs

* Made the Dialog footer match the Form footer style

* Fixed feedback form buttons

* Fixed cancel run dialog

* Test page uses the taskIdentifier in the path

* Test task button working

* Added Spline component for 404 logo to remove spline logo

* Removed todo comment

* Added a docs button to the PAT page

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
2024-11-18 17:11:06 +00:00
Willow (GHOST) 653d974da7 feat: exit if docker buildx can't be found for self-hosted builds (#1475)
* feat: exit if docker buildx can't be found for self-hosted builds

* chore: tweak debug log message

* chore: improve error message based on rabbit's suggestion
2024-11-18 12:17:48 +00:00
nicktrn 332854bbcb Release 3.1.3
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 19s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
🚀 Publish Trigger.dev Docker / units (push) Failing after 4s
2024-11-15 11:40:00 +00:00
github-actions[bot] 911447304c chore: Update version for release (#1469)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-15 11:39:24 +00:00
amuwal 2be1062f1e fix: unintended project initialization at absolute path /trigger during project initialization (#1412)
* Fix parsing of project path for cli init command

* Update development instructions for cli-v3

* Create gentle-mails-sip.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-11-15 11:34:51 +00:00
James Ritchie 64be7b04e8 Linking to more examples in the Next.js guide 2024-11-14 10:04:48 +00:00
Dan 925c463fe5 Added libreoffice example (#1472)
* Added Libreoffice example docs

* typo
2024-11-13 15:03:23 +00:00
James Ritchie e1bd6b3355 Fixed broken link 2024-11-13 13:55:06 +00:00
James Ritchie fd90f79ede Added realtime example link to Introduction page 2024-11-13 13:51:40 +00:00
James Ritchie 5d303ce6f2 New Realtime example added to docs 2024-11-13 13:45:47 +00:00
James Ritchie d98221ba7f Added the new quickstart video to the docs 2024-11-13 11:31:28 +00:00
Diego Valenzuela 29026a379b Fix: Typo on overview.mdx (#1460)
* Fix: Typo on overview.mdx

the import helloWorldTask wasn't called correctly at an example

* Fix: Typo update on overview.mdx

Now the import is called `helloWorld` instead of `helloWorldTask` to be consistent with the filename as requested
2024-11-12 18:29:33 +00:00
D-K-P 0706482232 Fix vercelSynEnvVars export 2024-11-12 12:37:21 +00:00
D-K-P 2e273e8fe2 Updated vercel env vars instructions and naming 2024-11-12 11:28:17 +00:00
Nico a5d59de39e Fix: vercelSyncEnvVars teamId (#1463)
* Update vercelSyncEnvVars.ts

* Update vercelSyncEnvVars.ts

* Update vercelSyncEnvVars.ts

* Update vercelSyncEnvVars.ts

* Update docs

* Add changeset
2024-11-12 11:19:25 +00:00
D-K-P 71808fafd1 Improved maxDuration comments in the templates 2024-11-07 14:02:56 +00:00
Matt Aitken 82ebfc7908 Made it clearer that tasks need to be exported 2024-11-06 15:17:12 +00:00
Matt Aitken f0996686e9 Added a db index to make the schedule list page faster
There was a slow query to get the latest run for a list of schedules
2024-11-06 11:56:28 +00:00
Matt Aitken e422fb5e4d Added the ability to switch database volumes locally without losing data, with docs 2024-11-06 10:55:19 +00:00
nicktrn ceac10b098 Release 3.1.2
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 21s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-05 15:25:20 +00:00
github-actions[bot] 365fabf9a0 chore: Update version for release (#1461)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-05 15:24:01 +00:00
nicktrn 21e1375760 Better logs for payload retrieval issues 2024-11-05 12:19:49 +00:00
nicktrn d7656314d6 Prevent stuck runs after duplicate dependency resume messages (#1459)
* ignore duplicate dependency resume messages

* add changeset
2024-11-05 12:00:02 +00:00
nicktrn 5368bcf6bd Improve resume reliability of restored runs (#1458)
* replay ready for resume

* clear replay state between attempts

* add changeset
2024-11-05 11:59:44 +00:00
D-K-P adf5970245 Shortened sidebar title to Vercel sync env vars 2024-11-04 14:58:01 +00:00
Dan aca2f54cb7 Docs - sync vercel env vars (#1426)
* Added sync env vars docs example

* Added links in the config + deploy files

* Updated copy

* Added vercel docs cards and added them to all of the relevant docs pages

* Added sync env vars to the intro page

* Added automatically sync env vars section to nextjs guide

* Added ‘Manually’

* Removed code block and updated title

* updated formatting and added vercelsyncenvvars to the config file

* Added missing comment

* Updated imports to /core

* Added sync env var docs link and note

* Improved the VERCEL_ACCESS_TOKEN note

* Added link to vercel

* Updated docs and improved formatting

* Copy tweaks

* Added space

* Updated deploy docs
2024-11-04 14:55:10 +00:00
Chibuike Chijioke 6313db698a fix(docs): Correct typo in '/idempotency' documentation (#1456) 2024-11-02 23:56:56 +00:00
Eric Allam c9811beae2 Release 3.1.1
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-11-01 21:33:00 +00:00
github-actions[bot] 97533cba2e chore: Update version for release (#1442)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-11-01 21:32:04 +00:00
Dan e92459bf1e Added revalidation docs (#1444)
* Added revalidation docs

* Typo

* Copy tweak
2024-11-01 21:25:44 +00:00
Eric Allam cc74cae393 chore: remove unnecessary browser export condition (#1455) 2024-11-01 21:11:45 +00:00
nicktrn 58def055d0 Add new internal error for very outdated SDK versions (#1453)
* add outdated sdk error and crash outdated runs instead of staying queued forever

* add changeset
2024-11-01 15:41:31 +00:00
D-K-P 41f5261fe5 Added drizzle docs and updated prisma 2024-11-01 14:40:25 +00:00
Eric Allam ce1a54eb3b Renamed useBatch to useRealtimeBatch (#1447)
* Renamed useBatch to useRealtimeBatch

* Use the new hook name in the nextjs-realtime ref
2024-11-01 13:23:02 +00:00
Eric Allam 25285488f8 Add individual run ids to auto-generated public access token when calling batchTrigger (#1449) 2024-11-01 13:22:34 +00:00
Eric Allam befdcef1f0 Add known issue for realtime (#1452) 2024-11-01 13:21:01 +00:00
nicktrn fa18e6c012 Increase maximum retry count for deploy run controller (#1450)
* increase max retries for all deploy run controller operations

* add changeset
2024-11-01 11:23:11 +00:00
nicktrn 4194bce4a3 Forked worker processes now inherit PATH from parent (#1448)
* set PATH when forking

* add changeset
2024-11-01 11:23:00 +00:00
nicktrn da08e5015f Pass init output to all error handlers (#1441)
* pass init output to all error handlers

* add changeset
2024-10-31 11:23:47 +00:00
D-K-P 9b7472844d Updated deploy docs 2024-10-31 09:49:59 +00:00
Dan eace78fa04 Added fal AI example (#1439) 2024-10-30 17:30:23 +00:00
Dan e81b2a7839 Firecrawl example docs (#1438)
* Added firecrawl example docs

* Added Firecrawl and scrape hn to the intro page table
2024-10-30 16:41:04 +00:00
Eric Allam cdcfc81aca Add API_ORIGIN env var to be able to split dashboard & API servers 2024-10-29 16:43:22 +00:00
Eric Allam 816b0f9e3d Add some more react hooks & realtime docs 2024-10-29 16:41:57 +00:00
Eric Allam 6fb073672d Add realtime API docs 2024-10-29 13:57:02 +00:00
Eric Allam 9203bd8e67 Add realtime walkthrough video to docs 2024-10-29 13:23:57 +00:00
Eric Allam 3252d9ec31 docs: realtime, react hooks, and frontend usage (#1434)
* WIP realtime/frontend docs

* WIP

* Deleted old examples

* Improved styling

* Improved the generated example styles

* More style improvements

* More realtime docs

* Couple doc tweeks

* runs-and-attempts -> runs

* Remove the prerelease package version

---------

Co-authored-by: James Ritchie <james@trigger.dev>
2024-10-29 12:31:04 +00:00
Eric Allam 45fdf35e20 Release 3.1.0
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 5s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-10-29 12:25:27 +00:00
github-actions[bot] 53841d7bf0 chore: Update version for release (#1423)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-29 12:24:21 +00:00
nicktrn d2c779eb0f Fixes for internal error reattempts (#1436)
* magic links on span event errors

* prevent task monitor from processing errors handled elsewhere

* exclusively use internal error code enum for completion data

* add complete attempt service opts

* reattempts need to go via the queue for task controllers that may have exited

* only infer retry config if completed via crash or system failure

* enhance error before deciding if retriable

* retry on SIGTERM

* enable retry config helper for latest sdk

* don't retry heartbeat timeouts for now

* enable task monitor to update fatal errors

* add missing service

* update retry config since package version

* don't alter completion time when updating existing error
2024-10-28 19:15:47 +00:00
Dan cbe51707a5 Added Sentry example (#1435)
* Added sentry docs

* Removed additionalPackages

* Updated description

* Copy updates
2024-10-28 15:57:41 +00:00
Eric Allam 3d7a6d8e9d Add missing indexes on Checkpoint table 2024-10-28 13:37:59 +00:00
Valentin Mocanu 72cdb5edc4 Supply correct namespace to TaskMonitor (#1419) 2024-10-27 12:53:43 +00:00
James Ritchie 1f11a8dde0 Added an AI prompt for converting v2 jobs to v3 tasks 2024-10-25 16:06:27 +01:00
Eric Allam af427aa32d Proxy no longer rewrites hostname, instead uses worker origin request forwarding 2024-10-24 17:02:57 +01:00
nicktrn 212f8539c3 Automatically reattempt after internal errors (#1424)
* refactor finalize run service

* refactor complete attempt service

* remove separate graceful exit handling

* refactor task status helpers

* clearly separate statuses in prisma schema

* all non-final statuses should be failable

* new import payload error code

* store default retry config if none set on task

* failed run service now respects retries

* fix merged task retry config indexing

* some errors should never be retried

* finalize run service takes care of acks now

* execution payload helper now with single object arg

* internal error code enum export

* unify failed and crashed run retries

* Prevent uncaught socket ack exceptions (#1415)

* catch all the remaining socket acks that could possibly throw

* wrap the remaining handlers in try catch

* New onboarding question (#1404)

* Updated “Twitter” to be “X (Twitter)”

* added Textarea to storybook

* Updated textarea styling to match input field

* WIP adding new text field to org creation page

* Added description to field

* Submit feedback to Plain when an org signs up

* Formatting improvement

* type improvement

* removed userId

* Moved submitting to Plain into its own file

* Change orgName with name

* use sendToPlain function for the help & feedback email form

* use name not orgName

* import cleanup

* Downgrading plan form uses sendToPlain

* Get the userId from requireUser only

* Added whitespace-pre-wrap to the message property on the run page

* use requireUserId

* Removed old Plain submit code

* Added a new Context page for the docs (#1416)

* Added a new context page with task context properties

* Removed code comments

* Added more crosslinks

* Fix updating many environment variables at once (#1413)

* Move code example to the side menu

* New docs example for creating a HN email summary

* doc: add instructions to create new reference project and run it locally (#1417)

* doc: add instructions to create new reference project and run it locally

* doc: Add instruction for running tunnel

* minor language improvement

* Fix several restore and resume bugs (#1418)

* try to correct resume messages with missing checkpoint

* prevent creating checkpoints for outdated task waits

* prevent creating checkpoints for outdated batch waits

* use heartbeats to check for and clean up any leftover containers

* lint

* improve exec logging

* improve resume attempt logs

* fix for resuming parents of canceled child runs

* separate SIGTERM from maybe OOM errors

* pretty errors can have magic dashboard links

* prevent uncancellable checkpoints

* simplify task run error code enum export

* grab the last, not the first child run

* Revert "prevent creating checkpoints for outdated batch waits"

This reverts commit f2b5c2ac42.

* Revert "grab the last, not the first child run"

This reverts commit 89ec5c8bfd.

* Revert "prevent creating checkpoints for outdated task waits"

This reverts commit 11066b4e74.

* more logs for resume message handling

* add magic error link comment

* add changeset

* chore: Update version for release (#1410)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Release 3.0.13

* capture ffmpeg oom errors

* respect maxAttempts=1 when failing before first attempt creation

* request worker exit on fatal errors

* fix error code merge

* add new error code to should retry

* pretty segfault errors

* pretty internal errors for attempt spans

* decrease oom false positives

* fix timeline event color for failed runs

* auto-retry packet import and export

* add sdk version check and complete event while completing attempt

* all internal errors become crashes by default

* use pretty error helpers exclusively

* error to debug log

* zodfetch fixes

* rename import payload to task input error

* fix true non-zero exit error display

* fix retry config parsing

* correctly mark crashes as crashed

* add changeset

* remove non-zero exit comment

* pretend we don't support default default retry configs yet

---------

Co-authored-by: James Ritchie <james@trigger.dev>
Co-authored-by: shubham yadav <126192924+yadavshubham01@users.noreply.github.com>
Co-authored-by: Tarun Pratap Singh <101409098+Wackyator@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-24 11:12:24 +01:00
shubham yadav 9a5e6e58be Fix: Handle circular references in flattenAttributes function (#1433)
* Fix: Handle circular references in flattenAttributes function

* Update flattenAttributes.test.ts

* Update packages/core/src/v3/utils/flattenAttributes.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/core/src/v3/utils/flattenAttributes.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Create brown-laws-rest.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Eric Allam <eric@trigger.dev>
2024-10-24 10:44:04 +01:00
Eric Allam c31700ae5f Fix issue with lost built trigger.dev files after prisma generate (#1429)
* Fix issue with lost built trigger.dev files after prisma generate on deploy

* Add changeset
2024-10-24 10:43:26 +01:00
Eric Allam cfb96859b3 fix: removing schedule instance no longer crashes (#1430) 2024-10-24 10:41:49 +01:00
James Ritchie 9bc641d15e An improved 404 page design (#1427)
* WIP improving the 404 page

* Improved 404 page layout

* Added a shortcut key

* Removed old assets and code
2024-10-24 10:37:24 +01:00
Matt Aitken a79075908e Unflattening array fix for very large arrays (#1432)
* fix unflattening of array indices

* Get tests passing

---------

Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
Co-authored-by: Eric Allam <eallam@icloud.com>
2024-10-23 20:58:02 +01:00
Eric Allam 7f9091f205 fix metadata system not updating because of dual package hazard (#1428) 2024-10-23 14:02:13 +01:00
James Ritchie 9f6887b048 Embed the hacker news youtube video instead 2024-10-23 13:13:18 +01:00
Dan 982906cbad Vercel sync env vars extension (#1425)
* Added vercelSyncEnvVars extension

* Updated extension and added try catch

* VercelEnvironment fix

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Added changeset

* Moved vercelSynvEnvVars to code and updated core.ts

* Fixed import

* removed type

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-10-23 13:01:30 +01:00
James Ritchie 90514a73bb Added video to hacker news example docs 2024-10-23 12:21:14 +01:00
Eric Allam 2d63c5db50 Set the api rate limiter redis config 2024-10-22 22:22:13 +01:00
Eric Allam 768036a223 Revert the changes to the provider tsconfigs 2024-10-21 15:19:10 +01:00
Eric Allam 2d8a41b18b feat: realtime (#1402)
* Denormalize run tags, increase character limit to 128

* WIP realtime subscribing to runs

* extracted the stream stuff into core, made it more reusable

* WIP tags

* Remove tags for now because it’s not support in electric

* Support async iterables, readable stream, and callback style subscription styles

* Remove tags streaming endpoint

* Add realtime rate limits and scope them to the /realtime path

* WIP rate limt per org

* Introduce per org rate limits

* WIP JWT auth

* Move migrations into new internal db package

* Resolve pnpm lock file

* Authenticating to the realtime API with JWTs are working

* realtime in the client

* Created react-hooks package and starting to move stuff in there

* Improve types for hooks

* schema tasks

* Added useBatch hook

* build uploadthing/fal demo and change how run metadata is synced to the server

* tweaks

* WIL realtime concurrency tracking

* Implement test for realtime client using testcontainers

also updated electric to latest version

* Allow customizing the expiration time of the automatic JWT created after triggering a task

* Add support for subscribing to run tags

* Improve auth types and API

* finalize the realtime API

* Fixed some example stuff

* Allow up to 10 run tags

* Remove core from docker-provider tsconfig paths to prevent it from being typechecked

* do the same for the kubernetes provider

* Fixing some typecheck errors

* Fix webapp type errors

* Update @trigger.dev/platform to 1.0.13

* Fix attw error

* Remove from/to in subscribeToRuns query params

* Add tests for the rate limit middleware and add custom JWT rate limits

* turn off webapp test parallelism

* Finish renaming jwt -> publicAccessToken and automatically give the JWT read access to the tags when using trigger

* Add changeset

* Attempt to fix unit tests in CI

* Skip running the auth rate limit middleware tests for now

* Try a beefier machine

* Try and run webapp tests separately

* Setup env vars

* Make sliding window test more reliabile
2024-10-21 15:07:08 +01:00
nicktrn 67542a54e8 Release 3.0.13
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 19s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-10-18 17:26:03 +01:00
github-actions[bot] f1d89c413b chore: Update version for release (#1410)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-18 17:24:53 +01:00
nicktrn 90593adea5 Fix several restore and resume bugs (#1418)
* try to correct resume messages with missing checkpoint

* prevent creating checkpoints for outdated task waits

* prevent creating checkpoints for outdated batch waits

* use heartbeats to check for and clean up any leftover containers

* lint

* improve exec logging

* improve resume attempt logs

* fix for resuming parents of canceled child runs

* separate SIGTERM from maybe OOM errors

* pretty errors can have magic dashboard links

* prevent uncancellable checkpoints

* simplify task run error code enum export

* grab the last, not the first child run

* Revert "prevent creating checkpoints for outdated batch waits"

This reverts commit f2b5c2ac42.

* Revert "grab the last, not the first child run"

This reverts commit 89ec5c8bfd.

* Revert "prevent creating checkpoints for outdated task waits"

This reverts commit 11066b4e74.

* more logs for resume message handling

* add magic error link comment

* add changeset
2024-10-18 16:46:38 +01:00
Tarun Pratap Singh 235ab90c3d doc: add instructions to create new reference project and run it locally (#1417)
* doc: add instructions to create new reference project and run it locally

* doc: Add instruction for running tunnel

* minor language improvement
2024-10-18 16:03:18 +01:00
James Ritchie ef7f112227 New docs example for creating a HN email summary 2024-10-17 13:56:34 +01:00
James Ritchie db70faa4c7 Move code example to the side menu 2024-10-17 13:56:34 +01:00
shubham yadav 1d87b5ea43 Fix updating many environment variables at once (#1413) 2024-10-17 12:24:50 +01:00
James Ritchie d3f10941fd Added a new Context page for the docs (#1416)
* Added a new context page with task context properties

* Removed code comments

* Added more crosslinks
2024-10-17 11:17:17 +01:00
James Ritchie 6dc556b704 New onboarding question (#1404)
* Updated “Twitter” to be “X (Twitter)”

* added Textarea to storybook

* Updated textarea styling to match input field

* WIP adding new text field to org creation page

* Added description to field

* Submit feedback to Plain when an org signs up

* Formatting improvement

* type improvement

* removed userId

* Moved submitting to Plain into its own file

* Change orgName with name

* use sendToPlain function for the help & feedback email form

* use name not orgName

* import cleanup

* Downgrading plan form uses sendToPlain

* Get the userId from requireUser only

* Added whitespace-pre-wrap to the message property on the run page

* use requireUserId

* Removed old Plain submit code
2024-10-17 10:54:38 +01:00
nicktrn b6d1e0d868 Prevent uncaught socket ack exceptions (#1415)
* catch all the remaining socket acks that could possibly throw

* wrap the remaining handlers in try catch
2024-10-16 22:42:27 +01:00
D-K-P f2c5243905 Copy updates 2024-10-16 17:16:52 +01:00
D-K-P 803350ae6e Updated supabase docs 2024-10-16 15:23:48 +01:00
James Ritchie b225423ce0 docs typo 2024-10-16 15:09:18 +01:00
Niels e36e3d54f2 Make ephemeral storage defaults configurable via env vars (#1407)
* Added support for the env vars `POD_EPHEMERAL_STORAGE_SIZE_LIMIT` and `POD_EPHEMERAL_STORAGE_SIZE_REQUEST`

* Reverted pnpm lockfile

* Made sure there is no diff between the main lockfile & PR's lockfile

* Not touching the storage for the index containers

* Not touching the storage for the prePull container
2024-10-16 13:26:48 +01:00
James Ritchie be7790bbdf Added log size info to the limits page 2024-10-15 16:58:36 +01:00
nicktrn feb4fcdac6 Fix bun runtime by downgrading to 1.1.24 (#1409)
* pin bun to 1.1.24 and use slim image

* add changeset

* add warning about bun version to docs
2024-10-14 18:00:10 +01:00
Dan a6de3f0ff3 README updates (#1408)
* Main README edits

* SDK readme edits

* CLI readme edits

* Create cool-keys-sit.md

---------

Co-authored-by: Eric Allam <eric@trigger.dev>
2024-10-14 16:39:19 +01:00
Matt Aitken 1c80a74885 Added a note to scheduled task docs about the delay option. 2024-10-11 18:58:39 +01:00
Dan 4c6f27e978 Updated sharp docs (#1403)
* Added prerequisites to ffmpeg and puppeteer

* Improved the sharp docs

* Updated sharp task code
2024-10-11 17:11:07 +01:00
nicktrn 367d7bdb4c Add more metadata to checkpoint creation logs 2024-10-11 15:55:31 +01:00
James Ritchie d998a2064e New runs fundamentals page (#1401)
* WIP runs guide

* WIP updating the runs and attempts page

* Added more diagrams to Runs page

* Fixed broken anchors

* More updates and diagram improvements

* Improved diagrams and copy

* More diagram improvements

* copy tweak

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-10-11 14:28:01 +01:00
James Ritchie ba96397f53 Updated the limits page 2024-10-10 15:21:53 +01:00
James Ritchie 244988e212 New Help & Feedback menu and tab-selected styles (#1374)
* Added a new dropdown help and feedback menu to the side menu

* Added a shortcut to the popover menu

* Removed dev cli connected button for now

* Contact us form uses original Feedback component to prevent broken links

* Improved the messaging when selecting different options in the email form

* buttons style tweak

* SideMenuItem supports the trailingIconClassName

* Adding a consistent focus-visible states

* Removing tooltips for now

* Squashed commit of the following:

commit 7d11123c0a
Author: Eric Goldman <eric@sequin.io>
Date:   Mon Sep 30 17:54:06 2024 -0700

    Add sequin guide (#1368)

    Co-authored-by: James Ritchie <james@trigger.dev>

commit 8da495ac00
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Mon Sep 30 13:42:22 2024 +0100

    Improve checkpoint reliability and cleanup of temp files (#1367)

    * improve cleanup reliability

    * improve logging

    * bye-bye execa

    * fix for trailing newlines

    * prettier errors

    * trim args and log output by default

    * fix archive cleanup

    * prevent potential memleak

    * more cleanup debug logs

    * ignore abort during cleanup

    * rename checkpoint dir env var and move to helper

    * add global never throw override

    * add tmp cleaner

    * also clean up checkpoint dir by default

    * split by any whitespace, not just tabs

    * only create tmp cleaner if paths to clean

commit 69ec68ee31
Author: Eric Allam <eallam@icloud.com>
Date:   Sun Sep 29 19:18:39 2024 -0700

    Release 3.0.9

commit a6ea8444c9
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date:   Sun Sep 29 19:17:26 2024 -0700

    chore: Update version for release (#1366)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

commit 4c1ee3d6ea
Author: Eric Allam <eallam@icloud.com>
Date:   Sun Sep 29 19:09:38 2024 -0700

    fix: run metadata not working when using npx/pnpm dlx

* More support for custom-focus

* More custom focus styles added

* Support for focus-visible style for the Segmented control

* Fixed table triple dot menu z-index issue

* Improved help menu wording

* When you submit the help form, close the modal

* focus-visible style for radio buttons

* button prop is now optional in the SideMenu component

* focus styling for a text link

* Deleted unused sequin files
2024-10-10 14:28:18 +01:00
Eric Allam b1319fb88c Update limits.mdx 2024-10-10 14:19:40 +01:00
James Ritchie cff2ebba49 Change plan feedback modal (#1393)
* Checkbox component can have its label styles

* Improved the dialog footer

* Handle sending feedback to Slack using Plain

* WIP making the modal conditional

* Moved the Plain form action into the select plan file

* removed comment

* Show a confirmation diaglog if you’re downgrading from Pro to Hobby

* Downgrading to Hobby works

* Use redirectWithErrorMessage instead of throw error

* The cancel form now submits the data correctly

* Modals don’t trigger when you upgrade

* Copy improvements

* Added a tooltip to explain the link to the pricing page

* Squashed commit of the following:

commit 886429b0ed
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:36:46 2024 +0100

    Removed emails, @trigger.dev/database and @trigger.dev/otlp-importer from changesets config

commit f65157a14f
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:31:27 2024 +0100

    Lockfile with run-engine removed

commit 3d67bb81e9
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:24:31 2024 +0100

    Removed run-engine from the webapp package.json/tsconfig

commit d30e9713f4
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:06:04 2024 +0100

    Dockerfile fix because the database package has been moved

commit f2babbf637
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 09:41:22 2024 -0700

    Internal packages (testcontainers, redis-worker and zod-worker) (#1392)

    * Some notes on the new run engine

    * lockfile with setup for the run engine

    * Documenting where TaskRun is currently mutated, to try figure out the shape of the new system

    * Added notes about how triggering currently works

    * Details about when triggering happens

    * Lots of notes about waitpoints

    * Started scaffolding the RunEngine

    * Sketch of Prisma waitpoint schema while it’s fresh in my mind

    * Got Prisma working with testcontainers

    * Use beforeEach/afterEach

    * Simple Prisma and Redis test

    * Return Redis options instead of a client

    * Simplified things

    * A very simple FIFO pull-based queue to check the tests working properly

    * Use vitest extend

    * Separate redis, postgres and combined tests for faster testing

    * Some fixes and test improvements

    * Pass a logger into the queue

    * A queue processor that processes items from the given queue as fast as it can

    * Test for retrying an item that wasn’t processed

    * First draft of waitpoints in the Prisma schema

    * Remove the custom logger from the test

    * Added a completedAt to Waitpoint

    * Notes on the flow for an execution starting

    * Added redlock, moved some files around

    * Starting point for the TaskRunExecutionSnapshot table

    * Added relationships to TaskRunExecutionSnapshot

    * Change some tsconfig

    * Moved some things around

    * Added some packages

    * WIP on the RunQueue

    * Fix for some imports

    * Key producer with some tests

    * Removed the nv type from the keys… it’s not useful to do global queries

    * Passing unit tests for all the public key producer functions

    * Some basic tests passing for the RunQueue

    * Simple enqueue test working

    * Enqueue and dequeue for dev is working

    * Don’t log everything during the tests

    * Enqueuing/dequeuing from the shared queue is working

    * Tests for getting a shared queue

    * The key producer sharedQueue can now be named, to allow multiple separate queues

    * The key producer uses the name of the queue as the input

    * Extra info in the Prisma schema

    * Dequeuing a message gets the payload and sets the task concurrency all in one Lua script

    * Adding more keys so we can read the concurrency from the queue

    * Setting the concurrency with dequeue and enquque is working

    * Improved the tests and fixed some bugs

    * Acking is resetting the concurrencies

    * Check the key has been removed after acking

    * Nacking is working

    * Changed the package to CommonJS + Node10 so it works with Redlock

    * Moved the database, otel and emails packages to be in internal-packages

    * Moved some Prisma code to the database package

    * Started using the RunEngine for triggering

    * Progress on run engine triggering, first waitpoint code

    * Create a delay waitpoint

    * Moved ZodWorker to an internal package so it can be used in the run engine as well as the webapp

    * Web app now uses the zod worker package

    * Added parseNaturalLanguageDuration to core/apps

    * internal-packages/zod-worker in the lockfile

    * Pass in the master queue, remove old rebalance workers code

    * Add masterQueue to TaskRun

    * Fixed the tests

    * Moved waitpoint code into the run engine, also the zod worker

    * Completing waitpoints

    * An experiment to create a new test container with environment

    * More changes to triggering

    * Started testing triggering

    * Test for a run getting triggered and being enqueued

    * Removed dequeueMessageInEnv

    * Update dev queue tests to use the shared queue function

    * Schema changes for TaskRunExecutionSnapshot

    * First execution snapshot when the run is created. Dequeue run function added to the engine

    * Separate internal package for testcontainers so they can be used elsewhere

    * Remove the simple queue and testcontainers from the run-engine. They’re going to be separate

    * Fix for the wrong path to the Prisma schem,a

    * Added the testcontainers package to the run-engine

    * redis-worker package, just a copy of the simple queue for now

    * The queue now uses Lua to enqueue dequeue

    * The queue now has a catalog and an invisible period after dequeuing

    * Added a visibility timeout and acking, with tests

    * Added more Redis connection logging, deleted todos

    * Visibility timeouts are now defined on the catalog and can be overridden when enqueuing

    * Dequeue multiple items at once

    * Test for dequeuing multiple items

    * Export some types to be used elsewhere

    * Partial refactor of the processor

    * First stab at a worker with concurrency and NodeWorkers

    * Don’t have a default visibility timeout in the queue

    * Worker setup and processing items in a simple test

    * Process jobs in parallel with retrying

    * Get the attempt when dequeuing

    * Workers do exponential backoff

    * Moved todos

    * DLQ functionality

    * DLQ tests

    * Same cluster for all keys in the same queue

    * Added DLQ tests

    * Whitespace

    * Redis pubsub to redrive from the worker

    * Fixed database paths

    * Fix for path to zod-worker

    * Fixes for typecheck errors, mostly with TS versions and module resolution

    * Redlock required a patch

    * Moved the new DB migrations to the new database package folder

    * Remove the run-engine package

    * Remove the RunEngine prisma schema changes

    * Delete triggerTaskV2

    * Remove zodworker test script (no tests)

    * Update test-containers readme

    * Generate the client first

    * Use a specific version of the prisma package

    * Generate the prisma client before running the unit tests

commit fc609470c4
Author: Dan <8297864+D-K-P@users.noreply.github.com>
Date:   Tue Oct 8 14:36:03 2024 +0100

    Supabase database webhook example upgrade (#1386)

    * Added overview for guides and examples section and split them all out

    * New supabase guide wip

    * Updated images and improved docs

    * Trimmed the supabase prereqs

    * Supabase guide wip

    * more updates

    * Replaced old database webhook guide

    * Created one intro page and removed snippets

    * Updated guide sidebar titles

    * Code updates

    * More improvements

    * Updates and added images

    * Compressed image

    * Updated guides descriptions and edge function basic

    * Removed bold

    * Updated redirects

    * Fixed broken links

    * Updated intro

commit 07f82eae54
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 13:28:54 2024 +0100

    Release 3.0.11

commit 13ebfcc5b9
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date:   Tue Oct 8 13:24:38 2024 +0100

    chore: Update version for release (#1381)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

commit 2a04d17e1f
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:24:23 2024 +0100

    Simplify showLogs expression

commit 002ae4bc0d
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:22:29 2024 +0100

    Fix dotenv overrides for dev runs (#1388)

    * override dashboard dev env vars with local .env

    * add changeset

    * add simple task for testing env vars

commit 047cb00417
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:22:05 2024 +0100

    Disable schedules for deleted orgs on next tick (#1383)

    * disable schedules for deleted orgs

    * add debug logs

commit 2c014f725a
Author: James Ritchie <james@trigger.dev>
Date:   Sun Oct 6 13:02:00 2024 -0700

    Override log retention (#1385)

    * set full log retention as admin

    * If run.logsDeletedAt is set, don’t bother getting the trace

commit a69e04f03a
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Sat Oct 5 14:18:58 2024 +0100

    Include push output in logs for self-hosted deploys (#1382)

    * include push output in logs

    * changeset

commit c5488df8ca
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Sat Oct 5 13:12:47 2024 +0100

    Fix CLI downgrade check (#1380)

    * fix downgrade detection

    * remove unused semver package from webapp

    * add changeset

commit 1caec27f72
Author: Eric Allam <eric@trigger.dev>
Date:   Fri Oct 4 15:33:35 2024 -0700

    docs: Max duration (#1379)

    * maxDuration docs

    * Update the init command to set the maxDuration and include a commented out maxDuration in the config file

commit e14c954e12
Author: Eric Allam <eallam@icloud.com>
Date:   Fri Oct 4 15:02:05 2024 -0700

    Release 3.0.10

commit 8e61f5d631
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date:   Fri Oct 4 14:59:07 2024 -0700

    chore: Update version for release (#1378)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

commit 08db565a72
Author: Eric Allam <eallam@icloud.com>
Date:   Thu Oct 3 12:38:25 2024 -0700

    improve the timed out description

commit 6d0884254e
Author: Eric Allam <eric@trigger.dev>
Date:   Thu Oct 3 12:43:26 2024 -0700

    feat: Add maxDuration to tasks (#1377)

    * WIP

    * Get max duration working on deployed runs

    * Actually set the timed out runs to status = TIMED_OUT

    * The client status for TIMED_OUT is now MAX_DURATION_EXCEEDED

    * New TimedOutIcon

    * Added new timedout icon

    * Add ability to opt-out of maxDuration with timeout.None

    * MAX_DURATION_EXCEEDED -> TIMED_OUT

    * changeset

    * Improved styling for the status tooltip content

    ---------

    Co-authored-by: James Ritchie <james@trigger.dev>

commit 665ccf88b7
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Thu Oct 3 12:33:18 2024 +0100

    Update github actions and self-hosting docs

commit 1ff7b861ca
Author: Eric Allam <eric@trigger.dev>
Date:   Wed Oct 2 18:26:36 2024 -0700

    Add max queue depth limits (#1376)

    * Add runs to an env queue, as well as the actual queue

    * Add queue size limit guard on triggering tasks

commit c531a9d986
Author: Eric Allam <eric@trigger.dev>
Date:   Wed Oct 2 15:30:39 2024 -0700

    fix: cleanup ttl expire run graphile jobs (#1373)

    * fix: remove ttl expire run graphile jobs when a run is started or completed

    * Update expireEnqueuedRun.server.ts

commit 0bf500fa95
Author: Matt Aitken <matt@mattaitken.com>
Date:   Wed Oct 2 15:30:16 2024 -0700

    Prioritize finishing waited runs (#1375)

    * If a tree node is missing, estimate the size as zero

    * Task to test prioritizing finishing existing runs after triggerAndWaits

    * When requeuing a run with a checkpoint, put it in the queue with the parent run time so it’s correctly prioritized

    * The same change but if there’s no checkpoint

* Squashed commit of the following:

commit 886429b0ed
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:36:46 2024 +0100

    Removed emails, @trigger.dev/database and @trigger.dev/otlp-importer from changesets config

commit f65157a14f
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:31:27 2024 +0100

    Lockfile with run-engine removed

commit 3d67bb81e9
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:24:31 2024 +0100

    Removed run-engine from the webapp package.json/tsconfig

commit d30e9713f4
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 18:06:04 2024 +0100

    Dockerfile fix because the database package has been moved

commit f2babbf637
Author: Matt Aitken <matt@mattaitken.com>
Date:   Tue Oct 8 09:41:22 2024 -0700

    Internal packages (testcontainers, redis-worker and zod-worker) (#1392)

    * Some notes on the new run engine

    * lockfile with setup for the run engine

    * Documenting where TaskRun is currently mutated, to try figure out the shape of the new system

    * Added notes about how triggering currently works

    * Details about when triggering happens

    * Lots of notes about waitpoints

    * Started scaffolding the RunEngine

    * Sketch of Prisma waitpoint schema while it’s fresh in my mind

    * Got Prisma working with testcontainers

    * Use beforeEach/afterEach

    * Simple Prisma and Redis test

    * Return Redis options instead of a client

    * Simplified things

    * A very simple FIFO pull-based queue to check the tests working properly

    * Use vitest extend

    * Separate redis, postgres and combined tests for faster testing

    * Some fixes and test improvements

    * Pass a logger into the queue

    * A queue processor that processes items from the given queue as fast as it can

    * Test for retrying an item that wasn’t processed

    * First draft of waitpoints in the Prisma schema

    * Remove the custom logger from the test

    * Added a completedAt to Waitpoint

    * Notes on the flow for an execution starting

    * Added redlock, moved some files around

    * Starting point for the TaskRunExecutionSnapshot table

    * Added relationships to TaskRunExecutionSnapshot

    * Change some tsconfig

    * Moved some things around

    * Added some packages

    * WIP on the RunQueue

    * Fix for some imports

    * Key producer with some tests

    * Removed the nv type from the keys… it’s not useful to do global queries

    * Passing unit tests for all the public key producer functions

    * Some basic tests passing for the RunQueue

    * Simple enqueue test working

    * Enqueue and dequeue for dev is working

    * Don’t log everything during the tests

    * Enqueuing/dequeuing from the shared queue is working

    * Tests for getting a shared queue

    * The key producer sharedQueue can now be named, to allow multiple separate queues

    * The key producer uses the name of the queue as the input

    * Extra info in the Prisma schema

    * Dequeuing a message gets the payload and sets the task concurrency all in one Lua script

    * Adding more keys so we can read the concurrency from the queue

    * Setting the concurrency with dequeue and enquque is working

    * Improved the tests and fixed some bugs

    * Acking is resetting the concurrencies

    * Check the key has been removed after acking

    * Nacking is working

    * Changed the package to CommonJS + Node10 so it works with Redlock

    * Moved the database, otel and emails packages to be in internal-packages

    * Moved some Prisma code to the database package

    * Started using the RunEngine for triggering

    * Progress on run engine triggering, first waitpoint code

    * Create a delay waitpoint

    * Moved ZodWorker to an internal package so it can be used in the run engine as well as the webapp

    * Web app now uses the zod worker package

    * Added parseNaturalLanguageDuration to core/apps

    * internal-packages/zod-worker in the lockfile

    * Pass in the master queue, remove old rebalance workers code

    * Add masterQueue to TaskRun

    * Fixed the tests

    * Moved waitpoint code into the run engine, also the zod worker

    * Completing waitpoints

    * An experiment to create a new test container with environment

    * More changes to triggering

    * Started testing triggering

    * Test for a run getting triggered and being enqueued

    * Removed dequeueMessageInEnv

    * Update dev queue tests to use the shared queue function

    * Schema changes for TaskRunExecutionSnapshot

    * First execution snapshot when the run is created. Dequeue run function added to the engine

    * Separate internal package for testcontainers so they can be used elsewhere

    * Remove the simple queue and testcontainers from the run-engine. They’re going to be separate

    * Fix for the wrong path to the Prisma schem,a

    * Added the testcontainers package to the run-engine

    * redis-worker package, just a copy of the simple queue for now

    * The queue now uses Lua to enqueue dequeue

    * The queue now has a catalog and an invisible period after dequeuing

    * Added a visibility timeout and acking, with tests

    * Added more Redis connection logging, deleted todos

    * Visibility timeouts are now defined on the catalog and can be overridden when enqueuing

    * Dequeue multiple items at once

    * Test for dequeuing multiple items

    * Export some types to be used elsewhere

    * Partial refactor of the processor

    * First stab at a worker with concurrency and NodeWorkers

    * Don’t have a default visibility timeout in the queue

    * Worker setup and processing items in a simple test

    * Process jobs in parallel with retrying

    * Get the attempt when dequeuing

    * Workers do exponential backoff

    * Moved todos

    * DLQ functionality

    * DLQ tests

    * Same cluster for all keys in the same queue

    * Added DLQ tests

    * Whitespace

    * Redis pubsub to redrive from the worker

    * Fixed database paths

    * Fix for path to zod-worker

    * Fixes for typecheck errors, mostly with TS versions and module resolution

    * Redlock required a patch

    * Moved the new DB migrations to the new database package folder

    * Remove the run-engine package

    * Remove the RunEngine prisma schema changes

    * Delete triggerTaskV2

    * Remove zodworker test script (no tests)

    * Update test-containers readme

    * Generate the client first

    * Use a specific version of the prisma package

    * Generate the prisma client before running the unit tests

commit fc609470c4
Author: Dan <8297864+D-K-P@users.noreply.github.com>
Date:   Tue Oct 8 14:36:03 2024 +0100

    Supabase database webhook example upgrade (#1386)

    * Added overview for guides and examples section and split them all out

    * New supabase guide wip

    * Updated images and improved docs

    * Trimmed the supabase prereqs

    * Supabase guide wip

    * more updates

    * Replaced old database webhook guide

    * Created one intro page and removed snippets

    * Updated guide sidebar titles

    * Code updates

    * More improvements

    * Updates and added images

    * Compressed image

    * Updated guides descriptions and edge function basic

    * Removed bold

    * Updated redirects

    * Fixed broken links

    * Updated intro

commit 07f82eae54
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 13:28:54 2024 +0100

    Release 3.0.11

commit 13ebfcc5b9
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date:   Tue Oct 8 13:24:38 2024 +0100

    chore: Update version for release (#1381)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

commit 2a04d17e1f
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:24:23 2024 +0100

    Simplify showLogs expression

commit 002ae4bc0d
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:22:29 2024 +0100

    Fix dotenv overrides for dev runs (#1388)

    * override dashboard dev env vars with local .env

    * add changeset

    * add simple task for testing env vars

commit 047cb00417
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Tue Oct 8 09:22:05 2024 +0100

    Disable schedules for deleted orgs on next tick (#1383)

    * disable schedules for deleted orgs

    * add debug logs

commit 2c014f725a
Author: James Ritchie <james@trigger.dev>
Date:   Sun Oct 6 13:02:00 2024 -0700

    Override log retention (#1385)

    * set full log retention as admin

    * If run.logsDeletedAt is set, don’t bother getting the trace

commit a69e04f03a
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Sat Oct 5 14:18:58 2024 +0100

    Include push output in logs for self-hosted deploys (#1382)

    * include push output in logs

    * changeset

commit c5488df8ca
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Sat Oct 5 13:12:47 2024 +0100

    Fix CLI downgrade check (#1380)

    * fix downgrade detection

    * remove unused semver package from webapp

    * add changeset

commit 1caec27f72
Author: Eric Allam <eric@trigger.dev>
Date:   Fri Oct 4 15:33:35 2024 -0700

    docs: Max duration (#1379)

    * maxDuration docs

    * Update the init command to set the maxDuration and include a commented out maxDuration in the config file

commit e14c954e12
Author: Eric Allam <eallam@icloud.com>
Date:   Fri Oct 4 15:02:05 2024 -0700

    Release 3.0.10

commit 8e61f5d631
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date:   Fri Oct 4 14:59:07 2024 -0700

    chore: Update version for release (#1378)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

commit 08db565a72
Author: Eric Allam <eallam@icloud.com>
Date:   Thu Oct 3 12:38:25 2024 -0700

    improve the timed out description

commit 6d0884254e
Author: Eric Allam <eric@trigger.dev>
Date:   Thu Oct 3 12:43:26 2024 -0700

    feat: Add maxDuration to tasks (#1377)

    * WIP

    * Get max duration working on deployed runs

    * Actually set the timed out runs to status = TIMED_OUT

    * The client status for TIMED_OUT is now MAX_DURATION_EXCEEDED

    * New TimedOutIcon

    * Added new timedout icon

    * Add ability to opt-out of maxDuration with timeout.None

    * MAX_DURATION_EXCEEDED -> TIMED_OUT

    * changeset

    * Improved styling for the status tooltip content

    ---------

    Co-authored-by: James Ritchie <james@trigger.dev>

commit 665ccf88b7
Author: nicktrn <55853254+nicktrn@users.noreply.github.com>
Date:   Thu Oct 3 12:33:18 2024 +0100

    Update github actions and self-hosting docs

commit 1ff7b861ca
Author: Eric Allam <eric@trigger.dev>
Date:   Wed Oct 2 18:26:36 2024 -0700

    Add max queue depth limits (#1376)

    * Add runs to an env queue, as well as the actual queue

    * Add queue size limit guard on triggering tasks

commit c531a9d986
Author: Eric Allam <eric@trigger.dev>
Date:   Wed Oct 2 15:30:39 2024 -0700

    fix: cleanup ttl expire run graphile jobs (#1373)

    * fix: remove ttl expire run graphile jobs when a run is started or completed

    * Update expireEnqueuedRun.server.ts

commit 0bf500fa95
Author: Matt Aitken <matt@mattaitken.com>
Date:   Wed Oct 2 15:30:16 2024 -0700

    Prioritize finishing waited runs (#1375)

    * If a tree node is missing, estimate the size as zero

    * Task to test prioritizing finishing existing runs after triggerAndWaits

    * When requeuing a run with a checkpoint, put it in the queue with the parent run time so it’s correctly prioritized

    * The same change but if there’s no checkpoint

* Revert "Squashed commit of the following:"

This reverts commit b837b5a558dc5187d89b09135276d16f6856f455.

* Removed console logs

* cleaned up conditionals

* Unlock free plan state

* Fixed subscribe button if you’re already github verified

* Simplified the downgrade reasons logic

* made periodEnd required

---------

Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
2024-10-10 14:12:15 +01:00
Dan 25c7ff173f Updated guides intro and side menu (#1398)
* Updated intro and moved stripe webhooks into the webhooks section

* Added additional resources links to nextjs and remix

* Updated intro page

* Changed formatting to improve layout

* Removed Supabase card from frameworks
2024-10-10 12:55:03 +01:00
Dan a6dbf8433c Webhook guides (#1396)
* Added nextjs webhook guide

* Updated intro page

* Copy improvement

* Added repo links to both supabase guides

* Updated structure and added an overview page

* Updated guides and simplified example code

* Added webhook handler for pages and split the docs

* Updated links
2024-10-10 10:18:28 +01:00
nicktrn 73f8d4f0d7 Release 3.0.12
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-10-09 16:21:13 +01:00
nicktrn 61c7605b54 Remove redlock patch 2024-10-09 16:20:40 +01:00
github-actions[bot] 8a70ce4cff chore: Update version for release (#1394)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-09 16:15:58 +01:00
nicktrn 4f85119dfd Misc fixes related to error display (#1397)
* Fix execute error handling

* replace internal errors on attempts

* correctly display env var errors while indexing

* display correct errors on crashed attempts

* add changeset
2024-10-09 15:10:48 +01:00
nicktrn 94170dec3b Fix dev command args 2024-10-09 13:33:19 +01:00
nicktrn bf05dac668 Fix last few internal packages paths 2024-10-09 12:52:52 +01:00
nicktrn 215c8ed6b2 Remove unused path arg from the CLI dev command (#1395)
* remove path arg from dev cli command

* add changeset
2024-10-09 12:49:35 +01:00
James Ritchie 2483da251a Removed the path argument from CLI dev command 2024-10-09 12:37:20 +01:00
nicktrn bf15d8aff1 Improve coordinator logs and extend structured logger (#1389)
* docker provider shouldn't force simulate by default

* structured logs for all things coordinator

* attributes for handler loggers

* add changeset

* fix tmp cleaner types

* remove unused simple logger import

* fields from args should override existing fields

* improve socket logs

* change log message position for easier scanning

* more logging improvements, more metadata
2024-10-09 12:20:55 +01:00
nicktrn 4b0f677774 Prettier errors and related improvements (#1387)
* improve get attempt payload logging

* only log checkpoint readiness timeouts, don't crash the run

* improve coordinator errors

* add links export to core

* remove unused deploy error utilities

* update cli errors and use new links from core

* log remaining failure reasons

* also parse execute errors in deployed worker

* add signal to unexpected exit messages

* start displaying prettier internal errors

* improve unexpected exit error parsing

* better errors for crashes

* fix unexpected error parsing for dev runs

* changeset

* parse graceful exit timeouts
2024-10-09 12:12:47 +01:00
Matt Aitken 886429b0ed Removed emails, @trigger.dev/database and @trigger.dev/otlp-importer from changesets config 2024-10-08 18:36:46 +01:00
Matt Aitken f65157a14f Lockfile with run-engine removed 2024-10-08 18:31:27 +01:00
Matt Aitken 3d67bb81e9 Removed run-engine from the webapp package.json/tsconfig 2024-10-08 18:24:31 +01:00
Matt Aitken d30e9713f4 Dockerfile fix because the database package has been moved 2024-10-08 18:06:04 +01:00
Matt Aitken f2babbf637 Internal packages (testcontainers, redis-worker and zod-worker) (#1392)
* Some notes on the new run engine

* lockfile with setup for the run engine

* Documenting where TaskRun is currently mutated, to try figure out the shape of the new system

* Added notes about how triggering currently works

* Details about when triggering happens

* Lots of notes about waitpoints

* Started scaffolding the RunEngine

* Sketch of Prisma waitpoint schema while it’s fresh in my mind

* Got Prisma working with testcontainers

* Use beforeEach/afterEach

* Simple Prisma and Redis test

* Return Redis options instead of a client

* Simplified things

* A very simple FIFO pull-based queue to check the tests working properly

* Use vitest extend

* Separate redis, postgres and combined tests for faster testing

* Some fixes and test improvements

* Pass a logger into the queue

* A queue processor that processes items from the given queue as fast as it can

* Test for retrying an item that wasn’t processed

* First draft of waitpoints in the Prisma schema

* Remove the custom logger from the test

* Added a completedAt to Waitpoint

* Notes on the flow for an execution starting

* Added redlock, moved some files around

* Starting point for the TaskRunExecutionSnapshot table

* Added relationships to TaskRunExecutionSnapshot

* Change some tsconfig

* Moved some things around

* Added some packages

* WIP on the RunQueue

* Fix for some imports

* Key producer with some tests

* Removed the nv type from the keys… it’s not useful to do global queries

* Passing unit tests for all the public key producer functions

* Some basic tests passing for the RunQueue

* Simple enqueue test working

* Enqueue and dequeue for dev is working

* Don’t log everything during the tests

* Enqueuing/dequeuing from the shared queue is working

* Tests for getting a shared queue

* The key producer sharedQueue can now be named, to allow multiple separate queues

* The key producer uses the name of the queue as the input

* Extra info in the Prisma schema

* Dequeuing a message gets the payload and sets the task concurrency all in one Lua script

* Adding more keys so we can read the concurrency from the queue

* Setting the concurrency with dequeue and enquque is working

* Improved the tests and fixed some bugs

* Acking is resetting the concurrencies

* Check the key has been removed after acking

* Nacking is working

* Changed the package to CommonJS + Node10 so it works with Redlock

* Moved the database, otel and emails packages to be in internal-packages

* Moved some Prisma code to the database package

* Started using the RunEngine for triggering

* Progress on run engine triggering, first waitpoint code

* Create a delay waitpoint

* Moved ZodWorker to an internal package so it can be used in the run engine as well as the webapp

* Web app now uses the zod worker package

* Added parseNaturalLanguageDuration to core/apps

* internal-packages/zod-worker in the lockfile

* Pass in the master queue, remove old rebalance workers code

* Add masterQueue to TaskRun

* Fixed the tests

* Moved waitpoint code into the run engine, also the zod worker

* Completing waitpoints

* An experiment to create a new test container with environment

* More changes to triggering

* Started testing triggering

* Test for a run getting triggered and being enqueued

* Removed dequeueMessageInEnv

* Update dev queue tests to use the shared queue function

* Schema changes for TaskRunExecutionSnapshot

* First execution snapshot when the run is created. Dequeue run function added to the engine

* Separate internal package for testcontainers so they can be used elsewhere

* Remove the simple queue and testcontainers from the run-engine. They’re going to be separate

* Fix for the wrong path to the Prisma schem,a

* Added the testcontainers package to the run-engine

* redis-worker package, just a copy of the simple queue for now

* The queue now uses Lua to enqueue dequeue

* The queue now has a catalog and an invisible period after dequeuing

* Added a visibility timeout and acking, with tests

* Added more Redis connection logging, deleted todos

* Visibility timeouts are now defined on the catalog and can be overridden when enqueuing

* Dequeue multiple items at once

* Test for dequeuing multiple items

* Export some types to be used elsewhere

* Partial refactor of the processor

* First stab at a worker with concurrency and NodeWorkers

* Don’t have a default visibility timeout in the queue

* Worker setup and processing items in a simple test

* Process jobs in parallel with retrying

* Get the attempt when dequeuing

* Workers do exponential backoff

* Moved todos

* DLQ functionality

* DLQ tests

* Same cluster for all keys in the same queue

* Added DLQ tests

* Whitespace

* Redis pubsub to redrive from the worker

* Fixed database paths

* Fix for path to zod-worker

* Fixes for typecheck errors, mostly with TS versions and module resolution

* Redlock required a patch

* Moved the new DB migrations to the new database package folder

* Remove the run-engine package

* Remove the RunEngine prisma schema changes

* Delete triggerTaskV2

* Remove zodworker test script (no tests)

* Update test-containers readme

* Generate the client first

* Use a specific version of the prisma package

* Generate the prisma client before running the unit tests
2024-10-08 17:41:22 +01:00
Dan fc609470c4 Supabase database webhook example upgrade (#1386)
* Added overview for guides and examples section and split them all out

* New supabase guide wip

* Updated images and improved docs

* Trimmed the supabase prereqs

* Supabase guide wip

* more updates

* Replaced old database webhook guide

* Created one intro page and removed snippets

* Updated guide sidebar titles

* Code updates

* More improvements

* Updates and added images

* Compressed image

* Updated guides descriptions and edge function basic

* Removed bold

* Updated redirects

* Fixed broken links

* Updated intro
2024-10-08 14:36:03 +01:00
nicktrn 07f82eae54 Release 3.0.11
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 4s
🚀 Publish Trigger.dev Docker / units (push) Failing after 19s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-10-08 13:28:54 +01:00
github-actions[bot] 13ebfcc5b9 chore: Update version for release (#1381)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-08 13:24:38 +01:00
nicktrn 2a04d17e1f Simplify showLogs expression 2024-10-08 09:24:23 +01:00
nicktrn 002ae4bc0d Fix dotenv overrides for dev runs (#1388)
* override dashboard dev env vars with local .env

* add changeset

* add simple task for testing env vars
2024-10-08 09:22:29 +01:00
nicktrn 047cb00417 Disable schedules for deleted orgs on next tick (#1383)
* disable schedules for deleted orgs

* add debug logs
2024-10-08 09:22:05 +01:00
James Ritchie 2c014f725a Override log retention (#1385)
* set full log retention as admin

* If run.logsDeletedAt is set, don’t bother getting the trace
2024-10-06 13:02:00 -07:00
nicktrn a69e04f03a Include push output in logs for self-hosted deploys (#1382)
* include push output in logs

* changeset
2024-10-05 14:18:58 +01:00
nicktrn c5488df8ca Fix CLI downgrade check (#1380)
* fix downgrade detection

* remove unused semver package from webapp

* add changeset
2024-10-05 13:12:47 +01:00
Eric Allam 1caec27f72 docs: Max duration (#1379)
* maxDuration docs

* Update the init command to set the maxDuration and include a commented out maxDuration in the config file
2024-10-04 15:33:35 -07:00
Eric Allam e14c954e12 Release 3.0.10 2024-10-04 15:02:05 -07:00
github-actions[bot] 8e61f5d631 chore: Update version for release (#1378)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-04 14:59:07 -07:00
Eric Allam 08db565a72 improve the timed out description
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-10-03 12:44:35 -07:00
Eric Allam 6d0884254e feat: Add maxDuration to tasks (#1377)
* WIP

* Get max duration working on deployed runs

* Actually set the timed out runs to status = TIMED_OUT

* The client status for TIMED_OUT is now MAX_DURATION_EXCEEDED

* New TimedOutIcon

* Added new timedout icon

* Add ability to opt-out of maxDuration with timeout.None

* MAX_DURATION_EXCEEDED -> TIMED_OUT

* changeset

* Improved styling for the status tooltip content

---------

Co-authored-by: James Ritchie <james@trigger.dev>
2024-10-03 12:43:26 -07:00
nicktrn 665ccf88b7 Update github actions and self-hosting docs 2024-10-03 12:33:18 +01:00
Eric Allam 1ff7b861ca Add max queue depth limits (#1376)
* Add runs to an env queue, as well as the actual queue

* Add queue size limit guard on triggering tasks
2024-10-02 18:26:36 -07:00
Eric Allam c531a9d986 fix: cleanup ttl expire run graphile jobs (#1373)
* fix: remove ttl expire run graphile jobs when a run is started or completed

* Update expireEnqueuedRun.server.ts
2024-10-02 15:30:39 -07:00
Matt Aitken 0bf500fa95 Prioritize finishing waited runs (#1375)
* If a tree node is missing, estimate the size as zero

* Task to test prioritizing finishing existing runs after triggerAndWaits

* When requeuing a run with a checkpoint, put it in the queue with the parent run time so it’s correctly prioritized

* The same change but if there’s no checkpoint
2024-10-02 15:30:16 -07:00
James Ritchie ceabfba767 Added puppeteer imports to the puppeteer trigger.config snippets 2024-10-01 15:26:47 -07:00
Dan 27e8f5c59a Added deepgram transcription example (#1372) 2024-10-01 13:40:09 +01:00
James Ritchie fff1c0a6f2 Sequin guide updates (#1371)
* Updated intro image style to match trigger style

* Typo fix

* Added some urls + a few copy fixes

* Added a new Guides side menu section
2024-09-30 18:11:49 -07:00
Eric Goldman 7d11123c0a Add sequin guide (#1368)
Co-authored-by: James Ritchie <james@trigger.dev>
2024-09-30 17:54:06 -07:00
nicktrn 8da495ac00 Improve checkpoint reliability and cleanup of temp files (#1367)
* improve cleanup reliability

* improve logging

* bye-bye execa

* fix for trailing newlines

* prettier errors

* trim args and log output by default

* fix archive cleanup

* prevent potential memleak

* more cleanup debug logs

* ignore abort during cleanup

* rename checkpoint dir env var and move to helper

* add global never throw override

* add tmp cleaner

* also clean up checkpoint dir by default

* split by any whitespace, not just tabs

* only create tmp cleaner if paths to clean
2024-09-30 13:42:22 +01:00
Eric Allam 69ec68ee31 Release 3.0.9
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 1s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-09-29 19:18:39 -07:00
github-actions[bot] a6ea8444c9 chore: Update version for release (#1366)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-29 19:17:26 -07:00
Eric Allam 4c1ee3d6ea fix: run metadata not working when using npx/pnpm dlx 2024-09-29 19:09:38 -07:00
James Ritchie 8e38db96a5 Added error descriptions to each of the lifecycle functions 2024-09-27 16:47:30 +01:00
Dan f154fcc9c5 Prisma guide (#1365)
* fix header

* Prisma first pass

* Copy updates

* Formatting

* Typo
2024-09-27 14:53:23 +01:00
James Ritchie 4906fe9cf0 Run page links to tasks & replay run modal improvements (#1364)
* Removed the inline-code accessory from the logs when calling trigger or batchTrigger from a run

* Removed re2 from the v3 catalog

* Added a Root badge to the runs list

* Keep the side panel open when switching tasks & remove links from detail panel

* Root and parent task styling inspector

* Hide the root badge if the task isn’t the root

* margin between the dev not running message

* improved spacing of items

* Improved Root badge style

* Show a table of triggered runs in the inspector

* Add parentSpanId index to the TaskRun table

* Fix for the run inspector now opening when linked from another run/replay

* Triggered runs table has a max height

* Added a description to the replay run modal and improved the styling slightly

* Only include a bottom border when the triggered run table is more than 4 items

* Improved the triggered runs table borders

* Improved the tables so they can have an optional sticky header

* Added table types to storybook

* Fix for hover states on different backgrounds & runs table select cell
2024-09-27 12:14:44 +01:00
Eric Allam 3f6fda0c3e Create FUNDING.yml 2024-09-26 18:22:54 +01:00
Eric Allam 6989f8366b Add a release guide 2024-09-26 15:43:27 +01:00
Eric Allam 9e61c6a490 Add runs metadata to docs sidebar 2024-09-26 15:15:00 +01:00
Eric Allam d32157212c Release 3.0.8
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-09-26 14:35:45 +01:00
github-actions[bot] 926459893b chore: Update version for release (#1351)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-26 14:33:30 +01:00
Eric Allam a0c7592110 Set the final error on the task run if it exists 2024-09-26 13:25:26 +01:00
Eric Allam 021efa382c Update metadata.update to save in API docs 2024-09-26 12:49:23 +01:00
Dan 308715b4ca Added supabase database operations and new snippet (#1359)
* Added supabase database examples

* Copy updates

* More copy updates

* Added comment about generating the typescript types

* Updated intro table

* Improved title

* Added supabase-docs-cards to go at the bottom of the examples and guides

* merge main

* Link fix

* Fix more links
2024-09-26 11:10:20 +01:00
Eric Allam 5fe2bab381 Fixed test page typescript error 2024-09-26 11:01:14 +01:00
Eric Allam eda348226d Store seed metadata separately to use in test UI and when replaying a run 2024-09-26 10:47:35 +01:00
Eric Allam 3c492bc202 feat: Run metadata (#1357)
* Run metadata

* Remove metadata from context, move it to it’s own tab

* More run metadata stuff

- Add metadata to testing
- Make using metadata outside of runs a no-op
- Add docs

* Replaying should copy over the metadata

* transfer final attempt output to the task run

* A couple of minor fixes

* Use the new clientOrThrow() method everywhere

* Cleaned up the update metadata endpoint and added an API doc page for it

* Mirror task run attempt errors and output
2024-09-26 09:23:38 +01:00
James Ritchie d74783c231 Moving the docs examples section into guides (#1356)
* Links to guides and examples from the introduction page

* Moving examples into guides

* update the redirect

* Fixed broken links

* Fixing redirect

* Added another redirect rule

* Trigger Mintlify build

* Removed redirect
2024-09-25 16:34:11 +01:00
James Ritchie 3af8ae5faf New puppeteer examples (#1355)
* WIP puppeteer examples

* 2 puppeteer examples

* Added another puppeteer example

* Copy improvements
2024-09-25 13:57:15 +01:00
nicktrn 79624c1d1c Update self-hosting docs (#1354)
* add docker only note

* add support section

* add large payloads section

* additional features section and misc updates

* troubleshooting section

* add auth section

* skip default pr checks for docs changes

* minor changes
2024-09-25 11:33:28 +01:00
nicktrn c063dadb74 Fix slack alert retries and text length limits (#1353)
* truncate slack text

* skip retrying on invalid block errors

* decrease deliver alert max attempts

* add sensible slack retry config

* decrease deliver alert priority

* Revert "decrease deliver alert priority"

This reverts commit d878b8b053.

* fix truncated code blocks

* consider backticks when truncating

* Revert "decrease deliver alert max attempts"

This reverts commit 9e02d0aa58.
2024-09-25 11:03:03 +01:00
Eric Allam d361e24bee Associate child runs with the parent span ID (#1352)
* Add safe rootTaskRunId index and a README to @trigger.dev/database

* Associate child runs with the span ID of the span in the parent run that triggered the child run

* Update deprecation notice doc links
2024-09-24 15:47:44 +01:00
James Ritchie bff38dceb5 Puppeteer extension: set the PUPPETEER_EXECUTABLE_PATH env var (#1350)
* Set the PUPPETEER_EXECUTABLE_PATH env var

* Create real-bags-joke.md
2024-09-24 13:25:00 +01:00
nicktrn 85ac0c6036 Release 3.0.7
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
2024-09-24 10:58:03 +01:00
github-actions[bot] af7194d078 chore: Update version for release (#1341)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-24 10:55:34 +01:00
nicktrn 0ecbcfdd86 Only pass trace context if request is from a worker 2024-09-24 09:49:11 +01:00
Eric Allam 40152af775 Load GITHUB_TOKEN env var in publish-prerelease, as it’s not required 2024-09-23 21:30:35 +01:00
Eric Allam 6d4c4d214f Attempt to use @remix-run/changelog-github to have better formatted changeset version descriptions 2024-09-23 21:10:26 +01:00
Niels aba51ab784 Added multiple env variables to kubernetes-provider (#1305)
* Trying out options for `COORDINATOR_PORT` and `COORDINATOR_HOST` env vars

* Added `KUBERNETES_NAMESPACE` env variable

* Reverted pnpm-lock.yaml

* restore pnpm-lock.yaml

* use options object for operations constructor

* consolidate coordinator env vars

---------

Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
2024-09-23 18:25:48 +01:00
D-K-P 6d5e701ef0 Updated copy to be clearer that it’s in your existing app 2024-09-23 18:10:05 +01:00
Dan 60c31787d7 Supabase Storage and Stripe webhook examples (#1345)
* Added supabase storage basic example and updated ffmpeg instructions

* Added stripe webhook example

* Copy tweaks

* Typos

* Updated stripe example to check for a specific event before triggering the task

* Simplified the storage example

* Added examples to intro page

* Added further instructions

* Code improvements

* Final tweaks
2024-09-23 17:44:13 +01:00
Eric Allam 3772b5ac78 New Doc: create your own build extension reference (#1347)
* Build extension guide WIP

* Create your own build extension guide
2024-09-23 17:17:54 +01:00
Eric Allam d7a65f3e7a Fix resolving external packages that are ESM only (#1346)
* Fix resolving external packages that are ESM only by falling back to mlly resolvePathSync. This will fix mupdf

* when publishing a prerelease and aborting, clear the git stage
2024-09-23 16:21:04 +01:00
James Ritchie 5cb59d8a76 Added a note about local development to examples that use build extensions 2024-09-23 16:02:04 +01:00
James Ritchie 2d350b8168 Removed instrumentation-fs docs reference 2024-09-23 15:41:47 +01:00
nicktrn b027d69365 Update one last action to node 20 2024-09-23 15:34:49 +01:00
nicktrn c8eae9d37a Comment out changesets mock 2024-09-23 15:19:02 +01:00
nicktrn 8e6eb4f6d8 GitHub workflow improvements (#1306)
* lint and action updates

* add custom image tag action

* remove publish infra bloat

* replace cancel action with native concurrency control

* ignore all docs changes for release trigger

* image action updates

* update publish trigger paths

* simplify semver checks

* make it possible to call publish

* add tests for custom action

* rename publish workflows

* call publish after successful package release

* fix inputs and published package parsing

* clarify image tag action errors

* move test action

* add test events

* add changesets action mock

* add docs checks

* add github action test readme

* fix docs check on push

* update action versions in docs

* cache npm for docs check

* pretend to fix bad docs link

* fix docs link

* Revert "fix docs link"

This reverts commit a7508f5d55.

* Revert "Revert "fix docs link""

This reverts commit ec642af3dc.

* improve caching

* disable automatic publishing after release

* limit docs checks to pushes to main and PRs

* fix broken links

* prevent word splitting and globbing

* use latest checkout action everywhere

* correctly detect prereleases as valid semver

* update to latest cache action
2024-09-23 15:14:34 +01:00
Eric Allam e81380314c Add retrieve background worker API endpoint 2024-09-23 14:23:40 +01:00
Harsh Shrikant Bhat 9ce3f790f9 fix: Added dev.vars into dotEnv file (#1340)
* Added dev.vars into dotEnv file

* Added changes

* Update yellow-knives-attack.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-09-21 09:12:48 +01:00
Eric Allam 04645e8329 Release 3.0.6 2024-09-20 16:25:19 +01:00
github-actions[bot] e47b6cf166 chore: Update version for release (#1328)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-20 16:24:45 +01:00
James Ritchie 09aaa807a6 Improvements to the Remix guide 2024-09-20 16:19:48 +01:00
Eric Allam fd9a748553 Fixes #1337 - update docs for triggerdev -> trigger bin name change
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-infra (push) Has been skipped
2024-09-20 16:12:14 +01:00
Thibaut Cuchet 1f5bcc73b5 fix: audiowaveform extension (#1335)
* fix: audiowaveform extension

* Create lovely-dolphins-chew.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-09-20 16:09:47 +01:00
James Ritchie 35c8e35674 Added snippets to the nextjs guide 2024-09-20 15:08:38 +01:00
James Ritchie 9d1398f2d9 Much better Remix guide, including Edge functions 2024-09-20 15:08:37 +01:00
Eric Allam 764f03a3c5 Fixed schema types for the runs.retrieve() SDK function 2024-09-20 13:23:48 +01:00
Matt Aitken b999c86e23 Fix for missing logs when triggering without a trigger-version (#1331)
* No longer require “trigger-version” to be passed for the traceContext to be populated

* Remove empty string
2024-09-20 11:14:04 +01:00
Eric Allam e79f0cc847 Add forgotten changeset for task hierarchy PR 2024-09-20 11:13:20 +01:00
Eric Allam ba3c5bdf33 Adding missing task run hierarchy to TaskRun table (#1332)
* Add task run hierarchical relationships to the database

* Add depth and related runs to the retrieve run API response

* Remove prisma optimize

* restructure the migrations to create the index concurrently

* Delete these tsbuildinfo files

* Fix type error by adding depth to the run list presenter

* Cleanup the task hierarchy, share more code

* Remove some fields from the list run response
2024-09-20 11:09:00 +01:00
James Ritchie 6976311e18 Improved the copy to link to aptGet and explain adding deployed packages 2024-09-20 08:57:09 +01:00
James Ritchie 3dd303bd5b Added build config section to pdf-to-image doc example 2024-09-19 17:29:09 +01:00
James Ritchie 1679a184ad Docs/pdf to image (#1330)
* Added pdf-to-image example

* Copy tweak

* Squashed commit of the following:

commit 64862db846
Author: Niels <info@flydev.nl>
Date:   Thu Sep 19 16:25:17 2024 +0200

    Update dotEnv.ts to ignore OTEL_EXPORTER_OTLP_ENDPOINT as well (#1307)

    * Update dotEnv.ts

    * Create four-buttons-run.md

    ---------

    Co-authored-by: Eric Allam <eallam@icloud.com>

commit c65d4822b4
Author: Thibaut Cuchet <thibautcuchet@gmail.com>
Date:   Thu Sep 19 16:22:57 2024 +0200

    Feat: Extension puppeteer (#1323)

    * feat: add puppeteer extension

    * chore: update package and config

    * feat: add puppeteer task

    * Create little-donkeys-protect.md

    ---------

    Co-authored-by: Eric Allam <eallam@icloud.com>

commit b4be736555
Author: Eric Allam <eallam@icloud.com>
Date:   Thu Sep 19 15:21:03 2024 +0100

    prismaExtension fixes for #1325 and #1327

* Copy tweak
2024-09-19 17:09:50 +01:00
Niels 64862db846 Update dotEnv.ts to ignore OTEL_EXPORTER_OTLP_ENDPOINT as well (#1307)
* Update dotEnv.ts

* Create four-buttons-run.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-09-19 15:25:17 +01:00
Thibaut Cuchet c65d4822b4 Feat: Extension puppeteer (#1323)
* feat: add puppeteer extension

* chore: update package and config

* feat: add puppeteer task

* Create little-donkeys-protect.md

---------

Co-authored-by: Eric Allam <eallam@icloud.com>
2024-09-19 15:22:57 +01:00
Eric Allam b4be736555 prismaExtension fixes for #1325 and #1327 2024-09-19 15:21:03 +01:00
Eric Allam 4e0bc485a1 Add support for Buffer in payloads and outputs 2024-09-19 13:20:31 +01:00
James Ritchie b590a318a2 Removed the usage prediction for now (#1326) 2024-09-19 11:58:06 +01:00
nicktrn 55dcdc7b52 Add self-hosting image update instructions 2024-09-19 11:57:50 +01:00
nicktrn 6952ec2c87 Prevent crashes on expected checkpoint cancellations (#1324)
* cancel checkpoint waits when cancelling runs

* only crash in case of readiness timeouts
2024-09-19 11:20:30 +01:00
Eric Allam b3a6f4e0ac Release 3.0.5
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 0s
🚀 Publish Trigger.dev Docker / units (push) Failing after 0s
🚀 Publish Trigger.dev Docker / publish (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-infra (push) Has been skipped
2024-09-18 22:08:45 +01:00
github-actions[bot] a538fa879f chore: Update version for release (#1322)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-18 22:07:50 +01:00
Eric Allam 3b15224453 Fix default machine preset in config not being used (#1321)
* Add additional error message and stack trace when a task file cannot be imported for run

* Apply default machine preset in config
2024-09-18 22:00:59 +01:00
nicktrn d8006e15ac Prevent abort signals from causing uncaught exceptions (#1320)
* never abort the same controller twice

* prevent uncaught exception when aborting pipe

* abort signal assertions and more logging

* never abort running pipe
2024-09-18 19:18:00 +01:00
nicktrn f89d93b905 Update self-hosting docs for switch to latest 2024-09-18 18:33:26 +01:00
Eric Allam 2dbf550a70 Release 3.0.4
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 19s
🚀 Publish Trigger.dev Docker / units (push) Failing after 20s
🚀 Publish Trigger.dev Docker / publish (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-infra (push) Has been skipped
2024-09-18 17:31:03 +01:00
github-actions[bot] 0ac7f4b24b chore: Update version for release (#1318)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-18 17:28:59 +01:00
nicktrn 8d1e41693a v3: self-hosting support for latest packages (#1319)
* display --profile flag after init if used

* add containerfile debug logs

* log all indexing errors in case of connection issues

* specify dockerfile syntax version

* add network flag for self-hosting

* move all self-hosting tags to latest

* add self-hosting update section

* manual setup subsection

* registry flag implies push

* add changeset
2024-09-18 17:07:47 +01:00
Eric Allam 4adc773c77 Auto-resolve payload/output presigned urls when retrieving a run with runs.retrieve (#1317) 2024-09-18 15:20:02 +01:00
Matt Aitken b5cdb0c855 Better logging when resuming with pause and no checkpoint 2024-09-18 13:55:59 +01:00
Eric Allam 7652d8e131 Release 3.0.3 2024-09-18 11:27:31 +01:00
Matt Aitken ce89925176 RESUME_AFTER_DEPENDENCY_WITH_ACK: any successful responses = success
Also added a backoff if the catch is hit, and log the error out
2024-09-18 11:26:33 +01:00
github-actions[bot] 33c108b739 chore: Update version for release (#1316)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-18 11:22:16 +01:00
Dan 382ce8daff Added overview pages for guides and examples, and improved examples (#1314)
* Added introduction page for guides

* New intro page for examples

* Fixed links

* Updated examples intro to include all of the new ones

* Improved FFmpeg example

* Improved the react pdf example

* Added Supabase overview page

* Updated card-supabase snippet

* Added sharp payload instructions

* Added vercel payload instructions

* Added dall-e payload instructions

* Added openai payload instructions

* Added resend payload instructions

* Made the prompts more consistent

* Minor tweaks and moved bun

* Updated links and added bun logo

---------

Co-authored-by: James Ritchie <james@jamesritchie.co.uk>
2024-09-18 11:08:55 +01:00
Eric Allam 3d53d4c086 Improve the update CLI command and fix missing tsconfig.json error (#1315)
* Fixes for CLI update command, and make the hide the "whoami" command output when running in dev

* Fix an issue where a missing tsconfig.json file would throw an error on dev/deploy

* Don’t show latest CLI warning when using a prerelease

* Only print CLI update required message when update is embedded

* Strip out TRIGGER\_ keys when using syncEnvVars, to prevent deploy errors
2024-09-18 11:07:09 +01:00
Matt Aitken 56a5b58849 Add acking to RESUME_AFTER_DEPENDENCY message to the coordinator (#1313)
* Fix for run filtering not working with some special characters (double encoded)

* Add the full dependentTaskAttempt to a ResumeBatchRunService log

* Added RESUME_AFTER_DEPENDENCY_WITH_ACK

* Set the delay to 5s

* If a checkpoint has been created, the coordinator won’t continue the run with RESUME_AFTER_DEPENDENCY_WITH_ACK

* If we’re keeping the run alive then set socket.data.requiresCheckpointResumeWithMessage to undefined

* Log out the data before and after setting socket.data.requiresCheckpointResumeWithMessage
2024-09-18 10:29:55 +01:00
Eric Allam 74c2076262 A couple of docs fixes 2024-09-17 20:27:17 +01:00
Dan a84e601da8 Added new example tasks (FFmpeg / Sharp / Vercel AI SDK) (#1312)
* Added FFmpeg / sharp / vercel and updated mint.json

* Amends including s3 -> r2
2024-09-17 14:16:10 +01:00
nicktrn 9a3eab5ac4 v3: docs improvements (#1302)
* pull out common cli options

* lint commands table

* update dev command link

* add undefined Crypto section

* add self-hosting section to github actions docs

* add cli usage section to self-hosting docs

* add skip telemetry env var to cli option docs

* add api url env var to cli options docs

* lowercase cli commands in sidebar

* add self-hosting beta notice

* update beta to latest tag on electric route

* add deploy command examples section

* fix env file option

* reorder deploy options sections

* cli docs fixes
2024-09-17 11:40:25 +01:00
1391 changed files with 60659 additions and 13913 deletions
+9 -18
View File
@@ -1,28 +1,19 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [
[
"@trigger.dev/*",
"trigger.dev"
]
"changelog": [
"@remix-run/changelog-github",
{
"repo": "triggerdotdev/trigger.dev"
}
],
"commit": false,
"fixed": [["@trigger.dev/*", "trigger.dev"]],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [
"webapp",
"emails",
"proxy",
"@trigger.dev/database",
"coordinator",
"docker-provider",
"kubernetes-provider",
"@trigger.dev/otlp-importer"
],
"ignore": ["webapp", "proxy", "coordinator", "docker-provider", "kubernetes-provider"],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}
}
+25 -3
View File
@@ -31,10 +31,32 @@ DEV_OTEL_BATCH_PROCESSING_ENABLED="0"
# AUTH_GITHUB_CLIENT_ID=
# AUTH_GITHUB_CLIENT_SECRET=
# Resend is an email service used for signing in to Trigger.dev via a Magic Link.
# Emails will print to the console if you leave these commented out
# Configure an email transport to allow users to sign in to Trigger.dev via a Magic Link.
# If none are configured, emails will print to the console instead.
# Uncomment one of the following blocks to allow delivery of
# Resend
### Visit https://resend.com, create an account and get your API key. Then insert it below along with your From and Reply To email addresses. Visit https://resend.com/docs for more information.
# RESEND_API_KEY=<api_key>
# EMAIL_TRANSPORT=resend
# FROM_EMAIL=
# REPLY_TO_EMAIL=
# RESEND_API_KEY=
# Generic SMTP
### Enter the configuration provided by your mail provider. Visit https://nodemailer.com/smtp/ for more information
### SMTP_SECURE = false will use STARTTLS when connecting to a server that supports it (usually port 587)
# EMAIL_TRANSPORT=smtp
# FROM_EMAIL=
# REPLY_TO_EMAIL=
# SMTP_HOST=
# SMTP_PORT=587
# SMTP_SECURE=false
# SMTP_USER=
# SMTP_PASSWORD=
# AWS Simple Email Service
### Authentication is configured using the default Node.JS credentials provider chain (https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-credential-providers/#fromnodeproviderchain)
# EMAIL_TRANSPORT=aws-ses
# FROM_EMAIL=
# REPLY_TO_EMAIL=
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [triggerdotdev]
+84
View File
@@ -0,0 +1,84 @@
name: "#️⃣ Get image tag (action)"
description: This action gets the image tag from the commit ref or input (if provided)
outputs:
tag:
description: The image tag
value: ${{ steps.get_tag.outputs.tag }}
is_semver:
description: Whether the tag is a semantic version
value: ${{ steps.check_semver.outputs.is_semver }}
inputs:
tag:
description: The image tag. If this is set it will return the tag as is.
required: false
default: ""
runs:
using: "composite"
steps:
- name: "#️⃣ Get image tag (step)"
id: get_tag
shell: bash
run: |
if [[ -n "${{ inputs.tag }}" ]]; then
tag="${{ inputs.tag }}"
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
if [[ "${{ github.ref_name }}" == infra-*-* ]]; then
env=$(echo ${{ github.ref_name }} | cut -d- -f2)
sha=$(echo ${{ github.sha }} | head -c7)
ts=$(date +%s)
tag=${env}-${sha}-${ts}
elif [[ "${{ github.ref_name }}" == v.docker.* ]]; then
version="${GITHUB_REF_NAME#v.docker.}"
tag="v${version}"
elif [[ "${{ github.ref_name }}" == build-* ]]; then
tag="${GITHUB_REF_NAME#build-}"
else
echo "Invalid git tag: ${{ github.ref_name }}"
exit 1
fi
elif [[ "${{ github.ref_name }}" == "main" ]]; then
tag="main"
else
echo "Invalid git ref: ${{ github.ref }}"
exit 1
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
- name: 🔍 Check for validity
id: check_validity
shell: bash
env:
tag: ${{ steps.get_tag.outputs.tag }}
run: |
if [[ "${tag}" =~ ^[a-z0-9]+([._-][a-z0-9]+)*$ ]]; then
echo "Tag is valid: ${tag}"
else
echo "Tag is not valid: ${tag}"
exit 1
fi
- name: 🆚 Check for semver
id: check_semver
shell: bash
env:
tag: ${{ steps.get_tag.outputs.tag }}
# Will match most semver formats except build metadata, i.e. v1.2.3+build.1
# Valid matches:
# v1.2.3
# v1.2.3-alpha
# v1.2.3-alpha.1
# v1.2.3-rc.1
# v1.2.3-beta-1
run: |
if [[ "${tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then
echo "Tag is a semantic version: ${tag}"
is_semver=true
else
echo "Tag is not a semantic version: ${tag}"
is_semver=false
fi
echo "is_semver=${is_semver}" >> "$GITHUB_OUTPUT"
+1
View File
@@ -0,0 +1 @@
This is the repo for Trigger.dev, a background jobs platform written in TypeScript. Our webapp at apps/webapp is a Remix 2.1 app that uses Node.js v20. Our SDK is an isomorphic TypeScript SDK at packages/trigger-sdk. Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code. Our tests are all vitest. We use prisma in internal-packages/database for our database interactions using PostgreSQL. For TypeScript, we usually use types over interfaces. We use zod a lot in packages/core and in the webapp. Avoid enums. Use strict mode. No default exports, use function declarations.
+70
View File
@@ -0,0 +1,70 @@
# GitHub Action Tests
This directory contains necessary files to allow local testing of GitHub Actions workflows, composite actions, etc. You will need to install [act](https://github.com/nektos/act) to perform tests.
## Workflow tests
Trigger specific workflow files by specifying their full path:
```
act -W .github/workflow/release.yml
```
You will likely need to override any custom runners we use, e.g. buildjet. For example:
```
override=catthehacker/ubuntu:act-latest
act -W .github/workflow/release.yml \
-P buildjet-8vcpu-ubuntu-2204=$override
# override multiple images at the same time
act -W .github/workflow/release.yml \
-P buildjet-8vcpu-ubuntu-2204=$override \
-P buildjet-16vcpu-ubuntu-2204=$override
```
Trigger with specific event payloads to test pushing to branches or tags:
```
override=catthehacker/ubuntu:act-latest
# simulate push to main
act -W .github/workflow/publish.yml \
-P buildjet-8vcpu-ubuntu-2204=$override \
-P buildjet-16vcpu-ubuntu-2204=$override \
-e .github/events/push-tag-main.json
# simulate a `build-` prefixed tag
act -W .github/workflow/publish.yml \
-P buildjet-8vcpu-ubuntu-2204=$override \
-P buildjet-16vcpu-ubuntu-2204=$override \
-e .github/events/push-tag-buld.json
```
By default, `act` will send a push event. To trigger a different event:
```
# basic syntax
act <EVENT> ...
# simulate a pull request
act pull_request
# only trigger a specific workflow
act pull_request -W .github/workflow/pr_checks.yml
```
## Composite action tests
The composite (custom) action tests can be run by triggering the `test-actions` workflow:
```
act -W .github/test/test-actions.yml
```
## Helpful flags
- `--pull=false` - perform fully offline tests if all images are already present
- `-j <job_name>` - run the specified job only
- `-l push` - list all workflows with push triggers
+3
View File
@@ -0,0 +1,3 @@
{
"ref": "refs/heads/main"
}
+3
View File
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/build-buildtag"
}
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/v.docker.nonsemver"
}
+3
View File
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/v.docker.1.2.3"
}
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/infra-prod-anything"
}
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/infra-test-anything"
}
+3
View File
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/1.2.3"
}
+3
View File
@@ -0,0 +1,3 @@
{
"ref": "refs/tags/standard-tag"
}
+152
View File
@@ -0,0 +1,152 @@
name: Test Actions
on:
workflow_dispatch:
jobs:
get-image-tag-none:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log current ref
run: |
echo "ref: ${{ github.ref }}"
echo "ref_type: ${{ github.ref_type }}"
echo "ref_name: ${{ github.ref_name }}"
- name: Run without input tag
id: get_tag
# this step may fail depending on the current ref
continue-on-error: true
uses: ./.github/actions/get-image-tag
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-null:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log current ref
run: |
echo "ref: ${{ github.ref }}"
echo "ref_type: ${{ github.ref_type }}"
echo "ref_name: ${{ github.ref_name }}"
- name: Run without input tag
id: get_tag
uses: ./.github/actions/get-image-tag
# this step may fail depending on the current ref
continue-on-error: true
with:
# this should behave exactly as when no tag is provided
tag: null
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-override:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run with tag override
id: get_tag
uses: ./.github/actions/get-image-tag
with:
tag: "abc-123"
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-invalid-string:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run with invalid string
id: get_tag
uses: ./.github/actions/get-image-tag
# this step is expected to fail
continue-on-error: true
with:
# does not end with alphanumeric character
tag: "abc-123-"
- name: Fail job if previous step did not fail
if: steps.get_tag.outcome != 'failure'
run: exit 1
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-prerelease:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run with prerelease semver
id: get_tag
uses: ./.github/actions/get-image-tag
with:
tag: "v1.2.3-beta.4"
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-semver:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run with basic semver
id: get_tag
uses: ./.github/actions/get-image-tag
with:
tag: "v1.2.3"
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
get-image-tag-invalid-semver:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run with invalid semver
id: get_tag
uses: ./.github/actions/get-image-tag
# this step is expected to fail
continue-on-error: true
with:
tag: "v1.2.3-"
- name: Fail job if previous step did not fail
if: steps.get_tag.outcome != 'failure'
run: exit 1
- name: Verify output
run: |
echo "${{ toJson(steps.get_tag) }}"
+42
View File
@@ -0,0 +1,42 @@
name: 📚 Docs Checks
on:
push:
branches:
- main
paths:
- "docs/**"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "docs/**"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check-broken-links:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./docs
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
- name: 📦 Cache npm
uses: actions/cache@v4
with:
path: |
~/.npm
key: |
${{ runner.os }}-mintlify
restore-keys: |
${{ runner.os }}-mintlify
- name: 🔗 Check for broken links
run: npx mintlify@4.0.222 broken-links
+4 -4
View File
@@ -1,4 +1,5 @@
name: "E2E"
on:
workflow_call:
inputs:
@@ -7,6 +8,7 @@ on:
default: webapp
required: false
type: string
jobs:
cli-v3:
name: "🧪 CLI v3 tests (${{ matrix.os }} - ${{ matrix.package-manager }})"
@@ -19,7 +21,7 @@ jobs:
package-manager: ["npm", "pnpm"]
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -29,7 +31,7 @@ jobs:
version: 8.15.5
- name: ⎔ Setup node
uses: buildjet/setup-node@v3
uses: buildjet/setup-node@v4
with:
node-version: 20.11.1
@@ -49,5 +51,3 @@ jobs:
shell: bash
run: |
LOG=debug PM=${{ matrix.package-manager }} pnpm --filter trigger.dev run test:e2e
+6 -5
View File
@@ -3,6 +3,8 @@ name: 🤖 PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
paths-ignore:
- "docs/**"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -30,12 +32,11 @@ jobs:
preview-release:
name: Preview Release
needs: [typecheck, units, e2e]
if: |
github.repository == 'triggerdotdev/trigger.dev'
if: github.repository == 'triggerdotdev/trigger.dev'
runs-on: buildjet-8vcpu-ubuntu-2204
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -45,7 +46,7 @@ jobs:
version: 8.15.5
- name: ⎔ Setup node
uses: buildjet/setup-node@v3
uses: buildjet/setup-node@v4
with:
node-version: 20.11.1
cache: "pnpm"
@@ -56,5 +57,5 @@ jobs:
- name: 🏗️ Build
run: pnpm run build --filter "@trigger.dev/*" --filter "trigger.dev"
- name: publish preview release
- name: Publish preview release
run: npx pkg-pr-new publish --no-template $(ls -d ./packages/*)
-74
View File
@@ -1,74 +0,0 @@
name: "🐳 Publish Docker"
on:
workflow_call:
jobs:
publish:
runs-on: ubuntu-latest
env:
PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING: 1
outputs:
version: ${{ steps.get_version.outputs.version }}
short_sha: ${{ steps.get_commit.outputs.sha_short }}
steps:
- name: Setup Depot CLI
uses: depot/setup-action@v1
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
with:
submodules: recursive
- name: 🆚 Get the version
id: get_version
run: |
IMAGE_TAG="${GITHUB_REF#refs/tags/}"
if [[ $GITHUB_REF == refs/tags/* ]]; then
if [[ $IMAGE_TAG == v.docker.* ]]; then
ORIGINAL_VERSION="${IMAGE_TAG#v.docker.}"
IMAGE_TAG="v${ORIGINAL_VERSION}"
elif [[ $IMAGE_TAG == build-* ]]; then
IMAGE_TAG="${IMAGE_TAG#build-}"
fi
echo "IMAGE_TAG=${IMAGE_TAG}"
elif [[ $GITHUB_REF == refs/heads/main ]]; then
# Handle main branch specifically
IMAGE_TAG="main"
echo "IMAGE_TAG=${IMAGE_TAG}"
else
echo "Invalid reference: ${GITHUB_REF}"
exit 1
fi
echo "::set-output name=version::${IMAGE_TAG}"
- name: 🔢 Get the commit hash
id: get_commit
run: |
echo ::set-output name=sha_short::$(echo ${{ github.sha }} | cut -c1-7)
- name: 📛 Set the tags
id: set_tags
run: |
ref_without_tag=ghcr.io/triggerdotdev/trigger.dev
image_tags=$ref_without_tag:${{ steps.get_version.outputs.version }}
# if it's a versioned tag, also tag it as v3
if [[ "${{ github.ref_name }}" == v.docker.* ]]; then
image_tags=$image_tags,$ref_without_tag:v3
fi
echo "IMAGE_TAGS=${image_tags}" >> "$GITHUB_OUTPUT"
- name: 🐙 Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🐳 Build image and push to GitHub Container Registry
uses: depot/build-push-action@v1
with:
file: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.set_tags.outputs.IMAGE_TAGS }}
push: true
-121
View File
@@ -1,121 +0,0 @@
name: "🚢 Publish Infra Images"
on:
workflow_call:
push:
tags:
- "infra-dev-*"
- "infra-test-*"
- "infra-prod-*"
paths:
- ".github/workflows/publish.yml"
- "packages/**"
- "!packages/**/*.md"
- "!packages/**/*.eslintrc"
- "apps/**"
- "!apps/**/*.md"
- "!apps/**/*.eslintrc"
- "integrations/**"
- "!integrations/**/*.md"
- "!integrations/**/*.eslintrc"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "turbo.json"
- "docker/Dockerfile"
- "docker/scripts/**"
- "tests/**"
permissions:
id-token: write
packages: write
contents: read
env:
AWS_REGION: us-east-1
jobs:
build:
strategy:
matrix:
package: [coordinator, docker-provider, kubernetes-provider]
runs-on: buildjet-16vcpu-ubuntu-2204
env:
DOCKER_BUILDKIT: "1"
steps:
- uses: actions/checkout@v4
- name: Generate image reference
id: prep
run: |
# set image repo
if [[ "${{ matrix.package }}" == *-provider ]]; then
provider_type=$(echo "${{ matrix.package }}" | cut -d- -f1)
repository=provider/${provider_type}
else
repository="${{ matrix.package }}"
fi
echo "REPOSITORY=${repository}" >> "$GITHUB_OUTPUT"
# set image tag
if [[ "${{ github.ref_type }}" == "tag" ]]; then
if [[ "${{ github.ref_name }}" == infra-*-* ]]; then
env=$(echo ${{ github.ref_name }} | cut -d- -f2)
sha=$(echo ${{ github.sha }} | head -c7)
ts=$(date +%s)
image_tag=${env}-${sha}-${ts}
elif [[ "${{ github.ref_name }}" == v.docker.* ]]; then
version="${GITHUB_REF_NAME#v.docker.}"
image_tag="v${version}"
elif [[ "${{ github.ref_name }}" == build-* ]]; then
image_tag="${GITHUB_REF_NAME#build-}"
else
echo "Invalid tag: ${{ github.ref_name }}"
exit 1
fi
elif [[ "${{ github.ref_name }}" == "main" ]]; then
image_tag="main"
else
echo "Invalid reference: ${{ github.ref }}"
exit 1
fi
echo "IMAGE_TAG=${image_tag}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# ..to avoid rate limits when pulling images
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 🚢 Build Container Image
run: |
docker build -t infra_image -f ./apps/${{ matrix.package }}/Containerfile .
# ..to push image
- name: 🐙 Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🐙 Push to GitHub Container Registry
run: |
docker tag infra_image $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
env:
REGISTRY: ghcr.io/triggerdotdev
REPOSITORY: ${{ steps.prep.outputs.REPOSITORY }}
IMAGE_TAG: ${{ steps.prep.outputs.IMAGE_TAG }}
- name: 🐙 Push 'v3' tag to GitHub Container Registry
if: startsWith(github.ref_name, 'v.docker.')
run: |
docker tag infra_image $REGISTRY/$REPOSITORY:v3
docker push $REGISTRY/$REPOSITORY:v3
env:
REGISTRY: ghcr.io/triggerdotdev
REPOSITORY: ${{ steps.prep.outputs.REPOSITORY }}
+66
View File
@@ -0,0 +1,66 @@
name: "🐳 Publish Webapp"
on:
workflow_call:
inputs:
image_tag:
description: The image tag to publish
type: string
required: false
default: ""
jobs:
publish:
runs-on: ubuntu-latest
env:
PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING: 1
outputs:
version: ${{ steps.get_tag.outputs.tag }}
short_sha: ${{ steps.get_commit.outputs.sha_short }}
steps:
- name: 🏭 Setup Depot CLI
uses: depot/setup-action@v1
- name: ⬇️ Checkout repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: "#️⃣ Get the image tag"
id: get_tag
uses: ./.github/actions/get-image-tag
with:
tag: ${{ inputs.image_tag }}
- name: 🔢 Get the commit hash
id: get_commit
run: |
echo "sha_short=$(echo ${{ github.sha }} | cut -c1-7)" >> "$GITHUB_OUTPUT"
- name: 📛 Set the tags
id: set_tags
run: |
ref_without_tag=ghcr.io/triggerdotdev/trigger.dev
image_tags=$ref_without_tag:${{ steps.get_tag.outputs.tag }}
# if tag is a semver, also tag it as v3
if [[ "${{ steps.get_tag.outputs.is_semver }}" == true ]]; then
image_tags=$image_tags,$ref_without_tag:v3
fi
echo "image_tags=${image_tags}" >> "$GITHUB_OUTPUT"
- name: 🐙 Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🐳 Build image and push to GitHub Container Registry
uses: depot/build-push-action@v1
with:
file: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.set_tags.outputs.image_tags }}
push: true
+87
View File
@@ -0,0 +1,87 @@
name: "⚒️ Publish Worker"
on:
workflow_call:
inputs:
image_tag:
description: The image tag to publish
type: string
required: false
default: ""
push:
tags:
- "infra-dev-*"
- "infra-test-*"
- "infra-prod-*"
permissions:
packages: write
contents: read
jobs:
build:
strategy:
matrix:
package: [coordinator, docker-provider, kubernetes-provider]
runs-on: buildjet-16vcpu-ubuntu-2204
env:
DOCKER_BUILDKIT: "1"
steps:
- name: ⬇️ Checkout git repo
uses: actions/checkout@v4
- name: 📦 Get image repo
id: get_repository
run: |
if [[ "${{ matrix.package }}" == *-provider ]]; then
provider_type=$(echo "${{ matrix.package }}" | cut -d- -f1)
repo=provider/${provider_type}
else
repo="${{ matrix.package }}"
fi
echo "repo=${repo}" >> "$GITHUB_OUTPUT"
- id: get_tag
uses: ./.github/actions/get-image-tag
with:
tag: ${{ inputs.image_tag }}
- name: 🐋 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# ..to avoid rate limits when pulling images
- name: 🐳 Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 🚢 Build Container Image
run: |
docker build -t infra_image -f ./apps/${{ matrix.package }}/Containerfile .
# ..to push image
- name: 🐙 Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🐙 Push to GitHub Container Registry
run: |
docker tag infra_image "$REGISTRY/$REPOSITORY:$IMAGE_TAG"
docker push "$REGISTRY/$REPOSITORY:$IMAGE_TAG"
env:
REGISTRY: ghcr.io/triggerdotdev
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
IMAGE_TAG: ${{ steps.get_tag.outputs.tag }}
- name: 🐙 Push 'v3' tag to GitHub Container Registry
if: steps.get_tag.outputs.is_semver == 'true'
run: |
docker tag infra_image "$REGISTRY/$REPOSITORY:v3"
docker push "$REGISTRY/$REPOSITORY:v3"
env:
REGISTRY: ghcr.io/triggerdotdev
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
+17 -5
View File
@@ -1,6 +1,12 @@
name: 🚀 Publish Trigger.dev Docker
on:
workflow_call:
inputs:
image_tag:
description: The image tag to publish
required: true
type: string
push:
branches:
- main
@@ -8,11 +14,13 @@ on:
- "v.docker.*"
- "build-*"
paths:
- ".github/actions/**/*.yml"
- ".github/workflows/publish.yml"
- ".github/workflows/typecheck.yml"
- ".github/workflows/unit-tests.yml"
- ".github/workflows/e2e.yml"
- ".github/workflows/publish-docker.yml"
- ".github/workflows/publish-webapp.yml"
- ".github/workflows/publish-worker.yml"
- "packages/**"
- "!packages/**/*.md"
- "!packages/**/*.eslintrc"
@@ -49,12 +57,16 @@ jobs:
uses: ./.github/workflows/unit-tests.yml
secrets: inherit
publish:
publish-webapp:
needs: [typecheck, units]
uses: ./.github/workflows/publish-docker.yml
uses: ./.github/workflows/publish-webapp.yml
secrets: inherit
with:
image_tag: ${{ inputs.image_tag }}
publish-infra:
publish-worker:
needs: [typecheck, units]
uses: ./.github/workflows/publish-infra.yml
uses: ./.github/workflows/publish-worker.yml
secrets: inherit
with:
image_tag: ${{ inputs.image_tag }}
+36 -10
View File
@@ -5,26 +5,27 @@ on:
branches:
- main
paths-ignore:
- "docs/**"
- "**.md"
- "**.mdx"
- ".github/CODEOWNERS"
- ".github/ISSUE_TEMPLATE/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
release:
name: 🦋 Changesets Release
runs-on: buildjet-8vcpu-ubuntu-2204
if: |
github.repository == 'triggerdotdev/trigger.dev'
runs-on: ubuntu-latest
if: github.repository == 'triggerdotdev/trigger.dev'
outputs:
published_packages: ${{ steps.changesets.outputs.publishedPackages }}
published: ${{ steps.changesets.outputs.published }}
published_packages: ${{ steps.changesets.outputs.publishedPackages }}
published_package_version: ${{ steps.get_version.outputs.package_version }}
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -34,7 +35,7 @@ jobs:
version: 8.15.5
- name: ⎔ Setup node
uses: buildjet/setup-node@v3
uses: buildjet/setup-node@v4
with:
node-version: 20.11.1
cache: "pnpm"
@@ -62,6 +63,7 @@ jobs:
# PR is merged, the workflow will run again and this action will build +
# publish to npm.
- name: 🚀 PR / Publish
if: ${{ !env.ACT }}
id: changesets
uses: changesets/action@v1
with:
@@ -73,3 +75,27 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# - name: 🚀 PR / Publish (mock)
# if: ${{ env.ACT }}
# id: changesets
# run: |
# echo "published=true" >> "$GITHUB_OUTPUT"
# echo "publishedPackages=[{\"name\": \"@xx/xx\", \"version\": \"1.2.0\"}, {\"name\": \"@xx/xy\", \"version\": \"0.8.9\"}]" >> "$GITHUB_OUTPUT"
- name: 📦 Get package version
if: steps.changesets.outputs.published == 'true'
id: get_version
run: |
package_version=$(echo '${{ steps.changesets.outputs.publishedPackages }}' | jq -r '.[0].version')
echo "package_version=${package_version}" >> "$GITHUB_OUTPUT"
publish:
needs: release
uses: ./.github/workflows/publish.yml
secrets: inherit
# if: needs.release.outputs.published == 'true'
# disable automatic publishing for now
if: false
with:
image_tag: v${{ needs.release.outputs.published_package_version }}
+5 -3
View File
@@ -1,13 +1,15 @@
name: "ʦ TypeScript"
on:
workflow_call:
jobs:
typecheck:
runs-on: buildjet-8vcpu-ubuntu-2204
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -17,7 +19,7 @@ jobs:
version: 8.15.5
- name: ⎔ Setup node
uses: buildjet/setup-node@v3
uses: buildjet/setup-node@v4
with:
node-version: 20.11.1
cache: "pnpm"
@@ -30,6 +32,6 @@ jobs:
- name: 🔎 Type check
run: pnpm run typecheck
- name: 🔎 Check exports
run: pnpm run check-exports
+22 -6
View File
@@ -1,13 +1,15 @@
name: "🧪 Unit Tests"
on:
workflow_call:
jobs:
unitTests:
name: "🧪 Unit Tests"
runs-on: buildjet-8vcpu-ubuntu-2204
runs-on: buildjet-16vcpu-ubuntu-2204
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -17,7 +19,7 @@ jobs:
version: 8.15.5
- name: ⎔ Setup node
uses: buildjet/setup-node@v3
uses: buildjet/setup-node@v4
with:
node-version: 20.11.1
cache: "pnpm"
@@ -25,6 +27,20 @@ jobs:
- name: 📥 Download deps
run: pnpm install --frozen-lockfile
- name: Run Unit Tests
run: |
pnpm run test
- name: 📀 Generate Prisma Client
run: pnpm run generate
- name: 🧪 Run Webapp Unit Tests
run: pnpm run test --filter webapp
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres
DIRECT_URL: postgresql://postgres:postgres@localhost:5432/postgres
SESSION_SECRET: "secret"
MAGIC_LINK_SECRET: "secret"
ENCRYPTION_KEY: "secret"
- name: 🧪 Run Package Unit Tests
run: pnpm run test --filter "@trigger.dev/*"
- name: 🧪 Run Internal Unit Tests
run: pnpm run test --filter "@internal/*"
+2 -2
View File
@@ -1,3 +1,3 @@
[submodule "packages/otlp-importer/protos"]
path = packages/otlp-importer/protos
[submodule "internal-packages/otlp-importer/protos"]
path = internal-packages/otlp-importer/protos
url = https://github.com/open-telemetry/opentelemetry-proto.git
+2 -1
View File
@@ -1,2 +1,3 @@
link-workspace-packages=false
public-hoist-pattern[]=*prisma*
public-hoist-pattern[]=*prisma*
prefer-workspace-packages=true
+2 -6
View File
@@ -1,8 +1,4 @@
{
"recommendations": [
"denoland.vscode-deno"
],
"unwantedRecommendations": [
]
"recommendations": ["bierner.comment-tagged-templates"],
"unwantedRecommendations": []
}
+31 -6
View File
@@ -13,6 +13,15 @@
"cwd": "${workspaceFolder}",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug realtimeStreams.test.ts",
"command": "pnpm run test -t RealtimeStreams",
"envFile": "${workspaceFolder}/.env",
"cwd": "${workspaceFolder}/apps/webapp",
"sourceMaps": true
},
{
"type": "chrome",
"request": "launch",
@@ -24,7 +33,7 @@
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 init CLI",
"command": "pnpm exec triggerdev init",
"command": "pnpm exec trigger init",
"cwd": "${workspaceFolder}/references/init-shell",
"sourceMaps": true
},
@@ -32,15 +41,31 @@
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 Dev CLI",
"command": "pnpm exec triggerdev dev",
"command": "pnpm exec trigger dev",
"cwd": "${workspaceFolder}/references/v3-catalog",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug Dev Next.js Realtime",
"command": "pnpm exec trigger dev",
"cwd": "${workspaceFolder}/references/nextjs-realtime",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug prisma-catalog deploy CLI",
"command": "pnpm exec trigger deploy --self-hosted --load-image",
"cwd": "${workspaceFolder}/references/prisma-catalog",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 Deploy CLI",
"command": "pnpm exec triggerdev deploy --self-hosted --load-image",
"command": "pnpm exec trigger deploy --self-hosted --load-image",
"cwd": "${workspaceFolder}/references/v3-catalog",
"sourceMaps": true
},
@@ -48,7 +73,7 @@
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 list-profiles CLI",
"command": "pnpm exec triggerdev list-profiles --log-level debug",
"command": "pnpm exec trigger list-profiles --log-level debug",
"cwd": "${workspaceFolder}/references/v3-catalog",
"sourceMaps": true
},
@@ -56,7 +81,7 @@
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 update CLI",
"command": "pnpm exec triggerdev update",
"command": "pnpm exec trigger update",
"cwd": "${workspaceFolder}/references/v3-catalog",
"sourceMaps": true
},
@@ -88,7 +113,7 @@
"type": "node-terminal",
"request": "launch",
"name": "debug v3 hello-world dev",
"command": "pnpm exec triggerdev dev",
"command": "pnpm exec trigger dev",
"cwd": "${workspaceFolder}/references/hello-world",
"sourceMaps": true
}
+7 -7
View File
@@ -114,7 +114,7 @@ pnpm i
```sh
cd references/v3-catalog
cp .env.example .env
pnpm exec triggerdev login -a http://localhost:3030
pnpm exec trigger login -a http://localhost:3030
```
This will open a new browser window and authorize the CLI against your local user account.
@@ -123,10 +123,10 @@ You can optionally pass a `--profile` flag to the `login` command, which will al
```sh
cd references/v3-catalog
pnpm exec triggerdev login -a http://localhost:3030 --profile local
pnpm exec trigger login -a http://localhost:3030 --profile local
# later when you run the dev or deploy command:
pnpm exec triggerdev dev --profile local
pnpm exec triggerdev deploy --profile local
pnpm exec trigger dev --profile local
pnpm exec trigger deploy --profile local
```
### Running
@@ -155,14 +155,14 @@ Note: You do not need to do the same for `@trigger.dev/sdk`, just core.
```sh
# in <root>/references/v3-catalog
pnpm exec triggerdev dev
pnpm exec trigger dev
```
If you want additional debug logging, you can use the `--log-level debug` flag:
```sh
# in <root>/references/v3-catalog
pnpm exec triggerdev dev --log-level debug
pnpm exec trigger dev --log-level debug
```
5. If you make any changes in the CLI/Core/SDK, you'll need to `CTRL+C` to exit the `dev` command and restart it to pickup changes. Any changes to the files inside of the `v3-catalog/src/trigger` dir will automatically be rebuilt by the `dev` command.
@@ -223,7 +223,7 @@ pnpm run db:studio
## Adding and running migrations
1. Modify packages/database/prisma/schema.prisma file
1. Modify internal-packages/database/prisma/schema.prisma file
2. Change directory to the packages/database folder
```sh
+21 -6
View File
@@ -15,13 +15,20 @@
## About Trigger.dev
Trigger.dev is an open source platform and SDK which allows you to create long-running background jobs with no timeouts. Write normal async code, deploy, and never hit a timeout.
Trigger.dev is an open source platform and SDK which allows you to create long-running background jobs. Write normal async code, deploy, and never hit a timeout.
#### Features:
### Key features:
- JavaScript and TypeScript SDK
- Write reliable code by default
- No timeouts
- Retries (with exponential backoff)
- Queues and concurrency controls
- Schedules and crons
- Full Observability; logs, live trace views, advanced filtering
- Custom alerts, get notified by email, Slack or webhooks
- No infrastructure to manage
- Elastic (scaling)
- Works with your existing tech stack
## In your codebase
@@ -45,7 +52,7 @@ export const helloWorld = task({
## 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](https://trigger.dev/docs/v3/open-source-self-hosting#overview).
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
@@ -59,11 +66,19 @@ View every task in every run so you can tell exactly what happened. We provide a
# Getting started
Visit our docs [here](https://trigger.dev/docs/v3/introduction) for a full guide on how to get started with Trigger.dev.
The quickest way to get started is to create an account and project in our [web app](https://cloud.trigger.dev), and follow the instructions in the onboarding. Build and deploy your first task in minutes.
## Self-host
### Useful links:
If you prefer to self-host, you can follow our [self-hosting guide](https://trigger.dev/docs/v3/open-source-self-hosting#overview).
- [Quick start](https://trigger.dev/docs/quick-start) - get up and running in minutes
- [How it works](https://trigger.dev/docs/v3/how-it-works) - understand how Trigger.dev works under the hood
- [Guides and examples](https://trigger.dev/docs/guides/introduction) - walk-through guides and code examples for popular frameworks and use cases
## Self-hosting
If you prefer to self-host Trigger.dev, you can follow our [self-hosting guide](https://trigger.dev/docs/v3/open-source-self-hosting#overview).
We also have a dedicated self-hosting channel in our [Discord server](https://trigger.dev/discord) for support.
## Development
+13
View File
@@ -0,0 +1,13 @@
## Guide on releasing a new version
1. Merge in the changeset PR into main, making sure to cancel both the release and publish github actions from that merge.
2. Pull the changes locally into main
3. Run `pnpm i` which will update the pnpm lock file with the new versions
4. create a commit with "Release 3.x.x" and push. This will build and release the packages
5. Create a git tag on that release commit with v.docker.3.x.x and push the tag to origin. This will publish the `v3.x.x` docker image to GitHub Container Registry.
6. Once the image is built and pushed, create a new GitHub release and select the tag you just created, along with the previous tag that was released.
7. This will generate some release notes. Edit out the package changes and leave only the server changes.
8. Name the release `@trigger.dev/docker@3.x.x`
9. Include the package link (e.g. https://github.com/triggerdotdev/trigger.dev/pkgs/container/trigger.dev/278459584?tag=v3.x.x)
10. Once the packages have been published, head over to the [v2-legacy repo](https://github.com/triggerdotdev/v2-legacy.trigger.dev) and follow the instructions in the README for creating a matching release.
11. Before deploying to cloud, compare the differences in the previously created release and double check to see if there are any migrations with indexes created concurrently, and make sure to run those before deploying.
+2 -2
View File
@@ -17,10 +17,10 @@
"license": "MIT",
"dependencies": {
"@trigger.dev/core": "workspace:*",
"execa": "^8.0.1",
"nanoid": "^5.0.6",
"prom-client": "^15.1.0",
"socket.io": "4.7.4"
"socket.io": "4.7.4",
"tinyexec": "^0.3.0"
},
"devDependencies": {
"@types/node": "^18",
+2 -13
View File
@@ -1,4 +1,3 @@
import type { Execa$ } from "execa";
import { setTimeout as timeout } from "node:timers/promises";
class ChaosMonkeyError extends Error {
@@ -35,11 +34,9 @@ export class ChaosMonkey {
}
async call({
$,
throwErrors = !this.disableErrors,
addDelays = !this.disableDelays,
}: {
$?: Execa$<string>;
throwErrors?: boolean;
addDelays?: boolean;
} = {}) {
@@ -60,11 +57,7 @@ export class ChaosMonkey {
chaosEvents.push(async () => {
console.log("🍌 Chaos monkey: Add delay");
if ($) {
await $`sleep ${this.delayInSeconds}`;
} else {
await timeout(this.delayInSeconds * 1000);
}
await timeout(this.delayInSeconds * 1000);
});
}
@@ -72,11 +65,7 @@ export class ChaosMonkey {
chaosEvents.push(async () => {
console.log("🍌 Chaos monkey: Throw error");
if ($) {
await $`false`;
} else {
throw new ChaosMonkey.Error("🍌 Chaos monkey: Throw error");
}
throw new ChaosMonkey.Error("🍌 Chaos monkey: Throw error");
});
}
+160 -82
View File
@@ -1,10 +1,13 @@
import { ExponentialBackoff } from "@trigger.dev/core/v3/apps";
import { testDockerCheckpoint, isExecaChildProcess } from "@trigger.dev/core/v3/apps";
import { SimpleLogger } from "@trigger.dev/core/v3/apps";
import { $ } from "execa";
import { testDockerCheckpoint } from "@trigger.dev/core/v3/apps";
import { nanoid } from "nanoid";
import fs from "node:fs/promises";
import { ChaosMonkey } from "./chaosMonkey";
import { Buildah, Crictl, Exec } from "./exec";
import { setTimeout } from "node:timers/promises";
import { TempFileCleaner } from "./cleaner";
import { numFromEnv, boolFromEnv } from "./util";
import { SimpleStructuredLogger } from "@trigger.dev/core/v3/utils/structuredLogger";
type CheckpointerInitializeReturn = {
canCheckpoint: boolean;
@@ -83,7 +86,7 @@ export class Checkpointer {
#canCheckpoint = false;
#dockerMode: boolean;
#logger = new SimpleLogger("[checkptr]");
#logger = new SimpleStructuredLogger("checkpointer");
#abortControllers = new Map<string, AbortController>();
#failedCheckpoints = new Map<string, unknown>();
#waitingForRetry = new Set<string>();
@@ -93,7 +96,6 @@ export class Checkpointer {
private registryTlsVerify: boolean;
private disableCheckpointSupport: boolean;
private checkpointPath: string;
private simulateCheckpointFailure: boolean;
private simulateCheckpointFailureSeconds: number;
@@ -101,6 +103,7 @@ export class Checkpointer {
private simulatePushFailureSeconds: number;
private chaosMonkey: ChaosMonkey;
private tmpCleaner?: TempFileCleaner;
constructor(private opts: CheckpointerOptions) {
this.#dockerMode = opts.dockerMode;
@@ -110,7 +113,6 @@ export class Checkpointer {
this.registryTlsVerify = opts.registryTlsVerify ?? true;
this.disableCheckpointSupport = opts.disableCheckpointSupport ?? false;
this.checkpointPath = opts.checkpointPath ?? "/checkpoints";
this.simulateCheckpointFailure = opts.simulateCheckpointFailure ?? false;
this.simulateCheckpointFailureSeconds = opts.simulateCheckpointFailureSeconds ?? 300;
@@ -118,6 +120,7 @@ export class Checkpointer {
this.simulatePushFailureSeconds = opts.simulatePushFailureSeconds ?? 300;
this.chaosMonkey = opts.chaosMonkey ?? new ChaosMonkey(!!process.env.CHAOS_MONKEY_ENABLED);
this.tmpCleaner = this.#createTmpCleaner();
}
async init(): Promise<CheckpointerInitializeReturn> {
@@ -134,18 +137,17 @@ export class Checkpointer {
return this.#getInitReturn(true);
}
this.#logger.error(testCheckpoint.message, testCheckpoint.error ?? "");
this.#logger.error(testCheckpoint.message, { error: testCheckpoint.error });
return this.#getInitReturn(false);
} else {
try {
await $`buildah login --get-login ${this.registryHost}`;
} catch (error) {
this.#logger.error(`No checkpoint support: Not logged in to registry ${this.registryHost}`);
return this.#getInitReturn(false);
}
}
return this.#getInitReturn(true);
const canLogin = await Buildah.canLogin(this.registryHost);
if (!canLogin) {
this.#logger.error(`No checkpoint support: Not logged in to registry ${this.registryHost}`);
}
return this.#getInitReturn(canLogin);
}
#getInitReturn(canCheckpoint: boolean): CheckpointerInitializeReturn {
@@ -183,7 +185,7 @@ export class Checkpointer {
if (this.#dockerMode) {
return basename;
} else {
return `${this.checkpointPath}/${basename}.tar`;
return Crictl.getExportLocation(basename);
}
}
@@ -248,7 +250,12 @@ export class Checkpointer {
return false;
}
controller.abort("cancelCheckpointing()");
if (controller.signal.aborted) {
this.#logger.debug("Controller already aborted", { runId });
return false;
}
controller.abort("cancelCheckpoint()");
this.#abortControllers.delete(runId);
return true;
@@ -284,7 +291,7 @@ export class Checkpointer {
});
this.#waitingForRetry.add(runId);
await new Promise((resolve) => setTimeout(resolve, delay.milliseconds));
await setTimeout(delay.milliseconds);
if (!this.#waitingForRetry.has(runId)) {
this.#logger.log("Checkpoint canceled while waiting for retry", { runId });
@@ -395,64 +402,63 @@ export class Checkpointer {
const controller = new AbortController();
this.#abortControllers.set(runId, controller);
const $$ = $({ signal: controller.signal });
const onAbort = () => {
this.#logger.error("Checkpoint aborted", { options });
controller.signal.removeEventListener("abort", onAbort);
};
controller.signal.addEventListener("abort", onAbort);
const shortCode = nanoid(8);
const imageRef = this.#getImageRef(projectRef, deploymentVersion, shortCode);
const exportLocation = this.#getExportLocation(projectRef, deploymentVersion, shortCode);
const buildah = new Buildah({ id: `${runId}-${shortCode}`, abortSignal: controller.signal });
const crictl = new Crictl({ id: `${runId}-${shortCode}`, abortSignal: controller.signal });
const cleanup = async () => {
const metadata = {
runId,
exportLocation,
imageRef,
};
if (this.#dockerMode) {
this.#logger.debug("Skipping cleanup in docker mode", metadata);
return;
}
try {
await $`rm ${exportLocation}`;
this.#logger.log("Deleted checkpoint archive", { exportLocation });
this.#logger.log("Cleaning up", metadata);
await $`buildah rmi ${imageRef}`;
this.#logger.log("Deleted checkpoint image", { imageRef });
try {
await buildah.cleanup();
await crictl.cleanup();
} catch (error) {
this.#logger.error("Failure during checkpoint cleanup", { exportLocation, error });
this.#logger.error("Error during cleanup", { ...metadata, error });
}
// Ensure only the current controller is removed
if (this.#abortControllers.get(runId) === controller) {
this.#abortControllers.delete(runId);
}
controller.signal.removeEventListener("abort", onAbort);
};
try {
await this.chaosMonkey.call({ $: $$ });
await this.chaosMonkey.call();
this.#logger.log("Checkpointing:", { options });
const containterName = this.#getRunContainerName(runId);
const containterNameWithAttempt = this.#getRunContainerName(runId, attemptNumber);
// Create checkpoint (docker)
if (this.#dockerMode) {
try {
if (this.opts.forceSimulate || !this.#canCheckpoint) {
this.#logger.log("Simulating checkpoint");
this.#logger.debug(await $$`docker pause ${containterNameWithAttempt}`);
} else {
if (this.simulateCheckpointFailure) {
if (performance.now() < this.simulateCheckpointFailureSeconds * 1000) {
this.#logger.error("Simulating checkpoint failure", { options });
throw new Error("SIMULATE_CHECKPOINT_FAILURE");
}
}
if (leaveRunning) {
this.#logger.debug(
await $$`docker checkpoint create --leave-running ${containterNameWithAttempt} ${exportLocation}`
);
} else {
this.#logger.debug(
await $$`docker checkpoint create ${containterNameWithAttempt} ${exportLocation}`
);
}
}
} catch (error) {
this.#logger.error("Failed while creating docker checkpoint", { exportLocation });
throw error;
}
await this.#createDockerCheckpoint(
controller.signal,
runId,
exportLocation,
leaveRunning,
attemptNumber
);
this.#logger.log("checkpoint created:", {
runId,
@@ -474,12 +480,7 @@ export class Checkpointer {
return { success: false, reason: "SKIP_RETRYING" };
}
const containerId = this.#logger.debug(
// @ts-expect-error
await $$`crictl ps`
.pipeStdout($$({ stdin: "pipe" })`grep ${containterName}`)
.pipeStdout($$({ stdin: "pipe" })`cut -f1 ${"-d "}`)
);
const containerId = await crictl.ps(containterName, true);
if (!containerId.stdout) {
this.#logger.error("could not find container id", { options, containterName });
@@ -496,7 +497,7 @@ export class Checkpointer {
}
// Create checkpoint
this.#logger.debug(await $$`crictl checkpoint --export=${exportLocation} ${containerId}`);
await crictl.checkpoint(containerId.stdout, exportLocation);
const postCheckpoint = performance.now();
// Print checkpoint size
@@ -504,23 +505,20 @@ export class Checkpointer {
this.#logger.log("checkpoint archive created", { size, options });
// Create image from checkpoint
const container = this.#logger.debug(await $$`buildah from scratch`);
const workingContainer = await buildah.from("scratch");
const postFrom = performance.now();
this.#logger.debug(await $$`buildah add ${container} ${exportLocation} /`);
await buildah.add(workingContainer.stdout, exportLocation, "/");
const postAdd = performance.now();
this.#logger.debug(
await $$`buildah config --annotation=io.kubernetes.cri-o.annotations.checkpoint.name=counter ${container}`
);
await buildah.config(workingContainer.stdout, [
`io.kubernetes.cri-o.annotations.checkpoint.name=${shortCode}`,
]);
const postConfig = performance.now();
this.#logger.debug(await $$`buildah commit ${container} ${imageRef}`);
await buildah.commit(workingContainer.stdout, imageRef);
const postCommit = performance.now();
this.#logger.debug(await $$`buildah rm ${container}`);
const postRm = performance.now();
if (this.simulatePushFailure) {
if (performance.now() < this.simulatePushFailureSeconds * 1000) {
this.#logger.error("Simulating push failure", { options });
@@ -529,9 +527,7 @@ export class Checkpointer {
}
// Push checkpoint image
this.#logger.debug(
await $$`buildah push --tls-verify=${String(this.registryTlsVerify)} ${imageRef}`
);
await buildah.push(imageRef, this.registryTlsVerify);
const postPush = performance.now();
const perf = {
@@ -540,8 +536,7 @@ export class Checkpointer {
"buildah add": postAdd - postFrom,
"buildah config": postConfig - postAdd,
"buildah commit": postCommit - postConfig,
"buildah rm": postRm - postCommit,
"buildah push": postPush - postRm,
"buildah push": postPush - postCommit,
};
this.#logger.log("Checkpointed and pushed image to:", { location: imageRef, perf });
@@ -554,24 +549,77 @@ export class Checkpointer {
},
};
} catch (error) {
if (isExecaChildProcess(error)) {
if (error.isCanceled) {
this.#logger.error("Checkpoint canceled", { options, error });
if (error instanceof Exec.Result) {
if (error.aborted) {
this.#logger.error("Checkpoint canceled: Exec", { options });
return { success: false, reason: "CANCELED" };
} else {
this.#logger.error("Checkpoint command error", { options, error });
return { success: false, reason: "ERROR" };
}
this.#logger.error("Checkpoint command error", { options, error });
return { success: false, reason: "ERROR" };
}
this.#logger.error("Unhandled checkpoint error", { options, error });
return { success: false, reason: "ERROR" };
} finally {
this.#abortControllers.delete(runId);
await cleanup();
if (controller.signal.aborted) {
this.#logger.error("Checkpoint canceled: Cleanup", { options });
// Overrides any prior return value
return { success: false, reason: "CANCELED" };
}
}
}
async #createDockerCheckpoint(
abortSignal: AbortSignal,
runId: string,
exportLocation: string,
leaveRunning: boolean,
attemptNumber?: number
) {
const containterNameWithAttempt = this.#getRunContainerName(runId, attemptNumber);
const exec = new Exec({ logger: this.#logger, abortSignal });
try {
if (this.opts.forceSimulate || !this.#canCheckpoint) {
this.#logger.log("Simulating checkpoint");
await exec.x("docker", ["pause", containterNameWithAttempt]);
return;
}
if (this.simulateCheckpointFailure) {
if (performance.now() < this.simulateCheckpointFailureSeconds * 1000) {
this.#logger.error("Simulating checkpoint failure", {
runId,
exportLocation,
leaveRunning,
attemptNumber,
});
throw new Error("SIMULATE_CHECKPOINT_FAILURE");
}
}
const args = ["checkpoint", "create"];
if (leaveRunning) {
args.push("--leave-running");
}
args.push(containterNameWithAttempt, exportLocation);
await exec.x("docker", args);
} catch (error) {
this.#logger.error("Failed while creating docker checkpoint", { exportLocation });
throw error;
}
}
@@ -590,4 +638,34 @@ export class Checkpointer {
#getRunContainerName(suffix: string, attemptNumber?: number) {
return `task-run-${suffix}${attemptNumber && attemptNumber > 1 ? `-att${attemptNumber}` : ""}`;
}
#createTmpCleaner() {
if (!boolFromEnv("TMP_CLEANER_ENABLED", false)) {
return;
}
const defaultPaths = [Buildah.tmpDir, Crictl.checkpointDir].filter(Boolean);
const pathsOverride = process.env.TMP_CLEANER_PATHS_OVERRIDE?.split(",").filter(Boolean) ?? [];
const paths = pathsOverride.length ? pathsOverride : defaultPaths;
if (paths.length === 0) {
this.#logger.error("TempFileCleaner enabled but no paths to clean", {
defaultPaths,
pathsOverride,
TMP_CLEANER_PATHS_OVERRIDE: process.env.TMP_CLEANER_PATHS_OVERRIDE,
});
return;
}
const cleaner = new TempFileCleaner({
paths,
maxAgeMinutes: numFromEnv("TMP_CLEANER_MAX_AGE_MINUTES", 60),
intervalSeconds: numFromEnv("TMP_CLEANER_INTERVAL_SECONDS", 300),
leadingEdge: boolFromEnv("TMP_CLEANER_LEADING_EDGE", false),
});
cleaner.start();
return cleaner;
}
}
+106
View File
@@ -0,0 +1,106 @@
import { SimpleStructuredLogger } from "@trigger.dev/core/v3/utils/structuredLogger";
import { Exec } from "./exec";
import { setTimeout } from "timers/promises";
interface TempFileCleanerOptions {
paths: string[];
maxAgeMinutes: number;
intervalSeconds: number;
leadingEdge?: boolean;
}
export class TempFileCleaner {
private enabled = false;
private logger: SimpleStructuredLogger;
private exec: Exec;
constructor(private opts: TempFileCleanerOptions) {
this.logger = new SimpleStructuredLogger("tmp-cleaner", undefined, { ...this.opts });
this.exec = new Exec({ logger: this.logger });
}
async start() {
this.logger.log("TempFileCleaner.start");
this.enabled = true;
if (!this.opts.leadingEdge) {
await this.wait();
}
while (this.enabled) {
try {
await this.clean();
} catch (error) {
this.logger.error("error during tick", { error });
}
await this.wait();
}
}
stop() {
this.logger.log("TempFileCleaner.stop");
this.enabled = false;
}
private wait() {
return setTimeout(this.opts.intervalSeconds * 1000);
}
private async clean() {
for (const path of this.opts.paths) {
try {
await this.cleanSingle(path);
} catch (error) {
this.logger.error("error while cleaning", { path, error });
}
}
}
private async cleanSingle(startingPoint: string) {
const maxAgeMinutes = this.opts.maxAgeMinutes;
const ignoreStartingPoint = ["!", "-path", startingPoint];
const onlyDirectDescendants = ["-maxdepth", "1"];
const onlyOldFiles = ["-mmin", `+${maxAgeMinutes}`];
const baseArgs = [
startingPoint,
...ignoreStartingPoint,
...onlyDirectDescendants,
...onlyOldFiles,
];
const duArgs = ["-exec", "du", "-ch", "{}", "+"];
const rmArgs = ["-exec", "rm", "-rf", "{}", "+"];
const du = this.x("find", [...baseArgs, ...duArgs]);
const duOutput = await du;
const duLines = duOutput.stdout.trim().split("\n");
const fileCount = duLines.length - 1; // last line is the total
const fileSize = duLines.at(-1)?.trim().split(/\s+/)[0];
if (fileCount === 0) {
this.logger.log("nothing to delete", { startingPoint, maxAgeMinutes });
return;
}
this.logger.log("deleting old files", { fileCount, fileSize, startingPoint, maxAgeMinutes });
const rm = this.x("find", [...baseArgs, ...rmArgs]);
const rmOutput = await rm;
if (rmOutput.stderr.length > 0) {
this.logger.error("delete unsuccessful", { rmOutput });
return;
}
this.logger.log("deleted old files", { fileCount, fileSize, startingPoint, maxAgeMinutes });
}
private get x() {
return this.exec.x.bind(this.exec);
}
}
+293
View File
@@ -0,0 +1,293 @@
import { SimpleStructuredLogger } from "@trigger.dev/core/v3/utils/structuredLogger";
import { randomUUID } from "crypto";
import { homedir } from "os";
import { type Result, x } from "tinyexec";
class TinyResult {
pid?: number;
exitCode?: number;
aborted: boolean;
killed: boolean;
constructor(result: Result) {
this.pid = result.pid;
this.exitCode = result.exitCode;
this.aborted = result.aborted;
this.killed = result.killed;
}
}
interface ExecOptions {
logger?: SimpleStructuredLogger;
abortSignal?: AbortSignal;
logOutput?: boolean;
trimArgs?: boolean;
neverThrow?: boolean;
}
export class Exec {
private logger: SimpleStructuredLogger;
private abortSignal: AbortSignal | undefined;
private logOutput: boolean;
private trimArgs: boolean;
private neverThrow: boolean;
constructor(opts: ExecOptions) {
this.logger = opts.logger ?? new SimpleStructuredLogger("exec");
this.abortSignal = opts.abortSignal;
this.logOutput = opts.logOutput ?? true;
this.trimArgs = opts.trimArgs ?? true;
this.neverThrow = opts.neverThrow ?? false;
}
async x(
command: string,
args?: string[],
opts?: { neverThrow?: boolean; ignoreAbort?: boolean }
) {
const argsTrimmed = this.trimArgs ? args?.map((arg) => arg.trim()) : args;
const commandWithFirstArg = `${command}${argsTrimmed?.length ? ` ${argsTrimmed[0]}` : ""}`;
this.logger.debug(`exec: ${commandWithFirstArg}`, { command, args, argsTrimmed });
const result = x(command, argsTrimmed, {
signal: opts?.ignoreAbort ? undefined : this.abortSignal,
// We don't use this as it doesn't cover killed and aborted processes
// throwOnError: true,
});
const output = await result;
const metadata = {
command,
argsRaw: args,
argsTrimmed,
globalOpts: {
trimArgs: this.trimArgs,
neverThrow: this.neverThrow,
hasAbortSignal: !!this.abortSignal,
},
localOpts: opts,
stdout: output.stdout,
stderr: output.stderr,
pid: result.pid,
exitCode: result.exitCode,
aborted: result.aborted,
killed: result.killed,
};
if (this.logOutput) {
this.logger.debug(`output: ${commandWithFirstArg}`, metadata);
}
if (this.neverThrow || opts?.neverThrow) {
return output;
}
if (result.aborted) {
this.logger.error(`aborted: ${commandWithFirstArg}`, metadata);
throw new TinyResult(result);
}
if (result.killed) {
this.logger.error(`killed: ${commandWithFirstArg}`, metadata);
throw new TinyResult(result);
}
if (result.exitCode !== 0) {
this.logger.error(`non-zero exit: ${commandWithFirstArg}`, metadata);
throw new TinyResult(result);
}
return output;
}
static Result = TinyResult;
}
interface BuildahOptions {
id?: string;
abortSignal?: AbortSignal;
}
export class Buildah {
private id: string;
private logger: SimpleStructuredLogger;
private exec: Exec;
private containers = new Set<string>();
private images = new Set<string>();
constructor(opts: BuildahOptions) {
this.id = opts.id ?? randomUUID();
this.logger = new SimpleStructuredLogger("buildah", undefined, { id: this.id });
this.exec = new Exec({
logger: this.logger,
abortSignal: opts.abortSignal,
});
this.logger.log("initiaized", { opts });
}
private get x() {
return this.exec.x.bind(this.exec);
}
async from(baseImage: string) {
const output = await this.x("buildah", ["from", baseImage]);
this.containers.add(output.stdout);
return output;
}
async add(container: string, src: string, dest: string) {
return await this.x("buildah", ["add", container, src, dest]);
}
async config(container: string, annotations: string[]) {
const args = ["config"];
for (const annotation of annotations) {
args.push(`--annotation=${annotation}`);
}
args.push(container);
return await this.x("buildah", args);
}
async commit(container: string, imageRef: string) {
const output = await this.x("buildah", ["commit", container, imageRef]);
this.images.add(output.stdout);
return output;
}
async push(imageRef: string, registryTlsVerify?: boolean) {
return await this.x("buildah", [
"push",
`--tls-verify=${String(!!registryTlsVerify)}`,
imageRef,
]);
}
async cleanup() {
if (this.containers.size > 0) {
try {
const output = await this.x("buildah", ["rm", ...this.containers], { ignoreAbort: true });
this.containers.clear();
if (output.stderr.length > 0) {
this.logger.error("failed to remove some containers", { output });
}
} catch (error) {
this.logger.error("failed to clean up containers", { error, containers: this.containers });
}
} else {
this.logger.debug("no containers to clean up");
}
if (this.images.size > 0) {
try {
const output = await this.x("buildah", ["rmi", ...this.images], { ignoreAbort: true });
this.images.clear();
if (output.stderr.length > 0) {
this.logger.error("failed to remove some images", { output });
}
} catch (error) {
this.logger.error("failed to clean up images", { error, images: this.images });
}
} else {
this.logger.debug("no images to clean up");
}
}
static async canLogin(registryHost: string) {
try {
await x("buildah", ["login", "--get-login", registryHost], { throwOnError: true });
return true;
} catch (error) {
return false;
}
}
static get tmpDir() {
return process.env.TMPDIR ?? "/var/tmp";
}
static get storageRootDir() {
return process.getuid?.() === 0
? "/var/lib/containers/storage"
: `${homedir()}/.local/share/containers/storage`;
}
}
interface CrictlOptions {
id?: string;
abortSignal?: AbortSignal;
}
export class Crictl {
private id: string;
private logger: SimpleStructuredLogger;
private exec: Exec;
private archives = new Set<string>();
constructor(opts: CrictlOptions) {
this.id = opts.id ?? randomUUID();
this.logger = new SimpleStructuredLogger("crictl", undefined, { id: this.id });
this.exec = new Exec({
logger: this.logger,
abortSignal: opts.abortSignal,
});
this.logger.log("initiaized", { opts });
}
private get x() {
return this.exec.x.bind(this.exec);
}
async ps(containerName: string, quiet?: boolean) {
return await this.x("crictl", ["ps", "--name", containerName, quiet ? "--quiet" : ""]);
}
async checkpoint(containerId: string, exportLocation: string) {
const output = await this.x("crictl", [
"checkpoint",
`--export=${exportLocation}`,
containerId,
]);
this.archives.add(exportLocation);
return output;
}
async cleanup() {
if (this.archives.size > 0) {
try {
const output = await this.x("rm", ["-v", ...this.archives], { ignoreAbort: true });
this.archives.clear();
if (output.stderr.length > 0) {
this.logger.error("failed to remove some archives", { output });
}
} catch (error) {
this.logger.error("failed to clean up archives", { error, archives: this.archives });
}
} else {
this.logger.debug("no archives to clean up");
}
}
static getExportLocation(identifier: string) {
return `${this.checkpointDir}/${identifier}.tar`;
}
static get checkpointDir() {
return process.env.CRI_CHECKPOINT_DIR ?? "/checkpoints";
}
}
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
export const boolFromEnv = (env: string, defaultValue: boolean): boolean => {
const value = process.env[env];
if (!value) {
return defaultValue;
}
return ["1", "true"].includes(value);
};
export const numFromEnv = (env: string, defaultValue: number): number => {
const value = process.env[env];
if (!value) {
return defaultValue;
}
return parseInt(value, 10);
};
+1 -1
View File
@@ -20,7 +20,7 @@ const OTEL_EXPORTER_OTLP_ENDPOINT =
process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://0.0.0.0:4318";
const FORCE_CHECKPOINT_SIMULATION = ["1", "true"].includes(
process.env.FORCE_CHECKPOINT_SIMULATION ?? "true"
process.env.FORCE_CHECKPOINT_SIMULATION ?? "false"
);
const logger = new SimpleLogger(`[${MACHINE_NAME}]`);
+69 -38
View File
@@ -1,27 +1,30 @@
import * as k8s from "@kubernetes/client-node";
import {
EnvironmentType,
MachinePreset,
PostStartCauses,
PreStopCauses,
} from "@trigger.dev/core/v3";
import {
ProviderShell,
SimpleLogger,
TaskOperations,
TaskOperationsCreateOptions,
TaskOperationsIndexOptions,
TaskOperationsPrePullDeploymentOptions,
TaskOperationsRestoreOptions,
} from "@trigger.dev/core/v3/apps";
import { SimpleLogger } from "@trigger.dev/core/v3/apps";
import {
MachinePreset,
PostStartCauses,
PreStopCauses,
EnvironmentType,
} from "@trigger.dev/core/v3";
import { TaskMonitor } from "./taskMonitor";
import { PodCleaner } from "./podCleaner";
import { TaskMonitor } from "./taskMonitor";
import { UptimeHeartbeat } from "./uptimeHeartbeat";
const RUNTIME_ENV = process.env.KUBERNETES_PORT ? "kubernetes" : "local";
const NODE_NAME = process.env.NODE_NAME || "local";
const OTEL_EXPORTER_OTLP_ENDPOINT =
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? "http://0.0.0.0:4318";
const COORDINATOR_HOST = process.env.COORDINATOR_HOST ?? undefined;
const COORDINATOR_PORT = process.env.COORDINATOR_PORT ?? undefined;
const KUBERNETES_NAMESPACE = process.env.KUBERNETES_NAMESPACE ?? "default";
const POD_CLEANER_INTERVAL_SECONDS = Number(process.env.POD_CLEANER_INTERVAL_SECONDS || "300");
@@ -31,6 +34,9 @@ const UPTIME_MAX_PENDING_RUNS = Number(process.env.UPTIME_MAX_PENDING_RUNS || "2
const UPTIME_MAX_PENDING_INDECES = Number(process.env.UPTIME_MAX_PENDING_INDECES || "10");
const UPTIME_MAX_PENDING_ERRORS = Number(process.env.UPTIME_MAX_PENDING_ERRORS || "10");
const POD_EPHEMERAL_STORAGE_SIZE_LIMIT = process.env.POD_EPHEMERAL_STORAGE_SIZE_LIMIT || "10Gi";
const POD_EPHEMERAL_STORAGE_SIZE_REQUEST = process.env.POD_EPHEMERAL_STORAGE_SIZE_REQUEST || "2Gi";
const logger = new SimpleLogger(`[${NODE_NAME}]`);
logger.log(`running in ${RUNTIME_ENV} mode`);
@@ -45,19 +51,22 @@ type ResourceQuantities = {
};
class KubernetesTaskOperations implements TaskOperations {
#namespace: Namespace;
#namespace: Namespace = {
metadata: {
name: "default",
},
};
#k8sApi: {
core: k8s.CoreV1Api;
batch: k8s.BatchV1Api;
apps: k8s.AppsV1Api;
};
constructor(namespace = "default") {
this.#namespace = {
metadata: {
name: namespace,
},
};
constructor(opts: { namespace?: string } = {}) {
if (opts.namespace) {
this.#namespace.metadata.name = opts.namespace;
}
this.#k8sApi = this.#createK8sApi();
}
@@ -229,16 +238,7 @@ class KubernetesTaskOperations implements TaskOperations {
imagePullPolicy: "IfNotPresent",
command: ["/bin/sh", "-c"],
args: ["printenv COORDINATOR_HOST | tee /etc/taskinfo/coordinator-host"],
env: [
{
name: "COORDINATOR_HOST",
valueFrom: {
fieldRef: {
fieldPath: "status.hostIP",
},
},
},
],
env: this.#coordinatorEnvVars,
volumeMounts: [
{
name: "taskinfo",
@@ -399,16 +399,51 @@ class KubernetesTaskOperations implements TaskOperations {
get #defaultResourceRequests(): ResourceQuantities {
return {
"ephemeral-storage": "2Gi",
"ephemeral-storage": POD_EPHEMERAL_STORAGE_SIZE_REQUEST,
};
}
get #defaultResourceLimits(): ResourceQuantities {
return {
"ephemeral-storage": "10Gi",
"ephemeral-storage": POD_EPHEMERAL_STORAGE_SIZE_LIMIT,
};
}
get #coordinatorHostEnvVar(): k8s.V1EnvVar {
return COORDINATOR_HOST
? {
name: "COORDINATOR_HOST",
value: COORDINATOR_HOST,
}
: {
name: "COORDINATOR_HOST",
valueFrom: {
fieldRef: {
fieldPath: "status.hostIP",
},
},
};
}
get #coordinatorPortEnvVar(): k8s.V1EnvVar | undefined {
if (COORDINATOR_PORT) {
return {
name: "COORDINATOR_PORT",
value: COORDINATOR_PORT,
};
}
}
get #coordinatorEnvVars(): k8s.V1EnvVar[] {
const envVars = [this.#coordinatorHostEnvVar];
if (this.#coordinatorPortEnvVar) {
envVars.push(this.#coordinatorPortEnvVar);
}
return envVars;
}
#getSharedEnv(envId: string): k8s.V1EnvVar[] {
return [
{
@@ -435,14 +470,6 @@ class KubernetesTaskOperations implements TaskOperations {
},
},
},
{
name: "COORDINATOR_HOST",
valueFrom: {
fieldRef: {
fieldPath: "status.hostIP",
},
},
},
{
name: "MACHINE_NAME",
valueFrom: {
@@ -451,6 +478,7 @@ class KubernetesTaskOperations implements TaskOperations {
},
},
},
...this.#coordinatorEnvVars,
];
}
@@ -623,7 +651,9 @@ class KubernetesTaskOperations implements TaskOperations {
}
const provider = new ProviderShell({
tasks: new KubernetesTaskOperations(),
tasks: new KubernetesTaskOperations({
namespace: KUBERNETES_NAMESPACE,
}),
type: "kubernetes",
});
@@ -631,6 +661,7 @@ provider.listen();
const taskMonitor = new TaskMonitor({
runtimeEnv: RUNTIME_ENV,
namespace: KUBERNETES_NAMESPACE,
onIndexFailure: async (deploymentId, details) => {
logger.log("Indexing failed", { deploymentId, details });
@@ -663,7 +694,7 @@ taskMonitor.start();
const podCleaner = new PodCleaner({
runtimeEnv: RUNTIME_ENV,
namespace: "default",
namespace: KUBERNETES_NAMESPACE,
intervalInSeconds: POD_CLEANER_INTERVAL_SECONDS,
});
@@ -672,7 +703,7 @@ podCleaner.start();
if (UPTIME_HEARTBEAT_URL) {
const uptimeHeartbeat = new UptimeHeartbeat({
runtimeEnv: RUNTIME_ENV,
namespace: "default",
namespace: KUBERNETES_NAMESPACE,
intervalInSeconds: UPTIME_INTERVAL_SECONDS,
pingUrl: UPTIME_HEARTBEAT_URL,
maxPendingRuns: UPTIME_MAX_PENDING_RUNS,
+16 -7
View File
@@ -3,13 +3,14 @@ import { SimpleLogger } from "@trigger.dev/core/v3/apps";
import { EXIT_CODE_ALREADY_HANDLED, EXIT_CODE_CHILD_NONZERO } from "@trigger.dev/core/v3/apps";
import { setTimeout } from "timers/promises";
import PQueue from "p-queue";
import type { Prettify } from "@trigger.dev/core/v3";
import { TaskRunErrorCodes, type Prettify, type TaskRunInternalError } from "@trigger.dev/core/v3";
type FailureDetails = Prettify<{
exitCode: number;
reason: string;
logs: string;
overrideCompletion: boolean;
errorCode: TaskRunInternalError["code"];
}>;
type IndexFailureHandler = (deploymentId: string, details: FailureDetails) => Promise<any>;
@@ -159,19 +160,27 @@ export class TaskMonitor {
let reason = rawReason || "Unknown error";
let logs = rawLogs || "";
let overrideCompletion = false;
/** This will only override existing task errors. It will not crash the run. */
let onlyOverrideExistingError = exitCode === EXIT_CODE_CHILD_NONZERO;
let errorCode: TaskRunInternalError["code"] = TaskRunErrorCodes.POD_UNKNOWN_ERROR;
switch (rawReason) {
case "Error":
reason = "Unknown error.";
errorCode = TaskRunErrorCodes.POD_UNKNOWN_ERROR;
break;
case "Evicted":
if (message.startsWith("Pod ephemeral local storage usage")) {
reason = "Storage limit exceeded.";
errorCode = TaskRunErrorCodes.DISK_SPACE_EXCEEDED;
} else if (message) {
reason = `Evicted: ${message}`;
errorCode = TaskRunErrorCodes.POD_EVICTED;
} else {
reason = "Evicted for unknown reason.";
errorCode = TaskRunErrorCodes.POD_EVICTED;
}
if (logs.startsWith("failed to try resolving symlinks")) {
@@ -179,10 +188,9 @@ export class TaskMonitor {
}
break;
case "OOMKilled":
overrideCompletion = true;
reason = `${
exitCode === EXIT_CODE_CHILD_NONZERO ? "Child process" : "Parent process"
} ran out of memory! Try choosing a machine preset with more memory for this task.`;
reason =
"[TaskMonitor] Your task ran out of memory. Try increasing the machine specs. If this doesn't fix it there might be a memory leak.";
errorCode = TaskRunErrorCodes.TASK_PROCESS_OOM_KILLED;
break;
default:
break;
@@ -192,7 +200,8 @@ export class TaskMonitor {
exitCode,
reason,
logs,
overrideCompletion,
overrideCompletion: onlyOverrideExistingError,
errorCode,
} satisfies FailureDetails;
const app = pod.metadata?.labels?.app;
+3 -2
View File
@@ -4,7 +4,8 @@
"private": true,
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev"
"dev": "wrangler dev",
"dry-run:staging": "wrangler deploy --dry-run --outdir=dist --env staging"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20240512.0",
@@ -15,7 +16,7 @@
"@aws-sdk/client-sqs": "^3.445.0",
"@trigger.dev/core": "workspace:*",
"ulidx": "^2.2.1",
"zod": "3.22.3",
"zod": "3.23.8",
"zod-error": "1.5.0"
}
}
+2 -20
View File
@@ -17,12 +17,9 @@ export interface Env {
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
if (!env.REWRITE_HOSTNAME) throw new Error("Missing REWRITE_HOSTNAME");
console.log("url", request.url);
if (!queueingIsEnabled(env)) {
console.log("Missing AWS credentials. Passing through to the origin.");
return redirectToOrigin(request, env);
return fetch(request);
}
const url = new URL(request.url);
@@ -42,25 +39,10 @@ export default {
}
//the same request but with the hostname (and port) changed
return redirectToOrigin(request, env);
return fetch(request);
},
};
function redirectToOrigin(request: Request, env: Env) {
const newUrl = new URL(request.url);
newUrl.hostname = env.REWRITE_HOSTNAME;
newUrl.port = env.REWRITE_PORT || newUrl.port;
const requestInit: RequestInit = {
method: request.method,
headers: request.headers,
body: request.body,
};
console.log("rewritten url", newUrl.toString());
return fetch(newUrl.toString(), requestInit);
}
function queueingIsEnabled(env: Env) {
return (
env.AWS_SQS_ACCESS_KEY_ID &&
@@ -0,0 +1,17 @@
export function KeyboardDownIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.8779 16.3905C12.4989 17.0854 11.5011 17.0854 11.1221 16.3905L6.80665 8.47885C6.44317 7.81248 6.92548 7 7.68454 7L16.3155 7C17.0745 7 17.5568 7.81248 17.1934 8.47885L12.8779 16.3905Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,17 @@
export function KeyboardLeftIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.60947 12.8779C6.91461 12.4989 6.91461 11.5011 7.60947 11.1221L15.5211 6.80665C16.1875 6.44317 17 6.92548 17 7.68454L17 16.3155C17 17.0745 16.1875 17.5568 15.5211 17.1934L7.60947 12.8779Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,17 @@
export function KeyboardRightIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.3905 11.1221C17.0854 11.5011 17.0854 12.4989 16.3905 12.8779L8.47885 17.1934C7.81248 17.5568 7 17.0745 7 16.3155L7 7.68454C7 6.92548 7.81248 6.44317 8.47885 6.80665L16.3905 11.1221Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,17 @@
export function KeyboardUpIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.1221 6.60947C11.5011 5.91461 12.4989 5.91461 12.8779 6.60947L17.1934 14.5211C17.5568 15.1875 17.0745 16 16.3155 16L7.68454 16C6.92548 16 6.44317 15.1875 6.80665 14.5211L11.1221 6.60947Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,17 @@
export function KeyboardWindowsIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="12"
height="16"
viewBox="0 0 12 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="1.66666" y="3.66663" width="4" height="4" fill="currentColor" />
<rect x="6.33334" y="3.66663" width="4" height="4" fill="currentColor" />
<rect x="1.66666" y="8.33337" width="4" height="4" fill="currentColor" />
<rect x="6.33334" y="8.33337" width="4" height="4" fill="currentColor" />
</svg>
);
}
@@ -0,0 +1,15 @@
export function SideMenuRightClosedIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="12" y="4" width="1" height="12" fill="currentColor" />
<rect x="2.5" y="3.5" width="15" height="13" rx="2.5" stroke="currentColor" />
</svg>
);
}
@@ -0,0 +1,19 @@
export function TimedOutIcon({ className }: { className?: string }) {
return (
<svg
className={className}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 2H8V3H9V4.07089C5.60771 4.55612 3 7.47353 3 11C3 14.866 6.13401 18 10 18C13.866 18 17 14.866 17 11C17 7.47353 14.3923 4.55612 11 4.07089V3H12V2H11H9ZM13.7603 3.36575C14.7218 2.40422 16.2807 2.40422 17.2422 3.36575C18.2038 4.32727 18.2038 5.8862 17.2422 6.84772L17.1462 6.94375C17.1251 6.96488 17.0908 6.96488 17.0697 6.94375L13.6642 3.53831C13.6431 3.51717 13.6431 3.4829 13.6642 3.46177L13.7603 3.36575ZM6.28876 3.58524C6.33584 3.53816 6.33584 3.46184 6.28876 3.41476L6.23971 3.36571C5.27819 2.40419 3.71925 2.40419 2.75773 3.36571C1.79621 4.32723 1.79621 5.88616 2.75773 6.84769L2.80678 6.89674C2.85386 6.94382 2.93019 6.94381 2.97726 6.89674L6.28876 3.58524ZM14.5858 17L16 15.5858L16.7071 16.2929C17.0976 16.6834 17.0976 17.3166 16.7071 17.7071C16.3166 18.0976 15.6834 18.0976 15.2929 17.7071L14.5858 17ZM5.42297 17L4.00875 15.5858L3.30165 16.2929C2.91112 16.6834 2.91112 17.3166 3.30165 17.7071C3.69217 18.0977 4.32534 18.0977 4.71586 17.7071L5.42297 17ZM6.29289 7.29289C6.68342 6.90237 7.31658 6.90237 7.70711 7.29289L10 9.58579L12.2929 7.29289C12.6834 6.90237 13.3166 6.90237 13.7071 7.29289C14.0976 7.68342 14.0976 8.31658 13.7071 8.70711L11.4142 11L13.7071 13.2929C14.0976 13.6834 14.0976 14.3166 13.7071 14.7071C13.3166 15.0976 12.6834 15.0976 12.2929 14.7071L10 12.4142L7.70711 14.7071C7.31658 15.0976 6.68342 15.0976 6.29289 14.7071C5.90237 14.3166 5.90237 13.6834 6.29289 13.2929L8.58579 11L6.29289 8.70711C5.90237 8.31658 5.90237 7.68342 6.29289 7.29289Z"
fill="currentColor"
/>
</svg>
);
}
+19
View File
@@ -0,0 +1,19 @@
export function LyftLogo({ className }: { className?: string }) {
return (
<svg
className={className}
width="48"
height="34"
viewBox="0 0 48 34"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0 0.593341H7.28904V20.1709C7.28904 23.2692 8.70514 25.1147 9.82493 25.9058C8.63943 26.9605 5.01673 27.8834 2.3162 25.6421C0.724053 24.3209 0 22.1485 0 20.1049V0.593341ZM45.5536 16.856V14.7986H47.7767V7.58069H45.3354C44.3982 3.24724 40.5432 0 35.9328 0C30.6217 0 26.3164 4.30894 26.3164 9.62402V26.48C27.8295 26.6928 29.6322 26.4536 31.1659 25.1807C32.7578 23.8594 33.4818 21.6872 33.4818 19.6436V19.0226H37.1222V11.8047H33.4818V9.62402H33.4905C33.4905 8.27426 34.5839 7.18004 35.9328 7.18004C37.2815 7.18004 38.3792 8.27426 38.3792 9.62402V16.856C38.3792 22.1711 42.6891 26.48 48 26.48V19.3C46.6513 19.3 45.5536 18.2057 45.5536 16.856ZM17.9474 7.58069V18.1737C17.9474 18.7751 17.4488 19.2626 16.8337 19.2626C16.2185 19.2626 15.7199 18.7751 15.7199 18.1737V7.58069H8.50752V20.0392C8.50752 22.2803 9.26697 25.1147 12.7231 26.0376C16.1828 26.9615 18.1899 25.049 18.1899 25.049C18.007 26.3089 16.8213 27.2318 14.9113 27.4296C13.4661 27.5791 11.6178 27.1 10.6959 26.7045V33.305C13.0451 33.9983 15.5298 34.2223 17.9614 33.7501C22.3744 32.8932 25.1596 29.2019 25.1596 24.2908V7.58069H17.9474Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,23 @@
export function MiddayLogo({ className }: { className?: string }) {
return (
<svg
className={className}
width={102}
height={30}
viewBox="0 0 100 30"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
fillRule="evenodd"
d="M14.347 0a14.931 14.931 0 0 0-6.282 1.68l6.282 10.88V0Zm0 17.443L8.067 28.32a14.933 14.933 0 0 0 6.28 1.68V17.443ZM15.652 30V17.432l6.285 10.887A14.932 14.932 0 0 1 15.652 30Zm0-17.43V0c2.26.097 4.392.693 6.287 1.682l-6.287 10.889ZM2.336 23.068l10.884-6.284-6.284 10.884a15.093 15.093 0 0 1-4.6-4.6Zm25.33-16.132-10.88 6.282 6.282-10.88a15.094 15.094 0 0 1 4.598 4.598ZM2.335 6.934a15.094 15.094 0 0 1 4.6-4.6l6.284 10.884L2.335 6.934Zm-.654 1.13A14.931 14.931 0 0 0 0 14.35h12.568L1.681 8.064Zm0 13.873a14.932 14.932 0 0 1-1.68-6.282h12.562L1.682 21.938Zm15.754-7.587H30a14.93 14.93 0 0 0-1.68-6.285L17.435 14.35Zm10.884 7.586-10.878-6.28H30a14.932 14.932 0 0 1-1.68 6.28Zm-11.533-5.151 6.281 10.88a15.092 15.092 0 0 0 4.598-4.599l-10.88-6.281Z"
clipRule="evenodd"
/>
<path
fill="currentColor"
d="M92.34 11.912h1.637l2.995 8.223 2.884-8.223h1.619l-4 11.107c-.372 1.06-1.08 1.544-2.196 1.544h-1.172v-1.358h1.024c.502 0 .8-.186.986-.707l.353-.912h-.52l-3.61-9.674ZM82.744 14.814c.39-1.916 1.916-3.126 4.018-3.126 2.549 0 3.963 1.489 3.963 4.13v3.964c0 .446.186.632.614.632h.39v1.358h-.65c-1.005 0-1.88-.335-1.861-1.544-.428.93-1.544 1.767-3.107 1.767-1.954 0-3.535-1.041-3.535-2.79 0-2.028 1.544-2.55 3.702-2.977l2.921-.558c-.018-1.712-.818-2.53-2.437-2.53-1.265 0-2.102.65-2.4 1.804l-1.618-.13Zm1.432 4.39c0 .8.689 1.452 2.14 1.433 1.637 0 2.92-1.153 2.92-3.442v-.167l-2.362.41c-1.47.26-2.698.371-2.698 1.767ZM80.129 8.563v13.21h-1.377l-.056-1.452c-.558 1.042-1.618 1.675-3.144 1.675-2.847 0-4.168-2.419-4.168-5.154s1.321-5.153 4.168-5.153c1.451 0 2.493.558 3.051 1.562V8.563h1.526Zm-7.145 8.28c0 1.915.819 3.701 2.884 3.701 2.028 0 2.865-1.823 2.865-3.702 0-1.953-.837-3.758-2.865-3.758-2.065 0-2.884 1.786-2.884 3.758ZM68.936 8.563v13.21H67.56l-.056-1.452c-.558 1.042-1.619 1.675-3.144 1.675-2.847 0-4.168-2.419-4.168-5.154s1.321-5.153 4.168-5.153c1.45 0 2.493.558 3.05 1.562V8.563h1.526Zm-7.144 8.28c0 1.915.819 3.701 2.884 3.701 2.028 0 2.865-1.823 2.865-3.702 0-1.953-.837-3.758-2.865-3.758-2.065 0-2.884 1.786-2.884 3.758ZM56.212 11.912h1.525v9.86h-1.525v-9.86Zm-.037-1.544V8.6h1.6v1.768h-1.6ZM40.224 11.912h1.395l.056 1.674c.446-1.21 1.47-1.898 2.846-1.898 1.414 0 2.438.763 2.865 2.084.428-1.34 1.47-2.084 3.014-2.084 1.973 0 3.126 1.377 3.126 3.74v6.344H52v-5.897c0-1.805-.707-2.828-1.916-2.828-1.544 0-2.437 1.041-2.437 2.846v5.88H46.12v-5.899c0-1.767-.725-2.827-1.916-2.827-1.526 0-2.456 1.079-2.456 2.827v5.898h-1.525v-9.86Z"
/>
</svg>
);
}
@@ -0,0 +1,41 @@
export function TldrawLogo({ className }: { className?: string }) {
return (
<svg
className={className}
width="96"
height="25"
viewBox="0 0 96 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.3031 0.283066C15.4501 0.283066 18.5971 0.281726 21.7441 0.283066C23.5701 0.283066 24.6473 1.36288 24.6486 3.19829C24.6513 9.4695 24.6513 15.7407 24.6486 22.0133C24.6486 23.8607 23.5808 24.9325 21.7521 24.9338C15.4581 24.9352 9.16417 24.9352 2.87018 24.9338C1.08836 24.9338 0.000510729 23.8446 -0.000828987 22.0521C-0.0021687 15.7581 -0.0021687 9.46414 0.000510729 3.17015C0.00185044 1.34546 1.08568 0.284406 2.93047 0.283066C6.05469 0.281726 9.18024 0.283066 12.3045 0.283066H12.3031ZM12.1223 16.9518C12.0499 17.7543 11.6386 18.3116 11.088 18.8006C10.8201 19.0391 10.4798 19.3713 10.8308 19.6902C11.0532 19.8938 11.5475 19.9997 11.8356 19.9019C13.7808 19.2374 15.2183 16.2498 14.582 14.3019C14.2725 13.3533 13.2825 12.6178 12.3674 12.6594C11.4095 12.7022 10.5682 13.4016 10.3525 14.3327C10.0819 15.4982 10.6553 16.3637 12.1236 16.9518H12.1223ZM12.4143 5.20384C11.2354 5.21858 10.315 6.1604 10.3257 7.34337C10.3364 8.52768 11.2662 9.47218 12.4331 9.48155C13.6134 9.49093 14.586 8.49016 14.5605 7.29112C14.5351 6.10815 13.5892 5.18776 12.4157 5.2025L12.4143 5.20384Z"
fill="currentColor"
/>
<path
d="M85.3405 16.6586C85.4195 16.4443 85.5267 16.2353 85.5722 16.0142C85.9849 13.9846 86.3961 11.9549 86.786 9.92119C86.8784 9.44024 87.1035 9.22588 87.6006 9.25402C88.3093 9.29287 89.2229 9.03832 89.6731 9.39067C90.1206 9.73899 90.138 10.6768 90.284 11.3681C90.6176 12.9597 90.9096 14.5606 91.2339 16.1536C91.2674 16.317 91.408 16.459 91.4978 16.6117C91.5808 16.455 91.7269 16.3023 91.7389 16.1415C91.889 14.1185 92.0323 12.0942 92.1449 10.0699C92.1784 9.48043 92.4021 9.23124 93.0063 9.25134C93.9602 9.28215 94.9167 9.25937 95.9992 9.25937C95.8612 10.157 95.7433 10.9809 95.604 11.8022C95.1793 14.3061 94.7292 16.8073 94.3259 19.3153C94.2201 19.9731 93.995 20.308 93.2582 20.2598C92.3472 20.1995 91.4268 20.2008 90.5158 20.2598C89.8781 20.3013 89.6316 20.0227 89.5284 19.4586C89.2564 17.9689 88.9724 16.4818 88.683 14.9947C88.6415 14.783 88.5397 14.5847 88.4647 14.3798L88.2543 14.3945C88.182 14.7026 88.1029 15.0094 88.0373 15.3189C87.7412 16.735 87.4425 18.1524 87.1598 19.5712C87.0593 20.0776 86.7873 20.2692 86.2702 20.2531C85.2668 20.2236 84.262 20.2249 83.2585 20.2531C82.807 20.2651 82.6048 20.0736 82.5351 19.6596C81.9979 16.4724 81.4526 13.2879 80.9247 10.0994C80.8149 9.4322 80.985 9.26607 81.6763 9.26071C82.4346 9.25536 83.1942 9.28081 83.9525 9.25134C84.3799 9.23526 84.538 9.37995 84.5688 9.81C84.7148 11.9013 84.8863 13.9899 85.0511 16.0785C85.0645 16.25 85.0872 16.4202 85.106 16.5916L85.3405 16.6586Z"
fill="currentColor"
/>
<path
d="M58.7188 5.17457C58.7188 5.4961 58.7188 5.73457 58.7188 5.97438C58.7188 10.3928 58.7188 14.8125 58.7188 19.2309C58.7188 20.1981 58.6692 20.2437 57.6832 20.245C56.7266 20.245 55.7701 20.245 54.7492 20.245C54.7305 19.8846 54.7332 19.5778 54.6943 19.2764C54.6648 19.05 54.5844 18.8316 54.5268 18.6092C54.3446 18.7432 54.1276 18.8477 53.9856 19.0165C53.3988 19.7132 52.7678 20.3107 51.7952 20.4178C50.0951 20.6041 48.6656 19.7091 48.5263 18.0157C48.3534 15.9151 48.399 13.7863 48.5075 11.6775C48.5731 10.3968 49.3663 9.47371 50.6618 9.16424C52.0082 8.84405 53.1804 9.15888 54.0472 10.3244C54.1651 10.4825 54.3621 10.583 54.5215 10.7103C54.5818 10.512 54.6903 10.3137 54.693 10.1141C54.7077 8.75295 54.7198 7.39046 54.693 6.03065C54.6809 5.38892 54.9435 5.15045 55.5691 5.16653C56.5913 5.19332 57.6135 5.17323 58.7188 5.17323V5.17457ZM54.6956 14.6879C54.6956 14.6879 54.6983 14.6879 54.6997 14.6879C54.6997 14.2431 54.7064 13.7983 54.6983 13.3535C54.6863 12.6984 54.4009 12.4827 53.522 12.4465C52.816 12.4171 52.4181 12.681 52.3953 13.2839C52.3605 14.1949 52.3578 15.1086 52.394 16.0182C52.4235 16.7778 53.1175 17.086 54.149 16.7658C54.3728 16.6961 54.6313 16.3866 54.6715 16.1522C54.7532 15.6766 54.6956 15.1782 54.6956 14.6892V14.6879Z"
fill="currentColor"
/>
<path
d="M79.2702 14.5379C79.2702 14.9612 79.2809 15.3859 79.2675 15.8093C79.2528 16.3103 79.2072 16.7886 79.9052 16.9105C80.0419 16.9346 80.1999 17.2937 80.2107 17.504C80.2482 18.2609 80.2442 19.0219 80.2107 19.7788C80.204 19.9383 79.991 20.2276 79.8891 20.2209C78.942 20.1566 77.9747 20.1312 77.061 19.9034C76.5974 19.7882 76.1821 19.3247 75.8365 18.9375C75.5176 18.5811 75.3328 18.5651 75.0796 18.9563C74.1592 20.3804 72.7833 20.6202 71.2587 20.3549C69.998 20.1352 69.1861 19.1559 69.1192 17.8805C69.1004 17.5241 69.1031 17.1664 69.1084 16.81C69.1299 14.988 70.1775 13.8948 72.0036 13.8265C72.873 13.7943 73.7439 13.8359 74.6133 13.805C74.8692 13.7957 75.1197 13.6537 75.3743 13.5733C75.2376 13.241 75.18 12.8257 74.9416 12.6006C74.7326 12.4037 74.3159 12.3314 74.0038 12.3582C72.8087 12.456 71.6124 12.5725 70.4321 12.7735C69.8815 12.8672 69.6778 12.7574 69.6872 12.2108C69.6993 11.5423 69.6483 10.8684 69.7127 10.2052C69.7354 9.96676 69.9712 9.60906 70.1789 9.54877C72.2661 8.94992 74.3896 8.7436 76.5171 9.29556C78.3324 9.7658 79.2072 10.9876 79.2702 13.0012C79.2863 13.5143 79.2729 14.0274 79.2729 14.5405L79.2702 14.5379ZM74.0426 15.6244C73.6956 15.7972 73.0177 15.9258 72.944 16.2112C72.6828 17.22 72.8797 17.721 74.0212 17.512C74.3668 17.4491 74.7138 17.3379 75.0286 17.1838C75.4359 16.9842 75.5833 16.2473 75.235 15.9941C74.9576 15.7932 74.5504 15.7704 74.0426 15.623V15.6244Z"
fill="currentColor"
/>
<path
d="M36.6847 6.1808C36.6847 6.91899 36.6834 7.60224 36.6847 8.28549C36.6874 9.2032 36.7437 9.25813 37.6855 9.25947C38.3527 9.26081 39.0212 9.25947 39.7862 9.25947C39.7862 10.4116 39.8062 11.5343 39.758 12.6543C39.7527 12.7816 39.3628 12.9745 39.1391 12.9933C38.563 13.0415 37.9802 13.0187 37.4001 13.0067C36.8937 12.9959 36.6646 13.2197 36.6807 13.7328C36.6981 14.2901 36.6727 14.8488 36.6887 15.4047C36.7102 16.1282 36.9848 16.4202 37.7016 16.4604C38.1906 16.4886 38.6822 16.4725 39.1739 16.4698C39.5731 16.4685 39.8196 16.6373 39.8223 17.0566C39.829 18.0802 39.825 19.105 39.825 20.2304C37.802 20.1822 35.7576 20.6095 34.0227 19.2176C33.1144 18.4888 32.7567 17.4572 32.691 16.3291C32.6468 15.5735 32.6709 14.8126 32.6669 14.0543C32.6615 13.0991 32.5879 13.0241 31.6501 13.0053C31.4973 13.0026 31.3433 12.9852 31.0927 12.9665C31.0927 11.8706 31.0633 10.7854 31.1249 9.70693C31.1343 9.54349 31.5683 9.28358 31.8081 9.27956C32.4512 9.26885 32.695 8.99688 32.6709 8.38061C32.6495 7.84607 32.6133 7.30214 32.695 6.77831C32.7299 6.55458 33.0407 6.21295 33.239 6.20358C34.3469 6.14731 35.4602 6.17678 36.6861 6.17678L36.6847 6.1808Z"
fill="currentColor"
/>
<path
d="M46.9683 20.2397C45.9474 20.2397 45.0766 20.2732 44.2098 20.2317C42.7214 20.162 41.7796 19.2631 41.5947 17.7894C41.5639 17.5469 41.5545 17.3004 41.5545 17.0552C41.5518 13.4206 41.5518 9.78594 41.5545 6.15129C41.5545 5.30191 41.6778 5.17732 42.5124 5.17464C43.5547 5.17062 44.5983 5.17464 45.7063 5.17464C45.7063 5.531 45.7063 5.79493 45.7063 6.05885C45.7063 9.27015 45.7143 12.4814 45.6982 15.6914C45.6956 16.2206 45.7746 16.5515 46.4177 16.5167C46.5945 16.5073 46.9388 16.7551 46.9442 16.8945C46.9884 17.9957 46.9683 19.0996 46.9683 20.2384V20.2397Z"
fill="currentColor"
/>
<path
d="M65.088 9.26208C65.088 9.88237 65.076 10.3915 65.0961 10.8992C65.1014 11.0265 65.2126 11.1497 65.2756 11.2757C65.3801 11.1819 65.5194 11.1069 65.5824 10.9903C65.7833 10.6206 65.9146 10.2093 66.1477 9.86361C66.6073 9.18304 67.3106 8.97404 68.0823 9.09729C68.2819 9.12945 68.5793 9.43222 68.5874 9.62112C68.6343 10.7559 68.6075 11.8933 68.6128 13.0307C68.6155 13.5184 68.3275 13.4487 67.9831 13.4353C67.2383 13.4058 66.4867 13.3991 65.7458 13.4607C65.2635 13.5009 65.0639 13.8305 65.0733 14.3543C65.1041 16.0263 65.0719 17.6983 65.0907 19.3702C65.0974 19.9865 64.8777 20.2745 64.2319 20.2531C63.3196 20.2236 62.4046 20.2317 61.4909 20.2531C61.1104 20.2611 60.9751 20.1111 60.9751 19.7467C60.9805 16.4925 60.9764 13.237 60.9805 9.98285C60.9805 9.58763 61.1117 9.26744 61.5833 9.26476C62.7154 9.2594 63.8474 9.26342 65.0867 9.26342L65.088 9.26208Z"
fill="currentColor"
/>
</svg>
);
}
@@ -0,0 +1,17 @@
export function UnkeyLogo({ className }: { className?: string }) {
return (
<svg
className={className}
width="94"
height="24"
viewBox="0 0 96 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.9012 20.0088C11.5775 20.0088 8.54297 17.1873 8.54297 12.3427V1.9082H11.3912V12.1564C11.3912 15.7499 12.9883 17.2405 16.9012 17.2405C20.8141 17.2405 22.4112 15.7499 22.4112 12.1564V1.9082H25.286V12.3427C25.286 17.1873 22.2515 20.0088 16.9012 20.0088ZM30.7083 19.7426H27.8335V6.51322H30.4688V10.6125H30.6551C31.0544 8.37651 32.8112 6.24703 36.1651 6.24703C39.8385 6.24703 41.6486 8.72256 41.6486 11.7837V19.7426H38.7738V12.5556C38.7738 10.0801 37.6558 8.82903 34.9141 8.82903C32.0127 8.82903 30.7083 10.3197 30.7083 13.1945V19.7426ZM47.085 19.7426H44.2102V1.9082H47.085V11.7571H50.8648L54.831 6.51322H58.1849L53.2072 12.8751L58.1583 19.7426H54.7777L50.8648 14.3391H47.085V19.7426ZM66.2537 20.0088C61.9149 20.0088 59.0667 17.5599 59.0667 13.1412C59.0667 9.01536 61.8883 6.24703 66.2005 6.24703C70.2997 6.24703 73.0947 8.50961 73.0947 12.529C73.0947 13.0081 73.0681 13.3808 72.9882 13.7801H61.7552C61.8616 16.3355 63.1127 17.693 66.1739 17.693C68.9422 17.693 70.0868 16.788 70.0868 15.2175V15.0045H72.9616V15.2441C72.9616 18.0657 70.1933 20.0088 66.2537 20.0088ZM66.1472 8.50961C63.2192 8.50961 61.9415 9.81392 61.7818 12.183H70.3796V12.1297C70.3796 9.68083 68.9688 8.50961 66.1472 8.50961ZM77.3773 24.2678H75.4874V21.6592H78.0694C79.2406 21.6592 79.7198 21.3398 80.1191 20.4347L80.4385 19.7426L73.9169 6.51322H77.1378L80.5183 13.5405L81.8226 16.7081H82.0356L83.2867 13.5139L86.401 6.51322H89.5686L82.6744 21.18C81.5831 23.5491 80.0924 24.2678 77.3773 24.2678Z"
fill="currentColor"
/>
</svg>
);
}
+27 -8
View File
@@ -1,7 +1,11 @@
import { HomeIcon } from "@heroicons/react/20/solid";
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
import { LinkButton } from "./primitives/Buttons";
import { Header1, Header3 } from "./primitives/Headers";
import { motion } from "framer-motion";
import { friendlyErrorDisplay } from "~/utils/httpErrors";
import { LinkButton } from "./primitives/Buttons";
import { Header1 } from "./primitives/Headers";
import { Paragraph } from "./primitives/Paragraph";
import Spline from "@splinetool/react-spline";
type ErrorDisplayOptions = {
button?: {
@@ -39,12 +43,27 @@ type DisplayOptionsProps = {
export function ErrorDisplay({ title, message, button }: DisplayOptionsProps) {
return (
<div className="p-4">
<Header1 className="mb-4 border-b border-charcoal-800 pb-4">{title}</Header1>
{message && <Header3>{message}</Header3>}
<LinkButton to={button ? button.to : "/"} variant="primary/medium" className="mt-8">
{button ? button.title : "Home"}
</LinkButton>
<div className="relative flex min-h-screen flex-col items-center justify-center bg-[#16181C]">
<div className="z-10 mt-[30vh] flex flex-col items-center gap-8">
<Header1>{title}</Header1>
{message && <Paragraph>{message}</Paragraph>}
<LinkButton
to={button ? button.to : "/"}
shortcut={{ modifiers: ["mod"], key: "g" }}
variant="primary/medium"
LeadingIcon={HomeIcon}
>
{button ? button.title : "Go to homepage"}
</LinkButton>
</div>
<motion.div
className="pointer-events-none absolute inset-0 overflow-hidden"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.5, duration: 2, ease: "easeOut" }}
>
<Spline scene="https://prod.spline.design/wRly8TZN-e0Twb8W/scene.splinecode" />
</motion.div>
</div>
);
}
+103 -158
View File
@@ -1,31 +1,24 @@
import { conform, useForm } from "@conform-to/react";
import { parse } from "@conform-to/zod";
import { BookOpenIcon } from "@heroicons/react/20/solid";
import {
CalendarDaysIcon,
ChevronRightIcon,
EnvelopeIcon,
LifebuoyIcon,
LightBulbIcon,
} from "@heroicons/react/24/solid";
import { InformationCircleIcon } from "@heroicons/react/20/solid";
import { EnvelopeIcon } from "@heroicons/react/24/solid";
import { Form, useActionData, useLocation, useNavigation } from "@remix-run/react";
import { DiscordIcon } from "@trigger.dev/companyicons";
import { ActivityIcon } from "lucide-react";
import { type ReactNode, useState } from "react";
import { type ReactNode, useEffect, useState } from "react";
import { type FeedbackType, feedbackTypeLabel, schema } from "~/routes/resources.feedback";
import { cn } from "~/utils/cn";
import { docsTroubleshootingPath } from "~/utils/pathBuilder";
import { Button, LinkButton } from "./primitives/Buttons";
import { Button } from "./primitives/Buttons";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "./primitives/Dialog";
import { Fieldset } from "./primitives/Fieldset";
import { FormButtons } from "./primitives/FormButtons";
import { FormError } from "./primitives/FormError";
import { Header1 } from "./primitives/Headers";
import { Icon } from "./primitives/Icon";
import { InfoPanel } from "./primitives/InfoPanel";
import { InputGroup } from "./primitives/InputGroup";
import { Label } from "./primitives/Label";
import { Paragraph } from "./primitives/Paragraph";
import { Select, SelectItem } from "./primitives/Select";
import { Sheet, SheetBody, SheetContent, SheetTrigger } from "./primitives/Sheet";
import { TextArea } from "./primitives/TextArea";
import { TextLink } from "./primitives/TextLink";
import { DialogClose } from "@radix-ui/react-dialog";
type FeedbackProps = {
button: ReactNode;
@@ -37,161 +30,113 @@ export function Feedback({ button, defaultValue = "bug" }: FeedbackProps) {
const location = useLocation();
const lastSubmission = useActionData();
const navigation = useNavigation();
const [type, setType] = useState<FeedbackType>(defaultValue);
const [form, { path, feedbackType, message }] = useForm({
id: "accept-invite",
// TODO: type this
lastSubmission: lastSubmission as any,
onValidate({ formData }) {
return parse(formData, { schema });
},
shouldRevalidate: "onInput",
});
if (
open &&
navigation.formAction === "/resources/feedback" &&
form.error === undefined &&
form.errors.length === 0
) {
setOpen(false);
}
useEffect(() => {
if (
navigation.formAction === "/resources/feedback" &&
navigation.state === "loading" &&
form.error === undefined &&
form.errors.length === 0
) {
setOpen(false);
}
}, [navigation, form]);
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild={true}>{button}</SheetTrigger>
<SheetContent className="@container">
<SheetBody className="flex h-full flex-col justify-between">
<LinkBanner
title="Join our Discord community"
icon={<DiscordIcon className="size-9" />}
to="https://trigger.dev/discord"
className="hover:border-text-link"
>
<Paragraph>The quickest way to get answers from the Trigger.dev community.</Paragraph>
</LinkBanner>
<LinkBanner
title="Book a 15 min chat with the founders"
icon={<CalendarDaysIcon className="size-9 text-green-500" />}
to="https://cal.com/team/triggerdotdev/founders-call"
className="hover:border-green-500"
>
<Paragraph>Have a question or want to chat? Book a time to talk with us.</Paragraph>
</LinkBanner>
<LinkBanner
title="Suggest a feature"
icon={<LightBulbIcon className="size-9 text-sun-500" />}
to="https://feedback.trigger.dev/"
className="hover:border-sun-400"
>
<Paragraph>Have an idea for a new feature or improvement? Let us know!</Paragraph>
</LinkBanner>
<LinkBanner
title="Troubleshooting"
icon={<LifebuoyIcon className="size-9 text-rose-500" />}
>
<Paragraph>
If you're having trouble, check out our troubleshooting guide or the Trigger.dev
Status page.
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{button}</DialogTrigger>
<DialogContent>
<DialogHeader>Contact us</DialogHeader>
<div className="mt-2 flex flex-col gap-4">
<div className="flex items-center gap-4">
<Icon icon={EnvelopeIcon} className="size-10 min-w-[2.5rem] text-blue-500" />
<Paragraph variant="base/bright">
How can we help? We read every message and will respond as quickly as we can.
</Paragraph>
<div className="flex flex-wrap gap-2">
<LinkButton
to={docsTroubleshootingPath("")}
variant="tertiary/medium"
LeadingIcon={BookOpenIcon}
>
Troubleshooting Docs
</LinkButton>
<LinkButton
to={"https://status.trigger.dev/"}
variant="tertiary/medium"
LeadingIcon={ActivityIcon}
>
Trigger.dev Status
</LinkButton>
</div>
</LinkBanner>
<LinkBanner
title="Send us an email"
icon={<EnvelopeIcon className="size-9 text-blue-500" />}
>
<Paragraph>We read every message and respond quickly.</Paragraph>
<Form method="post" action="/resources/feedback" {...form.props} className="w-full">
<Fieldset className="max-w-full gap-y-3">
<input value={location.pathname} {...conform.input(path, { type: "hidden" })} />
<InputGroup className="max-w-full">
<Select
{...conform.select(feedbackType)}
variant="tertiary/medium"
defaultValue={defaultValue}
placeholder="Select type"
text={(value) => feedbackTypeLabel[value]}
dropdownIcon
</div>
<hr className="border-charcoal-800" />
<Form method="post" action="/resources/feedback" {...form.props} className="w-full">
<Fieldset className="max-w-full gap-y-3">
<input value={location.pathname} {...conform.input(path, { type: "hidden" })} />
<InputGroup className="max-w-full">
{type === "feature" && (
<InfoPanel
icon={InformationCircleIcon}
iconClassName="text-blue-500"
panelClassName="w-full mb-2"
>
{Object.entries(feedbackTypeLabel).map(([name, title]) => (
<SelectItem key={name} value={name}>
{title}
</SelectItem>
))}
</Select>
<FormError id={feedbackType.errorId}>{feedbackType.error}</FormError>
</InputGroup>
<InputGroup className="max-w-full">
<Label>Message</Label>
<TextArea {...conform.textarea(message)} />
<FormError id={message.errorId}>{message.error}</FormError>
</InputGroup>
<FormError>{form.error}</FormError>
<div className="flex w-full justify-end">
<FormButtons
className="m-0 w-max"
confirmButton={
<Button type="submit" variant="tertiary/medium">
Send message
</Button>
}
/>
</div>
</Fieldset>
</Form>
</LinkBanner>
</SheetBody>
</SheetContent>
</Sheet>
);
}
function LinkBanner({
className,
icon,
title,
children,
to,
}: {
className?: string;
icon?: ReactNode;
title?: string;
children?: ReactNode;
to?: string;
}) {
return (
<a
href={to}
target="_blank"
className={cn(
"group/banner mb-4 flex w-full items-center justify-between rounded-md border border-grid-bright bg-charcoal-750 p-4 transition",
className
)}
>
<div className="flex w-full items-start gap-4">
<span>{icon}</span>
<div className="flex w-full flex-col gap-2">
<Header1 className="text-2xl font-semibold text-text-bright">{title}</Header1>
{children}
<Paragraph variant="small">
All our feature requests are public and voted on by the community. The best
way to submit your feature request is to{" "}
<TextLink to="https://feedback.trigger.dev">
post it to our feedback forum
</TextLink>
.
</Paragraph>
</InfoPanel>
)}
{type === "help" && (
<InfoPanel
icon={InformationCircleIcon}
iconClassName="text-blue-500"
panelClassName="w-full mb-2"
>
<Paragraph variant="small">
The quickest way to get answers from the Trigger.dev team and community is to{" "}
<TextLink to="https://trigger.dev/discord">ask in our Discord</TextLink>.
</Paragraph>
</InfoPanel>
)}
<Select
{...conform.select(feedbackType)}
variant="tertiary/medium"
value={type}
defaultValue={type}
setValue={(v) => setType(v as FeedbackType)}
placeholder="Select type"
text={(value) => feedbackTypeLabel[value as FeedbackType]}
dropdownIcon
>
{Object.entries(feedbackTypeLabel).map(([name, title]) => (
<SelectItem key={name} value={name}>
{title}
</SelectItem>
))}
</Select>
<FormError id={feedbackType.errorId}>{feedbackType.error}</FormError>
</InputGroup>
<InputGroup className="max-w-full">
<Label>Message</Label>
<TextArea {...conform.textarea(message)} />
<FormError id={message.errorId}>{message.error}</FormError>
</InputGroup>
<FormError>{form.error}</FormError>
<FormButtons
confirmButton={
<Button type="submit" variant="primary/medium">
Send message
</Button>
}
cancelButton={
<DialogClose asChild>
<Button variant="tertiary/medium">Cancel</Button>
</DialogClose>
}
/>
</Fieldset>
</Form>
</div>
</div>
{to && (
<ChevronRightIcon className="size-5 text-charcoal-500 transition group-hover:translate-x-1 group-hover/banner:text-text-bright" />
)}
</a>
</DialogContent>
</Dialog>
);
}
+10 -6
View File
@@ -26,14 +26,16 @@ function NextButton({ cursor }: { cursor?: string }) {
<LinkButton
to={path ?? "#"}
variant={"minimal/small"}
TrailingIcon="arrow-right"
TrailingIcon="chevron-right"
trailingIconClassName="text-text-dimmed"
className={cn(
"flex items-center",
!path &&
"cursor-not-allowed opacity-50 group-hover:bg-transparent group-hover:text-text-dimmed"
!path && "cursor-not-allowed opacity-50 group-hover/button:bg-transparent"
)}
onClick={(e) => !path && e.preventDefault()}
shortcut={{ key: "k" }}
tooltip="Next"
disabled={!path}
>
Next
</LinkButton>
@@ -47,14 +49,16 @@ function PreviousButton({ cursor }: { cursor?: string }) {
<LinkButton
to={path ?? "#"}
variant={"minimal/small"}
LeadingIcon="arrow-left"
LeadingIcon="chevron-left"
leadingIconClassName="text-text-dimmed"
className={cn(
"flex items-center",
!path &&
"cursor-not-allowed opacity-50 group-hover:bg-transparent group-hover:text-text-dimmed"
!path && "cursor-not-allowed opacity-50 group-hover/button:bg-transparent"
)}
onClick={(e) => !path && e.preventDefault()}
shortcut={{ key: "j" }}
tooltip="Previous"
disabled={!path}
>
Prev
</LinkButton>
@@ -9,6 +9,10 @@ import { LinkButton } from "./primitives/Buttons";
import { Header3 } from "./primitives/Headers";
import { Paragraph } from "./primitives/Paragraph";
import { TextLink } from "./primitives/TextLink";
import { TldrawLogo } from "~/assets/logos/TldrawLogo";
import { UnkeyLogo } from "~/assets/logos/UnkeyLogo";
import { LyftLogo } from "~/assets/logos/LyftLogo";
import { MiddayLogo } from "~/assets/logos/MiddayLogo";
interface QuoteType {
quote: string;
@@ -72,11 +76,12 @@ export function LoginPageLayout({ children }: { children: React.ReactNode }) {
<div className="flex flex-col items-center gap-4 px-8">
<Paragraph>Trusted by developers at</Paragraph>
<div className="flex w-full flex-wrap items-center justify-center gap-x-6 gap-y-3 text-charcoal-500 xl:justify-between xl:gap-0">
<VerizonLogo />
<ShopifyLogo />
<ATAndTLogo />
<LyftLogo className="w-11" />
<UnkeyLogo />
<MiddayLogo />
<AppsmithLogo />
<CalComLogo />
<TldrawLogo />
</div>
</div>
</div>
+48 -6
View File
@@ -1,3 +1,5 @@
import { createContext, useContext, useState } from "react";
import { useAppOrigin } from "~/hooks/useAppOrigin";
import { useProject } from "~/hooks/useProject";
import { InlineCode } from "./code/InlineCode";
import {
@@ -8,7 +10,31 @@ import {
} from "./primitives/ClientTabs";
import { ClipboardField } from "./primitives/ClipboardField";
import { Paragraph } from "./primitives/Paragraph";
import { useAppOrigin } from "~/hooks/useAppOrigin";
type PackageManagerContextType = {
activePackageManager: string;
setActivePackageManager: (value: string) => void;
};
const PackageManagerContext = createContext<PackageManagerContextType | undefined>(undefined);
export function PackageManagerProvider({ children }: { children: React.ReactNode }) {
const [activePackageManager, setActivePackageManager] = useState("npm");
return (
<PackageManagerContext.Provider value={{ activePackageManager, setActivePackageManager }}>
{children}
</PackageManagerContext.Provider>
);
}
function usePackageManager() {
const context = useContext(PackageManagerContext);
if (context === undefined) {
throw new Error("usePackageManager must be used within a PackageManagerProvider");
}
return context;
}
export function InitCommand({ appOrigin, apiKey }: { appOrigin: string; apiKey: string }) {
return (
@@ -131,7 +157,6 @@ export function TriggerDevStep({ extra }: { extra?: string }) {
);
}
// Trigger.dev version 3 setup commands
const v3PackageTag = "latest";
function getApiUrlArg() {
@@ -160,14 +185,19 @@ function getApiUrlArg() {
export function InitCommandV3() {
const project = useProject();
const projectRef = project.ref;
const apiUrlArg = getApiUrlArg();
const initCommandParts = [`trigger.dev@${v3PackageTag}`, "init", `-p ${projectRef}`, apiUrlArg];
const initCommand = initCommandParts.filter(Boolean).join(" ");
const { activePackageManager, setActivePackageManager } = usePackageManager();
return (
<ClientTabs defaultValue="npm">
<ClientTabs
defaultValue="npm"
value={activePackageManager}
onValueChange={setActivePackageManager}
>
<ClientTabsList>
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
@@ -202,8 +232,14 @@ export function InitCommandV3() {
}
export function TriggerDevStepV3() {
const { activePackageManager, setActivePackageManager } = usePackageManager();
return (
<ClientTabs defaultValue="npm">
<ClientTabs
defaultValue="npm"
value={activePackageManager}
onValueChange={setActivePackageManager}
>
<ClientTabsList>
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
@@ -238,8 +274,14 @@ export function TriggerDevStepV3() {
}
export function TriggerLoginStepV3() {
const { activePackageManager, setActivePackageManager } = usePackageManager();
return (
<ClientTabs defaultValue="npm">
<ClientTabs
defaultValue="npm"
value={activePackageManager}
onValueChange={setActivePackageManager}
>
<ClientTabsList>
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
+148
View File
@@ -0,0 +1,148 @@
import { Keyboard } from "lucide-react";
import { Header3 } from "./primitives/Headers";
import { Paragraph } from "./primitives/Paragraph";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "./primitives/SheetV3";
import { ShortcutKey } from "./primitives/ShortcutKey";
import { Button } from "./primitives/Buttons";
export function Shortcuts() {
return (
<Sheet>
<SheetTrigger asChild>
<Button
variant="small-menu-item"
LeadingIcon={Keyboard}
leadingIconClassName="text-blue-500"
data-action="shortcuts"
fullWidth
textAlignLeft
shortcut={{ modifiers: ["shift"], key: "?" }}
className="gap-x-0 pl-0.5"
iconSpacing="gap-x-0.5"
>
Shortcuts
</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>
<div className="flex items-center gap-x-2">
<Keyboard className="size-5 text-indigo-500" />
<span className="font-sans text-base font-medium text-text-bright">
Keyboard shortcuts
</span>
</div>
</SheetTitle>
<div className="space-y-6 px-4 pb-4 pt-2">
<div className="space-y-3">
<Header3>General</Header3>
<Shortcut name="Close">
<ShortcutKey shortcut={{ key: "esc" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Confirm">
<ShortcutKey shortcut={{ modifiers: ["mod"] }} variant="medium/bright" />
<ShortcutKey shortcut={{ key: "enter" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Filter">
<ShortcutKey shortcut={{ key: "f" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Select filter">
<ShortcutKey shortcut={{ key: "1" }} variant="medium/bright" />
<Paragraph variant="small" className="ml-1.5">
to
</Paragraph>
<ShortcutKey shortcut={{ key: "9" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Previous page">
<ShortcutKey shortcut={{ key: "j" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Next page">
<ShortcutKey shortcut={{ key: "k" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Help & Feedback">
<ShortcutKey shortcut={{ key: "h" }} variant="medium/bright" />
</Shortcut>
</div>
<div className="space-y-3">
<Header3>Runs page</Header3>
<Shortcut name="Bulk action: Cancel runs">
<ShortcutKey shortcut={{ key: "c" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Bulk action: Replay runs">
<ShortcutKey shortcut={{ key: "r" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Bulk action: Clear selection">
<ShortcutKey shortcut={{ key: "esc" }} variant="medium/bright" />
</Shortcut>
</div>
<div className="space-y-3">
<Header3>Run page</Header3>
<Shortcut name="Replay run">
<ShortcutKey shortcut={{ key: "r" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Overview">
<ShortcutKey shortcut={{ key: "o" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Details">
<ShortcutKey shortcut={{ key: "d" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Context">
<ShortcutKey shortcut={{ key: "c" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Metadata">
<ShortcutKey shortcut={{ key: "m" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Navigate">
<ShortcutKey shortcut={{ key: "arrowup" }} variant="medium/bright" />
<ShortcutKey shortcut={{ key: "arrowdown" }} variant="medium/bright" />
<ShortcutKey shortcut={{ key: "arrowleft" }} variant="medium/bright" />
<ShortcutKey shortcut={{ key: "arrowright" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Expand all">
<ShortcutKey shortcut={{ key: "e" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Collapse all">
<ShortcutKey shortcut={{ key: "w" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Toggle level">
<ShortcutKey shortcut={{ key: "0" }} variant="medium/bright" />
<Paragraph variant="small" className="ml-1.5">
to
</Paragraph>
<ShortcutKey shortcut={{ key: "9" }} variant="medium/bright" />
</Shortcut>
</div>
<div className="space-y-3">
<Header3>Schedules page</Header3>
<Shortcut name="New schedule">
<ShortcutKey shortcut={{ key: "n" }} variant="medium/bright" />
</Shortcut>
</div>
<div className="space-y-3">
<Header3>Alerts page</Header3>
<Shortcut name="New alert">
<ShortcutKey shortcut={{ key: "n" }} variant="medium/bright" />
</Shortcut>
</div>
</div>
</SheetHeader>
</SheetContent>
</Sheet>
);
}
function Shortcut({ children, name }: { children: React.ReactNode; name: string }) {
return (
<div className="flex items-center justify-between gap-x-2">
<span className="text-sm text-text-dimmed">{name}</span>
<span className="flex items-center gap-x-0.5">{children}</span>
</div>
);
}
@@ -27,7 +27,7 @@ export function FreePlanUsage({ to, percentage }: { to: string; percentage: numb
<ArrowUpCircleIcon className="h-5 w-5 text-text-dimmed" />
<Paragraph className="text-2sm text-text-bright">Free Plan</Paragraph>
</div>
<Link to={to} className="text-2sm text-text-link">
<Link to={to} className="text-2sm text-text-link focus-custom">
Upgrade
</Link>
</div>
@@ -8,32 +8,16 @@ type UsageBarProps = {
current: number;
billingLimit?: number;
tierLimit?: number;
projectedUsage?: number;
isPaying: boolean;
};
const startFactor = 4;
export function UsageBar({
current,
billingLimit,
tierLimit,
projectedUsage,
isPaying,
}: UsageBarProps) {
const getLargestNumber = Math.max(
current,
tierLimit ?? -Infinity,
projectedUsage ?? -Infinity,
billingLimit ?? -Infinity,
5
);
export function UsageBar({ current, billingLimit, tierLimit, isPaying }: UsageBarProps) {
const getLargestNumber = Math.max(current, tierLimit ?? -Infinity, billingLimit ?? -Infinity, 5);
//creates a maximum range for the progress bar, add 10% to the largest number so the bar doesn't reach the end
const maxRange = Math.round(getLargestNumber * 1.1);
const tierRunLimitPercentage = tierLimit ? Math.round((tierLimit / maxRange) * 100) : 0;
const projectedRunsPercentage = projectedUsage
? Math.round((projectedUsage / maxRange) * 100)
: 0;
const billingLimitPercentage =
billingLimit !== undefined ? Math.round((billingLimit / maxRange) * 100) : 0;
const usagePercentage = Math.round((current / maxRange) * 100);
@@ -42,7 +26,7 @@ export function UsageBar({
const usageCappedToLimitPercentage = Math.min(usagePercentage, tierRunLimitPercentage);
return (
<div className="h-fit w-full py-12">
<div className="h-fit w-full py-6">
<div className="relative h-3 w-full rounded-sm bg-background-bright">
{billingLimit !== undefined && (
<motion.div
@@ -93,23 +77,6 @@ export function UsageBar({
/>
</motion.div>
)}
{projectedUsage !== undefined && projectedUsage !== 0 && (
<motion.div
initial={{ width: projectedRunsPercentage / startFactor + "%" }}
animate={{ width: projectedRunsPercentage + "%" }}
transition={{ duration: 1.5, type: "spring" }}
style={{ width: `${projectedRunsPercentage}%` }}
className="absolute h-3 rounded-l-sm"
>
<Legend
text="Projected:"
value={formatCurrency(projectedUsage, false)}
position="topRow2"
percentage={projectedRunsPercentage}
/>
</motion.div>
)}
<motion.div
initial={{ width: usageCappedToLimitPercentage / startFactor + "%" }}
animate={{ width: usageCappedToLimitPercentage + "%" }}
@@ -241,7 +241,7 @@ export const CodeBlock = forwardRef<HTMLDivElement, CodeBlockProps>(
onMouseEnter={() => setMouseOver(true)}
onMouseLeave={() => setMouseOver(false)}
className={cn(
"absolute right-3 z-50 transition-colors duration-100 hover:cursor-pointer",
"absolute right-3 z-50 transition-colors duration-100 focus-custom hover:cursor-pointer",
showChrome ? "top-10" : "top-2.5",
copied ? "text-emerald-500" : "text-charcoal-500 hover:text-charcoal-300"
)}
@@ -112,9 +112,9 @@ export function JSONEditor(opts: JSONEditorProps) {
return (
<div
className={cn(
opts.className,
"grid",
showButtons ? "grid-rows-[2.5rem_1fr]" : "grid-rows-[1fr]"
showButtons ? "grid-rows-[2.5rem_1fr]" : "grid-rows-[1fr]",
opts.className
)}
>
{showButtons && (
@@ -1,18 +1,16 @@
import { ArrowPathIcon, ArrowRightIcon } from "@heroicons/react/20/solid";
import { ExclamationTriangleIcon } from "@heroicons/react/24/solid";
import { ArrowPathIcon } from "@heroicons/react/20/solid";
import { useFetcher } from "@remix-run/react";
import { useState } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components/primitives/Dialog";
import { generateTwoRandomWords } from "~/utils/randomWords";
import { Button } from "../primitives/Buttons";
import { Header1 } from "../primitives/Headers";
import { Input } from "../primitives/Input";
import { Paragraph } from "../primitives/Paragraph";
import { Spinner } from "../primitives/Spinner";
import { Callout } from "../primitives/Callout";
import { Fieldset } from "../primitives/Fieldset";
import { InputGroup } from "../primitives/InputGroup";
import { FormButtons } from "../primitives/FormButtons";
import { Input } from "../primitives/Input";
import { InputGroup } from "../primitives/InputGroup";
import { Paragraph } from "../primitives/Paragraph";
import { Spinner } from "../primitives/Spinner";
type ModalProps = {
id: string;
@@ -31,15 +29,17 @@ export function RegenerateApiKeyModal({ id, title }: ModalProps) {
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button
variant="minimal/small"
leadingIconClassName="text-text-dimmed"
variant="small-menu-item"
fullWidth
textAlignLeft
leadingIconClassName="text-success"
LeadingIcon={ArrowPathIcon}
>
Regenerate
Regenerate
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>{`Regenerate ${title} Environment Key`}</DialogHeader>
<DialogHeader>{`Regenerate ${title.toUpperCase()} environment key`}</DialogHeader>
<RegenerateApiKeyModalContent
id={id}
title={title}
@@ -62,10 +62,10 @@ const RegenerateApiKeyModalContent = ({ id, randomWord, title, closeModal }: Mod
}
return (
<div className="flex flex-col items-center gap-y-5 py-4">
<div className="flex flex-col items-center gap-y-4 pt-4">
<Callout variant="warning">
{`Regenerating the keys for this environment will temporarily break any live Jobs in the
${title} Environmentuntil the new API keys are set in the relevant environment variables.`}
{`Regenerating the keys for this environment will temporarily break any live tasks in the
${title} environment until the new API keys are set in the relevant environment variables.`}
</Callout>
<fetcher.Form
method="post"
@@ -73,7 +73,7 @@ const RegenerateApiKeyModalContent = ({ id, randomWord, title, closeModal }: Mod
className="mt-2 w-full"
>
<Fieldset className="w-full">
<InputGroup>
<InputGroup className="max-w-full">
<Paragraph variant="small/bright">Enter this text below to confirm:</Paragraph>
<Paragraph
variant="small"
@@ -93,14 +93,14 @@ const RegenerateApiKeyModalContent = ({ id, randomWord, title, closeModal }: Mod
confirmButton={
<Button
type="submit"
variant={"primary/small"}
variant={"primary/medium"}
LeadingIcon={isSubmitting ? Spinner : undefined}
disabled={confirmationText !== randomWord}
>
Regenerate
</Button>
}
cancelButton={<Button variant={"tertiary/small"}>Cancel</Button>}
cancelButton={<Button variant={"tertiary/medium"}>Cancel</Button>}
/>
</Fieldset>
</fetcher.Form>
@@ -1,14 +1,13 @@
import { ShieldCheckIcon } from "@heroicons/react/20/solid";
import { ArrowLeftIcon } from "@heroicons/react/24/solid";
import { DiscordIcon } from "@trigger.dev/companyicons";
import { User } from "@trigger.dev/database";
import { useFeatures } from "~/hooks/useFeatures";
import { cn } from "~/utils/cn";
import { accountPath, personalAccessTokensPath, rootPath } from "~/utils/pathBuilder";
import { Feedback } from "../Feedback";
import { Button, LinkButton } from "../primitives/Buttons";
import { LinkButton } from "../primitives/Buttons";
import { SideMenuHeader } from "./SideMenuHeader";
import { SideMenuItem } from "./SideMenuItem";
import { HelpAndFeedback } from "./HelpAndFeedbackPopover";
export function AccountSideMenu({ user }: { user: User }) {
const { v3Enabled } = useFeatures();
@@ -20,7 +19,7 @@ export function AccountSideMenu({ user }: { user: User }) {
)}
>
<div className="flex h-full flex-col">
<div className={cn("flex items-center justify-between border-b p-px transition")}>
<div className={cn("flex h-10 items-center justify-between border-b p-1 transition")}>
<LinkButton
variant="minimal/medium"
LeadingIcon={ArrowLeftIcon}
@@ -38,7 +37,7 @@ export function AccountSideMenu({ user }: { user: User }) {
<SideMenuItem
name="Your profile"
icon="account"
iconColor="text-indigo-500"
activeIconColor="text-indigo-500"
to={accountPath()}
data-action="account"
/>
@@ -49,7 +48,7 @@ export function AccountSideMenu({ user }: { user: User }) {
<SideMenuItem
name="Personal Access Tokens"
icon={ShieldCheckIcon}
iconColor="text-emerald-500"
activeIconColor="text-emerald-500"
to={personalAccessTokensPath()}
data-action="tokens"
/>
@@ -57,42 +56,7 @@ export function AccountSideMenu({ user }: { user: User }) {
)}
</div>
<div className="flex flex-col gap-1 border-t border-grid-bright p-1">
<SideMenuItem
name="Join our Discord"
icon={DiscordIcon}
to="https://trigger.dev/discord"
data-action="join our discord"
target="_blank"
/>
<SideMenuItem
name="Documentation"
icon="docs"
to="https://trigger.dev/docs"
data-action="documentation"
target="_blank"
/>
<SideMenuItem
name="Changelog"
icon="star"
to="https://trigger.dev/changelog"
data-action="changelog"
target="_blank"
/>
<Feedback
button={
<Button
variant="small-menu-item"
LeadingIcon="log"
data-action="help & feedback"
fullWidth
textAlignLeft
>
Help & Feedback
</Button>
}
/>
<HelpAndFeedback />
</div>
</div>
</div>
@@ -0,0 +1,183 @@
import {
ArrowUpRightIcon,
CalendarDaysIcon,
ChatBubbleLeftEllipsisIcon,
EnvelopeIcon,
LightBulbIcon,
SignalIcon,
} from "@heroicons/react/20/solid";
import { DiscordIcon, SlackIcon } from "@trigger.dev/companyicons";
import { Fragment, useState } from "react";
import { useCurrentPlan } from "~/routes/_app.orgs.$organizationSlug/route";
import { Feedback } from "../Feedback";
import { StepContentContainer } from "../StepContentContainer";
import { Button } from "../primitives/Buttons";
import { ClipboardField } from "../primitives/ClipboardField";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "../primitives/Dialog";
import { Icon } from "../primitives/Icon";
import { Paragraph } from "../primitives/Paragraph";
import { Popover, PopoverContent, PopoverSideMenuTrigger } from "../primitives/Popover";
import { StepNumber } from "../primitives/StepNumber";
import { MenuCount, SideMenuItem } from "./SideMenuItem";
import { Shortcuts } from "../Shortcuts";
export function HelpAndFeedback() {
const [isHelpMenuOpen, setHelpMenuOpen] = useState(false);
const currentPlan = useCurrentPlan();
return (
<Popover onOpenChange={(open) => setHelpMenuOpen(open)}>
<PopoverSideMenuTrigger isOpen={isHelpMenuOpen} shortcut={{ key: "h" }}>
<div className="flex items-center gap-1.5">
<ChatBubbleLeftEllipsisIcon className="size-4 text-success" />
Help & Feedback
</div>
</PopoverSideMenuTrigger>
<PopoverContent
className="min-w-[14rem] divide-y divide-grid-bright overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
align="start"
>
<Fragment>
<div className="flex flex-col gap-1 p-1">
<SideMenuItem
name="Documentation"
icon="docs"
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
inactiveIconColor="text-green-500"
activeIconColor="text-green-500"
to="https://trigger.dev/docs"
data-action="documentation"
target="_blank"
/>
</div>
<div className="flex flex-col gap-1 p-1">
<SideMenuItem
name="Status"
icon={SignalIcon}
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
inactiveIconColor="text-green-500"
activeIconColor="text-green-500"
to="https://status.trigger.dev/"
data-action="status"
target="_blank"
/>
<SideMenuItem
name="Suggest a feature"
icon={LightBulbIcon}
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
inactiveIconColor="text-sun-500"
activeIconColor="text-sun-500"
to="https://feedback.trigger.dev/"
data-action="suggest-a-feature"
target="_blank"
/>
<SideMenuItem
name="Changelog"
icon="star"
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
inactiveIconColor="text-sun-500"
activeIconColor="text-sun-500"
to="https://trigger.dev/changelog"
data-action="changelog"
target="_blank"
/>
<Shortcuts />
</div>
<div className="flex flex-col gap-1 p-1">
<Paragraph className="pb-1 pl-1.5 pt-1.5 text-xs">Need help?</Paragraph>
{currentPlan?.v3Subscription?.plan?.limits.support === "slack" && (
<div>
<Dialog>
<DialogTrigger asChild>
<Button
variant="small-menu-item"
LeadingIcon={SlackIcon}
data-action="join-our-slack"
fullWidth
textAlignLeft
>
<div className="flex w-full items-center justify-between">
<span className="text-text-bright">Join our Slack</span>
<MenuCount count="PRO" />
</div>
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>Join our Slack</DialogHeader>
<div className="mt-2 flex flex-col gap-4">
<div className="flex items-center gap-4">
<Icon icon={SlackIcon} className="h-10 w-10 min-w-[2.5rem]" />
<Paragraph variant="base/bright">
As a subscriber, you have access to a dedicated Slack channel for 1-to-1
support with the Trigger.dev team.
</Paragraph>
</div>
<hr className="border-charcoal-800" />
<div>
<StepNumber stepNumber="1" title="Email us" />
<StepContentContainer>
<Paragraph>
Send us an email to this address from your Trigger.dev account email
address:
<ClipboardField
variant="secondary/medium"
value="priority-support@trigger.dev"
className="my-2"
/>
</Paragraph>
</StepContentContainer>
<StepNumber stepNumber="2" title="Look out for an invite from Slack" />
<StepContentContainer>
<Paragraph>
As soon as we can, we'll setup a Slack Connect channel and say hello!
</Paragraph>
</StepContentContainer>
</div>
</div>
</DialogContent>
</Dialog>
</div>
)}
<SideMenuItem
name="Ask in our Discord"
icon={DiscordIcon}
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
to="https://trigger.dev/discord"
data-action="join our discord"
target="_blank"
/>
<SideMenuItem
name="Book a 15 min call"
icon={CalendarDaysIcon}
trailingIcon={ArrowUpRightIcon}
trailingIconClassName="text-text-dimmed"
inactiveIconColor="text-rose-500"
activeIconColor="text-rose-500"
to="https://cal.com/team/triggerdotdev/founders-call"
data-action="book-a-call"
target="_blank"
/>
<Feedback
button={
<Button
variant="small-menu-item"
LeadingIcon={EnvelopeIcon}
leadingIconClassName="text-blue-500"
data-action="contact-us"
fullWidth
textAlignLeft
>
Contact us
</Button>
}
/>
</div>
</Fragment>
</PopoverContent>
</Popover>
);
}
@@ -12,18 +12,18 @@ import {
RectangleStackIcon,
ServerStackIcon,
ShieldCheckIcon,
SignalIcon,
Squares2X2Icon,
} from "@heroicons/react/20/solid";
import { UserGroupIcon, UserPlusIcon } from "@heroicons/react/24/solid";
import { useNavigation } from "@remix-run/react";
import { DiscordIcon, SlackIcon } from "@trigger.dev/companyicons";
import { Fragment, useEffect, useRef, useState } from "react";
import { Fragment, ReactNode, useEffect, useRef, useState } from "react";
import { TaskIcon } from "~/assets/icons/TaskIcon";
import { useFeatures } from "~/hooks/useFeatures";
import { type MatchedOrganization } from "~/hooks/useOrganizations";
import { type MatchedProject } from "~/hooks/useProject";
import { type User } from "~/models/user.server";
import { useCurrentPlan } from "~/routes/_app.orgs.$organizationSlug/route";
import { FeedbackType } from "~/routes/resources.feedback";
import { cn } from "~/utils/cn";
import {
accountPath,
@@ -46,6 +46,7 @@ import {
projectSetupPath,
projectTriggersPath,
v3ApiKeysPath,
v3BatchesPath,
v3BillingPath,
v3ConcurrencyPath,
v3DeploymentsPath,
@@ -58,17 +59,13 @@ import {
v3TestPath,
v3UsagePath,
} from "~/utils/pathBuilder";
import { Feedback } from "../Feedback";
import { ImpersonationBanner } from "../ImpersonationBanner";
import { LogoIcon } from "../LogoIcon";
import { StepContentContainer } from "../StepContentContainer";
import { UserProfilePhoto } from "../UserProfilePhoto";
import { FreePlanUsage } from "../billing/v2/FreePlanUsage";
import { Badge } from "../primitives/Badge";
import { Button, LinkButton } from "../primitives/Buttons";
import { ClipboardField } from "../primitives/ClipboardField";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "../primitives/Dialog";
import { Icon } from "../primitives/Icon";
import { LinkButton } from "../primitives/Buttons";
import { Header2 } from "../primitives/Headers";
import { Paragraph } from "../primitives/Paragraph";
import {
Popover,
@@ -78,8 +75,8 @@ import {
PopoverMenuItem,
PopoverSectionHeader,
} from "../primitives/Popover";
import { StepNumber } from "../primitives/StepNumber";
import { TextLink } from "../primitives/TextLink";
import { HelpAndFeedback } from "./HelpAndFeedbackPopover";
import { SideMenuHeader } from "./SideMenuHeader";
import { SideMenuItem } from "./SideMenuItem";
@@ -91,8 +88,38 @@ type SideMenuProps = {
project: SideMenuProject;
organization: MatchedOrganization;
organizations: MatchedOrganization[];
button?: ReactNode;
defaultValue?: FeedbackType;
};
function V2Countdown() {
const [days, setDays] = useState(0);
useEffect(() => {
const targetDate = new Date("2025-01-31T00:00:00Z");
const calculateDays = () => {
const now = new Date();
const difference = targetDate.getTime() - now.getTime();
return Math.floor(difference / (1000 * 60 * 60 * 24));
};
const timer = setInterval(() => {
setDays(calculateDays());
}, 1000 * 60 * 60); // Update every hour
setDays(calculateDays()); // Initial calculation
return () => clearInterval(timer);
}, []);
return (
<Header2 className="flex-wrap gap-4 text-error">
V2 goes offline in <span className="tabular-nums">{days}d</span>
</Header2>
);
}
export function SideMenu({ user, project, organization, organizations }: SideMenuProps) {
const borderRef = useRef<HTMLDivElement>(null);
const [showHeaderDivider, setShowHeaderDivider] = useState(false);
@@ -171,7 +198,7 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
name="Team"
icon={UserGroupIcon}
to={organizationTeamPath(organization)}
iconColor="text-amber-500"
activeIconColor="text-amber-500"
data-action="team"
/>
{organization.projects.some((proj) => proj.version === "V3") && isManagedCloud && (
@@ -180,14 +207,14 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
name="Usage"
icon={ChartBarIcon}
to={v3UsagePath(organization)}
iconColor="text-green-600"
activeIconColor="text-green-600"
data-action="usage"
/>
<SideMenuItem
name="Billing"
icon={CreditCardIcon}
to={v3BillingPath(organization)}
iconColor="text-blue-600"
activeIconColor="text-blue-600"
data-action="billing"
badge={
currentPlan?.v3Subscription?.isPaying
@@ -202,14 +229,14 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
name="Usage (v2)"
icon={ChartBarIcon}
to={organizationBillingPath(organization)}
iconColor="text-green-600"
activeIconColor="text-green-600"
data-action="usage & billing"
/>
)}
<SideMenuItem
name="Organization settings"
icon="settings"
iconColor="text-teal-500"
activeIconColor="text-teal-500"
to={organizationSettingsPath(organization)}
data-action="organization-settings"
/>
@@ -217,7 +244,8 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
</div>
<div className="m-2">
{project.version === "V2" && (
<div className="flex flex-col gap-3 rounded border border-success/50 bg-success/10 p-3">
<div className="flex flex-col gap-3 rounded border border-error/50 bg-error/5 p-3">
<V2Countdown />
<Paragraph variant="small/bright">
This is a v2 project. V2 will be deprecated on January 31, 2025.{" "}
<TextLink
@@ -239,96 +267,7 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
)}
</div>
<div className="flex flex-col gap-1 border-t border-grid-bright p-1">
{currentPlan?.v3Subscription?.plan?.limits.support === "slack" && (
<Dialog>
<DialogTrigger asChild>
<Button
variant="small-menu-item"
LeadingIcon={SlackIcon}
data-action="join our slack"
fullWidth
textAlignLeft
>
Join our Slack
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>Join our Slack</DialogHeader>
<div className="mt-2 flex flex-col gap-4">
<div className="flex items-center gap-4">
<Icon icon={SlackIcon} className="h-10 w-10 min-w-[2.5rem]" />
<Paragraph variant="base/bright">
As a subscriber, you have access to a dedicated Slack channel for 1-to-1
support with the Trigger.dev team.
</Paragraph>
</div>
<hr className="border-charcoal-800" />
<div>
<StepNumber stepNumber="1" title="Email us" />
<StepContentContainer>
<Paragraph>
Send us an email to this address from your Trigger.dev account email
address:
<ClipboardField
variant="primary/medium"
value="priority-support@trigger.dev"
className="my-2"
/>
</Paragraph>
</StepContentContainer>
<StepNumber stepNumber="2" title="Look out for an invite from Slack" />
<StepContentContainer>
<Paragraph>
As soon as we can, we'll setup a Slack Connect channel and say hello!
</Paragraph>
</StepContentContainer>
</div>
</div>
</DialogContent>
</Dialog>
)}
<SideMenuItem
name="Join our Discord"
icon={DiscordIcon}
to="https://trigger.dev/discord"
data-action="join our discord"
target="_blank"
/>
<SideMenuItem
name="Documentation"
icon="docs"
to="https://trigger.dev/docs"
data-action="documentation"
target="_blank"
/>
<SideMenuItem
name="Changelog"
icon="star"
to="https://trigger.dev/changelog"
data-action="changelog"
target="_blank"
/>
<SideMenuItem
name="Status"
icon={SignalIcon}
to="https://status.trigger.dev/"
data-action="status"
target="_blank"
/>
<Feedback
button={
<Button
variant="small-menu-item"
LeadingIcon="log"
leadingIconClassName="text-primary"
data-action="help & feedback"
fullWidth
textAlignLeft
>
<span className="text-primary">Help & Feedback</span>
</Button>
}
/>
<HelpAndFeedback />
{isV3Project && isFreeV3User && (
<FreePlanUsage
to={v3BillingPath(organization)}
@@ -495,47 +434,47 @@ function V2ProjectSideMenu({
<SideMenuItem
name="Jobs"
icon="job"
iconColor="text-indigo-500"
activeIconColor="text-indigo-500"
to={projectPath(organization, project)}
data-action="jobs"
/>
<SideMenuItem
name="Runs"
icon="runs"
iconColor="text-teal-500"
activeIconColor="text-teal-500"
to={projectRunsPath(organization, project)}
/>
<SideMenuItem
name="Triggers"
icon="trigger"
iconColor="text-amber-500"
activeIconColor="text-amber-500"
to={projectTriggersPath(organization, project)}
data-action="triggers"
/>
<SideMenuItem
name="Events"
icon={CursorArrowRaysIcon}
iconColor="text-sky-500"
activeIconColor="text-sky-500"
to={projectEventsPath(organization, project)}
/>
<SideMenuItem
name="HTTP endpoints"
icon="http-endpoint"
iconColor="text-pink-500"
activeIconColor="text-pink-500"
to={projectHttpEndpointsPath(organization, project)}
data-action="httpendpoints"
/>
<SideMenuItem
name="Environments & API Keys"
icon="environment"
iconColor="text-rose-500"
activeIconColor="text-rose-500"
to={projectEnvironmentsPath(organization, project)}
data-action="environments & api keys"
/>
<SideMenuItem
name="Project settings"
icon="settings"
iconColor="text-teal-500"
activeIconColor="text-teal-500"
to={projectSettingsPath(organization, project)}
data-action="project-settings"
/>
@@ -550,49 +489,54 @@ function V3ProjectSideMenu({
project: SideMenuProject;
organization: MatchedOrganization;
}) {
const { alertsEnabled } = useFeatures();
return (
<>
<SideMenuHeader title={"Project"} />
<SideMenuItem
name="Tasks"
icon={TaskIcon}
iconColor="text-blue-500"
activeIconColor="text-blue-500"
to={v3ProjectPath(organization, project)}
data-action="tasks"
/>
<SideMenuItem
name="Runs"
icon="runs"
iconColor="text-teal-500"
activeIconColor="text-teal-500"
to={v3RunsPath(organization, project)}
/>
<SideMenuItem
name="Batches"
icon={Squares2X2Icon}
activeIconColor="text-blue-500"
to={v3BatchesPath(organization, project)}
data-action="batches"
/>
<SideMenuItem
name="Test"
icon={BeakerIcon}
iconColor="text-lime-500"
activeIconColor="text-lime-500"
to={v3TestPath(organization, project)}
data-action="test"
/>
<SideMenuItem
name="Schedules"
icon={ClockIcon}
iconColor="text-sun-500"
activeIconColor="text-sun-500"
to={v3SchedulesPath(organization, project)}
data-action="schedules"
/>
<SideMenuItem
name="API keys"
icon={KeyIcon}
iconColor="text-amber-500"
activeIconColor="text-amber-500"
to={v3ApiKeysPath(organization, project)}
data-action="api keys"
/>
<SideMenuItem
name="Environment variables"
icon={IdentificationIcon}
iconColor="text-pink-500"
activeIconColor="text-pink-500"
to={v3EnvironmentVariablesPath(organization, project)}
data-action="environment variables"
/>
@@ -600,30 +544,28 @@ function V3ProjectSideMenu({
<SideMenuItem
name="Deployments"
icon={ServerStackIcon}
iconColor="text-blue-500"
activeIconColor="text-blue-500"
to={v3DeploymentsPath(organization, project)}
data-action="deployments"
/>
{alertsEnabled && (
<SideMenuItem
name="Alerts"
icon={BellAlertIcon}
iconColor="text-red-500"
to={v3ProjectAlertsPath(organization, project)}
data-action="alerts"
/>
)}
<SideMenuItem
name="Alerts"
icon={BellAlertIcon}
activeIconColor="text-red-500"
to={v3ProjectAlertsPath(organization, project)}
data-action="alerts"
/>
<SideMenuItem
name="Concurrency limits"
icon={RectangleStackIcon}
iconColor="text-indigo-500"
activeIconColor="text-indigo-500"
to={v3ConcurrencyPath(organization, project)}
data-action="concurrency"
/>
<SideMenuItem
name="Project settings"
icon="settings"
iconColor="text-teal-500"
activeIconColor="text-teal-500"
to={v3ProjectSettingsPath(organization, project)}
data-action="project-settings"
/>
@@ -3,25 +3,26 @@ import { usePathName } from "~/hooks/usePathName";
import { cn } from "~/utils/cn";
import { LinkButton } from "../primitives/Buttons";
import { type IconNames } from "../primitives/NamedIcon";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../primitives/Tooltip";
import { Icon } from "../primitives/Icon";
import { IconExclamationCircle } from "@tabler/icons-react";
export function SideMenuItem({
icon,
iconColor,
activeIconColor,
inactiveIconColor,
trailingIcon,
trailingIconClassName,
name,
to,
hasWarning,
badge,
target,
subItem = false,
}: {
icon?: IconNames | React.ComponentType<any>;
iconColor?: string;
activeIconColor?: string;
inactiveIconColor?: string;
trailingIcon?: IconNames | React.ComponentType<any>;
trailingIconClassName?: string;
name: string;
to: string;
hasWarning?: string | boolean;
badge?: string;
target?: AnchorHTMLAttributes<HTMLAnchorElement>["target"];
subItem?: boolean;
@@ -35,11 +36,13 @@ export function SideMenuItem({
fullWidth
textAlignLeft
LeadingIcon={icon}
leadingIconClassName={isActive ? iconColor : "text-text-dimmed"}
leadingIconClassName={isActive ? activeIconColor : inactiveIconColor ?? "text-text-dimmed"}
TrailingIcon={trailingIcon}
trailingIconClassName={trailingIconClassName}
to={to}
target={target}
className={cn(
"text-text-bright group-hover:bg-charcoal-750",
"text-text-bright group-hover:bg-charcoal-750 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0",
subItem ? "text-text-dimmed" : "",
isActive ? "bg-tertiary text-text-bright" : "group-hover:text-text-bright"
)}
@@ -48,27 +51,13 @@ export function SideMenuItem({
{name}
<div className="flex items-center gap-1">
{badge !== undefined && <MenuCount count={badge} />}
{typeof hasWarning === "string" ? (
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Icon icon={IconExclamationCircle} className="h-5 w-5 text-error" />
</TooltipTrigger>
<TooltipContent className="flex items-center gap-1 border border-error bg-error/20 backdrop-blur-xl">
{hasWarning}
</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (
hasWarning && <Icon icon={IconExclamationCircle} className="h-5 w-5 text-error" />
)}
</div>
</div>
</LinkButton>
);
}
function MenuCount({ count }: { count: number | string }) {
export function MenuCount({ count }: { count: number | string }) {
return (
<div className="rounded-full bg-charcoal-900 px-2 py-1 text-xxs uppercase tracking-wider text-text-dimmed">
{count}
@@ -0,0 +1,177 @@
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/20/solid";
import { cn } from "~/utils/cn";
const variants = {
small: {
size: "size-[1rem]",
arrowHeadRight: "group-hover:translate-x-[3px]",
arrowLineRight: "h-[1.5px] w-[7px] translate-x-1 top-[calc(50%-0.5px)]",
arrowHeadLeft: "group-hover:translate-x-[3px]",
arrowLineLeft: "h-[1.5px] w-[7px] translate-x-1 top-[calc(50%-0.5px)]",
arrowHeadTopRight:
"-translate-x-0 transition group-hover:translate-x-[3px] group-hover:translate-y-[-3px]",
},
medium: {
size: "size-[1.1rem]",
arrowHeadRight: "group-hover:translate-x-[3px]",
arrowLineRight: "h-[1.5px] w-[9px] translate-x-1 top-[calc(50%-1px)]",
arrowHeadLeft: "group-hover:translate-x-[-3px]",
arrowLineLeft: "h-[1.5px] w-[9px] translate-x-1 top-[calc(50%-1px)]",
arrowHeadTopRight:
"-translate-x-0 transition group-hover:translate-x-[3px] group-hover:translate-y-[-3px]",
},
large: {
size: "size-6",
arrowHeadRight: "group-hover:translate-x-1",
arrowLineRight: "h-[2.3px] w-[12px] translate-x-[6px] top-[calc(50%-1px)]",
arrowHeadLeft: "group-hover:translate-x-1",
arrowLineLeft: "h-[2.3px] w-[12px] translate-x-[6px] top-[calc(50%-1px)]",
arrowHeadTopRight:
"-translate-x-0 transition group-hover:translate-x-[3px] group-hover:translate-y-[-3px]",
},
"extra-large": {
size: "size-8",
arrowHeadRight: "group-hover:translate-x-1",
arrowLineRight: "h-[3px] w-[16px] translate-x-[8px] top-[calc(50%-1.5px)]",
arrowHeadLeft: "group-hover:translate-x-1",
arrowLineLeft: "h-[3px] w-[16px] translate-x-[8px] top-[calc(50%-1.5px)]",
arrowHeadTopRight:
"-translate-x-0 transition group-hover:translate-x-[3px] group-hover:translate-y-[-3px]",
},
};
export const themes = {
dark: {
textStyle: "text-background-bright",
arrowLine: "bg-background-bright",
},
dimmed: {
textStyle: "text-text-dimmed",
arrowLine: "bg-text-dimmed",
},
bright: {
textStyle: "text-text-bright",
arrowLine: "bg-text-bright",
},
primary: {
textStyle: "text-text-dimmed group-hover:text-primary",
arrowLine: "bg-text-dimmed group-hover:bg-primary",
},
blue: {
textStyle: "text-text-dimmed group-hover:text-blue-500",
arrowLine: "bg-text-dimmed group-hover:bg-blue-500",
},
rose: {
textStyle: "text-text-dimmed group-hover:text-rose-500",
arrowLine: "bg-text-dimmed group-hover:bg-rose-500",
},
amber: {
textStyle: "text-text-dimmed group-hover:text-amber-500",
arrowLine: "bg-text-dimmed group-hover:bg-amber-500",
},
apple: {
textStyle: "text-text-dimmed group-hover:text-apple-500",
arrowLine: "bg-text-dimmed group-hover:bg-apple-500",
},
lavender: {
textStyle: "text-text-dimmed group-hover:text-lavender-500",
arrowLine: "bg-text-dimmed group-hover:bg-lavender-500",
},
};
type Variants = keyof typeof variants;
type Theme = keyof typeof themes;
type AnimatingArrowProps = {
className?: string;
variant?: Variants;
theme?: Theme;
direction?: "right" | "left" | "topRight";
};
export function AnimatingArrow({
className,
variant = "medium",
theme = "dimmed",
direction = "right",
}: AnimatingArrowProps) {
const variantStyles = variants[variant];
const themeStyles = themes[theme];
return (
<span className={cn("relative -mr-1 ml-1 flex", variantStyles.size, className)}>
{direction === "topRight" && (
<>
<svg
className={cn(
"absolute top-[5px] transition duration-200 ease-in-out",
themeStyles.textStyle
)}
width="9"
height="8"
viewBox="0 0 9 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M1.5 7L7.5 1" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
<svg
className={cn(
"absolute top-[5px] transition duration-300 ease-in-out",
themeStyles.textStyle,
variantStyles.arrowHeadTopRight
)}
width="9"
height="8"
viewBox="0 0 9 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M1 1H7.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
<path d="M7.5 7L7.5 1" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
<path d="M1 7.5L7.5 1" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</>
)}
{direction === "right" && (
<>
<span
className={cn(
"absolute rounded-full opacity-0 transition duration-300 ease-in-out group-hover:opacity-100",
variantStyles.arrowLineRight,
themeStyles.arrowLine
)}
/>
<ChevronRightIcon
className={cn(
"absolute -translate-x-0.5 transition duration-300 ease-in-out",
variantStyles.arrowHeadRight,
variantStyles.size,
themeStyles.textStyle
)}
/>
</>
)}
{direction === "left" && (
<>
<span
className={cn(
"absolute rounded-full opacity-0 transition duration-300 ease-in-out group-hover:opacity-100",
variantStyles.arrowLineLeft,
themeStyles.arrowLine
)}
/>
<ChevronLeftIcon
className={cn(
"absolute translate-x-0.5 transition duration-300 ease-in-out",
variantStyles.arrowHeadLeft,
variantStyles.size,
themeStyles.textStyle
)}
/>
</>
)}
</span>
);
}
@@ -45,7 +45,10 @@ export function AppliedFilter({
</div>
{removable && (
<button
className={cn("group flex size-6 items-center justify-center", variantClassName.clear)}
className={cn(
"group flex size-6 items-center justify-center focus-custom",
variantClassName.clear
)}
onClick={onRemove}
>
<XMarkIcon className="size-3.5" />
@@ -6,6 +6,8 @@ const variants = {
"grid place-items-center rounded-full px-2 h-5 tracking-wider text-xxs bg-charcoal-750 text-text-bright uppercase whitespace-nowrap",
small:
"grid place-items-center rounded-full px-[0.4rem] h-4 tracking-wider text-xxs bg-background-dimmed text-text-dimmed uppercase whitespace-nowrap",
"extra-small":
"grid place-items-center border border-charcoal-650 rounded-sm px-1 h-4 border-tracking-wider text-xxs bg-background-bright text-blue-500 whitespace-nowrap",
outline:
"grid place-items-center rounded-sm px-1.5 h-5 tracking-wider text-xxs border border-dimmed text-text-dimmed uppercase whitespace-nowrap",
"outline-rounded":
+100 -41
View File
@@ -1,9 +1,10 @@
import { Link, LinkProps, NavLink, NavLinkProps } from "@remix-run/react";
import React, { forwardRef, useImperativeHandle, useRef } from "react";
import React, { forwardRef, ReactNode, useImperativeHandle, useRef } from "react";
import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
import { cn } from "~/utils/cn";
import { IconNamesOrString, NamedIcon } from "./NamedIcon";
import { ShortcutKey } from "./ShortcutKey";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./Tooltip";
const sizes = {
small: {
@@ -41,40 +42,52 @@ type Size = keyof typeof sizes;
const theme = {
primary: {
textColor:
"text-charcoal-900 group-hover:text-charcoal-900 transition group-disabled:text-charcoal-900",
"text-charcoal-900 group-hover/button:text-charcoal-900 transition group-disabled/button:text-charcoal-900",
button:
"bg-primary group-hover:bg-apple-200 group-disabled:opacity-50 group-disabled:bg-primary group-disabled:pointer-events-none",
"bg-primary group-hover/button:bg-apple-200 group-disabled/button:opacity-50 group-disabled/button:bg-primary group-disabled/button:pointer-events-none",
shortcut:
"border-black/40 text-charcoal-900 group-hover:border-black/60 group-hover:text-charcoal-900",
"border-black/40 text-charcoal-900 group-hover/button:border-black/60 group-hover/button:text-charcoal-900",
icon: "text-charcoal-900",
},
secondary: {
textColor: "text-secondary group-hover:text-secondary transition group-disabled:text-secondary",
textColor: "text-text-bright transition group-disabled/button:text-text-dimmed/80",
button:
"bg-transparent border border-secondary group-hover:border-secondary group-hover:bg-secondary/10 group-disabled:opacity-30 group-disabled:border-secondary group-disabled:bg-transparent group-disabled:pointer-events-none",
"bg-secondary group-hover/button:bg-charcoal-600 group-hover/button:border-charcoal-650 border border-charcoal-600 group-disabled/button:bg-secondary group-disabled/button:opacity-60 group-disabled/button:pointer-events-none",
shortcut:
"border-secondary/30 text-secondary group-hover:text-text-bright/80 group-hover:border-dimmed/60",
"border-text-dimmed/40 text-text-dimmed group-hover/button:text-text-bright group-hover/button:border-text-dimmed",
icon: "text-text-bright",
},
tertiary: {
textColor: "text-text-bright transition group-disabled:text-text-dimmed/80",
textColor: "text-text-bright transition group-disabled/button:text-text-dimmed/80",
button:
"bg-tertiary group-hover:bg-charcoal-600 group-disabled:bg-tertiary group-disabled:opacity-60 group-disabled:pointer-events-none",
"bg-tertiary group-hover/button:bg-charcoal-600 group-disabled/button:bg-tertiary group-disabled/button:opacity-60 group-disabled/button:pointer-events-none",
shortcut:
"border-text-dimmed/40 text-text-dimmed group-hover:text-text-bright group-hover:border-text-dimmed",
"border-text-dimmed/40 text-text-dimmed group-hover/button:text-text-bright group-hover/button:border-text-dimmed",
icon: "text-text-bright",
},
minimal: {
textColor:
"text-text-dimmed group-hover:text-text-bright transition group-disabled:text-text-dimmed/80",
textColor: "text-text-dimmed group-disabled/button:text-text-dimmed transition",
button:
"bg-transparent group-hover:bg-tertiary disabled:opacity-50 group-disabled:bg-transparent group-disabled:pointer-events-none",
"bg-transparent group-hover/button:bg-tertiary disabled:opacity-50 group-disabled/button:bg-transparent group-disabled/button:pointer-events-none",
shortcut:
"border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60",
"border-dimmed/40 text-text-dimmed group-hover/button:text-text-bright/80 group-hover/button:border-dimmed/60",
icon: "text-text-dimmed",
},
danger: {
textColor:
"text-text-bright group-hover:text-white transition group-disabled:text-text-bright/80",
"text-text-bright group-hover/button:text-white transition group-disabled/button:text-text-bright/80",
button:
"bg-error group-hover:bg-rose-500 disabled:opacity-50 group-disabled:bg-error group-disabled:pointer-events-none",
shortcut: "border-text-bright text-text-bright group-hover:border-bright/60",
"bg-error group-hover/button:bg-rose-500 disabled:opacity-50 group-disabled/button:bg-error group-disabled/button:pointer-events-none",
shortcut: "border-text-bright text-text-bright group-hover/button:border-bright/60",
icon: "text-text-bright",
},
docs: {
textColor: "text-blue-200/70 transition group-disabled/button:text-text-dimmed/80",
button:
"bg-charcoal-700 border border-charcoal-600/50 shadow group-hover/button:bg-charcoal-650 group-disabled/button:bg-tertiary group-disabled/button:opacity-60 group-disabled/button:pointer-events-none",
shortcut:
"border-text-dimmed/40 text-text-dimmed group-hover/button:text-text-bright group-hover/button:border-text-dimmed",
icon: "text-blue-500",
},
};
@@ -84,7 +97,7 @@ function createVariant(sizeName: Size, themeName: Theme) {
return {
textColor: theme[themeName].textColor,
button: cn(sizes[sizeName].button, theme[themeName].button),
icon: sizes[sizeName].icon,
icon: cn(sizes[sizeName].icon, theme[themeName].icon),
iconSpacing: sizes[sizeName].iconSpacing,
shortcutVariant: sizes[sizeName].shortcutVariant,
shortcut: cn(sizes[sizeName].shortcut, theme[themeName].shortcut),
@@ -112,10 +125,14 @@ const variant = {
"danger/medium": createVariant("medium", "danger"),
"danger/large": createVariant("large", "danger"),
"danger/extra-large": createVariant("extra-large", "danger"),
"docs/small": createVariant("small", "docs"),
"docs/medium": createVariant("medium", "docs"),
"docs/large": createVariant("large", "docs"),
"docs/extra-large": createVariant("extra-large", "docs"),
"menu-item": {
textColor: "text-text-bright px-1",
button:
"h-9 px-[0.475rem] text-sm rounded-sm bg-transparent group-hover:bg-charcoal-800 transition",
"h-9 px-[0.475rem] text-sm rounded-sm bg-transparent group-hover/button:bg-charcoal-750",
icon: "h-5",
iconSpacing: "gap-x-0.5",
shortcutVariant: undefined,
@@ -124,7 +141,7 @@ const variant = {
"small-menu-item": {
textColor: "text-text-bright",
button:
"h-[1.8rem] px-[0.4rem] text-2sm rounded-sm text-text-dimmed bg-transparent group-hover:bg-charcoal-850 transition",
"h-[1.8rem] px-[0.4rem] text-2sm rounded-sm text-text-dimmed bg-transparent group-hover/button:bg-charcoal-750",
icon: "h-4",
iconSpacing: "gap-x-1.5",
shortcutVariant: undefined,
@@ -133,7 +150,7 @@ const variant = {
"small-menu-sub-item": {
textColor: "text-text-dimmed",
button:
"h-[1.8rem] px-[0.5rem] ml-5 text-2sm rounded-sm text-text-dimmed bg-transparent group-hover:bg-charcoal-850 transition",
"h-[1.8rem] px-[0.5rem] ml-5 text-2sm rounded-sm text-text-dimmed bg-transparent group-hover/button:bg-charcoal-750 focus-custom",
icon: undefined,
iconSpacing: undefined,
shortcutVariant: undefined,
@@ -142,7 +159,7 @@ const variant = {
};
const allVariants = {
$all: "font-normal text-center font-sans justify-center items-center shrink-0 transition duration-150 rounded-[3px] select-none group-focus:outline-none group-disabled:opacity-75 group-disabled:pointer-events-none",
$all: "font-normal text-center font-sans justify-center items-center shrink-0 transition duration-150 rounded-[3px] select-none group-focus/button:outline-none group-disabled/button:opacity-75 group-disabled/button:pointer-events-none focus-custom",
variant: variant,
};
@@ -157,6 +174,9 @@ export type ButtonContentPropsType = {
className?: string;
shortcut?: ShortcutDefinition;
variant: keyof typeof variant;
shortcutPosition?: "before-trailing-icon" | "after-trailing-icon";
tooltip?: ReactNode;
iconSpacing?: string;
};
export function ButtonContent(props: ButtonContentPropsType) {
@@ -170,36 +190,52 @@ export function ButtonContent(props: ButtonContentPropsType) {
fullWidth,
textAlignLeft,
className,
tooltip,
iconSpacing,
} = props;
const variation = allVariants.variant[props.variant];
// Based on the size prop, we'll use the corresponding variant classnames
const btnClassName = cn(allVariants.$all, variation.button);
const iconClassName = variation.icon;
const iconSpacingClassName = variation.iconSpacing;
const shortcutClassName = variation.shortcut;
const textColorClassName = variation.textColor;
return (
const renderShortcutKey = () =>
shortcut && (
<ShortcutKey
className={cn(shortcutClassName)}
shortcut={shortcut}
variant={variation.shortcutVariant ?? "medium"}
/>
);
const buttonContent = (
<div className={cn("flex", fullWidth ? "" : "w-fit text-xxs", btnClassName, className)}>
<div
className={cn(
textAlignLeft ? "text-left" : "justify-center",
"flex w-full items-center",
iconSpacingClassName
iconSpacingClassName,
iconSpacing
)}
>
{LeadingIcon &&
(typeof LeadingIcon === "string" ? (
<NamedIcon
name={LeadingIcon}
className={cn(iconClassName, leadingIconClassName, "shrink-0 justify-start")}
className={cn(
iconClassName,
leadingIconClassName,
"shrink-0 justify-start",
variation.icon
)}
/>
) : (
<LeadingIcon
className={cn(
iconClassName,
textColorClassName,
variation.icon,
leadingIconClassName,
"shrink-0 justify-start"
)}
@@ -215,32 +251,55 @@ export function ButtonContent(props: ButtonContentPropsType) {
<>{text}</>
))}
{shortcut &&
!tooltip &&
props.shortcutPosition === "before-trailing-icon" &&
renderShortcutKey()}
{TrailingIcon &&
(typeof TrailingIcon === "string" ? (
<NamedIcon
name={TrailingIcon}
className={cn(iconClassName, trailingIconClassName, "shrink-0 justify-end")}
className={cn(
iconClassName,
trailingIconClassName,
"shrink-0 justify-end",
variation.icon
)}
/>
) : (
<TrailingIcon
className={cn(
iconClassName,
textColorClassName,
variation.icon,
trailingIconClassName,
"shrink-0 justify-end"
)}
/>
))}
{shortcut && (
<ShortcutKey
className={cn(shortcutClassName)}
shortcut={shortcut}
variant={variation.shortcutVariant ?? "medium"}
/>
)}
{shortcut &&
!tooltip &&
(!props.shortcutPosition || props.shortcutPosition === "after-trailing-icon") &&
renderShortcutKey()}
</div>
</div>
);
if (tooltip) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>{buttonContent}</TooltipTrigger>
<TooltipContent className="text-dimmed flex items-center gap-3 py-1.5 pl-2.5 pr-3 text-xs">
{tooltip} {shortcut && renderShortcutKey()}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
return buttonContent;
}
type ButtonPropsType = Pick<
@@ -268,7 +327,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonPropsType>(
return (
<button
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
className={cn("group/button outline-none focus-custom", props.fullWidth ? "w-full" : "")}
type={type}
disabled={disabled}
onClick={onClick}
@@ -314,7 +373,7 @@ export const LinkButton = ({
return (
<div
className={cn(
"group pointer-events-none cursor-default opacity-40 outline-none",
"group/button pointer-events-none cursor-default opacity-40 outline-none",
props.fullWidth ? "w-full" : ""
)}
>
@@ -328,7 +387,7 @@ export const LinkButton = ({
<ExtLink
href={to.toString()}
ref={innerRef}
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
className={cn("group/button focus-custom", props.fullWidth ? "w-full" : "")}
onClick={onClick}
onMouseDown={onMouseDown}
onMouseEnter={onMouseEnter}
@@ -343,7 +402,7 @@ export const LinkButton = ({
<Link
to={to}
ref={innerRef}
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
className={cn("group/button focus-custom", props.fullWidth ? "w-full" : "")}
onClick={onClick}
onMouseDown={onMouseDown}
onMouseEnter={onMouseEnter}
@@ -364,7 +423,7 @@ export const NavLinkButton = ({ to, className, target, ...props }: NavLinkPropsT
return (
<NavLink
to={to}
className={cn("group outline-none", props.fullWidth ? "w-full" : "")}
className={cn("group/button outline-none", props.fullWidth ? "w-full" : "")}
target={target}
>
{({ isActive, isPending }) => (
@@ -61,6 +61,7 @@ export type CheckboxProps = Omit<
description?: string;
badges?: string[];
className?: string;
labelClassName?: string;
onChange?: (isChecked: boolean) => void;
};
@@ -78,6 +79,7 @@ export const CheckboxWithLabel = React.forwardRef<HTMLInputElement, CheckboxProp
badges,
disabled,
className,
labelClassName: externalLabelClassName,
...props
},
ref
@@ -148,7 +150,8 @@ export const CheckboxWithLabel = React.forwardRef<HTMLInputElement, CheckboxProp
htmlFor={id}
className={cn(
props.readOnly || disabled ? "cursor-default" : "cursor-pointer",
labelClassName
labelClassName,
externalLabelClassName
)}
onClick={(e) => e.preventDefault()}
>
@@ -5,7 +5,11 @@ import * as TabsPrimitive from "@radix-ui/react-tabs";
import { cn } from "~/utils/cn";
import { motion } from "framer-motion";
const ClientTabs = TabsPrimitive.Root;
const ClientTabs = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>
>((props, ref) => <TabsPrimitive.Root ref={ref} {...props} />);
ClientTabs.displayName = TabsPrimitive.Root.displayName;
const ClientTabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
@@ -1,4 +1,4 @@
import { BellAlertIcon } from "@heroicons/react/20/solid";
import { BellAlertIcon, XMarkIcon } from "@heroicons/react/20/solid";
import { CalendarDateTime, createCalendar } from "@internationalized/date";
import { useDateField, useDateSegment } from "@react-aria/datepicker";
import type { DateFieldState, DateSegment } from "@react-stately/datepicker";
@@ -12,7 +12,7 @@ const variants = {
small: {
fieldStyles: "h-5 text-sm rounded-sm px-0.5",
nowButtonVariant: "tertiary/small" as const,
clearButtonVariant: "minimal/small" as const,
clearButtonVariant: "tertiary/small" as const,
},
medium: {
fieldStyles: "h-7 text-base rounded px-1",
@@ -35,9 +35,12 @@ type DateFieldProps = {
showNowButton?: boolean;
showClearButton?: boolean;
onValueChange?: (value: Date | undefined) => void;
utc?: boolean;
variant?: Variant;
};
const deviceTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
export function DateField({
label,
defaultValue,
@@ -50,10 +53,11 @@ export function DateField({
showGuide = false,
showNowButton = false,
showClearButton = false,
utc = false,
variant = "small",
}: DateFieldProps) {
const [value, setValue] = useState<undefined | CalendarDateTime>(
utcDateToCalendarDate(defaultValue)
utc ? utcDateToCalendarDate(defaultValue) : dateToCalendarDate(defaultValue)
);
const state = useDateFieldState({
@@ -61,11 +65,11 @@ export function DateField({
onChange: (value) => {
if (value) {
setValue(value);
onValueChange?.(value.toDate("utc"));
onValueChange?.(value.toDate(utc ? "utc" : deviceTimezone));
}
},
minValue: utcDateToCalendarDate(minValue),
maxValue: utcDateToCalendarDate(maxValue),
minValue: utc ? utcDateToCalendarDate(minValue) : dateToCalendarDate(minValue),
maxValue: utc ? utcDateToCalendarDate(maxValue) : dateToCalendarDate(maxValue),
shouldForceLeadingZeros: true,
granularity,
locale: "en-US",
@@ -78,7 +82,9 @@ export function DateField({
useEffect(() => {
if (state.value === undefined && defaultValue === undefined) return;
const calendarDate = utcDateToCalendarDate(defaultValue);
const calendarDate = utc
? utcDateToCalendarDate(defaultValue)
: dateToCalendarDate(defaultValue);
//unchanged
if (state.value?.toDate("utc").getTime() === defaultValue?.getTime()) {
return;
@@ -134,23 +140,19 @@ export function DateField({
<Button
type="button"
variant={variants[variant].nowButtonVariant}
LeadingIcon={BellAlertIcon}
leadingIconClassName="text-text-dimmed group-hover:text-text-bright"
onClick={() => {
const now = new Date();
setValue(utcDateToCalendarDate(new Date()));
setValue(utc ? utcDateToCalendarDate(now) : dateToCalendarDate(now));
onValueChange?.(now);
}}
>
<span className="text-text-dimmed transition group-hover:text-text-bright">Now</span>
Now
</Button>
)}
{showClearButton && (
<Button
type="button"
variant={variants[variant].clearButtonVariant}
LeadingIcon={"close"}
leadingIconClassName="-mr-2"
onClick={() => {
setValue(undefined);
onValueChange?.(undefined);
@@ -181,7 +183,7 @@ function utcDateToCalendarDate(date?: Date) {
return date
? new CalendarDateTime(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCMonth() + 1,
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
@@ -190,6 +192,19 @@ function utcDateToCalendarDate(date?: Date) {
: undefined;
}
function dateToCalendarDate(date?: Date) {
return date
? new CalendarDateTime(
date.getFullYear(),
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds()
)
: undefined;
}
type DateSegmentProps = {
segment: DateSegment;
state: DateFieldState;
@@ -34,6 +34,7 @@ type DetailCellProps = {
description?: string | React.ReactNode;
className?: string;
variant?: keyof typeof variations;
boxClassName?: string;
};
export function DetailCell({
@@ -45,6 +46,7 @@ export function DetailCell({
description,
className,
variant = "small",
boxClassName,
}: DetailCellProps) {
const variation = variations[variant];
@@ -53,6 +55,7 @@ export function DetailCell({
<IconInBox
icon={leadingIcon}
className={cn("flex-none transition group-hover:border-charcoal-750", leadingIconClassName)}
boxClassName={boxClassName}
/>
<div className="flex flex-1 flex-col">
<Paragraph
@@ -50,7 +50,7 @@ const DialogContent = React.forwardRef<
>
<hr className="absolute left-0 top-11 w-full" />
{children}
<DialogPrimitive.Close className="ring-offset-background data-[state=open]:bg-accent data-[state=open]:text-muted-foreground focus-visible:ring-ring absolute right-3 top-3 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none">
<DialogPrimitive.Close className="data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-3 top-2 rounded-sm py-1 pr-1 opacity-70 transition-opacity focus-custom hover:opacity-100 disabled:pointer-events-none">
<div className="flex gap-x-2">
<ShortcutKey
shortcut={{
@@ -82,7 +82,7 @@ DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
className={cn("flex justify-between border-t border-grid-bright pt-4", className)}
{...props}
/>
);
@@ -106,7 +106,7 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-muted-foreground pt-4 text-sm", className)}
className={cn("pt-2 text-base text-text-dimmed", className)}
{...props}
/>
));
@@ -10,7 +10,12 @@ export function FormButtons({
className?: string;
}) {
return (
<div className={cn("flex w-full items-center justify-between", className)}>
<div
className={cn(
"flex w-full items-center justify-between border-t border-grid-bright pt-4",
className
)}
>
{cancelButton ? cancelButton : <div />} {confirmButton}
</div>
);
@@ -1,14 +1,17 @@
import { LinkButton } from "./Buttons";
import { Header3 } from "./Headers";
import { Paragraph } from "./Paragraph";
import { cn } from "~/utils/cn";
import { LinkButton } from "./Buttons";
import { Header2 } from "./Headers";
import { Paragraph } from "./Paragraph";
const variants = {
info: {
panelStyle: "border-grid-bright bg-background-bright",
panelStyle: "border-grid-bright bg-background-bright rounded-md border p-4 gap-3",
},
upgrade: {
panelStyle: "border-indigo-400/20 bg-indigo-800/10",
panelStyle: "border-indigo-400/20 bg-indigo-800/10 rounded-md border p-4 gap-3",
},
minimal: {
panelStyle: "max-w-full w-full py-3 px-3 gap-2",
},
};
@@ -43,7 +46,7 @@ export function InfoPanel({
className={cn(
variantStyle.panelStyle,
title ? "flex-col" : "",
"flex h-fit items-start gap-3 rounded-md border p-4",
"flex h-fit items-start",
panelClassName
)}
>
@@ -57,7 +60,7 @@ export function InfoPanel({
)}
</div>
<div className="flex flex-col gap-1">
{title && <Header3 className="text-text-bright">{title}</Header3>}
{title && <Header2 className="text-text-bright">{title}</Header2>}
{typeof children === "string" ? (
<Paragraph variant={"small"} className="text-text-dimmed">
{children}
@@ -4,7 +4,7 @@ import { cn } from "~/utils/cn";
import { Icon, RenderIcon } from "./Icon";
const containerBase =
"has-[:focus-visible]:outline-none has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-0 has-[:focus]:border-ring has-[:focus]:outline-none has-[:focus]:ring-2 has-[:focus]:ring-ring has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 ring-offset-background transition cursor-text";
"has-[:focus-visible]:outline-none has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-text-link has-[:focus-visible]:ring-offset-0 has-[:focus]:border-ring has-[:focus]:outline-none has-[:focus]:ring-2 has-[:focus]:ring-ring has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 ring-offset-background transition cursor-text";
const inputBase =
"h-full w-full text-text-bright bg-transparent file:border-0 file:bg-transparent file:text-base file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed outline-none ring-0 border-none";
@@ -1,19 +0,0 @@
import { Link } from "@remix-run/react";
import { cn } from "~/utils/cn";
type Props = Parameters<typeof Link>[0] & {
disabled?: boolean;
disabledClassName?: string;
};
export function LinkDisabled({ disabled = false, disabledClassName, ...props }: Props) {
if (disabled) {
return (
<span {...props} className={cn(props.className, disabledClassName)}>
{props.children}
</span>
);
} else {
return <Link {...props}>{props.children}</Link>;
}
}
@@ -49,7 +49,7 @@ export function PageTitle({ title, backButton }: PageTitleProps) {
<div className="group -ml-1.5 flex items-center gap-0">
<Link
to={backButton.to}
className="rounded px-1.5 py-1 text-xs text-text-dimmed transition group-hover:bg-charcoal-700 group-hover:text-text-bright"
className="rounded px-1.5 py-1 text-xs text-text-dimmed transition focus-custom group-hover:bg-charcoal-700 group-hover:text-text-bright"
>
{backButton.text}
</Link>
@@ -2,8 +2,7 @@ import { ChevronRightIcon } from "@heroicons/react/24/outline";
import { ChevronLeftIcon } from "@heroicons/react/24/solid";
import { Link, useLocation } from "@remix-run/react";
import { cn } from "~/utils/cn";
import { ButtonContent } from "./Buttons";
import { LinkDisabled } from "./LinkWithDisabled";
import { LinkButton } from "./Buttons";
export function PaginationControls({
currentPage,
@@ -20,17 +19,18 @@ export function PaginationControls({
}
return (
<nav className="flex items-center gap-1" aria-label="Pagination">
<LinkDisabled
<nav className="flex items-center gap-0.5" aria-label="Pagination">
<LinkButton
to={pageUrl(location, currentPage - 1)}
className={currentPage > 1 ? "group" : ""}
variant="minimal/small"
LeadingIcon={ChevronLeftIcon}
shortcut={{ key: "j" }}
tooltip="Previous"
disabled={currentPage === 1}
disabledClassName="opacity-30 cursor-default"
className={currentPage > 1 ? "group" : ""}
>
<ButtonContent variant="minimal/medium" LeadingIcon={ChevronLeftIcon}>
Previous
</ButtonContent>
</LinkDisabled>
Prev
</LinkButton>
{showPageNumbers
? calculatePageLinks(currentPage, totalPages).map((page, i) => (
@@ -38,16 +38,17 @@ export function PaginationControls({
))
: null}
<LinkDisabled
<LinkButton
to={pageUrl(location, currentPage + 1)}
className={currentPage !== totalPages ? "group" : ""}
variant="minimal/small"
TrailingIcon={ChevronRightIcon}
shortcut={{ key: "k" }}
tooltip="Next"
disabled={currentPage === totalPages}
disabledClassName="opacity-30 cursor-default"
className={currentPage !== totalPages ? "group" : ""}
>
<ButtonContent variant="minimal/medium" TrailingIcon={ChevronRightIcon}>
Next
</ButtonContent>
</LinkDisabled>
Next
</LinkButton>
</nav>
);
}
@@ -61,9 +62,9 @@ function pageUrl(location: ReturnType<typeof useLocation>, page: number): string
}
const baseClass =
"flex items-center justify-center border border-transparent h-8 w-8 text-xs font-medium transition text-text-dimmed rounded-sm";
"flex items-center justify-center border border-transparent min-w-6 h-6 px-1 text-xs font-medium transition text-text-dimmed rounded-sm focus-visible:focus-custom";
const unselectedClass = "hover:bg-tertiary hover:text-text-bright";
const selectedClass = "border-text-dimmed text-text-bright hover:bg-tertiary";
const selectedClass = "border-charcoal-600 bg-tertiary text-text-bright hover:bg-charcoal-600/50";
function PageLinkComponent({
page,
@@ -6,6 +6,8 @@ import * as React from "react";
import { cn } from "~/utils/cn";
import { type ButtonContentPropsType, LinkButton } from "./Buttons";
import { Paragraph, type ParagraphVariant } from "./Paragraph";
import { ShortcutKey } from "./ShortcutKey";
import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
@@ -91,7 +93,7 @@ function PopoverCustomTrigger({
<PopoverTrigger
{...props}
className={cn(
"group flex items-center justify-end gap-1 rounded text-text-dimmed transition hover:bg-charcoal-850 hover:text-text-bright",
"group flex items-center justify-end gap-1 rounded text-text-dimmed transition focus-custom hover:bg-charcoal-850 hover:text-text-bright",
className
)}
>
@@ -100,6 +102,45 @@ function PopoverCustomTrigger({
);
}
function PopoverSideMenuTrigger({
isOpen,
children,
className,
shortcut,
...props
}: { isOpen?: boolean; shortcut?: ShortcutDefinition } & React.ComponentPropsWithoutRef<
typeof PopoverTrigger
>) {
const ref = React.useRef<HTMLButtonElement>(null);
useShortcutKeys({
shortcut: shortcut,
action: (e) => {
e.preventDefault();
e.stopPropagation();
if (ref.current) {
ref.current.click();
}
},
});
return (
<PopoverTrigger
{...props}
ref={ref}
className={cn(
"flex h-[1.8rem] shrink-0 select-none items-center gap-x-1.5 rounded-sm bg-transparent px-[0.4rem] text-center font-sans text-2sm font-normal text-text-bright transition duration-150 focus-custom hover:bg-charcoal-750",
shortcut ? "justify-between" : "",
className
)}
>
{children}
{shortcut && (
<ShortcutKey className={cn("size-4 flex-none")} shortcut={shortcut} variant={"small"} />
)}
</PopoverTrigger>
);
}
function PopoverArrowTrigger({
isOpen,
children,
@@ -116,7 +157,7 @@ function PopoverArrowTrigger({
<PopoverTrigger
{...props}
className={cn(
"group flex h-6 items-center gap-1 rounded px-2 text-text-dimmed transition hover:bg-charcoal-700 hover:text-text-bright",
"group flex h-6 items-center gap-1 rounded px-2 text-text-dimmed transition focus-custom hover:bg-charcoal-700 hover:text-text-bright",
fullWidth && "w-full justify-between",
className
)}
@@ -149,11 +190,11 @@ function PopoverVerticalEllipseTrigger({
<PopoverTrigger
{...props}
className={cn(
"group flex items-center justify-end gap-1 rounded px-1.5 py-1.5 text-text-dimmed transition hover:bg-charcoal-750 hover:text-text-bright",
"group flex items-center justify-end gap-1 rounded-[3px] p-0.5 text-text-dimmed transition focus-custom hover:bg-tertiary hover:text-text-bright",
className
)}
>
<EllipsisVerticalIcon className={cn("h-5 w-5 transition group-hover:text-text-bright")} />
<EllipsisVerticalIcon className={cn("size-5 transition group-hover:text-text-bright")} />
</PopoverTrigger>
);
}
@@ -165,6 +206,7 @@ export {
PopoverCustomTrigger,
PopoverMenuItem,
PopoverSectionHeader,
PopoverSideMenuTrigger,
PopoverTrigger,
PopoverVerticalEllipseTrigger,
};
@@ -70,7 +70,7 @@ export function RadioButtonCircle({
return (
<div
className={cn(
"ring-offset-background focus-visible:ring-ring aspect-square h-4 w-4 shrink-0 overflow-hidden rounded-full border border-charcoal-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"ring-offset-background aspect-square h-4 w-4 shrink-0 overflow-hidden rounded-full border border-charcoal-600 focus-custom disabled:cursor-not-allowed disabled:opacity-50",
boxClassName
)}
>
@@ -81,7 +81,9 @@ export function RadioButtonCircle({
outerCircleClassName
)}
>
<Circle className={cn("h-1.5 w-1.5 fill-white text-white", innerCircleClassName)} />
<Circle
className={cn("size-1.5 fill-text-bright text-text-bright", innerCircleClassName)}
/>
</div>
)}
</div>
@@ -121,7 +123,7 @@ export const RadioGroupItem = React.forwardRef<
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"group flex cursor-pointer items-start gap-x-2 transition",
"group flex cursor-pointer items-start gap-x-2 transition focus-custom",
variation.button,
className
)}
@@ -129,7 +131,7 @@ export const RadioGroupItem = React.forwardRef<
>
<div
className={cn(
"ring-offset-background focus-visible:ring-ring aspect-square h-4 w-4 shrink-0 overflow-hidden rounded-full border border-charcoal-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"ring-offset-background focus-visible:ring-ring aspect-square h-4 w-4 shrink-0 overflow-hidden rounded-full border border-charcoal-600 focus-custom disabled:cursor-not-allowed disabled:opacity-50",
variation.inputPosition
)}
>
@@ -26,7 +26,7 @@ const ResizableHandle = ({
}) => (
<PanelResizer
className={cn(
"focus-visible:ring-ring group relative flex w-0.75 items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 hover:w-0.75 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary/50 focus-visible:ring-offset-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
"group relative flex w-0.75 items-center justify-center focus-custom after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 hover:w-0.75 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
size="3px"
@@ -65,10 +65,7 @@ export default function SegmentedControl({
value={option.value}
className={({ active, checked }) =>
cn(
"relative flex h-full grow cursor-pointer text-center font-normal focus:outline-none",
active
? "ring-offset-2 focus-visible:ring focus-visible:ring-secondary focus-visible:ring-opacity-60"
: "",
"relative flex h-full grow cursor-pointer text-center font-normal focus-custom",
checked
? variants[variant].active
: "text-text-dimmed transition hover:text-text-bright"
@@ -15,18 +15,18 @@ const sizes = {
button: "h-6 rounded text-xs px-2 ",
},
medium: {
button: "h-8 rounded text-xs px-3 text-sm",
button: "h-8 rounded px-3 text-sm",
},
};
const style = {
tertiary: {
button:
"bg-tertiary focus-within:ring-charcoal-500 border border-tertiary hover:text-text-bright hover:border-charcoal-600",
"bg-tertiary focus-custom border border-tertiary hover:text-text-bright hover:border-charcoal-600",
},
minimal: {
button:
"bg-transparent focus-within:ring-charcoal-500 hover:bg-tertiary disabled:bg-transparent disabled:pointer-events-none",
"bg-transparent focus-custom hover:bg-tertiary disabled:bg-transparent disabled:pointer-events-none",
},
};
@@ -322,7 +322,7 @@ export function SelectTrigger({
render={
<Ariakit.Select
className={cn(
"group flex items-center gap-1 outline-offset-0 focus-within:outline-none focus-within:ring-1 disabled:cursor-not-allowed disabled:opacity-50",
"group flex items-center gap-1 focus-custom disabled:cursor-not-allowed disabled:opacity-50",
variantClasses.button,
className
)}
@@ -426,7 +426,7 @@ export function SelectList(props: SelectListProps) {
<Component
{...props}
className={cn(
"overflow-y-auto overscroll-contain outline-none scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600",
"overflow-y-auto overscroll-contain scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600 focus-custom",
props.className
)}
/>
@@ -440,11 +440,11 @@ export interface SelectItemProps extends Ariakit.SelectItemProps {
}
const selectItemClasses =
"group cursor-pointer px-1 pt-1 text-xs text-text-dimmed outline-none last:pb-1";
"group cursor-pointer px-1 pt-1 text-2sm text-text-dimmed focus-custom last:pb-1";
export function SelectItem({
icon,
checkIcon = <Ariakit.SelectItemCheck className="size-8 flex-none text-white" />,
checkIcon = <Ariakit.SelectItemCheck className="size-8 flex-none text-text-bright" />,
shortcut,
...props
}: SelectItemProps) {
@@ -477,12 +477,16 @@ export function SelectItem({
)}
ref={ref}
>
<div className="flex h-7 w-full items-center gap-1 rounded-sm px-2 group-data-[active-item=true]:bg-tertiary">
<div className="flex h-8 w-full items-center gap-1 rounded-sm px-2 group-data-[active-item=true]:bg-tertiary">
{icon}
<div className="grow truncate">{props.children || props.value}</div>
{checkIcon}
{shortcut && (
<ShortcutKey className={cn("size-4 flex-none")} shortcut={shortcut} variant={"small"} />
<ShortcutKey
className={cn("size-4 flex-none transition duration-0 group-hover:border-charcoal-600")}
shortcut={shortcut}
variant={"small"}
/>
)}
</div>
</Ariakit.SelectItem>
@@ -613,7 +617,7 @@ export function SelectPopover({
"z-50 flex flex-col overflow-clip rounded border border-charcoal-700 bg-background-bright shadow-md outline-none animate-in fade-in-40",
"min-w-[max(180px,calc(var(--popover-anchor-width)+0.5rem))]",
"max-w-[min(480px,var(--popover-available-width))]",
"max-h-[min(480px,var(--popover-available-height))]",
"max-h-[min(600px,var(--popover-available-height))]",
"origin-[var(--popover-transform-origin)]",
className
)}
@@ -0,0 +1,126 @@
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "~/utils/cn";
import { Header2 } from "./Headers";
import { NamedIcon } from "./NamedIcon";
import { ShortcutKey } from "./ShortcutKey";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 overflow-y-auto bg-background-dimmed shadow-lg transition ease-in-out border-grid-dimmed data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-300",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
{children}
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, children, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn(
"sticky top-0 flex items-center justify-between border-b border-grid-bright bg-background-dimmed pb-1.5 pl-3 pr-1.5 pt-2",
className
)}
{...props}
>
{children}
<SheetPrimitive.Close className="flex items-center gap-1 rounded-sm p-1 pl-0 transition hover:bg-charcoal-750 focus-visible:focus-custom disabled:pointer-events-none">
<ShortcutKey shortcut={{ key: "esc" }} variant="small" />
<NamedIcon name="close" className="size-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Title>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("overflow-y-auto px-3 py-1", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetOverlay,
SheetPortal,
SheetTitle,
SheetTrigger,
};
@@ -1,25 +1,35 @@
import { Fragment } from "react";
import { Modifier, ShortcutDefinition } from "~/hooks/useShortcutKeys";
import { KeyboardDownIcon } from "~/assets/icons/KeyboardDownIcon";
import { KeyboardLeftIcon } from "~/assets/icons/KeyboardLeftIcon";
import { KeyboardRightIcon } from "~/assets/icons/KeyboardRightIcon";
import { KeyboardUpIcon } from "~/assets/icons/KeyboardUpIcon";
import { KeyboardWindowsIcon } from "~/assets/icons/KeyboardWindowsIcon";
import { Modifier, Shortcut } from "~/hooks/useShortcutKeys";
import { cn } from "~/utils/cn";
import { useOperatingSystem } from "./OperatingSystemProvider";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronUpIcon,
} from "@heroicons/react/20/solid";
const medium =
"text-[0.75rem] font-medium min-w-[17px] rounded-[2px] tabular-nums px-1 ml-1 -mr-0.5 flex items-center gap-x-1.5 border border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60 transition uppercase";
export const variants = {
small:
"text-[0.6rem] font-medium min-w-[17px] rounded-[2px] px-1 ml-1 -mr-0.5 grid place-content-center border border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60 transition uppercase",
medium:
"text-[0.75rem] font-medium min-w-[17px] rounded-[2px] px-1 ml-1 -mr-0.5 grid place-content-center border border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60 transition uppercase",
"text-[0.6rem] font-medium min-w-[17px] rounded-[2px] tabular-nums px-1 ml-1 -mr-0.5 flex items-center gap-x-1 border border-dimmed/40 text-text-dimmed group-hover:text-text-bright/80 group-hover:border-dimmed/60 transition uppercase",
medium,
"medium/bright": cn(medium, "bg-charcoal-750 text-text-bright border-charcoal-650"),
};
export type ShortcutKeyVariant = keyof typeof variants;
type ShortcutKey = Partial<Shortcut>;
type ShortcutKeyDefinition =
| {
windows: ShortcutKey;
mac: ShortcutKey;
}
| ShortcutKey;
type ShortcutKeyProps = {
shortcut: ShortcutDefinition;
shortcut: ShortcutKeyDefinition;
variant: ShortcutKeyVariant;
className?: string;
};
@@ -29,50 +39,62 @@ export function ShortcutKey({ shortcut, variant, className }: ShortcutKeyProps)
const isMac = platform === "mac";
let relevantShortcut = "mac" in shortcut ? (isMac ? shortcut.mac : shortcut.windows) : shortcut;
const modifiers = relevantShortcut.modifiers ?? [];
const character = keyString(relevantShortcut.key, isMac, variant);
const character = relevantShortcut.key ? keyString(relevantShortcut.key, isMac, variant) : null;
return (
<span className={cn(variants[variant], className)}>
{modifiers.map((k) => (
<Fragment key={k}>{modifierString(k, isMac)}</Fragment>
<span key={k}>
<span>{modifierString(k, isMac, variant)}</span>
</span>
))}
{character}
{character && <span>{character}</span>}
</span>
);
}
function keyString(key: String, isMac: boolean, size: "small" | "medium") {
function keyString(key: string, isMac: boolean, variant: "small" | "medium" | "medium/bright") {
key = key.toLowerCase();
const className = size === "small" ? "w-2.5 h-4" : "w-3 h-5";
const className = variant === "small" ? "w-2.5 h-4" : "w-3 h-5";
switch (key) {
case "enter":
return isMac ? "↵" : key;
return isMac ? "↵" : <span className="capitalize">Enter</span>;
case "esc":
return <span className="capitalize">Esc</span>;
case "del":
return <span className="capitalize">Del</span>;
case "arrowdown":
return <ChevronDownIcon className={className} />;
return <KeyboardDownIcon className={className} />;
case "arrowup":
return <ChevronUpIcon className={className} />;
return <KeyboardUpIcon className={className} />;
case "arrowleft":
return <ChevronLeftIcon className={className} />;
return <KeyboardLeftIcon className={className} />;
case "arrowright":
return <ChevronRightIcon className={className} />;
return <KeyboardRightIcon className={className} />;
default:
return key;
}
}
function modifierString(modifier: Modifier, isMac: boolean) {
function modifierString(
modifier: Modifier,
isMac: boolean,
variant: "small" | "medium" | "medium/bright"
): string | JSX.Element {
const className = variant === "small" ? "w-2.5 h-4" : "w-3.5 h-5";
switch (modifier) {
case "alt":
return isMac ? "⌥" : "Alt+";
return isMac ? "⌥" : <span className="capitalize">Alt</span>;
case "ctrl":
return isMac ? "⌃" : "Ctrl+";
return isMac ? "⌃" : <span className="capitalize">Ctrl</span>;
case "meta":
return isMac ? "⌘" : "⊞+";
return isMac ? "⌘" : <KeyboardWindowsIcon className={className} />;
case "shift":
return isMac ? "⇧" : "Shift+";
return "⇧";
case "mod":
return isMac ? "⌘" : "Ctrl+";
return isMac ? "⌘" : <span className="capitalize">Ctrl</span>;
}
}
@@ -26,8 +26,8 @@ export function Spinner({
foreground: "#3C4B62",
},
dark: {
background: "#15171A",
foreground: "#272A2E",
background: "rgba(18, 19, 23, 0.35)",
foreground: "#1A1B1F",
},
};
@@ -6,17 +6,17 @@ import { cn } from "~/utils/cn";
const variations = {
large: {
container: "flex items-center gap-x-2 rounded-md hover:bg-tertiary p-2 transition",
container: "flex items-center gap-x-2 rounded-md hover:bg-tertiary p-2 transition focus-custom",
root: "h-6 w-11",
thumb: "h-5 w-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
text: "text-sm text-charcoal-400 group-hover:text-charcoal-200 transition",
thumb: "size-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
text: "text-sm text-text-dimmed",
},
small: {
container:
"flex items-center gap-x-1.5 rounded hover:bg-tertiary pr-1 py-[0.1rem] pl-1.5 transition",
"flex items-center h-[1.5rem] gap-x-1.5 rounded hover:bg-tertiary disabled:hover:bg-transparent pr-1 py-[0.1rem] pl-1.5 transition focus-custom disabled:hover:text-charcoal-400 disabled:opacity-50 text-charcoal-400 hover:text-charcoal-200 disabled:hover:cursor-not-allowed hover:cursor-pointer",
root: "h-3 w-6",
thumb: "h-2.5 w-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
text: "text-xs text-charcoal-400 group-hover:text-charcoal-200 hover:cursor-pointer transition",
thumb: "size-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
text: "text-xs text-text-dimmed",
},
};
@@ -38,14 +38,14 @@ export const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitives.
) : null}
<div
className={cn(
"group-focus-visible:ring-ring group-focus-visible:ring-offset-background peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors group-focus-visible:ring-2 group-focus-visible:ring-offset-2 group-disabled:cursor-not-allowed group-disabled:opacity-50 group-data-[state=checked]:bg-secondary group-data-[state=unchecked]:bg-charcoal-700 focus-visible:outline-none",
"inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors group-disabled:cursor-not-allowed group-disabled:opacity-50 group-data-[state=checked]:bg-blue-500 group-data-[state=unchecked]:bg-charcoal-700 group-data-[state=unchecked]:group-hover:bg-charcoal-500/50",
root
)}
>
<SwitchPrimitives.Thumb
className={cn(
thumb,
"pointer-events-none block rounded-full bg-charcoal-200 shadow-lg ring-0 transition group-data-[state=checked]:bg-charcoal-700"
"pointer-events-none block rounded-full bg-charcoal-200 transition group-data-[state=checked]:bg-text-bright"
)}
/>
</div>
+122 -38
View File
@@ -17,12 +17,12 @@ export const Table = forwardRef<HTMLTableElement, TableProps>(
return (
<div
className={cn(
"overflow-x-auto whitespace-nowrap rounded-md border border-grid-bright scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600",
"overflow-x-auto whitespace-nowrap border-t border-grid-bright scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600",
containerClassName,
fullWidth && "w-full"
)}
>
<table ref={ref} className={cn("w-full divide-y", className)}>
<table ref={ref} className={cn("w-full", className)}>
{children}
</table>
</div>
@@ -40,7 +40,10 @@ export const TableHeader = forwardRef<HTMLTableSectionElement, TableHeaderProps>
return (
<thead
ref={ref}
className={cn("rounded-t-md", "relative divide-y divide-grid-dimmed", className)}
className={cn(
"sticky top-0 z-10 bg-background-dimmed after:absolute after:bottom-0 after:left-0 after:right-0 after:h-px after:bg-grid-bright",
className
)}
>
{children}
</thead>
@@ -56,7 +59,7 @@ type TableBodyProps = {
export const TableBody = forwardRef<HTMLTableSectionElement, TableBodyProps>(
({ className, children }, ref) => {
return (
<tbody ref={ref} className={cn("relative divide-y divide-grid-dimmed", className)}>
<tbody ref={ref} className={cn("relative overflow-y-auto", className)}>
{children}
</tbody>
);
@@ -67,12 +70,21 @@ type TableRowProps = {
className?: string;
children: ReactNode;
disabled?: boolean;
isSelected?: boolean;
};
export const TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(
({ className, disabled, children }, ref) => {
({ className, disabled, isSelected, children }, ref) => {
return (
<tr ref={ref} className={cn(disabled && "opacity-50", "group/table-row w-full", className)}>
<tr
ref={ref}
className={cn(
"group/table-row relative w-full after:absolute after:bottom-0 after:left-3 after:right-0 after:h-px after:bg-grid-dimmed",
disabled && "opacity-50",
isSelected && isSelectedStyle,
className
)}
>
{children}
</tr>
);
@@ -108,7 +120,7 @@ export const TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellP
ref={ref}
scope="col"
className={cn(
"px-3 py-2 align-middle text-xxs font-normal uppercase tracking-wider text-text-dimmed",
"px-3 py-2.5 pb-3 align-middle text-sm font-medium text-text-bright",
alignmentClassName,
className
)}
@@ -135,10 +147,23 @@ type TableCellProps = TableCellBasicProps & {
hasAction?: boolean;
isSticky?: boolean;
actionClassName?: string;
rowHoverStyle?: keyof typeof rowHoverStyles;
isSelected?: boolean;
};
const rowHoverStyles = {
default:
"group-hover/table-row:bg-charcoal-800 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-750 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-750 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
dimmed:
"group-hover/table-row:bg-charcoal-850 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-800 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-800 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
bright:
"group-hover/table-row:bg-charcoal-750 group-hover/table-row:before:absolute group-hover/table-row:before:bg-charcoal-700 group-hover/table-row:before:top-[-1px] group-hover/table-row:before:left-0 group-hover/table-row:before:h-px group-hover/table-row:before:w-3 group-hover/table-row:after:absolute group-hover/table-row:after:bg-charcoal-700 group-hover/table-row:after:bottom-0 group-hover/table-row:after:left-0 group-hover/table-row:after:h-px group-hover/table-row:after:w-3",
};
const stickyStyles =
"sticky right-0 z-10 w-[2.8rem] min-w-[2.8rem] bg-background-dimmed before:absolute before:pointer-events-none before:-left-8 before:top-0 before:h-full before:min-w-[2rem] before:bg-gradient-to-r before:from-transparent before:to-background before:content-[''] group-hover/table-row:before:to-charcoal-900";
"sticky right-0 bg-background-dimmed group-hover/table-row:bg-charcoal-750 w-[--sticky-width] [&:has(.group-hover\\/table-row\\:block)]:w-auto";
const isSelectedStyle = "bg-charcoal-750 group-hover:bg-charcoal-750";
export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
(
@@ -152,6 +177,8 @@ export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
onClick,
hasAction = false,
isSticky = false,
rowHoverStyle = "default",
isSelected,
},
ref
) => {
@@ -179,21 +206,21 @@ export const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
ref={ref}
className={cn(
"text-xs text-charcoal-400",
to || onClick || hasAction
? "cursor-pointer group-hover/table-row:bg-charcoal-900"
: "px-3 py-3 align-middle",
to || onClick || hasAction ? "cursor-pointer" : "px-3 py-3 align-middle",
!to && !onClick && alignmentClassName,
isSticky && stickyStyles,
isSelected && isSelectedStyle,
!isSelected && rowHoverStyles[rowHoverStyle],
className
)}
colSpan={colSpan}
>
{to ? (
<Link to={to} className={cn(flexClasses, actionClassName)}>
<Link to={to} className={cn("focus-custom", flexClasses, actionClassName)}>
{children}
</Link>
) : onClick ? (
<button onClick={onClick} className={cn(flexClasses, actionClassName)}>
<button onClick={onClick} className={cn("focus-custom", flexClasses, actionClassName)}>
{children}
</button>
) : (
@@ -224,7 +251,7 @@ export const TableCellChevron = forwardRef<
alignment="right"
>
{children}
<ChevronRightIcon className="h-4 w-4 text-text-dimmed transition group-hover:text-text-bright" />
<ChevronRightIcon className="size-4 text-text-dimmed transition group-hover:text-text-bright" />
</TableCell>
);
});
@@ -233,33 +260,90 @@ export const TableCellMenu = forwardRef<
HTMLTableCellElement,
{
className?: string;
children?: ReactNode;
isSticky?: boolean;
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
visibleButtons?: ReactNode;
hiddenButtons?: ReactNode;
popoverContent?: ReactNode;
children?: ReactNode;
isSelected?: boolean;
}
>(({ className, children, isSticky, onClick }, ref) => {
const [isOpen, setIsOpen] = useState(false);
return (
<TableCell
className={className}
isSticky={isSticky}
onClick={onClick}
ref={ref}
alignment="right"
hasAction={true}
>
<Popover onOpenChange={(open) => setIsOpen(open)}>
<PopoverVerticalEllipseTrigger isOpen={isOpen} />
<PopoverContent
className="w-fit max-w-[10rem] overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
align="end"
>
<div className="flex flex-col gap-1 p-1">{children}</div>
</PopoverContent>
</Popover>
</TableCell>
);
});
>(
(
{
className,
isSticky,
onClick,
visibleButtons,
hiddenButtons,
popoverContent,
children,
isSelected,
},
ref
) => {
const [isOpen, setIsOpen] = useState(false);
return (
<TableCell
className={className}
isSticky={isSticky}
onClick={onClick}
ref={ref}
alignment="right"
hasAction={true}
isSelected={isSelected}
>
<div className="relative h-full p-1">
<div
className={cn(
"absolute right-0 top-1/2 mr-1 flex -translate-y-1/2 items-center justify-end gap-0.5 rounded-[0.25rem] bg-background-dimmed p-0.5 group-hover/table-row:bg-background-bright group-hover/table-row:ring-1 group-hover/table-row:ring-grid-bright",
isSelected && isSelectedStyle,
isSelected &&
"group-hover/table-row:bg-charcoal-750 group-hover/table-row:ring-charcoal-600/50"
)}
>
{/* Hidden buttons that show on hover */}
{hiddenButtons && (
<div className="hidden pr-0.5 group-hover/table-row:block group-hover/table-row:border-r group-hover/table-row:border-grid-dimmed">
{hiddenButtons}
</div>
)}
{/* Always visible buttons */}
{visibleButtons}
{/* Always visible popover with ellipsis trigger */}
{popoverContent && (
<Popover onOpenChange={(open) => setIsOpen(open)}>
<PopoverVerticalEllipseTrigger
isOpen={isOpen}
className="duration-0 group-hover/table-row:text-text-bright"
/>
<PopoverContent
className="min-w-[10rem] max-w-[20rem] overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
align="end"
>
<div className="flex flex-col gap-1 p-1">{popoverContent}</div>
</PopoverContent>
</Popover>
)}
{/* Optionally pass in children to render in a popover */}
{!visibleButtons && !hiddenButtons && !popoverContent && (
<Popover onOpenChange={(open) => setIsOpen(open)}>
<PopoverVerticalEllipseTrigger isOpen={isOpen} />
<PopoverContent
className="w-fit max-w-[10rem] overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600"
align="end"
>
<div className="flex flex-col gap-1 p-1">{children}</div>
</PopoverContent>
</Popover>
)}
</div>
</div>
</TableCell>
);
}
);
type TableBlankRowProps = {
className?: string;
@@ -46,7 +46,7 @@ export function TabLink({
layoutId: string;
}) {
return (
<NavLink to={to} className="group flex flex-col items-center pt-1" end>
<NavLink to={to} className="group flex flex-col items-center pt-1 focus-custom" end>
{({ isActive, isPending }) => {
return (
<>
@@ -96,7 +96,8 @@ export function TabButton({
return (
<button
className={cn("group flex flex-col items-center pt-1", props.className)}
className={cn("group flex flex-col items-center pt-1 focus-custom", props.className)}
type="button"
ref={ref}
{...props}
>
@@ -8,7 +8,7 @@ export function TextArea({ className, rows, ...props }: TextAreaProps) {
{...props}
rows={rows ?? 6}
className={cn(
"ring-offset-background placeholder:text-muted-foreground focus:border-ring focus:ring-ring focus-visible:ring-ring w-full rounded-md border border-tertiary bg-tertiary px-3 text-sm text-text-bright transition file:border-0 file:bg-transparent file:text-base file:font-medium hover:border-charcoal-600 focus:outline-none focus:ring-2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50",
"placeholder:text-muted-foreground w-full rounded border border-charcoal-800 bg-charcoal-750 px-3 text-sm text-text-bright transition focus-custom focus-custom file:border-0 file:bg-transparent file:text-base file:font-medium hover:border-charcoal-600 hover:bg-charcoal-650 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
/>
@@ -6,6 +6,7 @@ import { useTypedLoaderData } from "remix-typedjson";
import { loader } from "~/root";
import { useEffect } from "react";
import { Paragraph } from "./Paragraph";
import { cn } from "~/utils/cn";
const defaultToastDuration = 5000;
const permanentToastDuration = 60 * 60 * 24 * 1000;
@@ -39,23 +40,27 @@ export function ToastUI({
}) {
return (
<div
className={`self-end rounded-md border border-grid-bright bg-background-dimmed`}
className={cn(
"self-end rounded-md border border-grid-bright bg-background-dimmed",
variant === "success" && "border-success",
variant === "error" && "border-error"
)}
style={{
width: toastWidth,
}}
>
<div className="flex w-full items-start gap-2 rounded-lg p-3">
{variant === "success" ? (
<CheckCircleIcon className="mt-1 h-6 min-h-[1.5rem] w-6 min-w-[1.5rem] text-green-600" />
<CheckCircleIcon className="mt-1 size-6 min-w-6 text-success" />
) : (
<ExclamationCircleIcon className="mt-1 h-6 w-6 min-w-[1.5rem] text-rose-600" />
<ExclamationCircleIcon className="mt-1 size-6 min-w-6 text-error" />
)}
<Paragraph className="py-1 text-text-dimmed">{message}</Paragraph>
<Paragraph className="py-1 text-text-bright">{message}</Paragraph>
<button
className="hover:bg-midnight-800 ms-auto rounded p-2 text-text-dimmed transition hover:text-text-bright"
onClick={() => toast.dismiss(t)}
>
<XMarkIcon className="h-4 w-4" />
<XMarkIcon className="size-4" />
</button>
</div>
</div>
@@ -41,7 +41,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1",
"z-50 overflow-hidden animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 focus-visible:outline-none",
variantClasses[variant],
className
)}
@@ -72,7 +72,9 @@ function SimpleTooltip({
return (
<TooltipProvider disableHoverableContent={disableHoverableContent}>
<Tooltip>
<TooltipTrigger className={cn("h-fit", buttonClassName)}>{button}</TooltipTrigger>
<TooltipTrigger tabIndex={-1} className={cn("h-fit", buttonClassName)}>
{button}
</TooltipTrigger>
<TooltipContent
side={side}
hidden={hidden}

Some files were not shown because too many files have changed in this diff Show More