Compare commits
388 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f275b47755 | |||
| cfb7481d7e | |||
| 57fcce90d9 | |||
| 2c0ea0c108 | |||
| e81317b72c | |||
| 946e429906 | |||
| 2e5a401ff7 | |||
| b8b84d8d16 | |||
| 039777bf63 | |||
| 3547ec13c3 | |||
| 3763577451 | |||
| c6618049f2 | |||
| 28d6aa9885 | |||
| 568786e4f6 | |||
| 38614ee526 | |||
| 15ad6bb5f8 | |||
| 15f431ada6 | |||
| 5163acc6ef | |||
| f9297d783a | |||
| c34a02c06f | |||
| 61ed1fb202 | |||
| 87638ba6c5 | |||
| 26b4100bb0 | |||
| 1157c2adf6 | |||
| 8613d3288b | |||
| ab008fbdff | |||
| 0b30197280 | |||
| 89a121f21e | |||
| 045a8c56af | |||
| d83c11db8c | |||
| 7efe14b835 | |||
| 37116aecf9 | |||
| 9a606e8f2a | |||
| b1e65ed500 | |||
| 26f3dbff06 | |||
| 5ee0b188bd | |||
| 4692cd6a55 | |||
| 7ad8c01853 | |||
| bc27b45fd7 | |||
| 94cc28d377 | |||
| 19e80cef3b | |||
| 5397cd3194 | |||
| f01af9c0ec | |||
| a288010d02 | |||
| b9a7a1c32b | |||
| 65b9a0dce5 | |||
| 7464006e19 | |||
| 590d56b7e7 | |||
| c75cb1e87e | |||
| 597b2f4a6f | |||
| 2e84c6bbb2 | |||
| 06c0cd5297 | |||
| 79eab3d62f | |||
| 6527723a0e | |||
| 3d6652f132 | |||
| da5d9779d4 | |||
| 865399e753 | |||
| 960ea6c8dd | |||
| 39ab48f0cb | |||
| 7341b4cf61 | |||
| 28c5acc6af | |||
| 4366eefc66 | |||
| cb95e761c1 | |||
| 7136748463 | |||
| b0cacfd75c | |||
| 81f03dac79 | |||
| e37d1eadcd | |||
| 23fb310374 | |||
| 797a1732d2 | |||
| c405a417e9 | |||
| 808deb1d77 | |||
| 6ac1473ec3 | |||
| 9c183abf4b | |||
| 33c33faae9 | |||
| 4cccbc2039 | |||
| cc061dedf8 | |||
| 402ce2210f | |||
| 329c5c4070 | |||
| 878aeb7a8c | |||
| 3ee396d788 | |||
| 090037602c | |||
| bee77051e7 | |||
| be6741a4a8 | |||
| 3e9b440322 | |||
| dfea5bc77c | |||
| 1eef30e298 | |||
| e5b9a9de3f | |||
| dfedd3a6e8 | |||
| a19845b4ca | |||
| 094f6f5a7a | |||
| fa60edce2b | |||
| ba44652457 | |||
| 931be39912 | |||
| 5048a27acb | |||
| 71fc615b31 | |||
| 20ed4e22ef | |||
| fc2d337a39 | |||
| 31d96f3862 | |||
| 7b43853ec6 | |||
| 40fa913272 | |||
| cdd5482aad | |||
| 4a3fa20ee7 | |||
| d49ed4cd47 | |||
| db3cf77f5b | |||
| c4a08961d6 | |||
| 5ba1643d46 | |||
| d189f425e8 | |||
| 0fe6fb83ac | |||
| f15ae41f48 | |||
| 46a07fc72e | |||
| 83af317739 | |||
| f4db1b2735 | |||
| 6d4922f419 | |||
| 6af098ee8a | |||
| 1dcb2ebcac | |||
| f65cb463cc | |||
| 2b4ce97f8a | |||
| 25abf319ab | |||
| 77807ab42a | |||
| f21990b14f | |||
| 1873d10e95 | |||
| 32ff3f3136 | |||
| 354b0aefb0 | |||
| aaa70a9aab | |||
| 3b90739087 | |||
| acaae993a5 | |||
| a74f0322e2 | |||
| 1a0286f6b0 | |||
| 64182483e2 | |||
| 87a25fba62 | |||
| 12803536fa | |||
| f160b34b34 | |||
| cca7da9da2 | |||
| 01cf5f3bdc | |||
| 33a928a9ea | |||
| c83443a41a | |||
| 374007bffd | |||
| 092382f319 | |||
| 79a0532e1d | |||
| 56c7c8b1ee | |||
| 722fe7b71e | |||
| 759793b2e3 | |||
| 99c6cd0371 | |||
| 9fbc5ab8de | |||
| 75ac2c9961 | |||
| 87330dd863 | |||
| 38fe9302cf | |||
| 33a455c593 | |||
| 37db0ac58d | |||
| 2cbf50b1cc | |||
| e26923eb19 | |||
| 3e63bcfb11 | |||
| 1e1c18c4a1 | |||
| 953e7fc918 | |||
| 8e147dbe0c | |||
| 86dbd5d1dc | |||
| e85ecfacba | |||
| f210532870 | |||
| 6c9ca686cb | |||
| 35b556d4a3 | |||
| c83339404a | |||
| 4172def1a3 | |||
| c99481ea8d | |||
| a11ddf6564 | |||
| 917a70fbe9 | |||
| 486d6818ba | |||
| 807b9d4c45 | |||
| 0013e78b1a | |||
| 9dd46c83fd | |||
| 1eb6bb8aa9 | |||
| 6c86946614 | |||
| 612b016a15 | |||
| be8beacaec | |||
| 4d316c5524 | |||
| 7fee5d6a87 | |||
| 0dd1aa5a5b | |||
| ed65ba4a73 | |||
| d39020370c | |||
| c18ba11819 | |||
| 5fbd7226eb | |||
| c9e27fd586 | |||
| 51b80eb09b | |||
| f409e9f329 | |||
| 304e6aaad5 | |||
| 3c5d02043e | |||
| 63980f63d4 | |||
| facd2b2131 | |||
| 25452588cc | |||
| 195d8c42fc | |||
| fe04b9d32d | |||
| d03b3aeb5f | |||
| 2ee33e70f7 | |||
| e9209629f7 | |||
| fa1e6bf5e6 | |||
| 93c3b10bf7 | |||
| 56cb2e3b07 | |||
| eabfb2457a | |||
| 317ab442ee | |||
| 2b24b36da6 | |||
| 161d59d01d | |||
| 821b75ed26 | |||
| 1f901e68d3 | |||
| 46d94a6a8f | |||
| 44c2146505 | |||
| ec2f1f5931 | |||
| e86c59f4ec | |||
| 6df6813a17 | |||
| f73679e2a6 | |||
| 68b866921a | |||
| 35364d615a | |||
| f64dd2a99c | |||
| a309a75a4d | |||
| c2e2f7cad9 | |||
| f69b92b153 | |||
| f8760fdd6b | |||
| caa4daabe2 | |||
| 67f685af26 | |||
| b2a8b5653f | |||
| 9232f019e1 | |||
| ac371664af | |||
| e4cca81124 | |||
| d76d2b86d2 | |||
| fcd2d6eea2 | |||
| 067064d19c | |||
| 52cdfb98a4 | |||
| 41261afcc4 | |||
| 77f71fdeb7 | |||
| ce0032e7e5 | |||
| c97ca350ad | |||
| 90abcb2cf7 | |||
| 8626172faa | |||
| 44ef97c656 | |||
| 7661fe5309 | |||
| beb02c871d | |||
| 8a47320272 | |||
| 114c8990a3 | |||
| 7e2d48ac6a | |||
| dbb6667889 | |||
| 29a02131d2 | |||
| 5d887f1cfb | |||
| 18f0e73ed4 | |||
| c4c1425c9b | |||
| 00bb3934ad | |||
| 324096e14e | |||
| 9cad2bb308 | |||
| eec537135a | |||
| 53e42d3350 | |||
| e74122977a | |||
| f32c3ebe2c | |||
| d07ac4fef0 | |||
| 183761b01f | |||
| 361ef70ce8 | |||
| 2bac0a4e5b | |||
| b89a68bb9c | |||
| 496dadebbd | |||
| 155a4eecd4 | |||
| 5eec1b6f7b | |||
| e2ce9472cf | |||
| 06f0b69cfb | |||
| 0ae43fde72 | |||
| 32f5b7e5c4 | |||
| e3a804ca64 | |||
| 6a3ee289b3 | |||
| 02a8605fec | |||
| dbd72e6bbf | |||
| d629c95daf | |||
| 04d6e8e7f0 | |||
| 7caf95158d | |||
| 8245448f29 | |||
| 4d85bcd60e | |||
| d8d156adac | |||
| 7d02c84c47 | |||
| a5d70b8c37 | |||
| d42cd9ffac | |||
| 1b19c83998 | |||
| c0be8bef23 | |||
| 90bc2d0b60 | |||
| 1c747f69f5 | |||
| 57914c7488 | |||
| 1939222d31 | |||
| c29f5fab7a | |||
| adb2cda614 | |||
| c462441f9e | |||
| 2681f6897d | |||
| 2322c67aff | |||
| f645663fd8 | |||
| f2f4d4b827 | |||
| 85108cfcb5 | |||
| 308bd355e2 | |||
| 4ab032c717 | |||
| 17a117d1ee | |||
| bc43cc232d | |||
| 94ae9e65f4 | |||
| 2ed7158cf1 | |||
| 9d8a21a3de | |||
| d313eaa742 | |||
| c5d91e7cca | |||
| cc668a1624 | |||
| d17173ec0a | |||
| ebcd886d20 | |||
| 4976bd1889 | |||
| 9da6d92fb3 | |||
| 9dee5429d5 | |||
| ebe90aac5c | |||
| 289d69c79d | |||
| 5bdaf4f662 | |||
| 67f47bc3df | |||
| 67ddd76ff3 | |||
| 95de883879 | |||
| 3227da122e | |||
| ae243c783a | |||
| eb3b7f5146 | |||
| 414439cac9 | |||
| 7dacccb70e | |||
| a5e1d0595e | |||
| 7e8c6e92a2 | |||
| 24542d4e21 | |||
| b975125af5 | |||
| cc8c60605b | |||
| 23adc15ce3 | |||
| 7204aa0c9a | |||
| 6750429cd4 | |||
| cfe0a6cbb8 | |||
| a9f95971e8 | |||
| d7eee844b7 | |||
| 4c52731d16 | |||
| e53447d0bf | |||
| 53ed23ac58 | |||
| 226fb4a349 | |||
| d89632eb9d | |||
| 4621196993 | |||
| 988e753c74 | |||
| aa49b2ca76 | |||
| fdcd2fdb27 | |||
| 62f94206bb | |||
| 7b6647cfd4 | |||
| 73828c5db7 | |||
| e1d942bb3a | |||
| a764cf64b3 | |||
| 018d51993a | |||
| 4ce51291de | |||
| e0cd68787d | |||
| 6601f4c505 | |||
| 6f62f0e2f1 | |||
| c00026e203 | |||
| 38ac365953 | |||
| 7cfb0f7d2d | |||
| bae194f366 | |||
| 398d95528d | |||
| d1b2ee5490 | |||
| d39b9bc060 | |||
| 0c0b7d86ee | |||
| 03c4d9504f | |||
| 0737bfc5fe | |||
| 80b4916094 | |||
| 00845b43b4 | |||
| 83a74808d5 | |||
| 951679cc10 | |||
| 3cd95f06b2 | |||
| de00fa91ae | |||
| 25d4f0b347 | |||
| 413aa28594 | |||
| 29e153bc54 | |||
| 7b1a2f60d0 | |||
| 2302626703 | |||
| 28b3193743 | |||
| 0fdf8d0f6a | |||
| 890c93a820 | |||
| 3bfcde99dc | |||
| d5a8d19b66 | |||
| 7a3a9a6f7c | |||
| a816c52699 | |||
| bdd3157a45 | |||
| 7337e75d1e | |||
| b39f1694c3 | |||
| b3a919293c | |||
| 927eb1d0ba | |||
| b812c6d984 | |||
| 6a768c3f84 | |||
| 83f4e65bc3 | |||
| ad33abe6bc | |||
| 2e1624235c | |||
| 647f09f2f3 | |||
| d0ad2bd38b | |||
| 3ae4e11bbe | |||
| 6f19a3e750 | |||
| e8442eedad | |||
| bd103802f9 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
run context jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Better docs for io.try
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Added retrying and better messaging
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
IO Logging now respects the job and client logLevel, and only outputs locally when ioLogLocalEnabled is true
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Adding support for trigger source in the run context, and make sure dynamic trigger runs are preprocessed so they have a chance of populating run properties
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/openai": patch
|
||||
---
|
||||
|
||||
Improved OpenAI task errors
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
A number of improvements to the initialization experience:
|
||||
|
||||
- Detect middleware usage and warn about how it could conflict with Trigger.dev and with a link to the docs
|
||||
- Lookup package versions and use the latest versions
|
||||
- Better error messages when registering an endpoint doesn't work
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/github": patch
|
||||
---
|
||||
|
||||
Fixed the broken export issue with two of the new tasks
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Fix for Next.js projects using the src dir
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Don't return the apiKey when they don't match
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/typeform": patch
|
||||
---
|
||||
|
||||
getAllResponses fixed
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Remove the localhost default for endpoint URL
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Fixed the version of the @trigger.dev/nextjs package
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
registerCron and unregisterCron jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Split the CLI into two commands, init and a new dev command
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/plain": patch
|
||||
---
|
||||
|
||||
Added upsertCustomTimelineEntry Task and exported the components from the plain package
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@trigger.dev/typeform": patch
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/github": patch
|
||||
"@trigger.dev/openai": patch
|
||||
"@trigger.dev/slack": patch
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Upgrade to zod 3.21.4
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
api.trigger.dev is now the default cloud url
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
io.runTask jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
[dev] Better handle errors when registering endpoint
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Improved the CLI prompts
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
io.sendEvent jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
deliverAt and timestamp event properties are now dates
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/openai": patch
|
||||
---
|
||||
|
||||
listModels returns the response.data instead of response.data.data
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
cronTrigger jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Added JSDocs related to logging
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Removed --tunnel option, currently we just support ngrok
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
intervalTrigger() jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Fixed responses from the PING action to match expected schema
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Adding more granular error messages around unauthorized requests
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
jsdocs for DynamicTrigger and DynamicSchedule
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Export the client from the generated code and added code comments
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/github": patch
|
||||
---
|
||||
|
||||
Fixed some properties that had API urls instead of HTML urls
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/nextjs": patch
|
||||
---
|
||||
|
||||
Adaptors no longer take an options object
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
"@trigger.dev/integration-kit": patch
|
||||
"@trigger.dev/typeform": patch
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/github": patch
|
||||
"@trigger.dev/openai": patch
|
||||
"@trigger.dev/resend": patch
|
||||
"@trigger.dev/plain": patch
|
||||
"@trigger.dev/slack": patch
|
||||
"@trigger.dev/nextjs": patch
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Set Node version to 16.8 and above
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/nextjs": patch
|
||||
---
|
||||
|
||||
Loosen the Next.js dependency version
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/internal": patch
|
||||
---
|
||||
|
||||
backgroundFetch jsdocs
|
||||
+69
-2
@@ -13,16 +13,83 @@
|
||||
"@trigger.dev/openai": "1.0.0-next.0",
|
||||
"@trigger.dev/database": "0.0.0",
|
||||
"@trigger.dev/init": "0.2.0",
|
||||
"@trigger.dev/integration-kit": "2.0.0-next.1"
|
||||
"@trigger.dev/integration-kit": "2.0.0-next.1",
|
||||
"@trigger.dev/resend": "1.0.0-next.1",
|
||||
"@trigger.dev/cli": "0.2.1-next.8",
|
||||
"@trigger.dev/typeform": "1.0.0-next.2",
|
||||
"@trigger.dev/plain": "1.0.0-next.2"
|
||||
},
|
||||
"changesets": [
|
||||
"afraid-hornets-cheer",
|
||||
"beige-maps-hug",
|
||||
"big-tables-search",
|
||||
"bright-buses-join",
|
||||
"bright-horses-bathe",
|
||||
"brown-bikes-bathe",
|
||||
"chatty-cars-agree",
|
||||
"chilly-meals-warn",
|
||||
"clever-bats-learn",
|
||||
"cuddly-pets-arrive",
|
||||
"curly-hornets-sort",
|
||||
"dirty-needles-kneel",
|
||||
"dull-bulldogs-design",
|
||||
"eight-buckets-agree",
|
||||
"eighty-queens-prove",
|
||||
"fast-ligers-wink",
|
||||
"four-ligers-perform",
|
||||
"friendly-parents-clean",
|
||||
"funny-elephants-sing",
|
||||
"gentle-dogs-end",
|
||||
"gentle-guests-leave",
|
||||
"great-meals-listen",
|
||||
"healthy-rockets-cry",
|
||||
"heavy-eyes-own",
|
||||
"heavy-mails-explain",
|
||||
"hot-eggs-protect",
|
||||
"hot-seals-press",
|
||||
"itchy-cars-count",
|
||||
"itchy-rockets-provide",
|
||||
"khaki-needles-wait",
|
||||
"long-clocks-hide",
|
||||
"lovely-hounds-accept",
|
||||
"lovely-plants-brake",
|
||||
"lucky-crews-matter",
|
||||
"metal-donkeys-relate",
|
||||
"modern-emus-suffer",
|
||||
"modern-turtles-eat",
|
||||
"moody-islands-melt",
|
||||
"odd-colts-smash",
|
||||
"pink-islands-pay",
|
||||
"pink-numbers-jam",
|
||||
"plenty-ties-raise",
|
||||
"popular-cooks-boil",
|
||||
"pretty-bats-obey",
|
||||
"quick-stingrays-own",
|
||||
"quiet-berries-tickle",
|
||||
"quiet-dryers-collect",
|
||||
"rich-clocks-attack",
|
||||
"rude-bees-taste",
|
||||
"shiny-mirrors-beam",
|
||||
"shy-bobcats-hear",
|
||||
"silent-mirrors-lay",
|
||||
"silver-insects-sneeze",
|
||||
"six-humans-happen",
|
||||
"sixty-pandas-deliver",
|
||||
"sixty-squids-wink",
|
||||
"strange-jobs-shout",
|
||||
"strong-cars-visit",
|
||||
"stupid-files-cough",
|
||||
"tough-walls-share"
|
||||
"sweet-adults-applaud",
|
||||
"sweet-cups-rescue",
|
||||
"sweet-snails-refuse",
|
||||
"tame-flowers-invite",
|
||||
"tasty-bats-flow",
|
||||
"ten-birds-confess",
|
||||
"thirty-apes-happen",
|
||||
"tidy-planes-compete",
|
||||
"tough-walls-share",
|
||||
"two-tools-hide",
|
||||
"wild-rats-mix",
|
||||
"young-birds-unite"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/typeform": patch
|
||||
---
|
||||
|
||||
safeBodyParse webhook import fixed
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Fixed the help defaults
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Initializing a next.js project now creates a better file structure
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
registerTrigger jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
io.registerInterval and io.unregisterInterval jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Fix when setting the url as an option
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@trigger.dev/integration-kit": patch
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/typeform": patch
|
||||
---
|
||||
|
||||
Creating the typeform integration package
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Removed the url option for TriggerClient
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Added JSdocs for io.wait and io.logger
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
isTriggerError jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
eventTrigger() jsdocs
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/openai": patch
|
||||
---
|
||||
|
||||
Adding support for output properties on tasks
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
io.try jsdocs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Added better Next Steps in the init cli command
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Fixed an issue that cause environment variables to be incorrectly added to .env.local
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/typeform": patch
|
||||
"@trigger.dev/integration-kit": patch
|
||||
---
|
||||
|
||||
integration-kit uses webhook package
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Added human readable cron expression property to cron triggers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/init": patch
|
||||
---
|
||||
|
||||
Fixed CLI showing undefined when not specifying a trigger-url flag
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/resend": patch
|
||||
---
|
||||
|
||||
Adding the resend integration package
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Added jsdocs for TriggerClient() and sendEvent()
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Better handle input for the --trigger-url option
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Improved the endpoint prompt
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/slack": patch
|
||||
---
|
||||
|
||||
Added joinConversation task, and automatically try and join a public conversation if the bot is not in it when posting a message
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/cli": patch
|
||||
---
|
||||
|
||||
Improved spinner and made port clear in logs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/nextjs": patch
|
||||
---
|
||||
|
||||
Update the devDependency on nextjs to be more permissive
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
Added JSdocs for Job
|
||||
@@ -0,0 +1,36 @@
|
||||
# YOU MUST SET THESE VARIABLES
|
||||
# Resend is an email service used for signing in to Trigger.dev via a Magic Link.
|
||||
### 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>
|
||||
FROM_EMAIL=
|
||||
REPLY_TO_EMAIL=
|
||||
|
||||
# YOU MIGHT LIKE TO MODIFY THESE VARIABLES
|
||||
SESSION_SECRET=abcdef1234
|
||||
MAGIC_LINK_SECRET=abcdef1234
|
||||
LOGIN_ORIGIN=http://localhost:3030
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=public
|
||||
REMIX_APP_PORT=3030
|
||||
APP_ENV=development
|
||||
APP_ORIGIN=http://localhost:3030
|
||||
NODE_ENV=development
|
||||
|
||||
# OPTIONAL VARIABLES
|
||||
AUTH_GITHUB_CLIENT_ID=
|
||||
AUTH_GITHUB_CLIENT_SECRET=
|
||||
|
||||
# CLOUD VARIABLES
|
||||
POSTHOG_PROJECT_KEY=
|
||||
PLAIN_API_KEY=
|
||||
SEED_CLOUD=
|
||||
SEED_CLOUD_EMAIL=
|
||||
SEED_CLOUD_GITHUB_ACCESS_TOKEN=
|
||||
SEED_CLOUD_SLACK_ACCESS_TOKEN=
|
||||
SEED_CLOUD_USER_GITHUB_ACCESS_TOKEN=
|
||||
CLOUD_AIRTABLE_CLIENT_ID=
|
||||
CLOUD_AIRTABLE_CLIENT_SECRET=
|
||||
CLOUD_GITHUB_CLIENT_ID=
|
||||
CLOUD_GITHUB_CLIENT_SECRET=
|
||||
CLOUD_SLACK_APP_HOST=
|
||||
CLOUD_SLACK_CLIENT_ID=
|
||||
CLOUD_SLACK_CLIENT_SECRET=
|
||||
@@ -1,70 +0,0 @@
|
||||
name: 🚀 Publish Trigger.dev Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev-q22023
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
name: ʦ TypeScript
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.18
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: 📀 Generate Prisma Client
|
||||
run: pnpm run generate
|
||||
|
||||
- name: 🔎 Type check
|
||||
run: pnpm run typecheck --filter webapp
|
||||
|
||||
publish:
|
||||
needs: [typecheck]
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- 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 and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
tags: ghcr.io/${{ github.repository }}:latest
|
||||
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:latest
|
||||
cache-to: type=inline
|
||||
@@ -0,0 +1,108 @@
|
||||
name: 🚀 Publish Trigger.dev Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
env:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
name: ʦ TypeScript
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.18
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: 📀 Generate Prisma Client
|
||||
run: pnpm run generate
|
||||
|
||||
- name: 🔎 Type check
|
||||
run: pnpm run typecheck --filter webapp
|
||||
|
||||
publish:
|
||||
needs: [typecheck]
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
outputs:
|
||||
version: ${{ steps.get_version.outputs.version }}
|
||||
short_sha: ${{ steps.get_commit.outputs.sha_short }}
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 🆚 Get the version
|
||||
id: get_version
|
||||
run: |
|
||||
IMAGE_TAG="${GITHUB_REF#refs/tags/}"
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
echo "IMAGE_TAG=${IMAGE_TAG}"
|
||||
elif [[ $GITHUB_REF == refs/heads/* ]]; then
|
||||
IMAGE_TAG="${GITHUB_REF#refs/heads/}"
|
||||
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: 🐳 Build Docker Image
|
||||
run: |
|
||||
docker build -t release_build_image -f ./docker/Dockerfile .
|
||||
|
||||
- name: 🐙 Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 🐙 Push to GitHub Container Registry
|
||||
run: |
|
||||
docker tag release_build_image $REGISTRY/$REPOSITORY:$IMAGE_TAG
|
||||
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
|
||||
env:
|
||||
REGISTRY: ghcr.io/triggerdotdev
|
||||
REPOSITORY: trigger.dev
|
||||
IMAGE_TAG: ${{ steps.get_version.outputs.version }}
|
||||
|
||||
- name: 🐙 Push 'latest' to GitHub Container Registry
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
docker tag release_build_image $REGISTRY/$REPOSITORY:latest
|
||||
docker push $REGISTRY/$REPOSITORY:latest
|
||||
env:
|
||||
REGISTRY: ghcr.io/triggerdotdev
|
||||
REPOSITORY: trigger.dev
|
||||
@@ -0,0 +1,67 @@
|
||||
name: 🦋 Changesets Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: 🦋 Changesets Release
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
if: |
|
||||
github.repository == 'triggerdotdev/trigger.dev'
|
||||
outputs:
|
||||
published_packages: ${{ steps.changesets.outputs.publishedPackages }}
|
||||
published: ${{ steps.changesets.outputs.published }}
|
||||
steps:
|
||||
- name: 🛑 Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.18
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: 📀 Generate Prisma Client
|
||||
run: pnpm run generate
|
||||
|
||||
- name: 🔎 Type check
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: 🔐 Setup npm auth
|
||||
run: |
|
||||
echo "registry=https://registry.npmjs.org" >> ~/.npmrc
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
|
||||
|
||||
# This action has two responsibilities. The first time the workflow runs
|
||||
# (initial push to the `main` branch) it will create a new branch and
|
||||
# then open a PR with the related changes for the new version. After the
|
||||
# PR is merged, the workflow will run again and this action will build +
|
||||
# publish to npm.
|
||||
- name: 🚀 PR / Publish
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
version: pnpm run changeset:version
|
||||
commit: "chore: Update version for release"
|
||||
title: "chore: Update version for release"
|
||||
publish: pnpm run changeset:release
|
||||
createGithubReleases: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -1,73 +0,0 @@
|
||||
# Warp Launch Configuration
|
||||
#
|
||||
#
|
||||
# Use this to start a certain configuration of windows, tabs, and panes
|
||||
# Open the launch configuration palette to access and open any launch configuration
|
||||
#
|
||||
# This file defines your launch configuration
|
||||
# More on how to do so here:
|
||||
# https://docs.warp.dev/features/session-management/launch-configurations
|
||||
#
|
||||
# All launch configurations are stored under ~/.warp/launch_configurations/
|
||||
# Edit them anytime!
|
||||
#
|
||||
# You can also add commands that run on-start for your launch configurations like so:
|
||||
# ---
|
||||
# name: Example with Command
|
||||
# windows:
|
||||
# - tabs:
|
||||
# - layout:
|
||||
# cwd: /Users/warp-user/project
|
||||
# commands:
|
||||
# - exec: code .
|
||||
|
||||
---
|
||||
name: Triggerdotdev
|
||||
windows:
|
||||
- tabs:
|
||||
- title: webapp
|
||||
layout:
|
||||
split_direction: vertical
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: pnpm run build --filter webapp
|
||||
- exec: pnpm run i-dev --filter webapp
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/apps/webapp
|
||||
- title: integrations
|
||||
layout:
|
||||
split_direction: vertical
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: pnpm run dev --filter integrations
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/apps/integrations
|
||||
- title: ngrok
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: ./scripts/proxy-webapp.sh <your-trigger-dev>
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: ./scripts/proxy-pizzly.sh <your-pizzly-dev>
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: ./scripts/proxy-wss.sh <your-wss-dev>
|
||||
- title: wss and examples
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/apps/wss
|
||||
commands:
|
||||
- exec: LOG_LEVEL=debug pnpm run dev
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/examples
|
||||
- title: emails
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/Work/Git/APIHero/trigger.dev/packages/emails
|
||||
commands:
|
||||
- exec: pnpm run dev
|
||||
- cwd: /Users/eric/Work/Git/APIHero/trigger.dev/packages/emails
|
||||
+9
-10
@@ -4,23 +4,22 @@ Trigger.dev uses [changesets](https://github.com/changesets/changesets) to manag
|
||||
|
||||
## Adding a changeset
|
||||
|
||||
To add a changeset, use `pnpm run changeset:add` and follow the instructions [here](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). Please only ever select one of our public packages when adding a changeset, which currently are:
|
||||
To add a changeset, use `pnpm run changeset:add` and follow the instructions [here](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). Please only ever select one of our public packages when adding a changeset.
|
||||
|
||||
- `@trigger.dev/sdk`
|
||||
- `@trigger.dev/integration-sdk`
|
||||
- `@trigger.dev/github`
|
||||
- `@trigger.dev/notion`
|
||||
- `@trigger.dev/slack`
|
||||
- `@trigger.dev/shopify`
|
||||
- `@trigger.dev/resend`
|
||||
|
||||
## Release instructions
|
||||
## Release instructions (local only)
|
||||
|
||||
Based on the instructions [here](https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md)
|
||||
|
||||
1. Run `pnpm run changeset:version`
|
||||
2. Run `pnpm run changeset:release`
|
||||
|
||||
## Release instructions (CI)
|
||||
|
||||
Please follow the best-practice of adding changesets in the same commit as the code making the change with `pnpm run changeset:add`, as it will allow our release.yml CI workflow to function properly:
|
||||
|
||||
- Anytime new changesets are added in a commit in the `main` branch, the [release.yml](./.github/workflows/release.yml) workflow will run and will automatically create/update a PR with a fresh run of `pnpm run changeset:version`.
|
||||
- When the version PR is merged into `main`, the release.yml workflow will automatically run `pnpm run changeset:release` to build and release packages to npm.
|
||||
|
||||
## Pre-release instructions
|
||||
|
||||
1. Add changesets as usual `pnpm run changeset:add`
|
||||
|
||||
@@ -1,25 +1,201 @@
|
||||
Copyright (c) 2022 API Hero Inc.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
- All content that resides under any "ee/" directory of this repository, if such directories exists, are licensed under the license defined in "ee/LICENSE".
|
||||
- All third party components incorporated into the Trigger.dev Software are licensed under the original license provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
|
||||
1. Definitions.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -4,18 +4,102 @@
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://imagedelivery.net/3TbraffuDZ4aEf8KWOmI_w/3f5ad4c1-c4c8-4277-b622-290e7f37bd00/public">
|
||||
<img alt="Trigger.dev logo" src="https://imagedelivery.net/3TbraffuDZ4aEf8KWOmI_w/a45d1fa2-0ae8-4a39-4409-f4f934bfae00/public">
|
||||
</picture>
|
||||
|
||||
### The background jobs framework for Next.js
|
||||
|
||||
[Discord](https://discord.gg/JtBAxBr2m3) | [Website](https://trigger.dev) | [Issues](https://github.com/triggerdotdev/trigger.dev/issues) | [Docs](https://trigger.dev/docs)
|
||||
|
||||
[](https://twitter.com/triggerdotdev)
|
||||
[](https://github.com/triggerdotdev/trigger.dev)
|
||||
|
||||
</div>
|
||||
|
||||
# **The background jobs framework for Next.js**
|
||||
|
||||
# About Trigger.dev
|
||||
Create long-running jobs directly in your codebase with features like API integrations, webhooks, scheduling and delays.
|
||||
|
||||
|
||||
### Long running Jobs on serverless
|
||||
|
||||
### _**Trigger.dev v2 is launching soon...**_
|
||||
Reliably run jobs and don’t worry about function timeouts, we handle those for you.
|
||||
|
||||
Visit the new landing page for [Trigger.dev v2](https://trigger.dev) and [sign up for early access.](https://bcymafitv0e.typeform.com/to/QQnotGJM#source=github)
|
||||
- Auto-resume after a function timeout
|
||||
- Auto-resume after a server outage
|
||||
- Add delays of up to a year
|
||||
|
||||
### In your codebase
|
||||
|
||||
Create Jobs where they belong: in your codebase. Version control, localhost, test, review, and deploy like you're already used to.
|
||||
|
||||
### Secure by design
|
||||
|
||||
We only receive Triggers and the data you choose to send to us. You can even completely self-host the entire platform.
|
||||
|
||||
### Don't worry about deployment
|
||||
|
||||
Just use our SDK to write Jobs in your Next.js codebase. There's nothing extra to deploy and no CI to configure, your Jobs just connect to our cloud. Or you can always self-host.
|
||||
|
||||
### Full visibility of every job run
|
||||
|
||||
View every Task in every Run so you can tell exactly what happened.
|
||||
|
||||

|
||||
|
||||
### Built-in integrations
|
||||
|
||||
Easily integrate with hundreds of third-party APIs – including your own. Use API keys (which never leave your server) or let us handle OAuth for you. Install our integration packages and easily subscribe to webhooks and perform common tasks, or you can easily use your existing favorite Node.JS SDKs and get resumability and idempotency through our `runTask` function.
|
||||
|
||||
### Trigger.dev Connect (coming soon)
|
||||
|
||||
Easily add integrations for your users.
|
||||
|
||||
# Getting started
|
||||
|
||||
Visit our docs [here](https://trigger.dev/docs).
|
||||
|
||||
## Self-host
|
||||
|
||||
We provide an official trigger.dev docker image you can use to easily self-host the platform. We're working on more extensive guides but we currently provide a [Fly.io example repository](https://github.com/triggerdotdev/fly.io) with instructions in the README for deploying and using a self-hosted instance of Trigger.dev on Fly.io.
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites
|
||||
- [Node.js](https://nodejs.org/en) version >=18.x
|
||||
- [pnpm package manager](https://pnpm.io/installation) version 7
|
||||
- [Docker](https://www.docker.com/get-started/)
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone the repo into a public GitHub repository or [fork the repo](https://github.com/triggerdotdev/trigger.dev/fork). If you plan to distribute the code, keep the source code public to comply with the [Apache Licence 2.0](https://github.com/triggerdotdev/trigger.dev/blob/main/LICENSE).
|
||||
|
||||
```
|
||||
git clone https://github.com/triggerdotdev/trigger.dev.git
|
||||
```
|
||||
> If you are on windows, run the following command on gitbash with admin privileges:
|
||||
> `git clone -c core.symlinks=true https://triggerdotdev/trigger.dev.git`
|
||||
2. Navigate to the project folder
|
||||
```
|
||||
cd trigger.dev
|
||||
```
|
||||
3. Install the required packages using pnpm.
|
||||
```
|
||||
pnpm i
|
||||
```
|
||||
4. Create your `.env` files
|
||||
```
|
||||
cp .env.example .env && cp packages/database/.env.example packages/database/.env
|
||||
```
|
||||
Open the root `.env` file and fill in the required values.
|
||||
6. Start Docker. This starts the required services like Postgres.
|
||||
```
|
||||
pnpm run docker
|
||||
```
|
||||
7. Migrate the database
|
||||
```
|
||||
pnpm run db:migrate
|
||||
```
|
||||
8. Run the seed script
|
||||
```
|
||||
pnpm run db:seed
|
||||
```
|
||||
5. Run the project. It should run on `port:3030`
|
||||
```
|
||||
pnpm run dev --filter webapp
|
||||
```
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
|
||||
TRIGGER_API_KEY=
|
||||
|
||||
TRIGGER_LOG_LEVEL=debug
|
||||
|
||||
|
||||
|
||||
##########################################################################################
|
||||
# ************************************* BASICS *******************************************
|
||||
##########################################################################################
|
||||
|
||||
APP_ENV=development
|
||||
|
||||
APP_ORIGIN=http://localhost:3000
|
||||
|
||||
NODE_ENV=development
|
||||
|
||||
SESSION_SECRET=
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
# ************************************* LOGIN *******************************************
|
||||
#########################################################################################
|
||||
|
||||
AUTH_GITHUB_CLIENT_ID=
|
||||
|
||||
AUTH_GITHUB_CLIENT_SECRET=
|
||||
|
||||
LOGIN_ORIGIN=http://localhost:3000
|
||||
|
||||
MAGIC_LINK_SECRET=
|
||||
|
||||
|
||||
|
||||
############################################################################################
|
||||
# ************************************ OPTIONAL ********************************************
|
||||
############################################################################################
|
||||
|
||||
POSTHOG_PROJECT_KEY=
|
||||
|
||||
|
||||
|
||||
############################################################################################
|
||||
# ************************************ DATABASE ********************************************
|
||||
############################################################################################
|
||||
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
||||
|
||||
|
||||
|
||||
################################################################################################
|
||||
# ********************************** INTEGRATIONS **********************************************
|
||||
################################################################################################
|
||||
|
||||
PIZZLY_HOST=http://localhost:3004
|
||||
|
||||
PIZZLY_SECRET_KEY=
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
# ************************************* EMAIL *******************************************
|
||||
#########################################################################################
|
||||
|
||||
FROM_EMAIL=
|
||||
|
||||
REPLY_TO_EMAIL=
|
||||
|
||||
RESEND_API_KEY=<api_key>
|
||||
@@ -1 +0,0 @@
|
||||
{"workspaceId":"63e5e42daf9a537ba8d9503c"}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ReactNode } from "react";
|
||||
import { MainCenteredContainer } from "./layout/AppLayout";
|
||||
import { Header1, Header2 } from "./primitives/Headers";
|
||||
import { NamedIcon, NamedIconInBox } from "./primitives/NamedIcon";
|
||||
import { Header2 } from "./primitives/Headers";
|
||||
import { NamedIconInBox } from "./primitives/NamedIcon";
|
||||
import { Paragraph } from "./primitives/Paragraph";
|
||||
|
||||
type ComingSoonProps = {
|
||||
@@ -23,9 +23,9 @@ export function ComingSoon({ title, description, icon }: ComingSoonProps) {
|
||||
) : (
|
||||
icon
|
||||
)}
|
||||
<div className="mt-0.5 flex flex-col">
|
||||
<div className="mt-0.5 flex flex-col gap-y-1">
|
||||
<Paragraph variant="extra-extra-small/caps">Coming soon</Paragraph>
|
||||
<Header1 className="-mt-0.5">{title}</Header1>
|
||||
<Header2 className="-mt-0.5">{title}</Header2>
|
||||
</div>
|
||||
</div>
|
||||
<Paragraph variant="small" className="p-4">
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
|
||||
import { LinkButton } from "./primitives/Buttons";
|
||||
import { Header1, Header3 } from "./primitives/Headers";
|
||||
import { friendlyErrorDisplay } from "~/utils/httpErrors";
|
||||
|
||||
type ErrorDisplayOptions = {
|
||||
button?: {
|
||||
title: string;
|
||||
to: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function RouteErrorDisplay(options?: ErrorDisplayOptions) {
|
||||
const error = useRouteError();
|
||||
|
||||
return (
|
||||
<>
|
||||
{isRouteErrorResponse(error) ? (
|
||||
<ErrorDisplay
|
||||
title={friendlyErrorDisplay(error.status, error.statusText).title}
|
||||
message={
|
||||
error.data.message ??
|
||||
friendlyErrorDisplay(error.status, error.statusText).message
|
||||
}
|
||||
{...options}
|
||||
/>
|
||||
) : error instanceof Error ? (
|
||||
<ErrorDisplay title={error.name} message={error.message} {...options} />
|
||||
) : (
|
||||
<ErrorDisplay
|
||||
title="Oops"
|
||||
message={JSON.stringify(error)}
|
||||
{...options}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
type DisplayOptionsProps = {
|
||||
title: string;
|
||||
message?: string;
|
||||
} & ErrorDisplayOptions;
|
||||
|
||||
export function ErrorDisplay({ title, message, button }: DisplayOptionsProps) {
|
||||
return (
|
||||
<div className="p-4">
|
||||
<Header1 className="mb-4 border-b border-slate-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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { H, HighlightOptions } from "highlight.run";
|
||||
import { useEffect } from "react";
|
||||
|
||||
interface Props extends HighlightOptions {
|
||||
projectId?: string;
|
||||
}
|
||||
|
||||
export function HighlightInit({ projectId, ...highlightOptions }: Props) {
|
||||
useEffect(() => {
|
||||
projectId && H.init(projectId, highlightOptions);
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -23,9 +23,9 @@ export function UserAvatar({
|
||||
className?: string;
|
||||
}) {
|
||||
return avatarUrl ? (
|
||||
<div>
|
||||
<div className={cn("grid aspect-square place-items-center", className)}>
|
||||
<img
|
||||
className={cn("aspect-square rounded-full p-[7%]", className)}
|
||||
className={cn("aspect-square rounded-full p-[7%]")}
|
||||
src={avatarUrl}
|
||||
alt={name ?? "User"}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
import { Link } from "@remix-run/react";
|
||||
import { Paragraph, TextLink } from "~/components/primitives/Paragraph";
|
||||
import { StepNumber } from "~/components/primitives/StepNumber";
|
||||
import { useAppOrigin } from "~/hooks/useAppOrigin";
|
||||
import { useDevEnvironment } from "~/hooks/useEnvironments";
|
||||
import { useJob } from "~/hooks/useJob";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { IntegrationIcon } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route";
|
||||
import { jobTestPath } from "~/utils/pathBuilder";
|
||||
import { InlineCode } from "../code/InlineCode";
|
||||
import { HelpPanelProps } from "../integrations/ApiKeyHelp";
|
||||
import { HelpInstall } from "../integrations/HelpInstall";
|
||||
import { HelpSamples } from "../integrations/HelpSamples";
|
||||
import { Button, LinkButton } from "../primitives/Buttons";
|
||||
import { Callout, variantClasses } from "../primitives/Callout";
|
||||
import {
|
||||
ClientTabs,
|
||||
ClientTabsContent,
|
||||
ClientTabsList,
|
||||
ClientTabsTrigger,
|
||||
} from "../primitives/ClientTabs";
|
||||
import { ClipboardField } from "../primitives/ClipboardField";
|
||||
import integrationButton from "./integration-button.png";
|
||||
import selectEnvironment from "./select-environment.png";
|
||||
import selectExample from "./select-example.png";
|
||||
import { Header2 } from "../primitives/Headers";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
import { EnvironmentLabel } from "../environments/EnvironmentLabel";
|
||||
|
||||
export function HowToSetupYourProject() {
|
||||
const devEnvironment = useDevEnvironment();
|
||||
const appOrigin = useAppOrigin();
|
||||
return (
|
||||
<>
|
||||
<StepNumber stepNumber="1" title="Run the CLI init command" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
Run this CLI command in a terminal window from your Next.js project.
|
||||
</Paragraph>
|
||||
<ClientTabs defaultValue="npm">
|
||||
<ClientTabsList>
|
||||
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"yarn"}>yarn</ClientTabsTrigger>
|
||||
</ClientTabsList>
|
||||
<ClientTabsContent value={"npm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
secure={`npx @trigger.dev/cli@latest init -k ••••••••• -t ${appOrigin}`}
|
||||
value={`npx @trigger.dev/cli@latest init -k ${devEnvironment?.apiKey} -t ${appOrigin}`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"pnpm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
secure={`pnpm dlx @trigger.dev/cli@latest init -k ••••••••• -t ${appOrigin}`}
|
||||
value={`pnpm dlx @trigger.dev/cli@latest init -k ${devEnvironment?.apiKey} -t ${appOrigin}`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"yarn"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
secure={`yarn @trigger.dev/cli@latest init -k ••••••••• -t ${appOrigin}`}
|
||||
value={`yarn @trigger.dev/cli@latest init -k ${devEnvironment?.apiKey} -t ${appOrigin}`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
</ClientTabs>
|
||||
<Paragraph spacing variant="small">
|
||||
It will ask you for a "unique ID for your endpoint". You can use the
|
||||
default by hitting enter.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="2" title="Run your Next.js app" />
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
Ensure your Next.js app is running locally on port 3000.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="3" title="Run the CLI dev command" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
The CLI <InlineCode>dev</InlineCode> command allows the Trigger.dev
|
||||
service to send messages to your Next.js site. This is required for
|
||||
registering Jobs, triggering them and running Tasks. To achieve this
|
||||
it creates a tunnel (using{" "}
|
||||
<TextLink href="https://ngrok.com/">ngrok</TextLink>) so Trigger.dev
|
||||
can send messages to your machine.
|
||||
</Paragraph>
|
||||
<Paragraph spacing>
|
||||
You should leave the <InlineCode>dev</InlineCode> command running when
|
||||
you're developing.
|
||||
</Paragraph>
|
||||
<Paragraph spacing>
|
||||
In a{" "}
|
||||
<strong className="text-bright">new terminal window or tab</strong>{" "}
|
||||
run:
|
||||
</Paragraph>
|
||||
<ClientTabs defaultValue="npm">
|
||||
<ClientTabsList>
|
||||
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"yarn"}>yarn</ClientTabsTrigger>
|
||||
</ClientTabsList>
|
||||
<ClientTabsContent value={"npm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`npx @trigger.dev/cli@latest dev`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"pnpm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`pnpm dlx @trigger.dev/cli@latest dev`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"yarn"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`yarn @trigger.dev/cli@latest dev`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
</ClientTabs>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="4" title="Check for Jobs" />
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
Once you've run the CLI command, click Refresh to view your example
|
||||
Job in the list.
|
||||
</Paragraph>
|
||||
<Button
|
||||
variant="primary/medium"
|
||||
className="mt-4"
|
||||
LeadingIcon="refresh"
|
||||
onClick={() => window.location.reload()}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</StepContentContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function HowToRunYourJob() {
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
const job = useJob();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Callout variant="info" className="mb-6">
|
||||
<Paragraph variant={"small"} className={variantClasses.info.textColor}>
|
||||
Scheduled Triggers <strong>do not</strong> trigger Jobs in the DEV
|
||||
Environment. When developing locally you should use the{" "}
|
||||
<Link
|
||||
to={jobTestPath(organization, project, job)}
|
||||
className="underline underline-offset-2 transition hover:text-blue-100"
|
||||
>
|
||||
Test feature
|
||||
</Link>{" "}
|
||||
to trigger any scheduled Jobs.
|
||||
</Paragraph>
|
||||
</Callout>
|
||||
|
||||
<Paragraph spacing>There are two ways to run your Job:</Paragraph>
|
||||
|
||||
<StepNumber stepNumber="1" title="Trigger a test Run" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
You can perform a Run with any payload you want, or use one of our
|
||||
examples, on the test page.
|
||||
</Paragraph>
|
||||
<LinkButton
|
||||
to={jobTestPath(organization, project, job)}
|
||||
variant={"primary/small"}
|
||||
LeadingIcon={"beaker"}
|
||||
leadingIconClassName="text-bright"
|
||||
>
|
||||
Test
|
||||
</LinkButton>
|
||||
</StepContentContainer>
|
||||
|
||||
<StepNumber stepNumber="2" title="Trigger your Job for real" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
Performing a real run depends on the type of Trigger your Job is
|
||||
using.
|
||||
</Paragraph>
|
||||
|
||||
<LinkButton
|
||||
to="https://trigger.dev/docs/documentation/guides/running-jobs"
|
||||
variant={"primary/small"}
|
||||
LeadingIcon={"docs"}
|
||||
leadingIconClassName="text-bright"
|
||||
>
|
||||
How to run a Job
|
||||
</LinkButton>
|
||||
</StepContentContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function HowToRunATest() {
|
||||
return (
|
||||
<>
|
||||
<StepNumber
|
||||
stepNumber="1"
|
||||
title="Select an environment
|
||||
"
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
Select the environment you’d like the test to run against.
|
||||
</Paragraph>
|
||||
<img src={selectEnvironment} className="mt-2 w-52" />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="2" title="Write your test payload" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
Write your own payload specific to your Job. Some Triggers also
|
||||
provide example payloads that you can select from. This will populate
|
||||
the code editor below.
|
||||
</Paragraph>
|
||||
<img src={selectExample} className="mt-2 h-40" />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="3" title="Run your test" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
When you’re happy with the payload, click Run test.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<Callout
|
||||
variant="docs"
|
||||
to="https://trigger.dev/docs/documentation/guides/testing-jobs"
|
||||
>
|
||||
Learn more about running tests.
|
||||
</Callout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function HowToConnectAnIntegration() {
|
||||
return (
|
||||
<>
|
||||
<StepNumber stepNumber="1" title="Select an API from the list" />
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
APIs marked with a
|
||||
<span
|
||||
className="mx-2 -mt-1 inline-flex"
|
||||
aria-label="Trigger.dev Integration icon"
|
||||
>
|
||||
<IntegrationIcon />
|
||||
</span>
|
||||
are Trigger.dev Integrations. These Integrations make connecting to
|
||||
the API easier by offering OAuth or API key authentication. All APIs
|
||||
can also be used with fetch or an SDK.
|
||||
</Paragraph>
|
||||
<img src={integrationButton} className="mt-2 h-10" />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="2" title="Choose how you want to connect" />
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
Follow the instructions for your chosen connection method in the
|
||||
popover form. If no Integration exists yet, you can request one by
|
||||
clicking the "I want an Integration" button.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber
|
||||
stepNumber="3"
|
||||
title="Your connection will appear in the list"
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
Once you've connected your API, it will appear in the list of
|
||||
Integrations below. You can view details and manage your connection by
|
||||
selecting it from the table.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<Callout
|
||||
variant={"docs"}
|
||||
to="https://trigger.dev/docs/integrations/introduction"
|
||||
>
|
||||
View the Integration docs page for more information on connecting an API
|
||||
using an Integration or other method.
|
||||
</Callout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function HowToUseThisIntegration({
|
||||
integration,
|
||||
help,
|
||||
integrationClient,
|
||||
}: HelpPanelProps) {
|
||||
return (
|
||||
<>
|
||||
<StepNumber stepNumber="1" title="Install the package" />
|
||||
<StepContentContainer>
|
||||
<HelpInstall packageName={integration.packageName} />
|
||||
</StepContentContainer>
|
||||
{help && (
|
||||
<>
|
||||
<StepNumber stepNumber="2" title="Create a Job" />
|
||||
<StepContentContainer>
|
||||
<HelpSamples
|
||||
help={help}
|
||||
integration={integration}
|
||||
integrationClient={integrationClient}
|
||||
/>
|
||||
</StepContentContainer>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function HowToUseApiKeysAndEndpoints() {
|
||||
return (
|
||||
<>
|
||||
<Paragraph spacing>
|
||||
Environments and Endpoints are used to connect your server to the
|
||||
Trigger.dev platform.
|
||||
</Paragraph>
|
||||
<Header2 spacing>Environments</Header2>
|
||||
<Paragraph spacing>
|
||||
Each environment has an API Key associated with it. This API Key is used
|
||||
to authenticate your Jobs with the Trigger.dev platform.
|
||||
</Paragraph>
|
||||
<Paragraph spacing>
|
||||
The API Key you use for your{" "}
|
||||
<TextLink to="https://trigger.dev/docs/documentation/concepts/client-adaptors">
|
||||
Client
|
||||
</TextLink>{" "}
|
||||
is how we know which environment to run your code against:
|
||||
</Paragraph>
|
||||
<CodeBlock
|
||||
showLineNumbers={false}
|
||||
className="mb-4"
|
||||
code={`export const client = new TriggerClient({
|
||||
id: "nextjs-example",
|
||||
//this environment variable should be set to your DEV API Key locally,
|
||||
//and your PROD API Key in production
|
||||
apiKey: process.env.TRIGGER_API_KEY!,
|
||||
});`}
|
||||
/>
|
||||
<StepNumber
|
||||
stepNumber="→"
|
||||
title={
|
||||
<span className="flex items-center gap-x-2">
|
||||
<span>Development</span>
|
||||
<EnvironmentLabel environment={{ type: "DEVELOPMENT" }} />
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<Paragraph>
|
||||
The <InlineCode>DEV</InlineCode> environment should only be used for
|
||||
local development. It’s where you can test your Jobs before deploying
|
||||
them to servers.
|
||||
</Paragraph>
|
||||
<Callout variant="warning" className="my-2">
|
||||
Scheduled Triggers do not trigger Jobs in the DEV Environment. When
|
||||
you’re working locally you should use the Test feature to trigger any
|
||||
scheduled Jobs.
|
||||
</Callout>
|
||||
</StepContentContainer>
|
||||
<StepNumber
|
||||
stepNumber="→"
|
||||
title={
|
||||
<span className="flex items-center gap-x-2">
|
||||
<span>Production</span>
|
||||
<EnvironmentLabel environment={{ type: "PRODUCTION" }} />
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
The <InlineCode>PROD</InlineCode> environment is where your Jobs will
|
||||
run in production. It’s where you can run your Jobs against real data.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<Header2 spacing>Endpoints</Header2>
|
||||
<Paragraph spacing>
|
||||
An Endpoint is a URL on your server that Trigger.dev can connect to.
|
||||
This URL is used to register Jobs, start them and orchestrate runs and
|
||||
retries.
|
||||
</Paragraph>
|
||||
<Paragraph spacing>
|
||||
<InlineCode>DEV</InlineCode> has multiple endpoints associated with it –
|
||||
one for each team member. This allows each team member to run their own
|
||||
Jobs, without interfering with each other.
|
||||
</Paragraph>
|
||||
<Paragraph spacing>
|
||||
All other environments have just a single endpoint (with a single URL)
|
||||
associated with them.
|
||||
</Paragraph>
|
||||
<Header2 spacing>Deployment</Header2>
|
||||
<Paragraph spacing>
|
||||
Deployment uses Environments and Endpoints to connect your Jobs to the
|
||||
Trigger.dev platform.
|
||||
</Paragraph>
|
||||
<Callout
|
||||
variant="docs"
|
||||
to="https://trigger.dev/docs/documentation/guides/deployment"
|
||||
>
|
||||
Read the deployment guide to learn more.
|
||||
</Callout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function StepContentContainer({ children }: { children: React.ReactNode }) {
|
||||
return <div className="mb-6 ml-9 mt-1">{children}</div>;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -1,20 +1,26 @@
|
||||
import {
|
||||
ApiAuthenticationMethodApiKey,
|
||||
Integration,
|
||||
} from "~/services/externalApis/types";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
import { Help, Integration } from "~/services/externalApis/types";
|
||||
import { InlineCode } from "../code/InlineCode";
|
||||
import { Header1, Header2 } from "../primitives/Headers";
|
||||
import { ClipboardField } from "../primitives/ClipboardField";
|
||||
import { Header1 } from "../primitives/Headers";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { HelpInstall } from "./HelpInstall";
|
||||
import { HelpSamples, ReplacementData } from "./HelpSamples";
|
||||
|
||||
export type HelpPanelIntegration = Pick<
|
||||
Integration,
|
||||
"name" | "packageName" | "identifier"
|
||||
>;
|
||||
|
||||
export type HelpPanelProps = {
|
||||
integration: HelpPanelIntegration;
|
||||
help?: Help;
|
||||
integrationClient?: ReplacementData;
|
||||
};
|
||||
|
||||
export function ApiKeyHelp({
|
||||
integration,
|
||||
apiAuth,
|
||||
}: {
|
||||
integration: Integration;
|
||||
apiAuth: ApiAuthenticationMethodApiKey;
|
||||
}) {
|
||||
help,
|
||||
integrationClient,
|
||||
}: HelpPanelProps) {
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<Header1 className="mb-2">
|
||||
@@ -28,17 +34,14 @@ export function ApiKeyHelp({
|
||||
First install the <InlineCode>{integration.packageName}</InlineCode>{" "}
|
||||
package using your preferred package manager. For example:
|
||||
</Paragraph>
|
||||
<ClipboardField
|
||||
variant="secondary/medium"
|
||||
value={`npm install ${integration.packageName}`}
|
||||
className="mb-4"
|
||||
/>
|
||||
{apiAuth.help.samples.map((sample, i) => (
|
||||
<div key={i}>
|
||||
<Paragraph spacing>{sample.title}</Paragraph>
|
||||
<CodeBlock code={sample.code} className="mb-4" />
|
||||
</div>
|
||||
))}
|
||||
<HelpInstall packageName={integration.packageName} />
|
||||
{help && (
|
||||
<HelpSamples
|
||||
help={help}
|
||||
integration={integration}
|
||||
integrationClient={integrationClient}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@ import {
|
||||
ApiAuthenticationMethodApiKey,
|
||||
Integration,
|
||||
} from "~/services/externalApis/types";
|
||||
import { docsIntegrationPath } from "~/utils/pathBuilder";
|
||||
import { LinkButton } from "../primitives/Buttons";
|
||||
import { Header1, Header2 } from "../primitives/Headers";
|
||||
import { NamedIconInBox } from "../primitives/NamedIcon";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { RadioGroup, RadioGroupItem } from "../primitives/RadioButton";
|
||||
import {
|
||||
Sheet,
|
||||
SheetBody,
|
||||
@@ -12,12 +16,9 @@ import {
|
||||
SheetHeader,
|
||||
SheetTrigger,
|
||||
} from "../primitives/Sheet";
|
||||
import { RadioGroup, RadioGroupItem } from "../primitives/RadioButton";
|
||||
import { ApiKeyHelp } from "./ApiKeyHelp";
|
||||
import { CustomHelp } from "./CustomHelp";
|
||||
import { SelectOAuthMethod } from "./SelectOAuthMethod";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { LinkButton } from "../primitives/Buttons";
|
||||
|
||||
type IntegrationMethod = "apikey" | "oauth2" | "custom";
|
||||
|
||||
@@ -26,7 +27,7 @@ export function ConnectToIntegrationSheet({
|
||||
organizationId,
|
||||
button,
|
||||
className,
|
||||
callbackUrl
|
||||
callbackUrl,
|
||||
}: {
|
||||
integration: Integration;
|
||||
organizationId: string;
|
||||
@@ -45,17 +46,17 @@ export function ConnectToIntegrationSheet({
|
||||
return (
|
||||
<Sheet>
|
||||
<SheetTrigger className={className}>{button}</SheetTrigger>
|
||||
<SheetContent size="lg">
|
||||
<SheetContent size="lg" className="relative">
|
||||
<SheetHeader>
|
||||
<NamedIconInBox name={integration.identifier} className="h-9 w-9" />
|
||||
<div className="grow">
|
||||
<Header2>{integration.name}</Header2>
|
||||
<Header1>{integration.name}</Header1>
|
||||
{integration.description && (
|
||||
<Paragraph variant="small">{integration.description}</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
<LinkButton
|
||||
to={`https://trigger.dev/docs/integrations/${integration.identifier}`}
|
||||
to={docsIntegrationPath(integration.identifier)}
|
||||
variant="secondary/small"
|
||||
LeadingIcon="docs"
|
||||
>
|
||||
@@ -115,7 +116,7 @@ function SelectedIntegrationMethod({
|
||||
integration,
|
||||
organizationId,
|
||||
method,
|
||||
callbackUrl
|
||||
callbackUrl,
|
||||
}: {
|
||||
integration: Integration;
|
||||
organizationId: string;
|
||||
@@ -128,12 +129,7 @@ function SelectedIntegrationMethod({
|
||||
case "apikey":
|
||||
const apiAuth = authMethods.find((a) => a.type === "apikey");
|
||||
if (!apiAuth) return null;
|
||||
return (
|
||||
<ApiKeyHelp
|
||||
integration={integration}
|
||||
apiAuth={apiAuth as ApiAuthenticationMethodApiKey}
|
||||
/>
|
||||
);
|
||||
return <ApiKeyHelp integration={integration} help={apiAuth.help} />;
|
||||
case "oauth2":
|
||||
return (
|
||||
<SelectOAuthMethod
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { conform, useForm } from "@conform-to/react";
|
||||
import { parse } from "@conform-to/zod";
|
||||
import { useFetcher, useLocation, useNavigation } from "@remix-run/react";
|
||||
import type { ConnectionType } from "@trigger.dev/database";
|
||||
import cuid from "cuid";
|
||||
import { useState } from "react";
|
||||
import simplur from "simplur";
|
||||
import { useFeatures } from "~/hooks/useFeatures";
|
||||
import { useTextFilter } from "~/hooks/useTextFilter";
|
||||
import { createSchema } from "~/routes/resources.connection.$organizationId.oauth2";
|
||||
import {
|
||||
@@ -18,13 +20,11 @@ import { Checkbox } from "../primitives/Checkbox";
|
||||
import { Fieldset } from "../primitives/Fieldset";
|
||||
import { FormError } from "../primitives/FormError";
|
||||
import { Header2, Header3 } from "../primitives/Headers";
|
||||
import { Hint } from "../primitives/Hint";
|
||||
import { Input } from "../primitives/Input";
|
||||
import { InputGroup } from "../primitives/InputGroup";
|
||||
import { Label } from "../primitives/Label";
|
||||
import { NamedIcon } from "../primitives/NamedIcon";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import type { ConnectionType } from "@trigger.dev/database";
|
||||
import { useFeatures } from "~/hooks/useFeatures";
|
||||
|
||||
export type Status = "loading" | "idle";
|
||||
|
||||
@@ -50,7 +50,14 @@ export function ConnectToOAuthForm({
|
||||
|
||||
const [
|
||||
form,
|
||||
{ title, scopes, hasCustomClient, customClientId, customClientSecret },
|
||||
{
|
||||
title,
|
||||
slug,
|
||||
scopes,
|
||||
hasCustomClient,
|
||||
customClientId,
|
||||
customClientSecret,
|
||||
},
|
||||
] = useForm({
|
||||
lastSubmission: fetcher.data,
|
||||
onValidate({ formData }) {
|
||||
@@ -110,6 +117,20 @@ export function ConnectToOAuthForm({
|
||||
<InputGroup>
|
||||
<FormError>{form.error}</FormError>
|
||||
</InputGroup>
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="large">ID</Label>
|
||||
<Input
|
||||
type="text"
|
||||
fullWidth
|
||||
{...conform.input(slug)}
|
||||
placeholder={`e.g. ${integration.identifier}`}
|
||||
/>
|
||||
<Hint>
|
||||
This is used in your code to reference this connection. It must be
|
||||
unique for this project.
|
||||
</Hint>
|
||||
<FormError>{slug.error}</FormError>
|
||||
</InputGroup>
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="large">Name</Label>
|
||||
<Input
|
||||
@@ -199,7 +220,7 @@ export function ConnectToOAuthForm({
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
/>
|
||||
<div className="flex flex-col gap-y-0.5 overflow-hidden rounded-md">
|
||||
<div className="mb-28 flex flex-col gap-y-0.5 overflow-hidden rounded-md">
|
||||
{filteredItems.length === 0 && (
|
||||
<Paragraph variant="small" className="p-4">
|
||||
No scopes match {filterText}. Try a different search query.
|
||||
@@ -240,18 +261,16 @@ export function ConnectToOAuthForm({
|
||||
</div>
|
||||
</Fieldset>
|
||||
|
||||
<div className="flex items-center justify-end gap-x-4">
|
||||
<div className="absolute bottom-0 left-0 flex w-full items-center justify-end gap-x-4 rounded-b-md border-t border-slate-800 bg-midnight-900 p-4">
|
||||
<FormError>{scopes.error}</FormError>
|
||||
<Button
|
||||
type="submit"
|
||||
className="flex gap-2"
|
||||
disabled={transition.state !== "idle"}
|
||||
variant="primary/medium"
|
||||
LeadingIcon={integration.identifier}
|
||||
>
|
||||
<>
|
||||
<NamedIcon name={integration.identifier} className={"h-4 w-4"} />
|
||||
Connect to {integration.name}
|
||||
</>
|
||||
Connect to {integration.name}
|
||||
</Button>
|
||||
</div>
|
||||
</fetcher.Form>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Integration } from "~/services/externalApis/types";
|
||||
import { InlineCode } from "../code/InlineCode";
|
||||
import {
|
||||
ClientTabs,
|
||||
ClientTabsList,
|
||||
ClientTabsTrigger,
|
||||
ClientTabsContent,
|
||||
} from "../primitives/ClientTabs";
|
||||
import { ClipboardField } from "../primitives/ClipboardField";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
|
||||
export function HelpInstall({ packageName }: { packageName: string }) {
|
||||
return (
|
||||
<>
|
||||
<ClientTabs defaultValue="npm">
|
||||
<ClientTabsList>
|
||||
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"yarn"}>yarn</ClientTabsTrigger>
|
||||
</ClientTabsList>
|
||||
<ClientTabsContent value={"npm"}>
|
||||
<ClipboardField
|
||||
variant="secondary/medium"
|
||||
value={`npm install ${packageName}`}
|
||||
className="mb-4"
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"pnpm"}>
|
||||
<ClipboardField
|
||||
variant="secondary/medium"
|
||||
value={`pnpm install ${packageName}`}
|
||||
className="mb-4"
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"yarn"}>
|
||||
<ClipboardField
|
||||
variant="secondary/medium"
|
||||
value={`yarn add ${packageName}`}
|
||||
className="mb-4"
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
</ClientTabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Integration } from "~/services/externalApis/types";
|
||||
import { HelpPanelIntegration, HelpPanelProps } from "./ApiKeyHelp";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
|
||||
export type ReplacementData = {
|
||||
slug: string;
|
||||
};
|
||||
|
||||
export function HelpSamples({
|
||||
help,
|
||||
integrationClient,
|
||||
integration,
|
||||
}: HelpPanelProps) {
|
||||
return (
|
||||
<>
|
||||
{help &&
|
||||
help.samples.map((sample, i) => {
|
||||
const code = runReplacers(
|
||||
sample.code,
|
||||
integrationClient,
|
||||
integration
|
||||
);
|
||||
return (
|
||||
<div key={i}>
|
||||
<Paragraph spacing>{sample.title}</Paragraph>
|
||||
<CodeBlock
|
||||
code={code}
|
||||
className="mb-4"
|
||||
highlightedRanges={sample.highlight}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const replacements = [
|
||||
{
|
||||
match: /__SLUG__/g,
|
||||
replacement: (
|
||||
data: ReplacementData | undefined,
|
||||
integration: HelpPanelIntegration
|
||||
) => {
|
||||
if (data) return data.slug;
|
||||
return integration.identifier;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function runReplacers(
|
||||
code: string,
|
||||
replacementData: ReplacementData | undefined,
|
||||
integration: HelpPanelIntegration
|
||||
) {
|
||||
replacements.forEach((r) => {
|
||||
code = code.replace(r.match, r.replacement(replacementData, integration));
|
||||
});
|
||||
|
||||
return code;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { docsIntegrationPath } from "~/utils/pathBuilder";
|
||||
import { LinkButton } from "../primitives/Buttons";
|
||||
import { Header1 } from "../primitives/Headers";
|
||||
import { NamedIconInBox } from "../primitives/NamedIcon";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import {
|
||||
Sheet,
|
||||
SheetBody,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTrigger,
|
||||
} from "../primitives/Sheet";
|
||||
import { SelectOAuthMethod } from "./SelectOAuthMethod";
|
||||
import { Integration } from "~/services/externalApis/types";
|
||||
import { Client } from "~/presenters/IntegrationsPresenter.server";
|
||||
|
||||
export function IntegrationWithMissingFieldSheet({
|
||||
integration,
|
||||
organizationId,
|
||||
button,
|
||||
callbackUrl,
|
||||
existingIntegration,
|
||||
className,
|
||||
}: {
|
||||
integration: Integration;
|
||||
organizationId: string;
|
||||
button: React.ReactNode;
|
||||
callbackUrl: string;
|
||||
existingIntegration: Client;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<Sheet>
|
||||
<SheetTrigger className={className}>{button}</SheetTrigger>
|
||||
<SheetContent size="lg" className="relative">
|
||||
<SheetHeader>
|
||||
<NamedIconInBox name={integration.identifier} className="h-9 w-9" />
|
||||
<div className="grow">
|
||||
<Header1>{integration.name}</Header1>
|
||||
{integration.description && (
|
||||
<Paragraph variant="small">{integration.description}</Paragraph>
|
||||
)}
|
||||
</div>
|
||||
<LinkButton
|
||||
to={docsIntegrationPath(integration.identifier)}
|
||||
variant="secondary/small"
|
||||
LeadingIcon="docs"
|
||||
>
|
||||
View docs
|
||||
</LinkButton>
|
||||
</SheetHeader>
|
||||
<SheetBody>
|
||||
<SelectOAuthMethod
|
||||
integration={integration}
|
||||
organizationId={organizationId}
|
||||
callbackUrl={callbackUrl}
|
||||
existingIntegration={existingIntegration}
|
||||
/>
|
||||
</SheetBody>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export function NoIntegrationSheet({
|
||||
<div className="flex items-center gap-1">
|
||||
<CheckIcon className="h-4 w-4 text-green-500" />
|
||||
<Paragraph variant="small">
|
||||
We'll let you know when the integration is available.
|
||||
We'll let you know when the Integration is available.
|
||||
</Paragraph>
|
||||
</div>
|
||||
) : (
|
||||
@@ -56,16 +56,16 @@ export function NoIntegrationSheet({
|
||||
>
|
||||
{isLoading
|
||||
? "Saving…"
|
||||
: `I want an integration for ${api.name}`}
|
||||
: `I want an Integration for ${api.name}`}
|
||||
</Button>
|
||||
</fetcher.Form>
|
||||
)}
|
||||
</SheetHeader>
|
||||
<SheetBody>
|
||||
<Callout variant="info">
|
||||
We don’t have an integration for the {api.name} API yet but you can
|
||||
We don’t have an Integration for the {api.name} API yet but you can
|
||||
request one by clicking the button above. In the meantime, connect
|
||||
to {api.name} using the methods below.
|
||||
to {api.name} using one of the methods below.
|
||||
</Callout>
|
||||
<CustomHelp name={api.name} />
|
||||
</SheetBody>
|
||||
|
||||
@@ -8,12 +8,16 @@ import type { ConnectionType } from "@trigger.dev/database";
|
||||
import { Header2 } from "../primitives/Headers";
|
||||
import { ConnectToOAuthForm } from "./ConnectToOAuthForm";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { Client } from "~/presenters/IntegrationsPresenter.server";
|
||||
import { UpdateOAuthForm } from "./UpdateOAuthForm";
|
||||
|
||||
export function SelectOAuthMethod({
|
||||
integration,
|
||||
organizationId,
|
||||
callbackUrl
|
||||
callbackUrl,
|
||||
existingIntegration,
|
||||
}: {
|
||||
existingIntegration?: Client;
|
||||
integration: Integration;
|
||||
organizationId: string;
|
||||
callbackUrl: string;
|
||||
@@ -91,14 +95,26 @@ export function SelectOAuthMethod({
|
||||
connectionType &&
|
||||
oAuthKey &&
|
||||
(connectionType === "DEVELOPER" ? (
|
||||
<ConnectToOAuthForm
|
||||
integration={integration}
|
||||
authMethod={selectedOAuthMethod}
|
||||
authMethodKey={oAuthKey}
|
||||
organizationId={organizationId}
|
||||
clientType={connectionType}
|
||||
callbackUrl={callbackUrl}
|
||||
/>
|
||||
existingIntegration ? (
|
||||
<UpdateOAuthForm
|
||||
existingIntegration={existingIntegration}
|
||||
integration={integration}
|
||||
authMethod={selectedOAuthMethod}
|
||||
authMethodKey={oAuthKey}
|
||||
organizationId={organizationId}
|
||||
clientType={connectionType}
|
||||
callbackUrl={callbackUrl}
|
||||
/>
|
||||
) : (
|
||||
<ConnectToOAuthForm
|
||||
integration={integration}
|
||||
authMethod={selectedOAuthMethod}
|
||||
authMethodKey={oAuthKey}
|
||||
organizationId={organizationId}
|
||||
clientType={connectionType}
|
||||
callbackUrl={callbackUrl}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
<Header2 className="mb-1 mt-4">User OAuth coming soon</Header2>
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import { conform, useForm } from "@conform-to/react";
|
||||
import { parse } from "@conform-to/zod";
|
||||
import { useFetcher, useLocation, useNavigation } from "@remix-run/react";
|
||||
import type { ConnectionType } from "@trigger.dev/database";
|
||||
import { useState } from "react";
|
||||
import simplur from "simplur";
|
||||
import { useFeatures } from "~/hooks/useFeatures";
|
||||
import { useTextFilter } from "~/hooks/useTextFilter";
|
||||
import {
|
||||
ApiAuthenticationMethodOAuth2,
|
||||
Integration,
|
||||
Scope,
|
||||
} from "~/services/externalApis/types";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { CodeBlock } from "../code/CodeBlock";
|
||||
import { Button } from "../primitives/Buttons";
|
||||
import { Checkbox } from "../primitives/Checkbox";
|
||||
import { Fieldset } from "../primitives/Fieldset";
|
||||
import { FormError } from "../primitives/FormError";
|
||||
import { Header2, Header3 } from "../primitives/Headers";
|
||||
import { Input } from "../primitives/Input";
|
||||
import { InputGroup } from "../primitives/InputGroup";
|
||||
import { Label } from "../primitives/Label";
|
||||
import { Paragraph } from "../primitives/Paragraph";
|
||||
import { Client } from "~/presenters/IntegrationsPresenter.server";
|
||||
import { schema } from "~/routes/resources.connection.$organizationId.oauth2.$integrationId";
|
||||
|
||||
export type Status = "loading" | "idle";
|
||||
|
||||
export function UpdateOAuthForm({
|
||||
existingIntegration,
|
||||
integration,
|
||||
authMethod,
|
||||
authMethodKey,
|
||||
organizationId,
|
||||
clientType,
|
||||
callbackUrl,
|
||||
}: {
|
||||
existingIntegration: Client;
|
||||
integration: Integration;
|
||||
authMethod: ApiAuthenticationMethodOAuth2;
|
||||
authMethodKey: string;
|
||||
organizationId: string;
|
||||
clientType: ConnectionType;
|
||||
callbackUrl: string;
|
||||
}) {
|
||||
const transition = useNavigation();
|
||||
const fetcher = useFetcher();
|
||||
const { isManagedCloud } = useFeatures();
|
||||
|
||||
const [
|
||||
form,
|
||||
{ title, scopes, hasCustomClient, customClientId, customClientSecret },
|
||||
] = useForm({
|
||||
lastSubmission: fetcher.data,
|
||||
onValidate({ formData }) {
|
||||
return parse(formData, {
|
||||
schema,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
const [selectedScopes, setSelectedScopes] = useState<Set<string>>(
|
||||
new Set(
|
||||
authMethod.scopes.filter((s) => s.defaultChecked).map((s) => s.name)
|
||||
)
|
||||
);
|
||||
|
||||
const requiresCustomOAuthApp = clientType === "EXTERNAL" || !isManagedCloud;
|
||||
|
||||
const [useMyOAuthApp, setUseMyOAuthApp] = useState(requiresCustomOAuthApp);
|
||||
|
||||
const { filterText, setFilterText, filteredItems } = useTextFilter<Scope>({
|
||||
items: authMethod.scopes,
|
||||
filter: (scope, text) => {
|
||||
if (scope.name.toLowerCase().includes(text.toLowerCase())) return true;
|
||||
if (
|
||||
scope.description &&
|
||||
scope.description.toLowerCase().includes(text.toLowerCase())
|
||||
)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<fetcher.Form
|
||||
method="put"
|
||||
action={`/resources/connection/${organizationId}/oauth2/${existingIntegration.id}`}
|
||||
{...form.props}
|
||||
className="flex h-full max-h-full flex-grow flex-col"
|
||||
>
|
||||
<Fieldset>
|
||||
<input type="hidden" name="id" value={existingIntegration.id} />
|
||||
<input
|
||||
type="hidden"
|
||||
name="integrationIdentifier"
|
||||
value={integration.identifier}
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
name="integrationAuthMethod"
|
||||
value={authMethodKey}
|
||||
/>
|
||||
<input type="hidden" name="redirectTo" value={location.pathname} />
|
||||
<InputGroup>
|
||||
<FormError>{form.error}</FormError>
|
||||
</InputGroup>
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="large">ID</Label>
|
||||
<Paragraph variant="small" className="mb-2">
|
||||
{existingIntegration.slug}
|
||||
</Paragraph>
|
||||
</InputGroup>
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="large">Name</Label>
|
||||
<Input
|
||||
type="text"
|
||||
fullWidth
|
||||
{...conform.input(title)}
|
||||
defaultValue={existingIntegration.title ?? undefined}
|
||||
placeholder={`e.g. Personal ${integration.name}`}
|
||||
/>
|
||||
<FormError>{title.error}</FormError>
|
||||
</InputGroup>
|
||||
<input type="hidden" name="clientType" value={clientType} />
|
||||
<div>
|
||||
<Header2>Use my OAuth App</Header2>
|
||||
<Paragraph variant="small" className="mb-2">
|
||||
To use your own OAuth app, check the option below and insert the
|
||||
details.
|
||||
</Paragraph>
|
||||
<Checkbox
|
||||
id="hasCustomClient"
|
||||
label="Use my OAuth App"
|
||||
variant="simple/small"
|
||||
disabled={requiresCustomOAuthApp}
|
||||
onChange={(checked) => setUseMyOAuthApp(checked)}
|
||||
{...conform.input(hasCustomClient, { type: "checkbox" })}
|
||||
defaultChecked={requiresCustomOAuthApp}
|
||||
/>
|
||||
{useMyOAuthApp && (
|
||||
<div className="ml-6 mt-2">
|
||||
<Paragraph variant="small" className="mb-2">
|
||||
Set the callback url to{" "}
|
||||
<CodeBlock code={callbackUrl} showLineNumbers={false} />
|
||||
</Paragraph>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex gap-2">
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="small">Client ID</Label>
|
||||
<Input
|
||||
fullWidth
|
||||
{...conform.input(customClientId, { type: "text" })}
|
||||
/>
|
||||
</InputGroup>
|
||||
<InputGroup fullWidth>
|
||||
<Label variant="small">Client secret</Label>
|
||||
<Input
|
||||
fullWidth
|
||||
{...conform.input(customClientSecret, {
|
||||
type: "password",
|
||||
})}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<FormError>{customClientId.error}</FormError>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Header2>Scopes</Header2>
|
||||
<Paragraph variant="small" className="mb-4">
|
||||
Select the scopes you want to grant to {integration.name} in order
|
||||
for it to access your data. Note: If you try and perform an action
|
||||
in a Job that requires a scope you haven’t granted, that task will
|
||||
fail.
|
||||
</Paragraph>
|
||||
{/* <Header3 className="mb-2">
|
||||
Select from popular scope collections
|
||||
</Header3>
|
||||
<fieldset>
|
||||
<Checkbox
|
||||
id="allScopes"
|
||||
label="Select all"
|
||||
variant="button/small"
|
||||
/>
|
||||
</fieldset> */}
|
||||
<div className="mb-2 mt-4 flex items-center justify-between">
|
||||
<Header3>Select {integration.name} scopes</Header3>
|
||||
<Paragraph variant="small" className="text-slate-500">
|
||||
{simplur`${selectedScopes.size} scope[|s] selected`}
|
||||
</Paragraph>
|
||||
</div>
|
||||
<Input
|
||||
placeholder="Search scopes"
|
||||
className="mb-2"
|
||||
variant="medium"
|
||||
icon="search"
|
||||
fullWidth={true}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
/>
|
||||
<div className="mb-28 flex flex-col gap-y-0.5 overflow-hidden rounded-md">
|
||||
{filteredItems.length === 0 && (
|
||||
<Paragraph variant="small" className="p-4">
|
||||
No scopes match {filterText}. Try a different search query.
|
||||
</Paragraph>
|
||||
)}
|
||||
{authMethod.scopes.map((s) => {
|
||||
return (
|
||||
<Checkbox
|
||||
key={s.name}
|
||||
id={s.name}
|
||||
value={s.name}
|
||||
name="scopes"
|
||||
label={s.name}
|
||||
defaultChecked={s.defaultChecked ?? false}
|
||||
badges={s.annotations?.map((a) => a.label)}
|
||||
description={s.description}
|
||||
variant="description"
|
||||
className={cn(
|
||||
filteredItems.find((f) => f.name === s.name) ? "" : "hidden"
|
||||
)}
|
||||
onChange={(isChecked) => {
|
||||
if (isChecked) {
|
||||
setSelectedScopes((selected) => {
|
||||
selected.add(s.name);
|
||||
return new Set(selected);
|
||||
});
|
||||
} else {
|
||||
setSelectedScopes((selected) => {
|
||||
selected.delete(s.name);
|
||||
return new Set(selected);
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Fieldset>
|
||||
|
||||
<div className="absolute bottom-0 left-0 flex w-full items-center justify-end gap-x-4 rounded-b-md border-t border-slate-800 bg-midnight-900 p-4">
|
||||
<FormError>{scopes.error}</FormError>
|
||||
<Button
|
||||
type="submit"
|
||||
className="flex gap-2"
|
||||
disabled={transition.state !== "idle"}
|
||||
variant="primary/medium"
|
||||
LeadingIcon={integration.identifier}
|
||||
>
|
||||
Connect to {integration.name}
|
||||
</Button>
|
||||
</div>
|
||||
</fetcher.Form>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import { runStatusTitle } from "../runs/RunStatuses";
|
||||
import { ProjectJob, useProject } from "~/hooks/useProject";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { JobRunStatus } from "~/models/job.server";
|
||||
import { cn } from "~/utils/cn";
|
||||
|
||||
export function JobsTable({
|
||||
jobs,
|
||||
@@ -46,7 +47,12 @@ export function JobsTable({
|
||||
jobs.map((job) => {
|
||||
const path = jobPath(organization, project, job);
|
||||
return (
|
||||
<TableRow key={job.id}>
|
||||
<TableRow
|
||||
key={job.id}
|
||||
className={cn(
|
||||
job.hasIntegrationsRequiringAction && "bg-rose-500/30"
|
||||
)}
|
||||
>
|
||||
<TableCell to={path}>
|
||||
<span className="flex items-center gap-2">
|
||||
<NamedIcon name={job.event.icon} className="h-8 w-8" />
|
||||
@@ -79,12 +85,30 @@ export function JobsTable({
|
||||
<SimpleTooltip
|
||||
key={integration.key}
|
||||
button={
|
||||
<NamedIcon
|
||||
name={integration.icon}
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
<div className="relative">
|
||||
<NamedIcon
|
||||
name={integration.icon}
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
{integration.setupStatus === "MISSING_FIELDS" && (
|
||||
<NamedIcon
|
||||
name="error"
|
||||
className="absolute -left-1 -top-1 h-4 w-4"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
content={
|
||||
<div>
|
||||
<p className="mb-1 text-rose-400">
|
||||
{integration.setupStatus === "MISSING_FIELDS" &&
|
||||
"This integration requires configuration"}
|
||||
</p>
|
||||
<p>
|
||||
{integration.title}: {integration.key}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
content={`${integration.title}: ${integration.key}`}
|
||||
/>
|
||||
))}
|
||||
</TableCell>
|
||||
@@ -126,10 +150,9 @@ export function JobsTable({
|
||||
</span>
|
||||
}
|
||||
value={
|
||||
<DateTime
|
||||
date={job.lastRun.createdAt}
|
||||
className={classForJobStatus(job.lastRun.status)}
|
||||
/>
|
||||
<span className={classForJobStatus(job.lastRun.status)}>
|
||||
<DateTime date={job.lastRun.createdAt} />
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -102,73 +102,77 @@ function BreadcrumbItem({
|
||||
case "projects":
|
||||
return <ProjectsMenu key={breadcrumb.slug} />;
|
||||
case "jobs":
|
||||
if (!organization || !project) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
key={breadcrumb.slug}
|
||||
to={projectPath(organization!, project!)}
|
||||
to={projectPath(organization, project)}
|
||||
title="Jobs"
|
||||
/>
|
||||
);
|
||||
case "environments":
|
||||
if (!organization || !project) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
key={breadcrumb.slug}
|
||||
to={projectEnvironmentsPath(organization!, project!)}
|
||||
to={projectEnvironmentsPath(organization, project)}
|
||||
title="Environments"
|
||||
/>
|
||||
);
|
||||
case "integrations":
|
||||
if (!organization || !project) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
key={breadcrumb.slug}
|
||||
to={projectIntegrationsPath(organization!, project!)}
|
||||
to={projectIntegrationsPath(organization, project)}
|
||||
title="Integrations"
|
||||
/>
|
||||
);
|
||||
case "integration":
|
||||
if (!organization || !project || !client) return null;
|
||||
return (
|
||||
<Fragment key={breadcrumb.slug}>
|
||||
<BreadcrumbLink
|
||||
to={projectIntegrationsPath(organization!, project!)}
|
||||
to={projectIntegrationsPath(organization, project)}
|
||||
title="Integrations"
|
||||
/>
|
||||
<BreadcrumbIcon />
|
||||
<BreadcrumbLink
|
||||
to={integrationClientPath(organization!, project!, client!)}
|
||||
title={client!.title}
|
||||
to={integrationClientPath(organization, project, client)}
|
||||
title={client.title}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case "integration-job":
|
||||
if (!organization || !project || !client) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
to={integrationClientPath(organization!, project!, client!)}
|
||||
to={integrationClientPath(organization, project, client)}
|
||||
title={"Jobs"}
|
||||
/>
|
||||
);
|
||||
case "integration-connections":
|
||||
if (!organization || !project || !client) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
to={integrationClientConnectionsPath(
|
||||
organization!,
|
||||
project!,
|
||||
client!
|
||||
)}
|
||||
to={integrationClientConnectionsPath(organization, project, client)}
|
||||
title={"Connections"}
|
||||
/>
|
||||
);
|
||||
case "integration-scopes":
|
||||
if (!organization || !project || !client) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
to={integrationClientScopesPath(organization!, project!, client!)}
|
||||
to={integrationClientScopesPath(organization, project, client)}
|
||||
title={"Scopes"}
|
||||
/>
|
||||
);
|
||||
case "job":
|
||||
if (!organization || !project || !job) return null;
|
||||
return (
|
||||
<Fragment key={breadcrumb.slug}>
|
||||
<BreadcrumbLink
|
||||
to={projectPath(organization!, project!)}
|
||||
to={projectPath(organization, project)}
|
||||
title="Jobs"
|
||||
/>
|
||||
<BreadcrumbIcon />
|
||||
@@ -176,32 +180,35 @@ function BreadcrumbItem({
|
||||
</Fragment>
|
||||
);
|
||||
case "test":
|
||||
if (!organization || !project || !job) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
key={breadcrumb.slug}
|
||||
to={jobTestPath(organization!, project!, job!)}
|
||||
to={jobTestPath(organization, project, job)}
|
||||
title="Test"
|
||||
/>
|
||||
);
|
||||
case "runs":
|
||||
if (!organization || !project || !job) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
key={breadcrumb.slug}
|
||||
to={jobPath(organization!, project!, job!)}
|
||||
to={jobPath(organization, project, job)}
|
||||
title="Runs"
|
||||
/>
|
||||
);
|
||||
case "run":
|
||||
if (!organization || !project || !job || !run) return null;
|
||||
return (
|
||||
<Fragment key={breadcrumb.slug}>
|
||||
<BreadcrumbLink
|
||||
to={jobPath(organization!, project!, job!)}
|
||||
to={jobPath(organization, project, job)}
|
||||
title="Runs"
|
||||
/>
|
||||
<BreadcrumbIcon />
|
||||
<BreadcrumbLink
|
||||
to={runDashboardPath(organization!, project!, job!, run!)}
|
||||
title={`Run #${run!.number}`}
|
||||
to={runDashboardPath(organization, project, job, run)}
|
||||
title={`Run #${run.number}`}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { Link } from "@remix-run/react";
|
||||
import { useState } from "react";
|
||||
import { useJob } from "~/hooks/useJob";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { jobPath } from "~/utils/pathBuilder";
|
||||
import { IconNames, NamedIcon } from "../primitives/NamedIcon";
|
||||
import { LabelValueStack } from "../primitives/LabelValueStack";
|
||||
import { NamedIcon } from "../primitives/NamedIcon";
|
||||
import {
|
||||
Popover,
|
||||
PopoverArrowTrigger,
|
||||
PopoverContent,
|
||||
PopoverMenuItem,
|
||||
PopoverSectionHeader,
|
||||
} from "../primitives/Popover";
|
||||
import { LabelValueStack } from "../primitives/LabelValueStack";
|
||||
import { LinkButton } from "../primitives/Buttons";
|
||||
import { Link } from "@remix-run/react";
|
||||
import { cn } from "~/utils/cn";
|
||||
|
||||
export function JobsMenu() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -29,7 +27,7 @@ export function JobsMenu() {
|
||||
{currentJob?.title ?? "Select a job"}
|
||||
</PopoverArrowTrigger>
|
||||
<PopoverContent
|
||||
className="w-80 overflow-y-auto p-0"
|
||||
className="min-w-[20rem] overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-700"
|
||||
align="start"
|
||||
collisionPadding={20}
|
||||
>
|
||||
@@ -42,11 +40,11 @@ export function JobsMenu() {
|
||||
key={job.id}
|
||||
to={jobPath(organization, project, job)}
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md p-2",
|
||||
"flex w-full items-center gap-2 rounded-md p-2 transition hover:bg-slate-800",
|
||||
isSelected && "bg-slate-750 group-hover:bg-slate-750"
|
||||
)}
|
||||
>
|
||||
<NamedIcon name={job.event.icon} className="h-6 w-6" />
|
||||
<NamedIcon name={job.event.icon} className="h-8 w-8" />
|
||||
<LabelValueStack
|
||||
label={job.title}
|
||||
value={job.slug}
|
||||
|
||||
@@ -7,10 +7,11 @@ import { Feedback } from "../Feedback";
|
||||
import { LogoIcon } from "../LogoIcon";
|
||||
import { LinkButton } from "../primitives/Buttons";
|
||||
import { Breadcrumb } from "./Breadcrumb";
|
||||
import { docsRoot } from "~/utils/pathBuilder";
|
||||
|
||||
export function NavBar() {
|
||||
return (
|
||||
<div className="z-50 flex w-full items-center justify-between gap-2 border-b border-divide py-1 pl-2 pr-2.5">
|
||||
<div className="z-50 flex w-full items-center justify-between gap-2 border-b border-divide py-1 pl-1 pr-2.5">
|
||||
<div className="flex gap-0.5">
|
||||
<Link to="/" className="p-2">
|
||||
<LogoIcon className="h-5 w-5" />
|
||||
@@ -20,7 +21,7 @@ export function NavBar() {
|
||||
</div>
|
||||
<div className="hidden items-center gap-2 sm:flex">
|
||||
<LinkButton
|
||||
to="https://docs.trigger.dev"
|
||||
to={docsRoot()}
|
||||
variant="secondary/small"
|
||||
LeadingIcon={BookOpenIcon}
|
||||
>
|
||||
@@ -75,7 +76,7 @@ function MobileDropdownMenu() {
|
||||
className="absolute inset-x-6 top-0 mt-20 flex origin-top flex-col gap-4 rounded-md bg-slate-800 p-4 text-lg tracking-tight text-slate-900 shadow-xl ring-1 ring-slate-700"
|
||||
>
|
||||
{/* <PrimaryA
|
||||
href="https://docs.trigger.dev"
|
||||
href={docsRoot()}
|
||||
target="_blank"
|
||||
className="max-w-full"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMatches } from "@remix-run/react";
|
||||
import { motion } from "framer-motion";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useJob, useOptionalJob } from "~/hooks/useJob";
|
||||
import { useOptionalIntegrationClient } from "~/hooks/useIntegrationClient";
|
||||
import { useOptionalJob } from "~/hooks/useJob";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { cn } from "~/utils/cn";
|
||||
@@ -13,11 +13,10 @@ import {
|
||||
projectIntegrationsPath,
|
||||
projectPath,
|
||||
} from "~/utils/pathBuilder";
|
||||
import { UserProfilePhoto } from "../UserProfilePhoto";
|
||||
import { NavLinkButton } from "../primitives/Buttons";
|
||||
import type { IconNames } from "../primitives/NamedIcon";
|
||||
import { SimpleTooltip } from "../primitives/Tooltip";
|
||||
import { UserProfilePhoto } from "../UserProfilePhoto";
|
||||
import { useOptionalIntegrationClient } from "~/hooks/useIntegrationClient";
|
||||
|
||||
export function SideMenuContainer({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
@@ -72,18 +71,21 @@ export function ProjectSideMenu() {
|
||||
to={projectPath(organization, project)}
|
||||
isCollapsed={isCollapsed}
|
||||
forceActive={jobsActive}
|
||||
data-action="jobs"
|
||||
/>
|
||||
<SideMenuItem
|
||||
name="Integrations"
|
||||
icon="integration"
|
||||
to={projectIntegrationsPath(organization, project)}
|
||||
isCollapsed={isCollapsed}
|
||||
data-action="integrations"
|
||||
/>
|
||||
<SideMenuItem
|
||||
name="Environments & API Keys"
|
||||
icon="environment"
|
||||
to={projectEnvironmentsPath(organization, project)}
|
||||
isCollapsed={isCollapsed}
|
||||
data-action="environments & api keys"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
@@ -92,18 +94,21 @@ export function ProjectSideMenu() {
|
||||
icon="team"
|
||||
to={organizationTeamPath(organization)}
|
||||
isCollapsed={isCollapsed}
|
||||
data-action="team"
|
||||
/>
|
||||
<SideMenuItem
|
||||
name="Usage & Billing"
|
||||
icon="billing"
|
||||
to={organizationBillingPath(organization)}
|
||||
isCollapsed={isCollapsed}
|
||||
data-action="usage & billing"
|
||||
/>
|
||||
<SideMenuItem
|
||||
name="Account"
|
||||
icon={UserProfilePhoto}
|
||||
to={accountPath()}
|
||||
isCollapsed={isCollapsed}
|
||||
data-action="account"
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
useIsNewOrganizationPage,
|
||||
useOrganizations,
|
||||
} from "~/hooks/useOrganizations";
|
||||
import { useOptionalProject, useProject } from "~/hooks/useProject";
|
||||
import { useOptionalProject } from "~/hooks/useProject";
|
||||
import {
|
||||
newOrganizationPath,
|
||||
newProjectPath,
|
||||
@@ -33,11 +33,15 @@ export function ProjectsMenu() {
|
||||
<PopoverArrowTrigger isOpen={isOpen}>
|
||||
{currentProject?.name ?? "Select a project"}
|
||||
</PopoverArrowTrigger>
|
||||
<PopoverContent className="w-80 p-0" align="start">
|
||||
<PopoverContent
|
||||
className="min-w-[20rem] overflow-y-auto p-0 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-700"
|
||||
align="start"
|
||||
collisionPadding={20}
|
||||
>
|
||||
{organizations.map((organization) => (
|
||||
<Fragment key={organization.id}>
|
||||
<PopoverSectionHeader title={organization.title} />
|
||||
<div className="flex flex-col gap-1 p-1">
|
||||
<div className="flex flex-col gap-1 p-1 ">
|
||||
{organization.projects.map((project) => {
|
||||
const isSelected = project.id === currentProject?.id;
|
||||
return (
|
||||
|
||||
@@ -4,39 +4,56 @@ import {
|
||||
InformationCircleIcon,
|
||||
LightBulbIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
BookOpenIcon,
|
||||
CheckCircleIcon,
|
||||
ChevronRightIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { Link } from "@remix-run/react";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { Paragraph } from "./Paragraph";
|
||||
import { CheckCircleIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
const variantClasses = {
|
||||
export const variantClasses = {
|
||||
info: {
|
||||
className: "border-blue-400/20 bg-blue-400/30",
|
||||
icon: <InformationCircleIcon className="h-5 w-5 shrink-0 text-blue-400" />,
|
||||
text: "text-blue-200",
|
||||
textColor: "text-blue-200",
|
||||
linkClassName: "transition hover:bg-blue-400/40",
|
||||
},
|
||||
warning: {
|
||||
className: "border-yellow-400/20 bg-yellow-400/30",
|
||||
icon: (
|
||||
<ExclamationCircleIcon className="h-5 w-5 shrink-0 text-yellow-400" />
|
||||
),
|
||||
text: "text-yellow-200",
|
||||
textColor: "text-yellow-200",
|
||||
linkClassName: "transition hover:bg-yellow-400/40",
|
||||
},
|
||||
error: {
|
||||
className: "border-[hsl(347,77%,50%)]/30 bg-[hsl(347,77%,50%)]/20",
|
||||
className: "border-rose-500/20 bg-rose-500/30",
|
||||
icon: (
|
||||
<ExclamationTriangleIcon className="h-5 w-5 shrink-0 text-rose-400" />
|
||||
),
|
||||
text: "text-rose-200",
|
||||
textColor: "text-rose-200",
|
||||
linkClassName: "transition hover:bg-rose-500/40",
|
||||
},
|
||||
idea: {
|
||||
className: "border-green-400/20 bg-green-400/30",
|
||||
icon: <LightBulbIcon className="h-5 w-5 shrink-0 text-green-400" />,
|
||||
text: "text-green-200",
|
||||
textColor: "text-green-200",
|
||||
linkClassName: "transition hover:bg-green-400/40",
|
||||
},
|
||||
success: {
|
||||
className: "border-green-400/20 bg-green-400/30",
|
||||
icon: <CheckCircleIcon className="h-5 w-5 shrink-0 text-green-400" />,
|
||||
text: "text-green-200",
|
||||
textColor: "text-green-200",
|
||||
linkClassName: "transition hover:bg-green-400/40",
|
||||
},
|
||||
docs: {
|
||||
className: "border-blue-400/20 bg-blue-400/30",
|
||||
icon: <BookOpenIcon className="mt-0.5 h-5 w-5 shrink-0 text-blue-400" />,
|
||||
textColor: "text-blue-200",
|
||||
linkClassName: "transition hover:bg-blue-400/40",
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -45,14 +62,81 @@ export function Callout({
|
||||
className,
|
||||
icon,
|
||||
variant,
|
||||
to,
|
||||
}: {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
icon?: React.ReactNode;
|
||||
variant: keyof typeof variantClasses;
|
||||
to?: string;
|
||||
}) {
|
||||
const variantDefinition = variantClasses[variant];
|
||||
|
||||
if (to !== undefined) {
|
||||
if (to.startsWith("http")) {
|
||||
return (
|
||||
<a
|
||||
href={to}
|
||||
target="_blank"
|
||||
className={cn(
|
||||
`flex w-full items-start justify-between gap-2.5 rounded-md border py-2 pl-2 pr-3 shadow-md backdrop-blur-sm`,
|
||||
variantDefinition.className,
|
||||
variantDefinition.linkClassName,
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className={"flex w-full items-start gap-x-2"}>
|
||||
{icon ? icon : variantDefinition.icon}
|
||||
|
||||
{typeof children === "string" ? (
|
||||
<Paragraph
|
||||
variant={"small"}
|
||||
className={variantDefinition.textColor}
|
||||
>
|
||||
{children}
|
||||
</Paragraph>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
<ArrowTopRightOnSquareIcon
|
||||
className={cn("h-5 w-5", variantDefinition.textColor)}
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Link
|
||||
to={to}
|
||||
className={cn(
|
||||
`flex w-full items-start justify-between gap-2.5 rounded-md border py-2 pl-2 pr-3 shadow-md backdrop-blur-sm`,
|
||||
variantDefinition.className,
|
||||
variantDefinition.linkClassName,
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className={"flex w-full items-start gap-x-2"}>
|
||||
{icon ? icon : variantDefinition.icon}
|
||||
|
||||
{typeof children === "string" ? (
|
||||
<Paragraph
|
||||
variant={"small"}
|
||||
className={variantDefinition.textColor}
|
||||
>
|
||||
{children}
|
||||
</Paragraph>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
<ChevronRightIcon
|
||||
className={cn("h-5 w-5", variantDefinition.textColor)}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -64,7 +148,7 @@ export function Callout({
|
||||
{icon ? icon : variantDefinition.icon}
|
||||
|
||||
{typeof children === "string" ? (
|
||||
<Paragraph variant={"small"} className={variantDefinition.text}>
|
||||
<Paragraph variant={"small"} className={variantDefinition.textColor}>
|
||||
{children}
|
||||
</Paragraph>
|
||||
) : (
|
||||
|
||||
@@ -13,7 +13,7 @@ const ClientTabsList = React.forwardRef<
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||
"inline-flex items-center justify-center transition duration-100",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -28,7 +28,7 @@ const ClientTabsTrigger = React.forwardRef<
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
"inline-flex items-center justify-center whitespace-nowrap border-r border-slate-700 px-2 text-sm ring-offset-background transition-all first:pl-0 last:border-none data-[state=active]:text-indigo-500 data-[state=inactive]:text-dimmed data-[state=inactive]:hover:text-bright focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -43,7 +43,7 @@ const ClientTabsContent = React.forwardRef<
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
"mt-1 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -69,10 +69,11 @@ const variations = {
|
||||
|
||||
type ClipboardFieldProps = {
|
||||
value: string;
|
||||
secure?: boolean;
|
||||
secure?: boolean | string;
|
||||
variant: keyof typeof variations;
|
||||
className?: string;
|
||||
icon?: IconNames | React.ReactNode;
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export function ClipboardField({
|
||||
@@ -81,8 +82,9 @@ export function ClipboardField({
|
||||
variant,
|
||||
className,
|
||||
icon,
|
||||
fullWidth = true,
|
||||
}: ClipboardFieldProps) {
|
||||
const [isSecure, setIsSecure] = useState(secure);
|
||||
const [isSecure, setIsSecure] = useState(secure !== undefined && secure);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const copy = useCallback(
|
||||
@@ -104,7 +106,9 @@ export function ClipboardField({
|
||||
const inputIcon = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<div className={cn(container, className)}>
|
||||
<div
|
||||
className={cn(container, fullWidth ? "w-full" : "max-w-max", className)}
|
||||
>
|
||||
{icon && (
|
||||
<div
|
||||
onClick={() => inputIcon.current && inputIcon.current.focus()}
|
||||
@@ -120,7 +124,13 @@ export function ClipboardField({
|
||||
<input
|
||||
type="text"
|
||||
ref={inputIcon}
|
||||
value={isSecure ? "•".repeat(value.length) : value}
|
||||
value={
|
||||
isSecure
|
||||
? typeof secure === "string"
|
||||
? secure
|
||||
: "•".repeat(value.length)
|
||||
: value
|
||||
}
|
||||
readOnly={true}
|
||||
className={cn("shrink grow select-all overflow-x-auto", input)}
|
||||
size={value.length}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user