888344797e
* Added more API icons * Updated the title * Added resources.codeexample.ts to pull in example code from github * Added regex to remove redundant express code from the examples * Added cal examples * Code changes onSubmit * Improved the code loading state * Removed request integration button * Improved the Customhelp copy * Fixed styling issues and removed imports * Added all the code examples * Don’t show title if there’s 1 or less examples * Updated copy for the non example version * Added example code to the apis without examples, added a focus state * Fixed titles * Got rid of the phantom gap * Made the copy more generic so it works on the integration pages as well * Removed import * Added view examples button to the integration pages * Removed fetch/sdk option from integration sheet * Apply code example regex on the server --------- Co-authored-by: Matt Aitken <matt@mattaitken.com>
173 lines
4.8 KiB
TypeScript
173 lines
4.8 KiB
TypeScript
import { User } from "@trigger.dev/database";
|
|
import { PrismaClient, prisma } from "~/db.server";
|
|
import { env } from "~/env.server";
|
|
import { Organization } from "~/models/organization.server";
|
|
import { Project } from "~/models/project.server";
|
|
import { Api, apisList } from "~/services/externalApis/apis.server";
|
|
import { integrationCatalog } from "~/services/externalApis/integrationCatalog.server";
|
|
import { Integration, OAuthClientSchema } from "~/services/externalApis/types";
|
|
import { getSecretStore } from "~/services/secrets/secretStore.server";
|
|
|
|
export type IntegrationOrApi =
|
|
| ({
|
|
type: "integration";
|
|
} & Integration)
|
|
| ({ type: "api" } & Api & { voted: boolean });
|
|
|
|
export type Client = Awaited<ReturnType<IntegrationsPresenter["call"]>>["clients"][number];
|
|
|
|
export class IntegrationsPresenter {
|
|
#prismaClient: PrismaClient;
|
|
|
|
constructor(prismaClient: PrismaClient = prisma) {
|
|
this.#prismaClient = prismaClient;
|
|
}
|
|
|
|
public async call({
|
|
userId,
|
|
organizationSlug,
|
|
}: {
|
|
userId: User["id"];
|
|
organizationSlug: Organization["slug"];
|
|
}) {
|
|
const clients = await this.#prismaClient.integration.findMany({
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
slug: true,
|
|
description: true,
|
|
setupStatus: true,
|
|
authMethod: {
|
|
select: {
|
|
type: true,
|
|
name: true,
|
|
},
|
|
},
|
|
definition: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
icon: true,
|
|
},
|
|
},
|
|
authSource: true,
|
|
connectionType: true,
|
|
scopes: true,
|
|
customClientReference: {
|
|
select: {
|
|
key: true,
|
|
},
|
|
},
|
|
createdAt: true,
|
|
_count: {
|
|
select: {
|
|
connections: true,
|
|
jobIntegrations: {
|
|
where: {
|
|
job: {
|
|
organization: {
|
|
slug: organizationSlug,
|
|
},
|
|
internal: false,
|
|
deletedAt: null,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
where: {
|
|
organization: {
|
|
slug: organizationSlug,
|
|
members: {
|
|
some: {
|
|
userId,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
orderBy: {
|
|
title: "asc",
|
|
},
|
|
});
|
|
|
|
const secretStore = getSecretStore(env.SECRET_STORE, {
|
|
prismaClient: this.#prismaClient,
|
|
});
|
|
|
|
const enrichedClients = await Promise.all(
|
|
clients.map(async (c) => {
|
|
let clientId: String | undefined = undefined;
|
|
if (c.customClientReference) {
|
|
const clientConfig = await secretStore.getSecret(
|
|
OAuthClientSchema,
|
|
c.customClientReference.key
|
|
);
|
|
clientId = clientConfig?.id;
|
|
}
|
|
|
|
return {
|
|
id: c.id,
|
|
title: c.title ?? c.slug,
|
|
icon: c.definition.icon ?? c.definition.id,
|
|
slug: c.slug,
|
|
integrationIdentifier: c.definition.id,
|
|
description: c.description,
|
|
scopesCount: c.scopes.length,
|
|
connectionsCount: c._count.connections,
|
|
jobCount: c._count.jobIntegrations,
|
|
createdAt: c.createdAt,
|
|
customClientId: clientId,
|
|
integration: {
|
|
identifier: c.definition.id,
|
|
name: c.definition.name,
|
|
},
|
|
authMethod: {
|
|
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,
|
|
};
|
|
})
|
|
);
|
|
|
|
const setupClients = enrichedClients.filter((c) => c.setupStatus === "COMPLETE");
|
|
const clientMissingFields = enrichedClients.filter((c) => c.setupStatus === "MISSING_FIELDS");
|
|
|
|
const integrations = Object.values(integrationCatalog.getIntegrations()).map((i) => ({
|
|
type: "integration" as const,
|
|
...i,
|
|
}));
|
|
|
|
//get all apis, some don't have integrations yet.
|
|
//get whether the user has voted for them or not
|
|
const votes = await this.#prismaClient.apiIntegrationVote.findMany({
|
|
select: {
|
|
apiIdentifier: true,
|
|
},
|
|
where: {
|
|
userId,
|
|
},
|
|
});
|
|
|
|
const apis = apisList
|
|
.filter((a) => !integrations.some((i) => i.identifier === a.identifier))
|
|
.map((a) => ({
|
|
type: "api" as const,
|
|
...a,
|
|
voted: votes.some((v) => v.apiIdentifier === a.identifier),
|
|
}));
|
|
|
|
const options = [...integrations, ...apis].sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
return {
|
|
clients: setupClients,
|
|
clientMissingFields,
|
|
options,
|
|
callbackUrl: `${env.APP_ORIGIN}/oauth2/callback`,
|
|
};
|
|
}
|
|
}
|