Registry rows already carry the URL and auth indicators, so clicking Add now registers in place: the card flips to a View link into the integration's hub, the user stays on the picker, and several adds can run at once. Each plugin exposes a headless useQuickAdd on its client plugin — MCP probes and declares the detected methods (sharing the add page's seed policy via mcpDetectedAuthSeeds), OpenAPI lets the spec carry auth, GraphQL declares the registry's header pattern. A quick add that cannot complete falls back to the configuration screen prefilled with the same facts. Also fixes two latent bugs this surfaced: the probe API response schema stripped versionNegotiation, so the legacy-protocol pin never survived the HTTP boundary; and per-row state keyed on domain|kind, which conflated two same-kind products on one domain (Google Photos Library and Picker).
Showing the changes to packages/plugins/openapi/src (1 of 11 files). Show all
Unified · Split
| @@ -1,6 +1,54 @@ | ||
| 1 | −import { lazy } from "react"; | |
| 2 | −import type { IntegrationPlugin, IntegrationPreset } from "@executor-js/sdk/client"; | |
| 1 | +import { lazy, useCallback } from "react"; | |
| 2 | +import { useAtomSet } from "@effect/atom-react"; | |
| 3 | +import * as Exit from "effect/Exit"; | |
| 4 | +import type { | |
| 5 | + IntegrationPlugin, | |
| 6 | + IntegrationPreset, | |
| 7 | + IntegrationQuickAddInput, | |
| 8 | + IntegrationQuickAddResult, | |
| 9 | +} from "@executor-js/sdk/client"; | |
| 10 | +import { slugifyNamespace } from "@executor-js/react/plugins/integration-identity"; | |
| 11 | +import { integrationWriteKeys } from "@executor-js/react/api/reactivity-keys"; | |
| 3 | 12 | import { openApiPresets } from "../sdk/presets"; |
| 13 | +import { addOpenApiSpec } from "./atoms"; | |
| 14 | +import { decodeOpenApiSpecOverrides } from "../sdk/spec-overrides"; | |
| 15 | + | |
| 16 | +/** One-click add for a registry OpenAPI row. The spec itself is the | |
| 17 | + * configuration: omitting `authenticationTemplate` and `baseUrl` tells the | |
| 18 | + * server to derive both from the document, exactly what the add page's | |
| 19 | + * untouched defaults submit. Registry spec overrides ride along. */ | |
| 20 | +function useOpenApiQuickAdd(): ( | |
| 21 | + input: IntegrationQuickAddInput, | |
| 22 | +) => Promise<IntegrationQuickAddResult> { | |
| 23 | + const doAdd = useAtomSet(addOpenApiSpec, { mode: "promiseExit" }); | |
| 24 | + return useCallback( | |
| 25 | + async (input) => { | |
| 26 | + const slug = slugifyNamespace(input.slug ?? input.name); | |
| 27 | + if (!slug) return { ok: false, reason: "no derivable slug" }; | |
| 28 | + // Registry overrides arrive as untyped JSON; a malformed patch goes to | |
| 29 | + // the configuration screen (its editor renders the parse error) rather | |
| 30 | + // than being silently dropped from a "successful" quick add. | |
| 31 | + const specOverrides = input.specOverrides | |
| 32 | + ? decodeOpenApiSpecOverrides(input.specOverrides) | |
| 33 | + : undefined; | |
| 34 | + if (input.specOverrides && input.specOverrides.length > 0 && specOverrides === undefined) { | |
| 35 | + return { ok: false, reason: "unparseable spec overrides" }; | |
| 36 | + } | |
| 37 | + const exit = await doAdd({ | |
| 38 | + payload: { | |
| 39 | + spec: { kind: "url" as const, url: input.url }, | |
| 40 | + slug, | |
| 41 | + name: input.name, | |
| 42 | + ...(specOverrides && specOverrides.length > 0 ? { specOverrides } : {}), | |
| 43 | + }, | |
| 44 | + reactivityKeys: integrationWriteKeys, | |
| 45 | + }); | |
| 46 | + if (Exit.isFailure(exit)) return { ok: false, reason: "add failed" }; | |
| 47 | + return { ok: true, slug: String(exit.value.slug) }; | |
| 48 | + }, | |
| 49 | + [doAdd], | |
| 50 | + ); | |
| 51 | +} | |
| 4 | 52 | |
| 5 | 53 | const importAdd = () => import("./AddOpenApiIntegration"); |
| 6 | 54 | const importEditSheet = () => import("./UpdateSpecSection"); |
| @@ -24,6 +72,7 @@ export const createOpenApiIntegrationPlugin = ( · 17 unmodified lines | ||
| 24 | 72 | void importEditSheet(); |
| 25 | 73 | void importAccounts(); |
| 26 | 74 | }, |
| 75 | + useQuickAdd: useOpenApiQuickAdd, | |
| 27 | 76 | }); |
| 28 | 77 | |
| 29 | 78 | export const openApiIntegrationPlugin: IntegrationPlugin = createOpenApiIntegrationPlugin(); |