diff --git a/.env.example b/.env.example index 2e1725cf0b..06cefc0aec 100644 --- a/.env.example +++ b/.env.example @@ -31,10 +31,32 @@ DEV_OTEL_BATCH_PROCESSING_ENABLED="0" # AUTH_GITHUB_CLIENT_ID= # AUTH_GITHUB_CLIENT_SECRET= -# Resend is an email service used for signing in to Trigger.dev via a Magic Link. -# Emails will print to the console if you leave these commented out +# Configure an email transport to allow users to sign in to Trigger.dev via a Magic Link. +# If none are configured, emails will print to the console instead. +# Uncomment one of the following blocks to allow delivery of + +# Resend ### Visit https://resend.com, create an account and get your API key. Then insert it below along with your From and Reply To email addresses. Visit https://resend.com/docs for more information. -# RESEND_API_KEY= +# EMAIL_TRANSPORT=resend +# FROM_EMAIL= +# REPLY_TO_EMAIL= +# RESEND_API_KEY= + +# Generic SMTP +### Enter the configuration provided by your mail provider. Visit https://nodemailer.com/smtp/ for more information +### SMTP_SECURE = false will use STARTTLS when connecting to a server that supports it (usually port 587) +# EMAIL_TRANSPORT=smtp +# FROM_EMAIL= +# REPLY_TO_EMAIL= +# SMTP_HOST= +# SMTP_PORT=587 +# SMTP_SECURE=false +# SMTP_USER= +# SMTP_PASSWORD= + +# AWS Simple Email Service +### Authentication is configured using the default Node.JS credentials provider chain (https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-credential-providers/#fromnodeproviderchain) +# EMAIL_TRANSPORT=aws-ses # FROM_EMAIL= # REPLY_TO_EMAIL= diff --git a/apps/webapp/app/components/SetupCommands.tsx b/apps/webapp/app/components/SetupCommands.tsx index 4071444ee3..dcfae4f88b 100644 --- a/apps/webapp/app/components/SetupCommands.tsx +++ b/apps/webapp/app/components/SetupCommands.tsx @@ -1,3 +1,5 @@ +import { createContext, useContext, useState } from "react"; +import { useAppOrigin } from "~/hooks/useAppOrigin"; import { useProject } from "~/hooks/useProject"; import { InlineCode } from "./code/InlineCode"; import { @@ -8,7 +10,31 @@ import { } from "./primitives/ClientTabs"; import { ClipboardField } from "./primitives/ClipboardField"; import { Paragraph } from "./primitives/Paragraph"; -import { useAppOrigin } from "~/hooks/useAppOrigin"; + +type PackageManagerContextType = { + activePackageManager: string; + setActivePackageManager: (value: string) => void; +}; + +const PackageManagerContext = createContext(undefined); + +export function PackageManagerProvider({ children }: { children: React.ReactNode }) { + const [activePackageManager, setActivePackageManager] = useState("npm"); + + return ( + + {children} + + ); +} + +function usePackageManager() { + const context = useContext(PackageManagerContext); + if (context === undefined) { + throw new Error("usePackageManager must be used within a PackageManagerProvider"); + } + return context; +} export function InitCommand({ appOrigin, apiKey }: { appOrigin: string; apiKey: string }) { return ( @@ -131,7 +157,6 @@ export function TriggerDevStep({ extra }: { extra?: string }) { ); } -// Trigger.dev version 3 setup commands const v3PackageTag = "latest"; function getApiUrlArg() { @@ -160,14 +185,19 @@ function getApiUrlArg() { export function InitCommandV3() { const project = useProject(); const projectRef = project.ref; - const apiUrlArg = getApiUrlArg(); const initCommandParts = [`trigger.dev@${v3PackageTag}`, "init", `-p ${projectRef}`, apiUrlArg]; const initCommand = initCommandParts.filter(Boolean).join(" "); + const { activePackageManager, setActivePackageManager } = usePackageManager(); + return ( - + npm pnpm @@ -202,8 +232,14 @@ export function InitCommandV3() { } export function TriggerDevStepV3() { + const { activePackageManager, setActivePackageManager } = usePackageManager(); + return ( - + npm pnpm @@ -238,8 +274,14 @@ export function TriggerDevStepV3() { } export function TriggerLoginStepV3() { + const { activePackageManager, setActivePackageManager } = usePackageManager(); + return ( - + npm pnpm diff --git a/apps/webapp/app/components/primitives/ClientTabs.tsx b/apps/webapp/app/components/primitives/ClientTabs.tsx index c8ac014dd3..52d10b8cfe 100644 --- a/apps/webapp/app/components/primitives/ClientTabs.tsx +++ b/apps/webapp/app/components/primitives/ClientTabs.tsx @@ -5,7 +5,11 @@ import * as TabsPrimitive from "@radix-ui/react-tabs"; import { cn } from "~/utils/cn"; import { motion } from "framer-motion"; -const ClientTabs = TabsPrimitive.Root; +const ClientTabs = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ); +ClientTabs.displayName = TabsPrimitive.Root.displayName; const ClientTabsList = React.forwardRef< React.ElementRef, diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index 99c810c76f..166b1531d5 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -44,9 +44,16 @@ const EnvironmentSchema = z.object({ HIGHLIGHT_PROJECT_ID: z.string().optional(), AUTH_GITHUB_CLIENT_ID: z.string().optional(), AUTH_GITHUB_CLIENT_SECRET: z.string().optional(), + EMAIL_TRANSPORT: z.enum(["resend", "smtp", "aws-ses"]).optional(), FROM_EMAIL: z.string().optional(), REPLY_TO_EMAIL: z.string().optional(), RESEND_API_KEY: z.string().optional(), + SMTP_HOST: z.string().optional(), + SMTP_PORT: z.coerce.number().optional(), + SMTP_SECURE: z.coerce.boolean().optional(), + SMTP_USER: z.string().optional(), + SMTP_PASSWORD: z.string().optional(), + PLAIN_API_KEY: z.string().optional(), RUNTIME_PLATFORM: z.enum(["docker-compose", "ecs", "local"]).default("local"), WORKER_SCHEMA: z.string().default("graphile_worker"), @@ -195,8 +202,16 @@ const EnvironmentSchema = z.object({ ORG_SLACK_INTEGRATION_CLIENT_SECRET: z.string().optional(), /** These enable the alerts feature in v3 */ + ALERT_EMAIL_TRANSPORT: z.enum(["resend", "smtp", "aws-ses"]).optional(), ALERT_FROM_EMAIL: z.string().optional(), + ALERT_REPLY_TO_EMAIL: z.string().optional(), ALERT_RESEND_API_KEY: z.string().optional(), + ALERT_SMTP_HOST: z.string().optional(), + ALERT_SMTP_PORT: z.coerce.number().optional(), + ALERT_SMTP_SECURE: z.coerce.boolean().optional(), + ALERT_SMTP_USER: z.string().optional(), + ALERT_SMTP_PASSWORD: z.string().optional(), + MAX_SEQUENTIAL_INDEX_FAILURE_COUNT: z.coerce.number().default(96), diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx index 74d5ca966c..69c63e5148 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam._index/route.tsx @@ -20,7 +20,12 @@ import { TypedAwait, typeddefer, useTypedLoaderData } from "remix-typedjson"; import { ExitIcon } from "~/assets/icons/ExitIcon"; import { TaskIcon } from "~/assets/icons/TaskIcon"; import { Feedback } from "~/components/Feedback"; -import { InitCommandV3, TriggerDevStepV3, TriggerLoginStepV3 } from "~/components/SetupCommands"; +import { + InitCommandV3, + PackageManagerProvider, + TriggerDevStepV3, + TriggerLoginStepV3, +} from "~/components/SetupCommands"; import { StepContentContainer } from "~/components/StepContentContainer"; import { AdminDebugTooltip } from "~/components/admin/debugTooltip"; import { InlineCode } from "~/components/code/InlineCode"; @@ -431,38 +436,40 @@ export default function Page() { function CreateTaskInstructions() { return ( -
-
- Get setup in 3 minutes -
- - I'm stuck! - - } - defaultValue="help" - /> + +
+
+ Get setup in 3 minutes +
+ + I'm stuck! + + } + defaultValue="help" + /> +
+ + + + + You'll notice a new folder in your project called{" "} + trigger. We've added a very simple example task + in here to help you get started. + + + + + + + + + This page will automatically refresh. +
- - - - - You’ll notice a new folder in your project called{" "} - trigger. We’ve added a very simple example task - in here to help you get started. - - - - - - - - - This page will automatically refresh. - -
+ ); } @@ -484,26 +491,28 @@ function UserHasNoTasks() { } > {open ? ( -
- Get setup in 3 minutes - - - - You'll need to open a terminal at the root of your project. - - - - - - - - - - - - This page will automatically refresh. - -
+ +
+ Get setup in 3 minutes + + + + You'll need to open a terminal at the root of your project. + + + + + + + + + + + + This page will automatically refresh. + +
+
) : ( "Your DEV environment isn't setup yet." )} diff --git a/apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx b/apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx index 4f71288991..1ac03e1ac7 100644 --- a/apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx +++ b/apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx @@ -661,19 +661,19 @@ export function TierPro({ - Upgrade plan? + Upgrade plan
- Are you sure you want to upgrade to the Pro plan? You will be charged the new - plan price for the remainder of this month on a pro rata basis. + Upgrade to get instant access to all the Pro features. You will be charged the + new plan price for the remainder of this month on a pro rata basis.