Early work on Trigger detail page
This commit is contained in:
@@ -38,6 +38,7 @@ export type Breadcrumb = {
|
||||
| "integration-connections"
|
||||
| "integration-scopes"
|
||||
| "triggers"
|
||||
| "trigger"
|
||||
| "environments"
|
||||
| "job"
|
||||
| "test"
|
||||
@@ -177,6 +178,14 @@ function BreadcrumbItem({
|
||||
title={"Triggers"}
|
||||
/>
|
||||
);
|
||||
case "trigger":
|
||||
if (!organization || !project) return null;
|
||||
return (
|
||||
<BreadcrumbLink
|
||||
to={projectTriggersPath(organization, project)}
|
||||
title={"Triggers"}
|
||||
/>
|
||||
);
|
||||
case "job":
|
||||
if (!organization || !project || !job) return null;
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { TriggerSource, User } from "@trigger.dev/database";
|
||||
import { PrismaClient, prisma } from "~/db.server";
|
||||
import { Organization } from "~/models/organization.server";
|
||||
import { Project } from "~/models/project.server";
|
||||
|
||||
export class DynamicTriggerSourcePresenter {
|
||||
#prismaClient: PrismaClient;
|
||||
|
||||
constructor(prismaClient: PrismaClient = prisma) {
|
||||
this.#prismaClient = prismaClient;
|
||||
}
|
||||
|
||||
public async call({
|
||||
userId,
|
||||
projectSlug,
|
||||
organizationSlug,
|
||||
triggerSourceId,
|
||||
}: {
|
||||
userId: User["id"];
|
||||
projectSlug: Project["slug"];
|
||||
organizationSlug: Organization["slug"];
|
||||
triggerSourceId: TriggerSource["id"];
|
||||
}) {
|
||||
const trigger = await this.#prismaClient.triggerSource.findUnique({
|
||||
select: {
|
||||
id: true,
|
||||
active: true,
|
||||
dynamicTrigger: true,
|
||||
integration: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
definitionId: true,
|
||||
setupStatus: true,
|
||||
},
|
||||
},
|
||||
environment: {
|
||||
select: {
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
params: true,
|
||||
registrations: true,
|
||||
sourceRegistrationJob: true,
|
||||
},
|
||||
where: {
|
||||
id: triggerSourceId,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
trigger,
|
||||
};
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
import { Response } from "@remix-run/node";
|
||||
import type { LoaderArgs } from "@remix-run/server-runtime";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
|
||||
import {
|
||||
PageHeader,
|
||||
PageInfoGroup,
|
||||
PageInfoProperty,
|
||||
PageInfoRow,
|
||||
PageTitle,
|
||||
PageTitleRow,
|
||||
} from "~/components/primitives/PageHeader";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { DynamicTriggerSourcePresenter } from "~/presenters/DynamicTriggerSourcePresenter.server";
|
||||
import { requireUser } from "~/services/session.server";
|
||||
import { Handle } from "~/utils/handle";
|
||||
import {
|
||||
TriggerSourceParamSchema,
|
||||
projectTriggersPath,
|
||||
} from "~/utils/pathBuilder";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const user = await requireUser(request);
|
||||
const { organizationSlug, projectParam, triggerParam } =
|
||||
TriggerSourceParamSchema.parse(params);
|
||||
|
||||
const presenter = new DynamicTriggerSourcePresenter();
|
||||
const { trigger } = await presenter.call({
|
||||
userId: user.id,
|
||||
organizationSlug,
|
||||
projectSlug: projectParam,
|
||||
triggerSourceId: triggerParam,
|
||||
});
|
||||
|
||||
if (!trigger) {
|
||||
throw new Response("Trigger not found", {
|
||||
status: 404,
|
||||
statusText: "Not Found",
|
||||
});
|
||||
}
|
||||
|
||||
return typedjson({ trigger });
|
||||
};
|
||||
|
||||
export const handle: Handle = {
|
||||
breadcrumb: {
|
||||
slug: "trigger",
|
||||
},
|
||||
};
|
||||
|
||||
//todo outlet somewhere, look at how I did this with the integration client page.
|
||||
|
||||
export default function Integrations() {
|
||||
const { trigger } = useTypedLoaderData<typeof loader>();
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader>
|
||||
<PageTitleRow>
|
||||
<PageTitle
|
||||
title="Trigger detail"
|
||||
backButton={{
|
||||
to: projectTriggersPath(organization, project),
|
||||
text: "Triggers",
|
||||
}}
|
||||
/>
|
||||
</PageTitleRow>
|
||||
<PageInfoRow>
|
||||
<PageInfoGroup>
|
||||
<PageInfoProperty
|
||||
icon={trigger.integration.definitionId}
|
||||
label="Integration"
|
||||
value={trigger.integration.title}
|
||||
/>
|
||||
</PageInfoGroup>
|
||||
</PageInfoRow>
|
||||
</PageHeader>
|
||||
|
||||
<PageBody scrollable={false}>
|
||||
{/* <div className="h-full overflow-y-auto p-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-700">
|
||||
<div>
|
||||
<Header2 spacing>External Triggers</Header2>
|
||||
<Paragraph variant="small" spacing>
|
||||
Webhooks are connected as external Triggers
|
||||
</Paragraph>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>Integration</TableHeaderCell>
|
||||
<TableHeaderCell>Properties</TableHeaderCell>
|
||||
<TableHeaderCell>Active</TableHeaderCell>
|
||||
<TableHeaderCell>Environment</TableHeaderCell>
|
||||
<TableHeaderCell hiddenLabel>Go to page</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{triggers.map((t) => {
|
||||
const path = triggerSourcePath(organization, project, t);
|
||||
return (
|
||||
<TableRow key={t.id}>
|
||||
<TableCell to={path}>
|
||||
<span className="flex items-center gap-1">
|
||||
<NamedIcon
|
||||
name={t.integration.definitionId}
|
||||
className="h-6 w-6"
|
||||
/>
|
||||
{t.integration.title}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
{t.params && (
|
||||
<SimpleTooltip
|
||||
button={
|
||||
<div className="flex max-w-[200px] items-start justify-start gap-5 truncate">
|
||||
{Object.entries(t.params).map(
|
||||
([label, value], index) => (
|
||||
<LabelValueStack
|
||||
key={index}
|
||||
label={label}
|
||||
value={value}
|
||||
className="last:truncate"
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
content={
|
||||
<div className="flex flex-col gap-2">
|
||||
{Object.entries(t.params).map(
|
||||
([label, value], index) => (
|
||||
<LabelValueStack
|
||||
key={index}
|
||||
label={label}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
{t.active ? (
|
||||
<CheckCircleIcon className="h-6 w-6 text-green-500" />
|
||||
) : (
|
||||
<XCircleIcon className="h-6 w-6 text-rose-500" />
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
<span className="flex">
|
||||
<EnvironmentLabel environment={t.environment} />
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCellChevron to={path} />
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div> */}
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
+3
-36
@@ -1,38 +1,20 @@
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
ChevronRightIcon,
|
||||
XCircleIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
|
||||
import type { LoaderArgs } from "@remix-run/server-runtime";
|
||||
import { useCallback, useState } from "react";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { LogoIcon } from "~/components/LogoIcon";
|
||||
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
|
||||
import { HowToConnectAnIntegration } from "~/components/helpContent/HelpContentText";
|
||||
import { ConnectToIntegrationSheet } from "~/components/integrations/ConnectToIntegrationSheet";
|
||||
import { IntegrationWithMissingFieldSheet } from "~/components/integrations/IntegrationWithMissingFieldSheet";
|
||||
import { NoIntegrationSheet } from "~/components/integrations/NoIntegrationSheet";
|
||||
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
|
||||
import { LinkButton } from "~/components/primitives/Buttons";
|
||||
import { Callout } from "~/components/primitives/Callout";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import { Header2 } from "~/components/primitives/Headers";
|
||||
import { Help, HelpContent, HelpTrigger } from "~/components/primitives/Help";
|
||||
import { Input } from "~/components/primitives/Input";
|
||||
import { LabelValueStack } from "~/components/primitives/LabelValueStack";
|
||||
import { NamedIcon, NamedIconInBox } from "~/components/primitives/NamedIcon";
|
||||
import { NamedIcon } from "~/components/primitives/NamedIcon";
|
||||
import {
|
||||
PageButtons,
|
||||
PageDescription,
|
||||
PageHeader,
|
||||
PageTitle,
|
||||
PageTitleRow,
|
||||
} from "~/components/primitives/PageHeader";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import { Switch } from "~/components/primitives/Switch";
|
||||
import {
|
||||
Table,
|
||||
TableBlankRow,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellChevron,
|
||||
@@ -43,23 +25,10 @@ import {
|
||||
import { SimpleTooltip } from "~/components/primitives/Tooltip";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { useTextFilter } from "~/hooks/useTextFilter";
|
||||
import { Organization } from "~/models/organization.server";
|
||||
import { Project } from "~/models/project.server";
|
||||
import {
|
||||
Client,
|
||||
IntegrationOrApi,
|
||||
IntegrationsPresenter,
|
||||
} from "~/presenters/IntegrationsPresenter.server";
|
||||
import { TriggersPresenter } from "~/presenters/TriggersPresenter.server";
|
||||
import { requireUser } from "~/services/session.server";
|
||||
import { Handle } from "~/utils/handle";
|
||||
import {
|
||||
ProjectParamSchema,
|
||||
docsCreateIntegration,
|
||||
integrationClientPath,
|
||||
triggerSourcePath,
|
||||
} from "~/utils/pathBuilder";
|
||||
import { ProjectParamSchema, triggerSourcePath } from "~/utils/pathBuilder";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const user = await requireUser(request);
|
||||
@@ -86,8 +55,6 @@ export default function Integrations() {
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
|
||||
console.log(triggers);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader>
|
||||
|
||||
@@ -35,6 +35,10 @@ export const IntegrationClientParamSchema = ProjectParamSchema.extend({
|
||||
clientParam: z.string(),
|
||||
});
|
||||
|
||||
export const TriggerSourceParamSchema = ProjectParamSchema.extend({
|
||||
triggerParam: z.string(),
|
||||
});
|
||||
|
||||
export function organizationsPath() {
|
||||
return `/`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user