Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/tiny-pillows-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@trigger.dev/airtable": patch
"@trigger.dev/sendgrid": patch
"@trigger.dev/supabase": patch
"@trigger.dev/typeform": patch
"@trigger.dev/sdk": patch
"@trigger.dev/github": patch
"@trigger.dev/openai": patch
"@trigger.dev/resend": patch
"@trigger.dev/stripe": patch
"@trigger.dev/plain": patch
"@trigger.dev/slack": patch
"@trigger.dev/core": patch
---

Add support for Bring Your Own Auth
9 changes: 9 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
"name": "Chrome webapp",
"url": "http://localhost:3030",
"webRoot": "${workspaceFolder}/apps/webapp/app"
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug BYO Auth",
"command": "pnpm run byo-auth",
"envFile": "${workspaceFolder}/references/job-catalog/.env",
"cwd": "${workspaceFolder}/references/job-catalog",
"sourceMaps": true
}
]
}
1 change: 1 addition & 0 deletions apps/webapp/app/components/jobs/JobsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function classForJobStatus(status: JobRunStatus) {
case "TIMED_OUT":
case "WAITING_ON_CONNECTIONS":
case "PENDING":
case "UNRESOLVED_AUTH":
return "text-rose-500";
default:
return "";
Expand Down
8 changes: 7 additions & 1 deletion apps/webapp/app/components/run/RunOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,13 @@ export function RunOverview({ run, trigger, showRerun, paths }: RunOverviewProps
<RunPanelHeader icon={trigger.icon} title={trigger.title} />
<RunPanelBody>
<RunPanelProperties
properties={[{ label: "Event name", text: run.event.name }, ...run.properties]}
properties={[{ label: "Event name", text: run.event.name }]
.concat(
run.event.externalAccount
? [{ label: "Account ID", text: run.event.externalAccount.identifier }]
: []
)
.concat(run.properties)}
/>
</RunPanelBody>
</RunPanel>
Expand Down
7 changes: 7 additions & 0 deletions apps/webapp/app/components/run/TriggerDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ export function TriggerDetail({
/>
)}
<RunPanelIconProperty icon="id" label="Event name" value={name} />
{trigger.externalAccount && (
<RunPanelIconProperty
icon="account"
label="Account ID"
value={trigger.externalAccount.identifier}
/>
)}
</RunPanelIconSection>
<RunPanelDivider />
<div className="mt-4 flex flex-col gap-2">
Expand Down
40 changes: 24 additions & 16 deletions apps/webapp/app/components/runs/RunStatuses.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import type { JobRunExecution, JobRunStatus } from "@trigger.dev/database";
import { NoSymbolIcon } from "@heroicons/react/20/solid";
import {
CheckCircleIcon,
ClockIcon,
ExclamationTriangleIcon,
StopIcon,
WrenchIcon,
XCircleIcon,
} from "@heroicons/react/24/solid";
import type { JobRunStatus } from "@trigger.dev/database";
import { cn } from "~/utils/cn";
import { Spinner } from "../primitives/Spinner";
import { HandRaisedIcon, NoSymbolIcon } from "@heroicons/react/20/solid";

export function hasFinished(status: JobRunStatus): boolean {
return (
status === "SUCCESS" ||
status === "FAILURE" ||
status === "ABORTED" ||
status === "TIMED_OUT" ||
status === "CANCELED"
status === "CANCELED" ||
status === "UNRESOLVED_AUTH"
);
}

Expand Down Expand Up @@ -48,6 +48,8 @@ export function RunStatusIcon({ status, className }: { status: JobRunStatus; cla
return <XCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "TIMED_OUT":
return <ExclamationTriangleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "UNRESOLVED_AUTH":
return <XCircleIcon className={cn(runStatusClassNameColor(status), className)} />;
case "WAITING_ON_CONNECTIONS":
return <WrenchIcon className={cn(runStatusClassNameColor(status), className)} />;
case "ABORTED":
Expand All @@ -63,26 +65,25 @@ export type RunBasicStatus = "WAITING" | "PENDING" | "RUNNING" | "COMPLETED" | "

export function runBasicStatus(status: JobRunStatus): RunBasicStatus {
switch (status) {
case "SUCCESS":
return "COMPLETED";
case "WAITING_ON_CONNECTIONS":
case "QUEUED":
case "PREPROCESSING":
case "PENDING":
return "PENDING";
case "STARTED":
return "RUNNING";
case "QUEUED":
return "PENDING";
case "FAILURE":
return "FAILED";
case "TIMED_OUT":
return "FAILED";
case "WAITING_ON_CONNECTIONS":
return "PENDING";
case "ABORTED":
return "FAILED";
case "PREPROCESSING":
return "PENDING";
case "UNRESOLVED_AUTH":
case "CANCELED":
case "ABORTED":
return "FAILED";
case "SUCCESS":
return "COMPLETED";
default: {
const _exhaustiveCheck: never = status;
throw new Error(`Non-exhaustive match for value: ${status}`);
}
}
}

Expand All @@ -108,6 +109,12 @@ export function runStatusTitle(status: JobRunStatus): string {
return "Preprocessing";
case "CANCELED":
return "Canceled";
case "UNRESOLVED_AUTH":
return "Unresolved auth";
default: {
const _exhaustiveCheck: never = status;
throw new Error(`Non-exhaustive match for value: ${status}`);
}
}
}

Expand All @@ -122,6 +129,7 @@ export function runStatusClassNameColor(status: JobRunStatus): string {
case "QUEUED":
return "text-amber-300";
case "FAILURE":
case "UNRESOLVED_AUTH":
return "text-rose-500";
case "TIMED_OUT":
return "text-amber-300";
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/models/runConnection.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function resolveRunConnections(
const result: Record<string, ConnectionAuth> = {};

for (const connection of connections) {
if (connection.integration.authSource === "LOCAL") {
if (connection.integration.authSource !== "HOSTED") {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,12 @@ export class IntegrationClientPresenter {
icon: integration.definition.icon,
},
authMethod: {
type: integration.authMethod?.type ?? "local",
name: integration.authMethod?.name ?? "Local Auth",
type:
integration.authMethod?.type ?? integration.authSource === "RESOLVER" ? "local" : "local",
name:
integration.authMethod?.name ?? integration.authSource === "RESOLVER"
? "Auth Resolver"
: "Local Auth",
},
help,
};
Expand Down
5 changes: 3 additions & 2 deletions apps/webapp/app/presenters/IntegrationsPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ export class IntegrationsPresenter {
name: c.definition.name,
},
authMethod: {
type: c.authMethod?.type ?? "local",
name: c.authMethod?.name ?? "Local Only",
type: c.authMethod?.type ?? c.authSource === "RESOLVER" ? "resolver" : "local",
name:
c.authMethod?.name ?? c.authSource === "RESOLVER" ? "Auth Resolver" : "Local Only",
},
authSource: c.authSource,
setupStatus: c.setupStatus,
Expand Down
5 changes: 5 additions & 0 deletions apps/webapp/app/presenters/RunPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ export class RunPresenter {
payload: true,
timestamp: true,
deliveredAt: true,
externalAccount: {
select: {
identifier: true,
},
},
},
},
tasks: {
Expand Down
12 changes: 12 additions & 0 deletions apps/webapp/app/presenters/TestJobPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ export class TestJobPresenter {
payload: true,
},
},
integrations: {
select: {
integration: {
select: {
authSource: true,
},
},
},
},
},
},
environment: {
Expand Down Expand Up @@ -99,6 +108,9 @@ export class TestJobPresenter {
...example,
payload: JSON.stringify(example.payload, exampleReplacer, 2),
})),
hasAuthResolver: alias.version.integrations.some(
(i) => i.integration.authSource === "RESOLVER"
),
})),
hasTestRuns: job._count.runs > 0,
};
Expand Down
5 changes: 5 additions & 0 deletions apps/webapp/app/presenters/TriggerDetailsPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export class TriggerDetailsPresenter {
payload: true,
timestamp: true,
deliveredAt: true,
externalAccount: {
select: {
identifier: true,
},
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useForm } from "@conform-to/react";
import { conform, useForm } from "@conform-to/react";
import { parse } from "@conform-to/zod";
import { PopoverTrigger } from "@radix-ui/react-popover";
import { Form, useActionData, useSubmit } from "@remix-run/react";
Expand All @@ -14,6 +14,9 @@ import { Button, ButtonContent } from "~/components/primitives/Buttons";
import { Callout } from "~/components/primitives/Callout";
import { FormError } from "~/components/primitives/FormError";
import { Help, HelpContent, HelpTrigger } from "~/components/primitives/Help";
import { Input } from "~/components/primitives/Input";
import { InputGroup } from "~/components/primitives/InputGroup";
import { Label } from "~/components/primitives/Label";
import { Popover, PopoverContent } from "~/components/primitives/Popover";
import {
Select,
Expand Down Expand Up @@ -69,6 +72,7 @@ const schema = z.object({
}),
environmentId: z.string(),
versionId: z.string(),
accountId: z.string().optional(),
});

//todo save the chosen environment to a cookie (for that user), use it to default the env dropdown
Expand All @@ -84,11 +88,7 @@ export const action: ActionFunction = async ({ request, params }) => {
}

const testService = new TestJobService();
const run = await testService.call({
environmentId: submission.value.environmentId,
payload: submission.value.payload,
versionId: submission.value.versionId,
});
const run = await testService.call(submission.value);

if (!run) {
return redirectBackWithErrorMessage(
Expand Down Expand Up @@ -124,6 +124,7 @@ export default function Page() {
const [defaultJson, setDefaultJson] = useState<string>(startingJson);
const currentJson = useRef<string>(defaultJson);
const [selectedEnvironmentId, setSelectedEnvironmentId] = useState<string>(environments[0].id);
const [currentAccountId, setCurrentAccountId] = useState<string | undefined>(undefined);

const selectedEnvironment = environments.find((e) => e.id === selectedEnvironmentId);

Expand All @@ -139,6 +140,7 @@ export default function Page() {
payload: currentJson.current,
environmentId: selectedEnvironmentId,
versionId: selectedEnvironment?.versionId ?? "",
...(currentAccountId ? { accountId: currentAccountId } : {}),
},
{
action: "",
Expand All @@ -147,10 +149,10 @@ export default function Page() {
);
e.preventDefault();
},
[currentJson, selectedEnvironmentId]
[currentJson, selectedEnvironmentId, currentAccountId]
);

const [form, { environmentId, payload }] = useForm({
const [form, { environmentId, payload, accountId }] = useForm({
id: "test-job",
lastSubmission,
onValidate({ formData }) {
Expand Down Expand Up @@ -234,15 +236,32 @@ export default function Page() {
</div>
<HelpTrigger title="How do I run a test?" />
</div>
<div className="flex-1 overflow-auto rounded border border-slate-850 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-700">
<JSONEditor
defaultValue={defaultJson}
readOnly={false}
basicSetup
onChange={(v) => (currentJson.current = v)}
minHeight="150px"
/>
</div>
<InputGroup fullWidth>
<Label variant="small">Payload</Label>
<div className="flex-1 overflow-auto rounded border border-slate-850 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-700">
<JSONEditor
defaultValue={defaultJson}
readOnly={false}
basicSetup
onChange={(v) => (currentJson.current = v)}
minHeight="150px"
/>
</div>
</InputGroup>

{selectedEnvironment?.hasAuthResolver && (
<InputGroup fullWidth className="mb-4 mt-4">
<Label variant="small">Account ID</Label>
<Input
type="text"
fullWidth
value={currentAccountId}
placeholder={`e.g. abc_1234`}
onChange={(e) => setCurrentAccountId(e.target.value)}
/>
<FormError>{accountId.error}</FormError>
</InputGroup>
)}
<div className="flex flex-none items-center justify-between">
{payload.error ? (
<FormError id={payload.errorId}>{payload.error}</FormError>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,19 @@ class CreateExternalConnectionService {
environment: AuthenticatedEnvironment,
payload: CreateExternalConnectionBody
) {
const externalAccount = await this.#prismaClient.externalAccount.findUniqueOrThrow({
const externalAccount = await this.#prismaClient.externalAccount.upsert({
where: {
environmentId_identifier: {
environmentId: environment.id,
identifier: accountIdentifier,
},
},
create: {
environmentId: environment.id,
organizationId: environment.organizationId,
identifier: accountIdentifier,
},
update: {},
});

const integration = await this.#prismaClient.integration.findUniqueOrThrow({
Expand Down
Loading