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/react (1 of 11 files). Show all
Unified · Split
| @@ -1,6 +1,54 @@ | |||
| 1 | import { lazy } from "react"; | 1 | import { lazy, useCallback } from "react"; |
| 2 | import type { IntegrationPlugin, IntegrationPreset } from "@executor-js/sdk/client"; | 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 | import { openApiPresets } from "../sdk/presets"; | 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 | const importAdd = () => import("./AddOpenApiIntegration"); | 53 | const importAdd = () => import("./AddOpenApiIntegration"); |
| 6 | const importEditSheet = () => import("./UpdateSpecSection"); | 54 | const importEditSheet = () => import("./UpdateSpecSection"); |
| @@ -24,6 +72,7 @@ export const createOpenApiIntegrationPlugin = ( · 17 unmodified lines | |||
| 24 | void importEditSheet(); | 72 | void importEditSheet(); |
| 25 | void importAccounts(); | 73 | void importAccounts(); |
| 26 | }, | 74 | }, |
| 75 | useQuickAdd: useOpenApiQuickAdd, | ||
| 27 | }); | 76 | }); |
| 28 | 77 | ||
| 29 | export const openApiIntegrationPlugin: IntegrationPlugin = createOpenApiIntegrationPlugin(); | 78 | export const openApiIntegrationPlugin: IntegrationPlugin = createOpenApiIntegrationPlugin(); |