History

Keep source forms on local error messages

Rhys Sullivan committed 6 months ago

Commit 2256b0c1 parent dfda4fb2 files · +28 −36Browse files

Unified · Split

2 files
  1. packages/plugins/graphql/src/react/AddGraphqlSource.tsx +12 −8
  2. packages/plugins/mcp/src/react/AddMcpSource.tsx +16 −28
packages/plugins/graphql/src/react/AddGraphqlSource.tsx+12−8
@@ -1,8 +1,9 @@
11 import { useCallback, useState } from "react";
22 import { useAtomSet } from "@effect/atom-react";
33 import * as Exit from "effect/Exit";
4+import * as Option from "effect/Option";
5+import * as Schema from "effect/Schema";
46
5−import { useErrorMessageFromExit } from "@executor-js/react/api/error-reporting";
67 import { useScope } from "@executor-js/react/api/scope-context";
78 import { sourceWriteKeys } from "@executor-js/react/api/reactivity-keys";
89 import {
@@ -44,6 +45,15 @@ import { addGraphqlSourceOptimistic } from "./atoms"; · 35 unmodified lines
4445 import { initialGraphqlCredentials } from "./defaults";
4546 import type { GraphqlCredentialInput } from "../sdk/types";
4647
48+const ErrorMessage = Schema.Struct({ message: Schema.String });
49+const decodeErrorMessage = Schema.decodeUnknownOption(ErrorMessage);
50+
51+const errorMessageFromExit = (exit: Exit.Exit<unknown, unknown>, fallback: string): string =>
52+ Option.match(Option.flatMap(Exit.findErrorOption(exit), decodeErrorMessage), {
53+ onNone: () => fallback,
54+ onSome: ({ message }) => message,
55+ });
56+
4757 type AuthMode = "none" | "oauth2";
4858
4959 export default function AddGraphqlSource(props: {
@@ -60,7 +70,6 @@ export default function AddGraphqlSource(props: { · 10 unmodified lines
6070 const [addError, setAddError] = useState<string | null>(null);
6171 const [authMode, setAuthMode] = useState<AuthMode>("none");
6272 const [tokens, setTokens] = useState<OAuthCompletionPayload | null>(null);
63− const errorMessageFromExit = useErrorMessageFromExit();
6473
6574 const scopeId = useScope();
6675 const { credentialTargetScope: requestCredentialTargetScope } = useCredentialTargetScope();
@@ -161,12 +170,7 @@ export default function AddGraphqlSource(props: { · 94 unmodified lines
161170 reactivityKeys: sourceWriteKeys,
162171 });
163172 if (Exit.isFailure(exit)) {
164− setAddError(
165− errorMessageFromExit(exit, "Failed to add source", {
166− surface: "graphql_source",
167− action: "add_source",
168− }),
169− );
173+ setAddError(errorMessageFromExit(exit, "Failed to add source"));
170174 setAdding(false);
171175 return;
172176 }
packages/plugins/mcp/src/react/AddMcpSource.tsx+16−28
@@ -1,8 +1,9 @@
11 import { useReducer, useCallback, useEffect, useRef, useState, type ReactNode } from "react";
22 import { useAtomSet } from "@effect/atom-react";
33 import * as Exit from "effect/Exit";
4+import * as Option from "effect/Option";
5+import * as Schema from "effect/Schema";
46
5−import { useErrorMessageFromExit } from "@executor-js/react/api/error-reporting";
67 import { useScope } from "@executor-js/react/api/scope-context";
78 import { Button } from "@executor-js/react/components/button";
89 import {
@@ -59,6 +60,15 @@ import { probeMcpEndpoint, addMcpSourceOptimistic } from "./atoms"; · 50 unmodified lines
5960 import { mcpPresets, type McpPreset } from "../sdk/presets";
6061 import { MCP_OAUTH_CONNECTION_SLOT, type McpCredentialInput } from "../sdk/types";
6162
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+
6272 // ---------------------------------------------------------------------------
6373 // Preset lookup
6474 // ---------------------------------------------------------------------------
@@ -291,7 +301,6 @@ export default function AddMcpSource(props: { · 226 unmodified lines
291301 const doAdd = useAtomSet(addMcpSourceOptimistic(scopeId), {
292302 mode: "promiseExit",
293303 });
294− const errorMessageFromExit = useErrorMessageFromExit();
295304 const secretList = useSecretPickerSecrets();
296305 const oauth = useOAuthPopupFlow<OAuthCompletionPayload>({
297306 popupName: "mcp-oauth",
@@ -348,16 +357,13 @@ export default function AddMcpSource(props: { · 50 unmodified lines
348357 if (Exit.isFailure(exit)) {
349358 dispatch({
350359 type: "probe-fail",
351− error: errorMessageFromExit(exit, "Failed to connect", {
352− surface: "mcp_source",
353− action: "probe_remote_source",
354− }),
360+ error: errorMessageFromExit(exit, "Failed to connect"),
355361 });
356362 return;
357363 }
358364 setRemoteAuthMode(exit.value.requiresOAuth ? "oauth2" : "none");
359365 dispatch({ type: "probe-ok", probe: exit.value });
360− }, [state.url, scopeId, doProbe, remoteCredentials, errorMessageFromExit]);
366+ }, [state.url, scopeId, doProbe, remoteCredentials]);
361367
362368 // Keep the latest handleProbe in a ref so the debounced effect can call it
363369 // without depending on its identity (which changes every render).
@@ -477,10 +483,7 @@ export default function AddMcpSource(props: { · 113 unmodified lines
477483 if (Exit.isFailure(exit)) {
478484 dispatch({
479485 type: "add-fail",
480− error: errorMessageFromExit(exit, "Failed to add source", {
481− surface: "mcp_source",
482− action: "add_remote_source",
483− }),
486+ error: errorMessageFromExit(exit, "Failed to add source"),
484487 });
485488 return;
486489 }
@@ -496,7 +499,6 @@ export default function AddMcpSource(props: { · 9 unmodified lines
496499 doAdd,
497500 props,
498501 scopeId,
499− errorMessageFromExit,
500502 requestCredentialTargetScope,
501503 oauthCredentialTargetScope,
502504 ]);
@@ -547,26 +549,12 @@ export default function AddMcpSource(props: { · 44 unmodified lines
547549 reactivityKeys: sourceWriteKeys,
548550 });
549551 if (Exit.isFailure(exit)) {
550− setStdioError(
551− errorMessageFromExit(exit, "Failed to add source", {
552− surface: "mcp_source",
553− action: "add_stdio_source",
554− }),
555− );
552+ setStdioError(errorMessageFromExit(exit, "Failed to add source"));
556553 setStdioAdding(false);
557554 return;
558555 }
559556 props.onComplete();
560− }, [
561− stdioCommand,
562− stdioArgs,
563− stdioEnv,
564− stdioIdentity,
565− doAdd,
566− scopeId,
567− props,
568− errorMessageFromExit,
569− ]);
557+ }, [stdioCommand, stdioArgs, stdioEnv, stdioIdentity, doAdd, scopeId, props]);
570558
571559 // ---- Render ----
572560