import { deleteIntegration, redeliverIntegration, runGithubJob, testIntegration, updateIntegration, } from "~/fns/integrations"; import { useAction } from "~/hooks/use-action"; import { Button } from "~/components/ui/Button"; import { CheckboxField, ErrorBanner, SelectField, TextAreaField, TextField } from "~/components/ui/Field"; import { Badge, Panel, RelativeTime } from "~/components/ui/Primitives"; import { DEFAULT_LINEAR_MAPPING, INTEGRATION_EVENT_LABELS, INTEGRATION_EVENTS, INTEGRATION_KIND_LABELS, } from "~/lib/integrations"; import type { GithubMirrorDirection, IntegrationEvent, SlackChannelRoute } from "~/lib/integrations"; import type { IntegrationsData, ScopeParams } from "./IntegrationsPage"; type Integration = IntegrationsData["integrations"][number]; const DELIVERY_OPTIONS = [ { value: "instant", label: "Instant" }, { value: "digest", label: "Digest (batched)" }, ]; const MIRROR_OPTIONS = [ { value: "none", label: "Off" }, { value: "push", label: "gitfor → GitHub" }, { value: "pull", label: "GitHub → gitfor (force mirror, overwrites)" }, ]; const STATUS_TONE = { success: "green", failed: "red", dead: "red", pending: "amber" } as const; function isEvent(value: string): value is IntegrationEvent { return INTEGRATION_EVENTS.some((event) => event === value); } /** One channel per line: `C0123ABCD: pull_request, release`. */ function parseChannels(text: string): SlackChannelRoute[] { return text .split("\n") .map((line) => line.trim()) .filter(Boolean) .map((line) => { const [channel, events = ""] = line.split(":", 2); return { channel: channel.trim(), events: events .split(",") .map((event) => event.trim()) .filter(isEvent), }; }); } function formatChannels(routes: SlackChannelRoute[] | undefined): string { return (routes ?? []).map((route) => `${route.channel}: ${route.events.join(", ")}`).join("\n"); } function Deliveries({ integration, scope }: { integration: Integration; scope: ScopeParams }) { const redeliver = useAction(redeliverIntegration); return (