Integrations can be enabled just for admins, or turned off for everyone
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as fs from "node:fs";
|
||||
import { getCatalog } from "internal-catalog";
|
||||
|
||||
export function getIntegrations() {
|
||||
export function getIntegrations(showAdminOnly: boolean) {
|
||||
const file = fs.readFileSync("./integrations.yml", "utf8");
|
||||
return getCatalog(file);
|
||||
return getCatalog(file, showAdminOnly);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export class WorkflowRunPresenter {
|
||||
throw new Error(`Workflow run with id ${id} not found`);
|
||||
}
|
||||
|
||||
const integrations = getIntegrations();
|
||||
const integrations = getIntegrations(true);
|
||||
const steps = await Promise.all(
|
||||
workflowRun.tasks.map((step) => parseStep(step, integrations))
|
||||
);
|
||||
|
||||
@@ -20,13 +20,13 @@ import { useCurrentOrganization } from "~/hooks/useOrganizations";
|
||||
import type { OrgWorkflow } from "~/hooks/useWorkflows";
|
||||
import { useWorkflows } from "~/hooks/useWorkflows";
|
||||
import { getIntegrations } from "~/models/integrations.server";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { requireUser } from "~/services/session.server";
|
||||
import { formatDateTime } from "~/utils";
|
||||
import { getIntegration } from "~/utils/integrations";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
await requireUserId(request);
|
||||
return typedjson({ integrations: getIntegrations() });
|
||||
const user = await requireUser(request);
|
||||
return typedjson({ integrations: getIntegrations(user.admin) });
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
|
||||
@@ -18,12 +18,13 @@ import {
|
||||
import { useCurrentOrganization } from "~/hooks/useOrganizations";
|
||||
import { getConnectedApiConnectionsForOrganizationSlug } from "~/models/apiConnection.server";
|
||||
import { getIntegrations } from "~/models/integrations.server";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { requireUser } from "~/services/session.server";
|
||||
import { formatDateTime } from "~/utils";
|
||||
import { getIntegration } from "~/utils/integrations";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
await requireUserId(request);
|
||||
const user = await requireUser(request);
|
||||
|
||||
const { organizationSlug } = params;
|
||||
invariant(organizationSlug, "organizationSlug not found");
|
||||
|
||||
@@ -31,7 +32,7 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
slug: organizationSlug,
|
||||
});
|
||||
|
||||
return typedjson({ connections, integrations: getIntegrations() });
|
||||
return typedjson({ connections, integrations: getIntegrations(user.admin) });
|
||||
};
|
||||
|
||||
export default function Integrations() {
|
||||
|
||||
@@ -12,16 +12,16 @@ import { getConnectedApiConnectionsForOrganizationSlug } from "~/models/apiConne
|
||||
import { getIntegrations } from "~/models/integrations.server";
|
||||
import { getRuntimeEnvironmentFromRequest } from "~/models/runtimeEnvironment.server";
|
||||
import { getWorkflowFromSlugs } from "~/models/workflow.server";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { requireUser } from "~/services/session.server";
|
||||
|
||||
export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const userId = await requireUserId(request);
|
||||
const user = await requireUser(request);
|
||||
const { organizationSlug, workflowSlug } = params;
|
||||
invariant(organizationSlug, "organizationSlug not found");
|
||||
invariant(workflowSlug, "workflowSlug not found");
|
||||
|
||||
let workflow = await getWorkflowFromSlugs({
|
||||
userId,
|
||||
userId: user.id,
|
||||
organizationSlug,
|
||||
workflowSlug,
|
||||
});
|
||||
@@ -30,6 +30,8 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
throw new Response("Not Found", { status: 404 });
|
||||
}
|
||||
|
||||
const integrations = getIntegrations(user.admin);
|
||||
|
||||
const rules = workflow.rules.map((r) => ({
|
||||
...r,
|
||||
trigger: TriggerMetadataSchema.parse(r.trigger),
|
||||
@@ -43,7 +45,7 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
slug: organizationSlug,
|
||||
});
|
||||
|
||||
const externalSourceIntegration = getIntegrations().find(
|
||||
const externalSourceIntegration = integrations.find(
|
||||
(i) => i.slug === workflow?.externalSource?.service
|
||||
);
|
||||
const externalSourceSlot =
|
||||
@@ -60,7 +62,7 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
||||
const connectionSlots = {
|
||||
source: externalSourceSlot,
|
||||
services: workflow.externalServices.flatMap((c) => {
|
||||
const integration = getIntegrations().find((i) => i.slug === c.service);
|
||||
const integration = integrations.find((i) => i.slug === c.service);
|
||||
|
||||
if (!integration) {
|
||||
return [];
|
||||
|
||||
@@ -71,7 +71,7 @@ export const action = async ({ request }: ActionArgs) => {
|
||||
}
|
||||
|
||||
const parsed = parsedResult.data;
|
||||
const integrationInfo = getIntegrations().find(
|
||||
const integrationInfo = getIntegrations(true).find(
|
||||
(i) => i.slug === parsed.service
|
||||
);
|
||||
if (!integrationInfo) {
|
||||
|
||||
@@ -42,9 +42,29 @@
|
||||
client_id: "09bd8b46-6b80-4343-9ffd-5750a8c3e2f1"
|
||||
production:
|
||||
client_id: abcdefg
|
||||
- name: Shopify
|
||||
slug: shopify
|
||||
icon: /integrations/shopify.png
|
||||
enabledFor: admins
|
||||
authentication:
|
||||
type: oauth
|
||||
scopes:
|
||||
- data.records:read
|
||||
- data.records:write
|
||||
- data.recordComments:read
|
||||
- data.recordComments:write
|
||||
- schema.bases:read
|
||||
- schema.bases:write
|
||||
- webook:manage
|
||||
environments:
|
||||
development:
|
||||
client_id: "09bd8b46-6b80-4343-9ffd-5750a8c3e2f1"
|
||||
production:
|
||||
client_id: abcdefg
|
||||
- name: Mailgun
|
||||
slug: mailgun
|
||||
icon: /integrations/mailgun.png
|
||||
enabledFor: admins
|
||||
authentication:
|
||||
type: api_key
|
||||
header_name: "Authorization"
|
||||
|
||||
@@ -2,10 +2,19 @@ import { z } from "zod";
|
||||
import { parseDocument } from "yaml";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const enabledForSchema = z.union([
|
||||
z.literal("all"),
|
||||
z.literal("admins"),
|
||||
z.literal("none"),
|
||||
]);
|
||||
|
||||
type EnabledFor = z.infer<typeof enabledForSchema>;
|
||||
|
||||
const integrationMetadataSchema = z.object({
|
||||
name: z.string(),
|
||||
slug: z.string(),
|
||||
icon: z.string(),
|
||||
enabledFor: enabledForSchema.default("all"),
|
||||
});
|
||||
|
||||
const oAuthIntegrationAuthenticationSchema = z.object({
|
||||
@@ -37,9 +46,20 @@ const schema = z.array(integrationSchema);
|
||||
type Catalog = z.infer<typeof schema>;
|
||||
export type CatalogIntegration = Catalog[number];
|
||||
|
||||
export function getCatalog(raw: string) {
|
||||
export function getCatalog(raw: string, isAdmin: boolean) {
|
||||
const doc = parseDocument(raw);
|
||||
invariant(doc, `Catalog doc is not defined: ${raw}`);
|
||||
const jsObject = doc.toJS();
|
||||
return schema.parse(jsObject);
|
||||
const catalog = schema.parse(jsObject);
|
||||
|
||||
return catalog.filter((i) => {
|
||||
switch (i.enabledFor) {
|
||||
case "all":
|
||||
return true;
|
||||
case "admins":
|
||||
return isAdmin;
|
||||
case "none":
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ program
|
||||
const pizzly_host = options.pizzlyhost ?? "http://localhost:3004";
|
||||
|
||||
const file = fs.readFileSync(integration_file_path, "utf8");
|
||||
const catalog = getCatalog(file);
|
||||
const catalog = getCatalog(file, true);
|
||||
|
||||
const client = new SecretsManagerClient({
|
||||
region: "us-east-1",
|
||||
|
||||
Reference in New Issue
Block a user