diff --git a/apps/webapp/app/services/jobs/registerJob.server.ts b/apps/webapp/app/services/jobs/registerJob.server.ts index db45ee672..8da6d153e 100644 --- a/apps/webapp/app/services/jobs/registerJob.server.ts +++ b/apps/webapp/app/services/jobs/registerJob.server.ts @@ -280,9 +280,12 @@ export class RegisterJobService { }, }); - for (const trigger of metadata.triggers) { - await this.#upsertEventDispatcher(trigger, job, jobVersion, environment); - } + await this.#upsertEventDispatcher( + metadata.trigger, + job, + jobVersion, + environment + ); return jobVersion; } @@ -327,6 +330,17 @@ export class RegisterJobService { }, }); + if (trigger.elements) { + await this.#prismaClient.jobVersion.update({ + where: { + id: jobVersion.id, + }, + data: { + elements: trigger.elements, + }, + }); + } + break; } case "scheduled": { diff --git a/apps/webapp/prisma/migrations/20230605144132_add_elements_to_job_versions/migration.sql b/apps/webapp/prisma/migrations/20230605144132_add_elements_to_job_versions/migration.sql new file mode 100644 index 000000000..c8f8a0328 --- /dev/null +++ b/apps/webapp/prisma/migrations/20230605144132_add_elements_to_job_versions/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "JobVersion" ADD COLUMN "elements" JSONB; diff --git a/apps/webapp/prisma/schema.prisma b/apps/webapp/prisma/schema.prisma index 536cee89c..7c43f7c92 100644 --- a/apps/webapp/prisma/schema.prisma +++ b/apps/webapp/prisma/schema.prisma @@ -32,7 +32,7 @@ model User { featureCloud Boolean @default(false) isOnHostedRepoWaitlist Boolean @default(false) - marketingEmails Boolean @default(true) + marketingEmails Boolean @default(true) confirmedBasicDetails Boolean @default(false) orgMemberships OrgMember[] @@ -195,10 +195,10 @@ enum OrgMemberRole { } model OrgMemberInvite { - id String @id @default(cuid()) - token String @unique @default(cuid()) + id String @id @default(cuid()) + token String @unique @default(cuid()) email String - role OrgMemberRole @default(MEMBER) + role OrgMemberRole @default(MEMBER) organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) organizationId String @@ -326,6 +326,8 @@ model JobVersion { version String eventSpecification Json + elements Json? + job Job @relation(fields: [jobId], references: [id], onDelete: Cascade, onUpdate: Cascade) jobId String diff --git a/examples/nextjs-example/src/pages/api/trigger.ts b/examples/nextjs-example/src/pages/api/trigger.ts index 7a7147bba..a9c930334 100644 --- a/examples/nextjs-example/src/pages/api/trigger.ts +++ b/examples/nextjs-example/src/pages/api/trigger.ts @@ -1,5 +1,4 @@ import { - comboTrigger, cronTrigger, customEvent, customTrigger, diff --git a/integrations/github/src/sources.ts b/integrations/github/src/sources.ts index d9f61d552..8c4655cfc 100644 --- a/integrations/github/src/sources.ts +++ b/integrations/github/src/sources.ts @@ -35,6 +35,13 @@ export function createRepoEventSource( schema: z.object({ repo: z.string() }), integration, key: (params) => params.repo, + elements: (params) => [ + { + label: "Repo", + text: params.repo, + url: `https://github.com/${params.repo}`, + }, + ], filter: (params) => ({ repository: { full_name: [params.repo], @@ -190,6 +197,13 @@ export function createOrgEventSource( integration, schema: z.object({ org: z.string() }), key: (params) => params.org, + elements: (params) => [ + { + label: "Org", + text: params.org, + url: `https://github.com/${params.org}`, + }, + ], filter: (params) => ({ organization: { login: [params.org], diff --git a/packages/internal/src/schemas/api.ts b/packages/internal/src/schemas/api.ts index 8e2598ad1..dea883393 100644 --- a/packages/internal/src/schemas/api.ts +++ b/packages/internal/src/schemas/api.ts @@ -136,7 +136,7 @@ export const JobMetadataSchema = z.object({ name: z.string(), version: z.string(), event: EventSpecificationSchema, - triggers: z.array(TriggerMetadataSchema), + trigger: TriggerMetadataSchema, integrations: z.record(IntegrationConfigSchema), internal: z.boolean().default(false), queue: z.union([QueueOptionsSchema, z.string()]).optional(), diff --git a/packages/trigger-sdk/src/index.ts b/packages/trigger-sdk/src/index.ts index bb069eb5a..e109dc64e 100644 --- a/packages/trigger-sdk/src/index.ts +++ b/packages/trigger-sdk/src/index.ts @@ -2,7 +2,6 @@ export * from "./job"; export * from "./triggerClient"; export * from "./integrations"; export * from "./triggers/customTrigger"; -export * from "./triggers/comboTrigger"; export * from "./triggers/externalSource"; export * from "./triggers/dynamic"; export * from "./triggers/scheduled"; diff --git a/packages/trigger-sdk/src/job.ts b/packages/trigger-sdk/src/job.ts index 11677b136..d5f43f77e 100644 --- a/packages/trigger-sdk/src/job.ts +++ b/packages/trigger-sdk/src/job.ts @@ -113,7 +113,7 @@ export class Job< name: this.name, version: this.version, event: this.trigger.event, - triggers: this.trigger.toJSON(), + trigger: this.trigger.toJSON(), integrations: this.integrations, queue: this.options.queue, startPosition: this.options.startPosition ?? "latest", diff --git a/packages/trigger-sdk/src/triggers/comboTrigger.ts b/packages/trigger-sdk/src/triggers/comboTrigger.ts deleted file mode 100644 index 6f28e2344..000000000 --- a/packages/trigger-sdk/src/triggers/comboTrigger.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { TriggerMetadata } from "@trigger.dev/internal"; -import { Job } from "../job"; -import { TriggerClient } from "../triggerClient"; -import { EventSpecification, Trigger } from "../types"; - -type ComboTriggerOptions< - TEventSpecification extends EventSpecification, - TTriggers extends Array> -> = { - event: TEventSpecification; - triggers: TTriggers; -}; - -class ComboTrigger< - TEventSpecification extends EventSpecification, - TTriggers extends Array> -> implements Trigger -{ - #options: ComboTriggerOptions; - - constructor(options: ComboTriggerOptions) { - this.#options = options; - } - - toJSON(): Array { - return this.#options.triggers.flatMap((trigger) => trigger.toJSON()); - } - - get event() { - return this.#options.event; - } - - get requiresPreparaton(): boolean { - return this.#options.triggers.some((trigger) => trigger.requiresPreparaton); - } - - attachToJob( - triggerClient: TriggerClient, - job: Job, any>, - index?: number - ): void { - this.#options.triggers.forEach((trigger, i) => - trigger.attachToJob(triggerClient, job, i) - ); - } -} - -export function comboTrigger< - TEventSpecification extends EventSpecification, - TTriggers extends Array> ->( - options: ComboTriggerOptions -): Trigger { - return new ComboTrigger(options); -} diff --git a/packages/trigger-sdk/src/triggers/customTrigger.ts b/packages/trigger-sdk/src/triggers/customTrigger.ts index 4e5471d7a..06513538f 100644 --- a/packages/trigger-sdk/src/triggers/customTrigger.ts +++ b/packages/trigger-sdk/src/triggers/customTrigger.ts @@ -25,21 +25,19 @@ export class CustomTrigger> this.#options = options; } - toJSON(): Array { - return [ - { - type: "static", - title: this.#options.name ?? this.#options.event.title, - rule: { - event: this.#options.name ?? this.#options.event.name, - source: this.#options.source ?? "trigger.dev", - payload: deepMergeFilters( - this.#options.filter ?? {}, - this.#options.event.filter ?? {} - ), - }, + toJSON(): TriggerMetadata { + return { + type: "static", + title: this.#options.name ?? this.#options.event.title, + rule: { + event: this.#options.name ?? this.#options.event.name, + source: this.#options.source ?? "trigger.dev", + payload: deepMergeFilters( + this.#options.filter ?? {}, + this.#options.event.filter ?? {} + ), }, - ]; + }; } get requiresPreparaton(): boolean { diff --git a/packages/trigger-sdk/src/triggers/dynamic.ts b/packages/trigger-sdk/src/triggers/dynamic.ts index 9e982caa2..f39aa109a 100644 --- a/packages/trigger-sdk/src/triggers/dynamic.ts +++ b/packages/trigger-sdk/src/triggers/dynamic.ts @@ -39,13 +39,11 @@ export class DynamicTrigger< client.attachDynamicTrigger(this); } - toJSON(): Array { - return [ - { - type: "dynamic", - id: this.#options.id, - }, - ]; + toJSON(): TriggerMetadata { + return { + type: "dynamic", + id: this.#options.id, + }; } get id() { @@ -97,8 +95,7 @@ export class DynamicTrigger< attachToJob( triggerClient: TriggerClient, - job: Job, any>, - index?: number + job: Job, any> ): void { triggerClient.attachJobToDynamicTrigger(job, this); } diff --git a/packages/trigger-sdk/src/triggers/externalSource.ts b/packages/trigger-sdk/src/triggers/externalSource.ts index 5e71bbf7f..3c738dd05 100644 --- a/packages/trigger-sdk/src/triggers/externalSource.ts +++ b/packages/trigger-sdk/src/triggers/externalSource.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { + DisplayElement, EventFilter, HandleTriggerSource, Logger, @@ -108,6 +109,7 @@ type ExternalSourceOptions< filter: FilterFunction; handler: HandlerFunction; key: KeyFunction; + elements?: (params: TParams) => DisplayElement[]; }; export class ExternalSource< @@ -142,6 +144,10 @@ export class ExternalSource< return this.options.filter(params); } + elements(params: TParams): DisplayElement[] { + return this.options.elements?.(params) ?? []; + } + async register( params: TParams, registerEvent: RegisterSourceEvent, @@ -232,27 +238,25 @@ export class ExternalSourceTrigger< return true; } - toJSON(): Array { - return [ - { - type: "static", - title: "External Source", - rule: { - event: this.event.name, - payload: deepMergeFilters( - this.options.source.filter(this.options.params), - this.event.filter ?? {} - ), - source: this.event.source, - }, + toJSON(): TriggerMetadata { + return { + type: "static", + title: "External Source", + rule: { + event: this.event.name, + payload: deepMergeFilters( + this.options.source.filter(this.options.params), + this.event.filter ?? {} + ), + source: this.event.source, }, - ]; + elements: this.options.source.elements(this.options.params), + }; } attachToJob( triggerClient: TriggerClient, - job: Job, any>, - index?: number + job: Job, any> ) { triggerClient.attachSource({ key: slugifyId(this.options.source.key(this.options.params)), diff --git a/packages/trigger-sdk/src/triggers/notifications.ts b/packages/trigger-sdk/src/triggers/notifications.ts index d95656123..2ba6b9b9b 100644 --- a/packages/trigger-sdk/src/triggers/notifications.ts +++ b/packages/trigger-sdk/src/triggers/notifications.ts @@ -57,22 +57,20 @@ export class MissingConnectionNotification job: Job, any> ): void {} - toJSON(): Array { - return [ - { - type: "static", - title: this.event.title, - rule: { - event: this.event.name, - source: "trigger.dev", - payload: { - client: { - id: this.options.integrations.map((i) => i.id), - }, + toJSON(): TriggerMetadata { + return { + type: "static", + title: this.event.title, + rule: { + event: this.event.name, + source: "trigger.dev", + payload: { + client: { + id: this.options.integrations.map((i) => i.id), }, }, }, - ]; + }; } get requiresPreparaton(): boolean { @@ -109,22 +107,20 @@ export class MissingConnectionResolvedNotification job: Job, any> ): void {} - toJSON(): Array { - return [ - { - type: "static", - title: this.event.title, - rule: { - event: this.event.name, - source: "trigger.dev", - payload: { - client: { - id: this.options.integrations.map((i) => i.id), - }, + toJSON(): TriggerMetadata { + return { + type: "static", + title: this.event.title, + rule: { + event: this.event.name, + source: "trigger.dev", + payload: { + client: { + id: this.options.integrations.map((i) => i.id), }, }, }, - ]; + }; } get requiresPreparaton(): boolean { diff --git a/packages/trigger-sdk/src/triggers/scheduled.ts b/packages/trigger-sdk/src/triggers/scheduled.ts index 78e6430b0..8b8319652 100644 --- a/packages/trigger-sdk/src/triggers/scheduled.ts +++ b/packages/trigger-sdk/src/triggers/scheduled.ts @@ -38,18 +38,16 @@ export class IntervalTrigger implements Trigger { job: Job, any> ): void {} - toJSON(): Array { - return [ - { - type: "scheduled", - schedule: { - type: "interval", - options: { - seconds: this.options.seconds, - }, + toJSON(): TriggerMetadata { + return { + type: "scheduled", + schedule: { + type: "interval", + options: { + seconds: this.options.seconds, }, }, - ]; + }; } get requiresPreparaton(): boolean { @@ -85,18 +83,16 @@ export class CronTrigger implements Trigger { job: Job, any> ): void {} - toJSON(): Array { - return [ - { - type: "scheduled", - schedule: { - type: "cron", - options: { - cron: this.options.cron, - }, + toJSON(): TriggerMetadata { + return { + type: "scheduled", + schedule: { + type: "cron", + options: { + cron: this.options.cron, }, }, - ]; + }; } get requiresPreparaton(): boolean { @@ -145,13 +141,11 @@ export class DynamicSchedule implements Trigger { triggerClient.attachDynamicSchedule(this.options.id, job); } - toJSON(): Array { - return [ - { - type: "dynamic", - id: this.options.id, - }, - ]; + toJSON(): TriggerMetadata { + return { + type: "dynamic", + id: this.options.id, + }; } get requiresPreparaton(): boolean { diff --git a/packages/trigger-sdk/src/types.ts b/packages/trigger-sdk/src/types.ts index a8ed3d917..82db829ad 100644 --- a/packages/trigger-sdk/src/types.ts +++ b/packages/trigger-sdk/src/types.ts @@ -33,13 +33,12 @@ export type TriggerEventType> = export interface Trigger> { event: TEventSpec; - toJSON(): Array; + toJSON(): TriggerMetadata; // Attach this trigger to the job and the trigger client // Gives different triggers the ability to do things like register internal jobs attachToJob( triggerClient: TriggerClient, - job: Job, any>, - index?: number + job: Job, any> ): void; requiresPreparaton: boolean; }