import { useState, type ReactNode } from "react";import { Link, useNavigate } from "@tanstack/react-router";import { type CompleteSourceOAuthResult, type CreateSourcePayload, type InstanceConfig, type Loadable, type StartSourceOAuthPayload, type SecretListItem, type Source, type UpdateSourcePayload, useCreateSecret, useCreateSource, useInstanceConfig, useRefreshSecrets, useRemoveSource, useSecrets, useStartSourceOAuth, useSource, useUpdateSource,} from "@executor/react";import { Badge } from "../components/ui/badge";import { Button } from "../components/ui/button";import { LoadableBlock } from "../components/loadable";import { SourceFavicon } from "../components/source-favicon";import { IconArrowLeft, IconPencil, IconPlus, IconSpinner, IconTrash,} from "../components/icons";import { cn } from "../lib/utils";import { sourceTemplates, type SourceTemplate } from "./source-templates";import { getDomain } from "tldts"; type StatusBannerState = { tone: "info" | "success" | "error"; text: string;}; type SourceOAuthPopupMessage = | { type: "executor:oauth-result"; ok: true; sessionId: string; auth: CompleteSourceOAuthResult["auth"]; } | { type: "executor:oauth-result"; ok: false; sessionId: string | null; error: string; }; const SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS = 2 * 60_000;const SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX = "executor:oauth-result:"; type TransportValue = "" | NonNullable<Source["transport"]>; type SourceFormState = { name: string; kind: Source["kind"]; endpoint: string; namespace: string; enabled: boolean; transport: TransportValue; queryParamsText: string; headersText: string; specUrl: string; defaultHeadersText: string; authKind: Source["auth"]["kind"]; authHeaderName: string; authPrefix: string; bearerProviderId: string; bearerHandle: string; oauthAccessProviderId: string; oauthAccessHandle: string; oauthRefreshProviderId: string; oauthRefreshHandle: string;}; const kindOptions: ReadonlyArray<Source["kind"]> = ["mcp", "openapi", "graphql", "internal"]; const transportOptions: ReadonlyArray<NonNullable<Source["transport"]>> = [ "auto", "streamable-http", "sse",]; const authOptions: ReadonlyArray<Source["auth"]["kind"]> = ["none", "bearer", "oauth2"]; const trimToNull = (value: string): string | null => { const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null;}; const namespaceFromUrl = (url: string): string => { try { const domain = getDomain(url); if (!domain) return ""; const dot = domain.indexOf("."); return dot > 0 ? domain.slice(0, dot) : domain; } catch { return ""; }}; const readStoredSourceOAuthPopupResult = (sessionId: string): SourceOAuthPopupMessage | null => { if (typeof window === "undefined") { return null; } const raw = window.localStorage.getItem( `${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`, ); if (!raw) { return null; } try { return JSON.parse(raw) as SourceOAuthPopupMessage; } catch { return null; }}; const clearStoredSourceOAuthPopupResult = (sessionId: string): void => { if (typeof window === "undefined") { return; } window.localStorage.removeItem(`${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`);}; const startSourceOAuthPopup = async (input: { authorizationUrl: string; sessionId: string;}): Promise<CompleteSourceOAuthResult["auth"]> => { if (typeof window === "undefined") { throw new Error("OAuth popup is only available in a browser context"); } clearStoredSourceOAuthPopupResult(input.sessionId); const popup = window.open( input.authorizationUrl, "executor-source-oauth", "popup=yes,width=520,height=720", ); if (!popup) { throw new Error("Popup blocked. Allow popups and try again."); } popup.focus(); return await new Promise<CompleteSourceOAuthResult["auth"]>((resolve, reject) => { let settled = false; let closedPoll = 0; let resultTimeout = 0; const cleanup = () => { window.removeEventListener("message", onMessage); if (closedPoll) { window.clearInterval(closedPoll); } if (resultTimeout) { window.clearTimeout(resultTimeout); } if (!popup.closed) { popup.close(); } clearStoredSourceOAuthPopupResult(input.sessionId); }; const settleWithError = (message: string) => { if (settled) { return; } settled = true; cleanup(); reject(new Error(message)); }; const settleFromPayload = (data: SourceOAuthPopupMessage) => { if (!data.ok) { settleWithError(data.error || "OAuth failed"); return; } if (settled) { return; } settled = true; cleanup(); resolve(data.auth); }; const onMessage = (event: MessageEvent) => { if (event.origin !== window.location.origin) { return; } const data = event.data as SourceOAuthPopupMessage | undefined; if (!data || data.type !== "executor:oauth-result") { return; } if (data.ok && data.sessionId !== input.sessionId) { return; } if (!data.ok && data.sessionId !== null && data.sessionId !== input.sessionId) { return; } settleFromPayload(data); }; window.addEventListener("message", onMessage); resultTimeout = window.setTimeout(() => { settleWithError("OAuth popup timed out before completion. Please try again."); }, SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS); closedPoll = window.setInterval(() => { const stored = readStoredSourceOAuthPopupResult(input.sessionId); if (stored) { settleFromPayload(stored); return; } if (popup.closed) { // Stop polling — only run one final deferred check to give the // callback page time to write localStorage before we give up. window.clearInterval(closedPoll); closedPoll = 0; window.setTimeout(() => { const delayedStored = readStoredSourceOAuthPopupResult(input.sessionId); if (delayedStored) { settleFromPayload(delayedStored); return; } settleWithError("OAuth popup was closed before completion."); }, 1500); } }, 300); });}; const stringMapToEditor = (value: Source["queryParams"] | Source["headers"] | Source["defaultHeaders"]): string => value === null ? "" : JSON.stringify(value, null, 2); const defaultFormState = (template?: SourceTemplate): SourceFormState => ({ name: template?.name ?? "", kind: template?.kind ?? "openapi", endpoint: template?.endpoint ?? "", namespace: template ? namespaceFromUrl(template.endpoint) : "", enabled: true, transport: template?.kind === "mcp" ? "auto" : "", queryParamsText: "", headersText: "", specUrl: template && "specUrl" in template ? template.specUrl : "", defaultHeadersText: "", authKind: "none", authHeaderName: "Authorization", authPrefix: "Bearer ", bearerProviderId: "", bearerHandle: "", oauthAccessProviderId: "", oauthAccessHandle: "", oauthRefreshProviderId: "", oauthRefreshHandle: "",}); const formStateFromSource = (source: Source): SourceFormState => ({ name: source.name, kind: source.kind, endpoint: source.endpoint, namespace: source.namespace ?? "", enabled: source.enabled, transport: source.kind === "mcp" ? (source.transport ?? "auto") : "", queryParamsText: stringMapToEditor(source.queryParams), headersText: stringMapToEditor(source.headers), specUrl: source.specUrl ?? "", defaultHeadersText: stringMapToEditor(source.defaultHeaders), authKind: source.auth.kind, authHeaderName: source.auth.kind === "none" ? "Authorization" : source.auth.headerName, authPrefix: source.auth.kind === "none" ? "Bearer " : source.auth.prefix, bearerProviderId: source.auth.kind === "bearer" ? source.auth.token.providerId : "", bearerHandle: source.auth.kind === "bearer" ? source.auth.token.handle : "", oauthAccessProviderId: source.auth.kind === "oauth2" ? source.auth.accessToken.providerId : "", oauthAccessHandle: source.auth.kind === "oauth2" ? source.auth.accessToken.handle : "", oauthRefreshProviderId: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.providerId : "", oauthRefreshHandle: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.handle : "",}); const parseJsonStringMap = (label: string, text: string): Record<string, string> | null => { const trimmed = text.trim(); if (trimmed.length === 0) { return null; } let parsed: unknown; try { parsed = JSON.parse(trimmed); } catch (error) { throw new Error(`${label} must be valid JSON.`); } if (parsed === null || Array.isArray(parsed) || typeof parsed !== "object") { throw new Error(`${label} must be a JSON object with string values.`); } const entries = Object.entries(parsed as Record<string, unknown>); const normalized: Record<string, string> = {}; for (const [key, value] of entries) { if (typeof value !== "string") { throw new Error(`${label} must only contain string values.`); } normalized[key] = value; } return Object.keys(normalized).length === 0 ? null : normalized;}; const buildAuthPayload = (state: SourceFormState): CreateSourcePayload["auth"] => { if (state.authKind === "none") { return { kind: "none" }; } const headerName = state.authHeaderName.trim() || "Authorization"; const prefix = state.authPrefix; if (state.authKind === "bearer") { const providerId = state.bearerProviderId.trim(); const handle = state.bearerHandle.trim(); if (!providerId || !handle) { throw new Error("Bearer auth requires a token. Select or create a secret."); } return { kind: "bearer", headerName, prefix, token: { providerId, handle, }, }; } const accessProviderId = state.oauthAccessProviderId.trim(); const accessHandle = state.oauthAccessHandle.trim(); if (!accessProviderId || !accessHandle) { throw new Error("OAuth2 auth requires an access token. Select or create a secret."); } const refreshProviderId = trimToNull(state.oauthRefreshProviderId); const refreshHandle = trimToNull(state.oauthRefreshHandle); if ((refreshProviderId === null) !== (refreshHandle === null)) { throw new Error("OAuth2 refresh token provider ID and handle must be set together."); } return { kind: "oauth2", headerName, prefix, accessToken: { providerId: accessProviderId, handle: accessHandle, }, refreshToken: refreshProviderId === null || refreshHandle === null ? null : { providerId: refreshProviderId, handle: refreshHandle, }, };}; const buildRequestedSourceStatus = (state: SourceFormState): CreateSourcePayload["status"] => { if (state.kind !== "mcp" && state.kind !== "openapi" && state.kind !== "graphql") { return undefined; } return state.enabled ? "connected" : "draft";}; const buildSourcePayload = (state: SourceFormState): CreateSourcePayload => { const name = state.name.trim(); const endpoint = state.endpoint.trim(); if (!name) { throw new Error("Source name is required."); } if (!endpoint) { throw new Error("Source endpoint is required."); } const shared = { name, kind: state.kind, endpoint, status: buildRequestedSourceStatus(state), enabled: state.enabled, namespace: trimToNull(state.namespace), auth: buildAuthPayload(state), } satisfies Pick<CreateSourcePayload, "name" | "kind" | "endpoint" | "status" | "enabled" | "namespace" | "auth">; if (state.kind === "mcp") { return { ...shared, transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), specUrl: null, defaultHeaders: null, }; } if (state.kind === "openapi") { const specUrl = state.specUrl.trim(); if (!specUrl) { throw new Error("OpenAPI sources require a spec URL."); } return { ...shared, transport: null, queryParams: null, headers: null, specUrl, defaultHeaders: parseJsonStringMap("Default headers", state.defaultHeadersText), }; } if (state.kind === "graphql") { return { ...shared, transport: null, queryParams: null, headers: null, specUrl: null, defaultHeaders: parseJsonStringMap("Default headers", state.defaultHeadersText), }; } return { ...shared, transport: null, queryParams: null, headers: null, specUrl: null, defaultHeaders: null, };}; const buildUpdatePayload = (state: SourceFormState): UpdateSourcePayload => ({ ...buildSourcePayload(state),}); const buildStartSourceOAuthPayload = (state: SourceFormState): StartSourceOAuthPayload => { if (state.kind !== "mcp") { throw new Error("OAuth sign-in is only available for MCP sources."); } const endpoint = state.endpoint.trim(); if (!endpoint) { throw new Error("Source endpoint is required before starting OAuth."); } return { provider: "mcp", name: trimToNull(state.name), endpoint, transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), };}; export function NewSourcePage() { return <SourceEditor key="create" mode="create" />;} export function EditSourcePage(props: { sourceId: string }) { const source = useSource(props.sourceId); return (Lines 1–500 of 1260. Load more
import { useState, type ReactNode } from "react"; import { Link, useNavigate } from "@tanstack/react-router"; import { type CompleteSourceOAuthResult, type CreateSourcePayload, type InstanceConfig, type Loadable, type StartSourceOAuthPayload, type SecretListItem, type Source, type UpdateSourcePayload, useCreateSecret, useCreateSource, useInstanceConfig, useRefreshSecrets, useRemoveSource, useSecrets, useStartSourceOAuth, useSource, useUpdateSource, } from "@executor/react"; import { Badge } from "../components/ui/badge"; import { Button } from "../components/ui/button"; import { LoadableBlock } from "../components/loadable"; import { SourceFavicon } from "../components/source-favicon"; import { IconArrowLeft, IconPencil, IconPlus, IconSpinner, IconTrash, } from "../components/icons"; import { cn } from "../lib/utils"; import { sourceTemplates, type SourceTemplate } from "./source-templates"; import { getDomain } from "tldts"; type StatusBannerState = { tone: "info" | "success" | "error"; text: string; }; type SourceOAuthPopupMessage = | { type: "executor:oauth-result"; ok: true; sessionId: string; auth: CompleteSourceOAuthResult["auth"]; } | { type: "executor:oauth-result"; ok: false; sessionId: string | null; error: string; }; const SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS = 2 * 60_000; const SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX = "executor:oauth-result:"; type TransportValue = "" | NonNullable<Source["transport"]>; type SourceFormState = { name: string; kind: Source["kind"]; endpoint: string; namespace: string; enabled: boolean; transport: TransportValue; queryParamsText: string; headersText: string; specUrl: string; defaultHeadersText: string; authKind: Source["auth"]["kind"]; authHeaderName: string; authPrefix: string; bearerProviderId: string; bearerHandle: string; oauthAccessProviderId: string; oauthAccessHandle: string; oauthRefreshProviderId: string; oauthRefreshHandle: string; }; const kindOptions: ReadonlyArray<Source["kind"]> = ["mcp", "openapi", "graphql", "internal"]; const transportOptions: ReadonlyArray<NonNullable<Source["transport"]>> = [ "auto", "streamable-http", "sse", ]; const authOptions: ReadonlyArray<Source["auth"]["kind"]> = ["none", "bearer", "oauth2"]; const trimToNull = (value: string): string | null => { const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; }; const namespaceFromUrl = (url: string): string => { try { const domain = getDomain(url); if (!domain) return ""; const dot = domain.indexOf("."); return dot > 0 ? domain.slice(0, dot) : domain; } catch { return ""; } }; const readStoredSourceOAuthPopupResult = (sessionId: string): SourceOAuthPopupMessage | null => { if (typeof window === "undefined") { return null; } const raw = window.localStorage.getItem( `${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`, ); if (!raw) { return null; } try { return JSON.parse(raw) as SourceOAuthPopupMessage; } catch { return null; } }; const clearStoredSourceOAuthPopupResult = (sessionId: string): void => { if (typeof window === "undefined") { return; } window.localStorage.removeItem(`${SOURCE_OAUTH_POPUP_RESULT_STORAGE_KEY_PREFIX}${sessionId}`); }; const startSourceOAuthPopup = async (input: { authorizationUrl: string; sessionId: string; }): Promise<CompleteSourceOAuthResult["auth"]> => { if (typeof window === "undefined") { throw new Error("OAuth popup is only available in a browser context"); } clearStoredSourceOAuthPopupResult(input.sessionId); const popup = window.open( input.authorizationUrl, "executor-source-oauth", "popup=yes,width=520,height=720", ); if (!popup) { throw new Error("Popup blocked. Allow popups and try again."); } popup.focus(); return await new Promise<CompleteSourceOAuthResult["auth"]>((resolve, reject) => { let settled = false; let closedPoll = 0; let resultTimeout = 0; const cleanup = () => { window.removeEventListener("message", onMessage); if (closedPoll) { window.clearInterval(closedPoll); } if (resultTimeout) { window.clearTimeout(resultTimeout); } if (!popup.closed) { popup.close(); } clearStoredSourceOAuthPopupResult(input.sessionId); }; const settleWithError = (message: string) => { if (settled) { return; } settled = true; cleanup(); reject(new Error(message)); }; const settleFromPayload = (data: SourceOAuthPopupMessage) => { if (!data.ok) { settleWithError(data.error || "OAuth failed"); return; } if (settled) { return; } settled = true; cleanup(); resolve(data.auth); }; const onMessage = (event: MessageEvent) => { if (event.origin !== window.location.origin) { return; } const data = event.data as SourceOAuthPopupMessage | undefined; if (!data || data.type !== "executor:oauth-result") { return; } if (data.ok && data.sessionId !== input.sessionId) { return; } if (!data.ok && data.sessionId !== null && data.sessionId !== input.sessionId) { return; } settleFromPayload(data); }; window.addEventListener("message", onMessage); resultTimeout = window.setTimeout(() => { settleWithError("OAuth popup timed out before completion. Please try again."); }, SOURCE_OAUTH_POPUP_RESULT_TIMEOUT_MS); closedPoll = window.setInterval(() => { const stored = readStoredSourceOAuthPopupResult(input.sessionId); if (stored) { settleFromPayload(stored); return; } if (popup.closed) { // Stop polling — only run one final deferred check to give the // callback page time to write localStorage before we give up. window.clearInterval(closedPoll); closedPoll = 0; window.setTimeout(() => { const delayedStored = readStoredSourceOAuthPopupResult(input.sessionId); if (delayedStored) { settleFromPayload(delayedStored); return; } settleWithError("OAuth popup was closed before completion."); }, 1500); } }, 300); }); }; const stringMapToEditor = (value: Source["queryParams"] | Source["headers"] | Source["defaultHeaders"]): string => value === null ? "" : JSON.stringify(value, null, 2); const defaultFormState = (template?: SourceTemplate): SourceFormState => ({ name: template?.name ?? "", kind: template?.kind ?? "openapi", endpoint: template?.endpoint ?? "", namespace: template ? namespaceFromUrl(template.endpoint) : "", enabled: true, transport: template?.kind === "mcp" ? "auto" : "", queryParamsText: "", headersText: "", specUrl: template && "specUrl" in template ? template.specUrl : "", defaultHeadersText: "", authKind: "none", authHeaderName: "Authorization", authPrefix: "Bearer ", bearerProviderId: "", bearerHandle: "", oauthAccessProviderId: "", oauthAccessHandle: "", oauthRefreshProviderId: "", oauthRefreshHandle: "", }); const formStateFromSource = (source: Source): SourceFormState => ({ name: source.name, kind: source.kind, endpoint: source.endpoint, namespace: source.namespace ?? "", enabled: source.enabled, transport: source.kind === "mcp" ? (source.transport ?? "auto") : "", queryParamsText: stringMapToEditor(source.queryParams), headersText: stringMapToEditor(source.headers), specUrl: source.specUrl ?? "", defaultHeadersText: stringMapToEditor(source.defaultHeaders), authKind: source.auth.kind, authHeaderName: source.auth.kind === "none" ? "Authorization" : source.auth.headerName, authPrefix: source.auth.kind === "none" ? "Bearer " : source.auth.prefix, bearerProviderId: source.auth.kind === "bearer" ? source.auth.token.providerId : "", bearerHandle: source.auth.kind === "bearer" ? source.auth.token.handle : "", oauthAccessProviderId: source.auth.kind === "oauth2" ? source.auth.accessToken.providerId : "", oauthAccessHandle: source.auth.kind === "oauth2" ? source.auth.accessToken.handle : "", oauthRefreshProviderId: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.providerId : "", oauthRefreshHandle: source.auth.kind === "oauth2" && source.auth.refreshToken !== null ? source.auth.refreshToken.handle : "", }); const parseJsonStringMap = (label: string, text: string): Record<string, string> | null => { const trimmed = text.trim(); if (trimmed.length === 0) { return null; } let parsed: unknown; try { parsed = JSON.parse(trimmed); } catch (error) { throw new Error(`${label} must be valid JSON.`); } if (parsed === null || Array.isArray(parsed) || typeof parsed !== "object") { throw new Error(`${label} must be a JSON object with string values.`); } const entries = Object.entries(parsed as Record<string, unknown>); const normalized: Record<string, string> = {}; for (const [key, value] of entries) { if (typeof value !== "string") { throw new Error(`${label} must only contain string values.`); } normalized[key] = value; } return Object.keys(normalized).length === 0 ? null : normalized; }; const buildAuthPayload = (state: SourceFormState): CreateSourcePayload["auth"] => { if (state.authKind === "none") { return { kind: "none" }; } const headerName = state.authHeaderName.trim() || "Authorization"; const prefix = state.authPrefix; if (state.authKind === "bearer") { const providerId = state.bearerProviderId.trim(); const handle = state.bearerHandle.trim(); if (!providerId || !handle) { throw new Error("Bearer auth requires a token. Select or create a secret."); } return { kind: "bearer", headerName, prefix, token: { providerId, handle, }, }; } const accessProviderId = state.oauthAccessProviderId.trim(); const accessHandle = state.oauthAccessHandle.trim(); if (!accessProviderId || !accessHandle) { throw new Error("OAuth2 auth requires an access token. Select or create a secret."); } const refreshProviderId = trimToNull(state.oauthRefreshProviderId); const refreshHandle = trimToNull(state.oauthRefreshHandle); if ((refreshProviderId === null) !== (refreshHandle === null)) { throw new Error("OAuth2 refresh token provider ID and handle must be set together."); } return { kind: "oauth2", headerName, prefix, accessToken: { providerId: accessProviderId, handle: accessHandle, }, refreshToken: refreshProviderId === null || refreshHandle === null ? null : { providerId: refreshProviderId, handle: refreshHandle, }, }; }; const buildRequestedSourceStatus = (state: SourceFormState): CreateSourcePayload["status"] => { if (state.kind !== "mcp" && state.kind !== "openapi" && state.kind !== "graphql") { return undefined; } return state.enabled ? "connected" : "draft"; }; const buildSourcePayload = (state: SourceFormState): CreateSourcePayload => { const name = state.name.trim(); const endpoint = state.endpoint.trim(); if (!name) { throw new Error("Source name is required."); } if (!endpoint) { throw new Error("Source endpoint is required."); } const shared = { name, kind: state.kind, endpoint, status: buildRequestedSourceStatus(state), enabled: state.enabled, namespace: trimToNull(state.namespace), auth: buildAuthPayload(state), } satisfies Pick<CreateSourcePayload, "name" | "kind" | "endpoint" | "status" | "enabled" | "namespace" | "auth">; if (state.kind === "mcp") { return { ...shared, transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), specUrl: null, defaultHeaders: null, }; } if (state.kind === "openapi") { const specUrl = state.specUrl.trim(); if (!specUrl) { throw new Error("OpenAPI sources require a spec URL."); } return { ...shared, transport: null, queryParams: null, headers: null, specUrl, defaultHeaders: parseJsonStringMap("Default headers", state.defaultHeadersText), }; } if (state.kind === "graphql") { return { ...shared, transport: null, queryParams: null, headers: null, specUrl: null, defaultHeaders: parseJsonStringMap("Default headers", state.defaultHeadersText), }; } return { ...shared, transport: null, queryParams: null, headers: null, specUrl: null, defaultHeaders: null, }; }; const buildUpdatePayload = (state: SourceFormState): UpdateSourcePayload => ({ ...buildSourcePayload(state), }); const buildStartSourceOAuthPayload = (state: SourceFormState): StartSourceOAuthPayload => { if (state.kind !== "mcp") { throw new Error("OAuth sign-in is only available for MCP sources."); } const endpoint = state.endpoint.trim(); if (!endpoint) { throw new Error("Source endpoint is required before starting OAuth."); } return { provider: "mcp", name: trimToNull(state.name), endpoint, transport: state.transport === "" ? "auto" : state.transport, queryParams: parseJsonStringMap("Query params", state.queryParamsText), headers: parseJsonStringMap("Request headers", state.headersText), }; }; export function NewSourcePage() { return <SourceEditor key="create" mode="create" />; } export function EditSourcePage(props: { sourceId: string }) { const source = useSource(props.sourceId); return (