| @@ -1,8 +1,9 @@ |
| 1 | import { useReducer, useCallback, useEffect, useRef, useState, type ReactNode } from "react"; | 1 | import { useReducer, useCallback, useEffect, useRef, useState, type ReactNode } from "react"; |
| 2 | import { useAtomSet } from "@effect/atom-react"; | 2 | import { useAtomSet } from "@effect/atom-react"; |
| 3 | import * as Exit from "effect/Exit"; | 3 | import * as Exit from "effect/Exit"; |
| | 4 | import * as Option from "effect/Option"; |
| | 5 | import * as Schema from "effect/Schema"; |
| 4 | | 6 | |
| 5 | import { useErrorMessageFromExit } from "@executor-js/react/api/error-reporting"; | | |
| 6 | import { useScope } from "@executor-js/react/api/scope-context"; | 7 | import { useScope } from "@executor-js/react/api/scope-context"; |
| 7 | import { Button } from "@executor-js/react/components/button"; | 8 | import { Button } from "@executor-js/react/components/button"; |
| 8 | import { | 9 | import { |
| @@ -59,6 +60,15 @@ import { probeMcpEndpoint, addMcpSourceOptimistic } from "./atoms"; · 50 unmodified lines |
| 59 | import { mcpPresets, type McpPreset } from "../sdk/presets"; | 60 | import { mcpPresets, type McpPreset } from "../sdk/presets"; |
| 60 | import { MCP_OAUTH_CONNECTION_SLOT, type McpCredentialInput } from "../sdk/types"; | 61 | import { MCP_OAUTH_CONNECTION_SLOT, type McpCredentialInput } from "../sdk/types"; |
| 61 | | 62 | |
| | 63 | const ErrorMessage = Schema.Struct({ message: Schema.String }); |
| | 64 | const decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage); |
| | 65 | |
| | 66 | const errorMessageFromExit = (exit: Exit.Exit<unknown, unknown>, fallback: string): string => |
| | 67 | Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), { |
| | 68 | onNone: () => fallback, |
| | 69 | onSome: ({ message }) => message, |
| | 70 | }); |
| | 71 | |
| 62 | // --------------------------------------------------------------------------- | 72 | // --------------------------------------------------------------------------- |
| 63 | // Preset lookup | 73 | // Preset lookup |
| 64 | // --------------------------------------------------------------------------- | 74 | // --------------------------------------------------------------------------- |
| @@ -291,7 +301,6 @@ export default function AddMcpSource(props: { · 226 unmodified lines |
| 291 | const doAdd = useAtomSet(addMcpSourceOptimistic(scopeId), { | 301 | const doAdd = useAtomSet(addMcpSourceOptimistic(scopeId), { |
| 292 | mode: "promiseExit", | 302 | mode: "promiseExit", |
| 293 | }); | 303 | }); |
| 294 | const errorMessageFromExit = useErrorMessageFromExit(); | | |
| 295 | const secretList = useSecretPickerSecrets(); | 304 | const secretList = useSecretPickerSecrets(); |
| 296 | const oauth = useOAuthPopupFlow<OAuthCompletionPayload>({ | 305 | const oauth = useOAuthPopupFlow<OAuthCompletionPayload>({ |
| 297 | popupName: "mcp-oauth", | 306 | popupName: "mcp-oauth", |
| @@ -348,16 +357,13 @@ export default function AddMcpSource(props: { · 50 unmodified lines |
| 348 | if (Exit.isFailure(exit)) { | 357 | if (Exit.isFailure(exit)) { |
| 349 | dispatch({ | 358 | dispatch({ |
| 350 | type: "probe-fail", | 359 | type: "probe-fail", |
| 351 | error: errorMessageFromExit(exit, "Failed to connect", { | 360 | error: errorMessageFromExit(exit, "Failed to connect"), |
| 352 | surface: "mcp_source", | | |
| 353 | action: "probe_remote_source", | | |
| 354 | }), | | |
| 355 | }); | 361 | }); |
| 356 | return; | 362 | return; |
| 357 | } | 363 | } |
| 358 | setRemoteAuthMode(exit.value.requiresOAuth ? "oauth2" : "none"); | 364 | setRemoteAuthMode(exit.value.requiresOAuth ? "oauth2" : "none"); |
| 359 | dispatch({ type: "probe-ok", probe: exit.value }); | 365 | dispatch({ type: "probe-ok", probe: exit.value }); |
| 360 | }, [state.url, scopeId, doProbe, remoteCredentials, errorMessageFromExit]); | 366 | }, [state.url, scopeId, doProbe, remoteCredentials]); |
| 361 | | 367 | |
| 362 | // Keep the latest handleProbe in a ref so the debounced effect can call it | 368 | // Keep the latest handleProbe in a ref so the debounced effect can call it |
| 363 | // without depending on its identity (which changes every render). | 369 | // without depending on its identity (which changes every render). |
| @@ -477,10 +483,7 @@ export default function AddMcpSource(props: { · 113 unmodified lines |
| 477 | if (Exit.isFailure(exit)) { | 483 | if (Exit.isFailure(exit)) { |
| 478 | dispatch({ | 484 | dispatch({ |
| 479 | type: "add-fail", | 485 | type: "add-fail", |
| 480 | error: errorMessageFromExit(exit, "Failed to add source", { | 486 | error: errorMessageFromExit(exit, "Failed to add source"), |
| 481 | surface: "mcp_source", | | |
| 482 | action: "add_remote_source", | | |
| 483 | }), | | |
| 484 | }); | 487 | }); |
| 485 | return; | 488 | return; |
| 486 | } | 489 | } |
| @@ -496,7 +499,6 @@ export default function AddMcpSource(props: { · 9 unmodified lines |
| 496 | doAdd, | 499 | doAdd, |
| 497 | props, | 500 | props, |
| 498 | scopeId, | 501 | scopeId, |
| 499 | errorMessageFromExit, | | |
| 500 | requestCredentialTargetScope, | 502 | requestCredentialTargetScope, |
| 501 | oauthCredentialTargetScope, | 503 | oauthCredentialTargetScope, |
| 502 | ]); | 504 | ]); |
| @@ -547,26 +549,12 @@ export default function AddMcpSource(props: { · 44 unmodified lines |
| 547 | reactivityKeys: sourceWriteKeys, | 549 | reactivityKeys: sourceWriteKeys, |
| 548 | }); | 550 | }); |
| 549 | if (Exit.isFailure(exit)) { | 551 | if (Exit.isFailure(exit)) { |
| 550 | setStdioError( | 552 | setStdioError(errorMessageFromExit(exit, "Failed to add source")); |
| 551 | errorMessageFromExit(exit, "Failed to add source", { | | |
| 552 | surface: "mcp_source", | | |
| 553 | action: "add_stdio_source", | | |
| 554 | }), | | |
| 555 | ); | | |
| 556 | setStdioAdding(false); | 553 | setStdioAdding(false); |
| 557 | return; | 554 | return; |
| 558 | } | 555 | } |
| 559 | props.onComplete(); | 556 | props.onComplete(); |
| 560 | }, [ | 557 | }, [stdioCommand, stdioArgs, stdioEnv, stdioIdentity, doAdd, scopeId, props]); |
| 561 | stdioCommand, | | |
| 562 | stdioArgs, | | |
| 563 | stdioEnv, | | |
| 564 | stdioIdentity, | | |
| 565 | doAdd, | | |
| 566 | scopeId, | | |
| 567 | props, | | |
| 568 | errorMessageFromExit, | | |
| 569 | ]); | | |
| 570 | | 558 | |
| 571 | // ---- Render ---- | 559 | // ---- Render ---- |
| 572 | | 560 | |