import { useState } from "react"; import { createIntegration } from "~/fns/integrations"; import type { listIntegrations } from "~/fns/integrations"; import { useAction } from "~/hooks/use-action"; import { Button, buttonClass } from "~/ui/Button"; import { SelectField, TextField } from "~/ui/Field"; import { ErrorBanner } from "~/ui/Callout"; import { EmptyState } from "~/ui/EmptyState"; import { Panel } from "~/ui/Panel"; import { DEFAULT_INTEGRATION_EVENTS, INTEGRATION_EVENT_LABELS, INTEGRATION_EVENTS } from "~/lib/integrations"; import { IntegrationCard } from "./IntegrationCard"; import { Callout } from "~/ui/Callout"; export type IntegrationsData = Awaited>; export type ScopeParams = { owner: string; repo: string | null }; const WEBHOOK_KINDS = [ { value: "slack", label: "Slack (incoming webhook)", placeholder: "https://hooks.slack.com/services/…" }, { value: "google_chat", label: "Google Chat (space webhook)", placeholder: "https://chat.googleapis.com/v1/spaces/…", }, { value: "webhook", label: "Generic webhook (signed JSON)", placeholder: "https://example.com/hooks/gitfor" }, ] as const; type WebhookKind = (typeof WEBHOOK_KINDS)[number]["value"]; function installHref(provider: string, scope: ScopeParams): string { const query = new URLSearchParams({ owner: scope.owner }); if (scope.repo) query.set("repo", scope.repo); return `/integrations/${provider}/install?${query.toString()}`; } function ConnectApps({ data, scope }: { data: IntegrationsData; scope: ScopeParams }) { const apps = [ { provider: "slack", label: "Add to Slack", enabled: data.providers.slackOAuth }, { provider: "linear", label: "Connect Linear", enabled: data.providers.linear }, { provider: "github", label: "Install GitHub App", enabled: data.providers.githubApp }, ]; return (
{apps.map((app) => app.enabled ? ( {app.label} ) : ( {app.label} (not configured) ), )}

Slack slash command URL: {data.slashCommandUrl} · GitHub App webhook URL:{" "} {data.githubWebhookUrl}

); } function AddWebhook({ data, scope }: { data: IntegrationsData; scope: ScopeParams }) { const create = useAction(createIntegration); const [kind, setKind] = useState("slack"); const [secret, setSecret] = useState(null); const meta = WEBHOOK_KINDS.find((entry) => entry.value === kind) ?? WEBHOOK_KINDS[0]; return (
{ event.preventDefault(); const element = event.currentTarget; const form = new FormData(element); const events = INTEGRATION_EVENTS.filter((name) => form.get(`event-${name}`) === "on"); const provided = String(form.get("secret") ?? "").trim(); const result = await create.run({ data: { ...scope, kind, name: String(form.get("name") ?? "").trim() || meta.label, url: String(form.get("url") ?? ""), events, secret: provided || null, }, }); if (result) { setSecret(result.signingSecret); element.reset(); } }} > {secret && ( Signing secret (shown once): {secret} )} setKind(value as WebhookKind)} options={WEBHOOK_KINDS} /> {kind === "webhook" && ( )}
Events (quiet by default) {INTEGRATION_EVENTS.map((name) => ( ))}
); } export function IntegrationsPage({ data, scope }: { data: IntegrationsData; scope: ScopeParams }) { return (
{data.integrations.length === 0 ? ( ) : ( data.integrations.map((integration) => ( )) )}
); }