(
(
}
);
+const stickyStyles =
+ "sticky right-0 z-10 w-[2.8rem] min-w-[2.8rem] bg-background before:absolute before:pointer-events-none before:-left-8 before:top-0 before:h-full before:min-w-[2rem] before:bg-gradient-to-r before:from-transparent before:to-background before:content-[''] group-hover:before:to-slate-900";
+
export const TableCellChevron = forwardRef<
HTMLTableCellElement,
{
className?: string;
to?: string;
children?: ReactNode;
+ isSticky?: boolean;
onClick?: (event: React.MouseEvent) => void;
}
->(({ className, to, children, onClick }, ref) => {
+>(({ className, to, children, isSticky, onClick }, ref) => {
return (
-
+
{children}
);
});
+export const TableCellMenu = forwardRef<
+ HTMLTableCellElement,
+ {
+ className?: string;
+ children?: ReactNode;
+ isSticky?: boolean;
+ onClick?: (event: React.MouseEvent) => void;
+ }
+>(({ className, children, isSticky, onClick }, ref) => {
+ const [isOpen, setIsOpen] = useState(false);
+ return (
+
+ setIsOpen(open)}>
+
+
+ {children}
+
+
+
+ );
+});
+
type TableBlankRowProps = {
className?: string;
colSpan: number;
diff --git a/apps/webapp/app/components/primitives/Tabs.tsx b/apps/webapp/app/components/primitives/Tabs.tsx
index e5a79af21..dc52ad22f 100644
--- a/apps/webapp/app/components/primitives/Tabs.tsx
+++ b/apps/webapp/app/components/primitives/Tabs.tsx
@@ -12,7 +12,7 @@ export type TabsProps = {
export function Tabs({ tabs, className }: TabsProps) {
return (
-
+
{tabs.map((tab, index) => (
{({ isActive, isPending }) => (
diff --git a/apps/webapp/app/components/runs/RunsTable.tsx b/apps/webapp/app/components/runs/RunsTable.tsx
index 87d060e1a..7f185e3c3 100644
--- a/apps/webapp/app/components/runs/RunsTable.tsx
+++ b/apps/webapp/app/components/runs/RunsTable.tsx
@@ -109,7 +109,7 @@ export function RunsTable({
{run.createdAt ? : "–"}
-
+
);
})
diff --git a/apps/webapp/app/components/stories/Badges.stories.tsx b/apps/webapp/app/components/stories/Badges.stories.tsx
index 16a2469d4..93a7f566f 100644
--- a/apps/webapp/app/components/stories/Badges.stories.tsx
+++ b/apps/webapp/app/components/stories/Badges.stories.tsx
@@ -20,7 +20,6 @@ function BadgesExample() {
Default
Outline
- Green
);
}
diff --git a/apps/webapp/app/components/stories/Button.stories.tsx b/apps/webapp/app/components/stories/Button.stories.tsx
index 3cf689332..3e3dd3979 100644
--- a/apps/webapp/app/components/stories/Button.stories.tsx
+++ b/apps/webapp/app/components/stories/Button.stories.tsx
@@ -253,13 +253,11 @@ function ButtonList({ primary }: { primary: string }) {
Large buttons
-
+
Continue with GitHub
-
-
Continue with Email
+
+
+ This is a delete button
+
diff --git a/apps/webapp/app/hooks/useJobs.tsx b/apps/webapp/app/hooks/useJobs.tsx
index f3feff4a1..80115f12e 100644
--- a/apps/webapp/app/hooks/useJobs.tsx
+++ b/apps/webapp/app/hooks/useJobs.tsx
@@ -8,6 +8,10 @@ export type ProjectJob = UseDataFunctionReturn
["projectJobs"][num
export const jobsMatchId =
"routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam";
+
+// This is only used in the JobsMenu component, which is the breadcrumb job list dropdown.
+// This dropdown is only shown once you have selected a job, so we can assume that
+// the route above has loaded and we can use the data from it.
export function useOptionalJobs(matches?: RouteMatch[]) {
const routeMatch = useTypedMatchesData({
id: jobsMatchId,
diff --git a/apps/webapp/app/models/message.server.ts b/apps/webapp/app/models/message.server.ts
index 01bd1edd3..d1278c1c2 100644
--- a/apps/webapp/app/models/message.server.ts
+++ b/apps/webapp/app/models/message.server.ts
@@ -102,6 +102,25 @@ export async function jsonWithSuccessMessage(
});
}
+export async function jsonWithErrorMessage(
+ data: any,
+ request: Request,
+ message: string,
+ options?: ToastMessageOptions
+) {
+ const session = await getSession(request.headers.get("cookie"));
+
+ setErrorMessage(session, message, options);
+
+ return json(data, {
+ headers: {
+ "Set-Cookie": await commitSession(session, {
+ expires: new Date(Date.now() + ONE_YEAR),
+ }),
+ },
+ });
+}
+
export async function redirectWithSuccessMessage(
path: string,
request: Request,
diff --git a/apps/webapp/app/models/organization.server.ts b/apps/webapp/app/models/organization.server.ts
index 891f4c57c..da9db9a54 100644
--- a/apps/webapp/app/models/organization.server.ts
+++ b/apps/webapp/app/models/organization.server.ts
@@ -49,6 +49,7 @@ export function getOrganizations({ userId }: { userId: User["id"] }) {
jobs: {
where: {
internal: false,
+ deletedAt: null,
},
},
},
diff --git a/apps/webapp/app/presenters/IntegrationClientPresenter.server.ts b/apps/webapp/app/presenters/IntegrationClientPresenter.server.ts
index fa3c453d3..3dea16ff0 100644
--- a/apps/webapp/app/presenters/IntegrationClientPresenter.server.ts
+++ b/apps/webapp/app/presenters/IntegrationClientPresenter.server.ts
@@ -63,6 +63,7 @@ export class IntegrationClientPresenter {
slug: projectSlug,
},
internal: false,
+ deletedAt: null,
},
},
},
diff --git a/apps/webapp/app/presenters/IntegrationsPresenter.server.ts b/apps/webapp/app/presenters/IntegrationsPresenter.server.ts
index 09c6cd927..45fe63547 100644
--- a/apps/webapp/app/presenters/IntegrationsPresenter.server.ts
+++ b/apps/webapp/app/presenters/IntegrationsPresenter.server.ts
@@ -71,6 +71,7 @@ export class IntegrationsPresenter {
slug: projectSlug,
},
internal: false,
+ deletedAt: null,
},
},
},
diff --git a/apps/webapp/app/presenters/JobListPresenter.server.ts b/apps/webapp/app/presenters/JobListPresenter.server.ts
index 0c3917d93..3c997c646 100644
--- a/apps/webapp/app/presenters/JobListPresenter.server.ts
+++ b/apps/webapp/app/presenters/JobListPresenter.server.ts
@@ -47,6 +47,7 @@ export class JobListPresenter {
version: true,
eventSpecification: true,
properties: true,
+ status: true,
runs: {
select: {
createdAt: true,
@@ -92,6 +93,7 @@ export class JobListPresenter {
},
where: {
internal: false,
+ deletedAt: null,
organization: orgWhere,
project: {
slug: projectSlug,
@@ -162,11 +164,19 @@ export class JobListPresenter {
properties = [...properties, ...versionProperties];
}
+ const environments = job.aliases.map((alias) => ({
+ type: alias.environment.type,
+ enabled: alias.version.status === "ACTIVE",
+ lastRun: alias.version.runs.at(0)?.createdAt,
+ version: alias.version.version,
+ }));
+
return {
id: job.id,
slug: job.slug,
title: job.title,
version: alias.version.version,
+ status: alias.version.status,
dynamic: job.dynamicTriggers.length > 0,
event: {
title: eventSpecification.title,
@@ -179,6 +189,7 @@ export class JobListPresenter {
),
lastRun,
properties,
+ environments,
};
})
.filter(Boolean);
diff --git a/apps/webapp/app/presenters/ProjectPresenter.server.ts b/apps/webapp/app/presenters/ProjectPresenter.server.ts
index 93877d363..fe55f354a 100644
--- a/apps/webapp/app/presenters/ProjectPresenter.server.ts
+++ b/apps/webapp/app/presenters/ProjectPresenter.server.ts
@@ -80,6 +80,7 @@ export class ProjectPresenter {
},
where: {
internal: false,
+ deletedAt: null,
},
orderBy: [{ title: "asc" }],
},
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam._index/route.tsx
index 8c487f691..f62347a0b 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam._index/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam._index/route.tsx
@@ -73,8 +73,6 @@ export default function Page() {
const { filterText, setFilterText, filteredItems } = useFilterJobs(jobs);
- const { width, height } = useWindowSize();
-
return (
@@ -104,7 +102,6 @@ export default function Page() {
)}
-
Jobs
- {jobs.length === 1 && jobs.every((r) => r.lastRun === undefined) && (
-
- )}
+ {jobs.length === 1 &&
+ jobs.every((r) => r.lastRun === undefined) &&
+ jobs.every((i) => i.hasIntegrationsRequiringAction === false) && (
+
+ )}
>
) : (
@@ -194,7 +193,7 @@ function ExampleJobs() {
{example.icon}
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx
index 23bcac69f..1c653370a 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx
@@ -355,7 +355,7 @@ function ConnectedIntegrationsList({
-
+
);
})}
@@ -454,7 +454,7 @@ function IntegrationsWithMissingFields({
integration={integration}
organizationId={organizationId}
button={
-
+
}
callbackUrl={callbackUrl}
existingIntegration={client}
@@ -482,7 +482,7 @@ function AddIntegrationConnection({
icon?: string;
}) {
return (
-
+
+
+ {(open) => (
+
+
+
+ Environments
+
+
+
+
+
+ Disable this Job in all environments before deleting
+
+
+
+
+
+ Delete Job
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
);
}
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam/route.tsx
index d2c563f73..166ab1e74 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam/route.tsx
@@ -2,6 +2,7 @@ import { Outlet, useLocation } from "@remix-run/react";
import type { LoaderArgs } from "@remix-run/server-runtime";
import { Fragment } from "react";
import { typedjson } from "remix-typedjson";
+import { JobStatusBadge } from "~/components/jobs/JobStatusBadge";
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
import { JobsMenu } from "~/components/navigation/JobsMenu";
import { BreadcrumbLink } from "~/components/navigation/NavBar";
@@ -134,6 +135,18 @@ export default function Job() {
}
/>
)}
+
+ }
+ />
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.team/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.team/route.tsx
index c1aeacfad..8d19ed9a4 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.team/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.team/route.tsx
@@ -103,7 +103,7 @@ export default function Page() {
Members
-
+
{members.map((member) => (
{
+ const { jobId } = ParamSchema.parse(params);
+ const userId = await requireUserId(request);
+
+ // Find the job
+ const job = await prisma.job.findFirst({
+ where: {
+ id: jobId,
+ organization: {
+ members: {
+ some: {
+ userId,
+ },
+ },
+ },
+ },
+ });
+
+ if (!job) {
+ return jsonWithErrorMessage({ ok: false }, request, `Job could not be scheduled for deletion.`);
+ }
+ try {
+ const deleteJobService = new DeleteJobService();
+
+ await deleteJobService.call(job);
+
+ const url = new URL(request.url);
+ const redirectTo = url.searchParams.get("redirectTo");
+
+ logger.debug("Job scheduled for deletion", {
+ url,
+ redirectTo,
+ job,
+ });
+
+ if (typeof redirectTo === "string" && redirectTo.length > 0) {
+ return redirectWithSuccessMessage(
+ redirectTo,
+ request,
+ `Job ${job.slug} has been scheduled for deletion.`
+ );
+ }
+
+ return jsonWithSuccessMessage(
+ { ok: true },
+ request,
+ `Job ${job.slug} has been scheduled for deletion.`
+ );
+ } catch (error) {
+ const message = error instanceof Error ? error.message : "Unknown error";
+
+ return jsonWithErrorMessage(
+ { ok: false },
+ request,
+ `Job could not be scheduled for deletion: ${message}`
+ );
+ }
+};
diff --git a/apps/webapp/app/services/endpoints/indexEndpoint.server.ts b/apps/webapp/app/services/endpoints/indexEndpoint.server.ts
index c0fe2a8ee..066bf85be 100644
--- a/apps/webapp/app/services/endpoints/indexEndpoint.server.ts
+++ b/apps/webapp/app/services/endpoints/indexEndpoint.server.ts
@@ -65,6 +65,7 @@ export class IndexEndpointService {
const existingJobs = await this.#prismaClient.job.findMany({
where: {
projectId: endpoint.projectId,
+ deletedAt: null,
},
include: {
aliases: {
@@ -99,9 +100,11 @@ export class IndexEndpointService {
}
} else {
try {
- await this.#registerJobService.call(endpoint, job);
+ const registeredVersion = await this.#registerJobService.call(endpoint, job);
- indexStats.jobs++;
+ if (registeredVersion) {
+ indexStats.jobs++;
+ }
} catch (error) {
logger.error("Failed to register job", {
endpointId: endpoint.id,
diff --git a/apps/webapp/app/services/jobs/deleteJob.server.ts b/apps/webapp/app/services/jobs/deleteJob.server.ts
new file mode 100644
index 000000000..975f10f46
--- /dev/null
+++ b/apps/webapp/app/services/jobs/deleteJob.server.ts
@@ -0,0 +1,45 @@
+import type { Job } from "@trigger.dev/database";
+import type { PrismaClient } from "~/db.server";
+import { prisma } from "~/db.server";
+import { telemetry } from "../telemetry.server";
+
+export class DeleteJobService {
+ #prismaClient: PrismaClient;
+
+ constructor(prismaClient: PrismaClient = prisma) {
+ this.#prismaClient = prismaClient;
+ }
+
+ public async call(job: Job) {
+ // Make sure that all the latest versions are disabled
+ const latestVersions = await this.#prismaClient.jobAlias.findMany({
+ where: {
+ jobId: job.id,
+ name: "latest",
+ },
+ include: {
+ version: true,
+ },
+ });
+
+ const allDisabled = latestVersions.every((alias) => alias.version.status === "DISABLED");
+
+ if (!allDisabled) {
+ throw new Error("All latest versions must be disabled before deleting a job");
+ }
+
+ // Okay now we need to delete a job by setting the deletedAt field and enqueuing a job to cleanup the job
+ await this.#prismaClient.job.update({
+ where: {
+ id: job.id,
+ },
+ data: {
+ deletedAt: new Date(),
+ },
+ });
+
+ telemetry.project.deletedJob({
+ job,
+ });
+ }
+}
diff --git a/apps/webapp/app/services/jobs/registerJob.server.ts b/apps/webapp/app/services/jobs/registerJob.server.ts
index e92610752..c66a6e157 100644
--- a/apps/webapp/app/services/jobs/registerJob.server.ts
+++ b/apps/webapp/app/services/jobs/registerJob.server.ts
@@ -34,7 +34,21 @@ export class RegisterJobService {
endpoint: Endpoint,
environment: AuthenticatedEnvironment,
metadata: JobMetadata
- ): Promise {
+ ): Promise {
+ // Check the job doesn't already exist and is deleted
+ const existingJob = await this.#prismaClient.job.findUnique({
+ where: {
+ projectId_slug: {
+ projectId: environment.projectId,
+ slug: metadata.id,
+ },
+ },
+ });
+
+ if (existingJob && existingJob.deletedAt && !metadata.enabled) {
+ return;
+ }
+
const integrations = new Map();
for (const [, jobIntegration] of Object.entries(metadata.integrations)) {
@@ -155,6 +169,7 @@ export class RegisterJobService {
},
update: {
title: metadata.name,
+ deletedAt: metadata.enabled ? null : undefined,
},
include: {
integrations: {
diff --git a/apps/webapp/app/services/telemetry.server.ts b/apps/webapp/app/services/telemetry.server.ts
index 464d4f8b8..6f476feee 100644
--- a/apps/webapp/app/services/telemetry.server.ts
+++ b/apps/webapp/app/services/telemetry.server.ts
@@ -1,3 +1,4 @@
+import { Job } from "@trigger.dev/database";
import { TriggerClient } from "@trigger.dev/sdk";
import { PostHog } from "posthog-node";
import { env } from "~/env.server";
@@ -149,6 +150,14 @@ class Telemetry {
},
});
},
+ deletedJob: ({ job }: { job: Job }) => {
+ this.#triggerClient?.sendEvent({
+ name: "job.deleted",
+ payload: {
+ id: job.id,
+ },
+ });
+ },
};
#capture(event: CaptureEvent) {
diff --git a/apps/webapp/app/utils/pathBuilder.ts b/apps/webapp/app/utils/pathBuilder.ts
index e9ea222b3..6c51c6634 100644
--- a/apps/webapp/app/utils/pathBuilder.ts
+++ b/apps/webapp/app/utils/pathBuilder.ts
@@ -115,6 +115,10 @@ export function projectPath(organization: OrgForPath, project: ProjectForPath) {
return `/orgs/${organizationParam(organization)}/projects/${projectParam(project)}`;
}
+export function projectJobsPath(organization: OrgForPath, project: ProjectForPath) {
+ return projectPath(organization, project);
+}
+
export function projectIntegrationsPath(organization: OrgForPath, project: ProjectForPath) {
return `${projectPath(organization, project)}/integrations`;
}
diff --git a/apps/webapp/tailwind.config.js b/apps/webapp/tailwind.config.js
index 98770b0ee..eba7a5640 100644
--- a/apps/webapp/tailwind.config.js
+++ b/apps/webapp/tailwind.config.js
@@ -144,6 +144,7 @@ module.exports = {
},
devEnv: colors.pink,
liveEnv: colors.green,
+ uiBorder: slate[800],
},
borderRadius: {
lg: radius,
diff --git a/docs/documentation/guides/jobs/managing.mdx b/docs/documentation/guides/jobs/managing.mdx
new file mode 100644
index 000000000..3323a0425
--- /dev/null
+++ b/docs/documentation/guides/jobs/managing.mdx
@@ -0,0 +1,84 @@
+---
+title: "Managing Jobs"
+description: "Managing jobs in your codebase and the dashboard"
+---
+
+## Disabling jobs
+
+To prevent a job from processing new runs, you can disable it by setting the `enabled` option:
+
+```ts
+client.defineJob({
+ id: "example-job",
+ name: "Example Job",
+ version: "0.1.0",
+ trigger: eventTrigger({ name: "example.event" }),
+ enabled: false,
+ run: async (payload, io, ctx) => {
+ // your job code here
+ },
+});
+```
+
+If you omit the `enabled` option, it will default to `true`.
+
+The job will only be disabled in environments that have seen the `enabled = false` value. So the job will remain enabled in production until the code with the `enabled = false` is deployed to production.
+
+
+ Currently this is the only way to disable a job. If you'd like to disable a job in the Dashboard,
+ please reach out to us on [Discord](https://discord.gg/kA47vcd8P6) and let us know 👋
+
+
+Once a job is disabled no **new** runs will be created for that job, and it will still be visible in the Dashboard as disabled:
+
+
+
+### In-progress runs
+
+In-progress runs will be allowed to finish, even runs that are currently delayed from a call to `io.wait`. If you'd like to completely stop in-progress runs, you have two options:
+
+- Set the `enabled` option to false and then `throw` an error at the top of your job `run` function.
+
+```ts
+client.defineJob({
+ id: "example-job",
+ name: "Example Job",
+ version: "0.1.0",
+ trigger: eventTrigger({ name: "example.event" }),
+ enabled: false,
+ run: async (payload, io, ctx) => {
+ throw new Error("Job disabled");
+ },
+});
+```
+
+- Delete the job from your codebase. This will disable the job as well but also stop in progress runs.
+
+### Disabling in production with env vars
+
+You can easily disable jobs in production using env vars so you don't have to deploy new code to disable a job.
+
+```ts
+client.defineJob({
+ id: "example-job",
+ name: "Example Job",
+ version: "0.1.0",
+ trigger: eventTrigger({ name: "example.event" }),
+ enabled: process.env.TRIGGER_JOBS_DISABLED === "true",
+ run: async (payload, io, ctx) => {
+ // your job code here
+ },
+});
+```
+
+Then you can disable the job in production by setting the `TRIGGER_JOBS_DISABLED` env var to `"true"`. And removing the env var will re-enable the job.
+
+## Deleting jobs
+
+Once you have disabled a job in all environments, you can delete it from the dashboard by navigating to the Job list page and clicking the "triple-dot" menu next to the job you want to delete:
+
+
+
+This will bring up a dialog confirming that you want to delete the job and all of its history:
+
+
diff --git a/docs/images/delete-job.png b/docs/images/delete-job.png
new file mode 100644
index 000000000..0bb1abf2f
Binary files /dev/null and b/docs/images/delete-job.png differ
diff --git a/docs/images/disabled-job.png b/docs/images/disabled-job.png
new file mode 100644
index 000000000..74824bafd
Binary files /dev/null and b/docs/images/disabled-job.png differ
diff --git a/docs/images/job-triple-dot-menu.png b/docs/images/job-triple-dot-menu.png
new file mode 100644
index 000000000..80a9adeac
Binary files /dev/null and b/docs/images/job-triple-dot-menu.png differ
diff --git a/docs/mint.json b/docs/mint.json
index 95571328d..e7a977b1a 100644
--- a/docs/mint.json
+++ b/docs/mint.json
@@ -63,7 +63,10 @@
"documentation/introduction",
{
"group": "Quick Starts",
- "pages": ["documentation/quickstarts/nextjs", "documentation/quickstarts/supabase"]
+ "pages": [
+ "documentation/quickstarts/nextjs",
+ "documentation/quickstarts/supabase"
+ ]
},
"documentation/guides/create-a-job",
"documentation/guides/video-walkthrough"
@@ -114,6 +117,7 @@
"documentation/guides/cli",
"documentation/guides/manual",
"documentation/guides/running-jobs",
+ "documentation/guides/jobs/managing",
{
"group": "Using the Dashboard",
"pages": [
@@ -167,7 +171,10 @@
},
{
"group": "Overview",
- "pages": ["integrations/introduction", "integrations/create"]
+ "pages": [
+ "integrations/introduction",
+ "integrations/create"
+ ]
},
{
"group": "Integrations",
@@ -180,23 +187,30 @@
"integrations/apis/github-tasks"
]
},
-
{
"group": "OpenAI",
- "pages": ["integrations/apis/openai"]
+ "pages": [
+ "integrations/apis/openai"
+ ]
},
"integrations/apis/plain",
{
"group": "Resend",
- "pages": ["integrations/apis/resend"]
+ "pages": [
+ "integrations/apis/resend"
+ ]
},
{
"group": "SendGrid",
- "pages": ["integrations/apis/sendgrid"]
+ "pages": [
+ "integrations/apis/sendgrid"
+ ]
},
{
"group": "Slack",
- "pages": ["integrations/apis/slack"]
+ "pages": [
+ "integrations/apis/slack"
+ ]
},
{
"group": "Supabase",
@@ -258,7 +272,10 @@
"sdk/dynamictrigger/constructor",
{
"group": "Instance methods",
- "pages": ["sdk/dynamictrigger/register", "sdk/dynamictrigger/unregister"]
+ "pages": [
+ "sdk/dynamictrigger/register",
+ "sdk/dynamictrigger/unregister"
+ ]
}
]
},
@@ -269,7 +286,10 @@
"sdk/dynamicschedule/constructor",
{
"group": "Instance methods",
- "pages": ["sdk/dynamicschedule/register", "sdk/dynamicschedule/unregister"]
+ "pages": [
+ "sdk/dynamicschedule/register",
+ "sdk/dynamicschedule/unregister"
+ ]
}
]
},
@@ -290,7 +310,10 @@
},
{
"group": "Overview",
- "pages": ["examples/introduction", "examples/examples-repository"]
+ "pages": [
+ "examples/introduction",
+ "examples/examples-repository"
+ ]
}
],
"footerSocials": {
@@ -303,4 +326,4 @@
"apiKey": "phc_hwYmedO564b3Ik8nhA4Csrb5SueY0EwFJWCbseGwWW"
}
}
-}
+}
\ No newline at end of file
diff --git a/docs/sdk/job.mdx b/docs/sdk/job.mdx
index a597620ec..a9bc27f81 100644
--- a/docs/sdk/job.mdx
+++ b/docs/sdk/job.mdx
@@ -49,27 +49,6 @@ client.defineJob({
});
```
-```ts queue options
-client.defineJob({
- id: "github-integration-on-issue",
- name: "GitHub Integration - On Issue",
- version: "0.1.0",
- trigger: github.triggers.repo({
- event: events.onIssue,
- owner: "triggerdotdev",
- repo: "empty",
- }),
- queue: {
- name: "my-queue",
- maxConcurrent: 10, // only 10 runs can happen at the same time
- },
- run: async (payload, io, ctx) => {
- await io.logger.info("This is a simple log info message");
- return { payload, ctx };
- },
-});
-```
-
# Constructor
@@ -114,6 +93,9 @@ client.defineJob({
Imports the specified integrations into the Job. The integrations will be available on the `io` object in the `run()` function with the same name as the key. For example:
+
+ The `enabled` property is an optional property that specifies whether the Job is enabled or not. The Job will be enabled by default if you omit this property. When a job is disabled, no new runs will be triggered or resumed. In progress runs will continue to run until they are finished or delayed by using `io.wait`.
+
The `logLevel` property is an optional property that specifies the level of
logging for the Job. The level is inherited from the client if you omit this property.
diff --git a/packages/database/prisma/migrations/20230823124049_add_deleted_at_to_jobs/migration.sql b/packages/database/prisma/migrations/20230823124049_add_deleted_at_to_jobs/migration.sql
new file mode 100644
index 000000000..091492ed2
--- /dev/null
+++ b/packages/database/prisma/migrations/20230823124049_add_deleted_at_to_jobs/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Job" ADD COLUMN "deletedAt" TIMESTAMP(3);
diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma
index 7bf609470..f41f67b04 100644
--- a/packages/database/prisma/schema.prisma
+++ b/packages/database/prisma/schema.prisma
@@ -420,6 +420,8 @@ model Job {
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
+ deletedAt DateTime?
+
@@unique([projectId, slug])
}
diff --git a/packages/trigger-sdk/src/triggerClient.ts b/packages/trigger-sdk/src/triggerClient.ts
index 9881d78da..a6d774354 100644
--- a/packages/trigger-sdk/src/triggerClient.ts
+++ b/packages/trigger-sdk/src/triggerClient.ts
@@ -605,15 +605,6 @@ export class TriggerClient {
}
async #executeJob(body: RunJobBody, job: Job, any>): Promise {
- if (!job.enabled) {
- return {
- status: "ERROR",
- error: {
- message: "Job is disabled",
- },
- };
- }
-
this.#internalLogger.debug("executing job", {
execution: body,
job: job.toJSON(),