@stigmer/react 0.0.82 → 0.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +3 -3
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/library/ResourceListView.d.ts +57 -7
- package/library/ResourceListView.d.ts.map +1 -1
- package/library/ResourceListView.js +147 -37
- package/library/ResourceListView.js.map +1 -1
- package/library/index.d.ts +1 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js.map +1 -1
- package/mcp-server/McpServerConfigPanel.d.ts +45 -0
- package/mcp-server/McpServerConfigPanel.d.ts.map +1 -1
- package/mcp-server/McpServerConfigPanel.js +90 -14
- package/mcp-server/McpServerConfigPanel.js.map +1 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +168 -23
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/McpServerPicker.js +3 -3
- package/mcp-server/McpServerPicker.js.map +1 -1
- package/mcp-server/OAuthAppForm.d.ts +58 -0
- package/mcp-server/OAuthAppForm.d.ts.map +1 -0
- package/mcp-server/OAuthAppForm.js +67 -0
- package/mcp-server/OAuthAppForm.js.map +1 -0
- package/mcp-server/index.d.ts +6 -0
- package/mcp-server/index.d.ts.map +1 -1
- package/mcp-server/index.js +3 -0
- package/mcp-server/index.js.map +1 -1
- package/mcp-server/useDisconnectOAuth.d.ts +40 -0
- package/mcp-server/useDisconnectOAuth.d.ts.map +1 -0
- package/mcp-server/useDisconnectOAuth.js +46 -0
- package/mcp-server/useDisconnectOAuth.js.map +1 -0
- package/mcp-server/useMcpServerCredentials.d.ts +48 -0
- package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
- package/mcp-server/useMcpServerCredentials.js +18 -2
- package/mcp-server/useMcpServerCredentials.js.map +1 -1
- package/mcp-server/useOAuthGrantStatus.d.ts +9 -0
- package/mcp-server/useOAuthGrantStatus.d.ts.map +1 -1
- package/mcp-server/useOAuthGrantStatus.js +6 -1
- package/mcp-server/useOAuthGrantStatus.js.map +1 -1
- package/mcp-server/useOrgOAuthApp.d.ts +82 -0
- package/mcp-server/useOrgOAuthApp.d.ts.map +1 -0
- package/mcp-server/useOrgOAuthApp.js +160 -0
- package/mcp-server/useOrgOAuthApp.js.map +1 -0
- package/package.json +4 -4
- package/src/index.ts +3 -0
- package/src/library/ResourceListView.tsx +303 -46
- package/src/library/index.ts +4 -1
- package/src/mcp-server/McpServerConfigPanel.tsx +370 -45
- package/src/mcp-server/McpServerDetailView.tsx +447 -47
- package/src/mcp-server/McpServerPicker.tsx +3 -3
- package/src/mcp-server/OAuthAppForm.tsx +304 -0
- package/src/mcp-server/index.ts +9 -0
- package/src/mcp-server/useDisconnectOAuth.ts +76 -0
- package/src/mcp-server/useMcpServerCredentials.ts +70 -2
- package/src/mcp-server/useOAuthGrantStatus.ts +19 -1
- package/src/mcp-server/useOrgOAuthApp.ts +250 -0
- package/styles.css +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EnvVarInput } from "@stigmer/sdk";
|
|
2
|
+
import { OAuthConnectionHealth } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
2
3
|
import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
3
4
|
import type { DiscoveredTool } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
|
|
4
5
|
import type { ToolApprovalPolicy } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/spec_pb";
|
|
@@ -50,6 +51,23 @@ export interface McpServerOAuthSignInProps {
|
|
|
50
51
|
readonly phase: OAuthConnectPhase;
|
|
51
52
|
/** `true` when the OAuth token already exists in the personal environment. */
|
|
52
53
|
readonly isConnected: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Health of the OAuth connection. Drives the status dot color and
|
|
56
|
+
* label beyond the binary `isConnected` boolean.
|
|
57
|
+
*/
|
|
58
|
+
readonly connectionHealth?: OAuthConnectionHealth;
|
|
59
|
+
/**
|
|
60
|
+
* Called to disconnect the OAuth grant. When provided and the user
|
|
61
|
+
* is connected, a "Disconnect" link is shown. The parent is responsible
|
|
62
|
+
* for refreshing credentials after the promise resolves.
|
|
63
|
+
*/
|
|
64
|
+
readonly onDisconnect?: () => Promise<void>;
|
|
65
|
+
/** `true` while a disconnect operation is in flight. */
|
|
66
|
+
readonly isDisconnecting?: boolean;
|
|
67
|
+
/** Error from the most recent failed disconnect, or `null`. */
|
|
68
|
+
readonly disconnectError?: Error | null;
|
|
69
|
+
/** Clear the disconnect error state. */
|
|
70
|
+
readonly onClearDisconnectError?: () => void;
|
|
53
71
|
/** Error from the most recent failed OAuth attempt, or `null`. */
|
|
54
72
|
readonly error: Error | null;
|
|
55
73
|
/** Clear the OAuth error state. */
|
|
@@ -59,11 +77,38 @@ export interface McpServerOAuthSignInProps {
|
|
|
59
77
|
* Disables the sign-in button and shows an informational message.
|
|
60
78
|
*/
|
|
61
79
|
readonly isVendorApprovalPending?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* `true` when the platform OAuth app's vendor approval is PENDING
|
|
82
|
+
* or REJECTED — the platform sign-in flow is blocked. Covers both
|
|
83
|
+
* statuses. When omitted, falls back to `isVendorApprovalPending`.
|
|
84
|
+
*/
|
|
85
|
+
readonly isVendorApprovalBlocked?: boolean;
|
|
62
86
|
/**
|
|
63
87
|
* Documentation URL for bringing your own OAuth token.
|
|
64
88
|
* Shown as a help link when `isVendorApprovalPending` is `true`.
|
|
65
89
|
*/
|
|
66
90
|
readonly vendorApprovalDocsUrl?: string | null;
|
|
91
|
+
/**
|
|
92
|
+
* `true` when the BYOA (Bring Your Own App) option is relevant:
|
|
93
|
+
* the server uses vendor OAuth and no org override exists.
|
|
94
|
+
*/
|
|
95
|
+
readonly canBringOwnApp?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* `true` when an org-level BYOA override is active.
|
|
98
|
+
*/
|
|
99
|
+
readonly isOrgOAuthApp?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Open the BYOA form. The parent is responsible for rendering the
|
|
102
|
+
* form/dialog and handling the mutation.
|
|
103
|
+
*/
|
|
104
|
+
readonly onBringOwnApp?: () => void;
|
|
105
|
+
/**
|
|
106
|
+
* Remove the org's BYOA override. The parent is responsible for
|
|
107
|
+
* refreshing state after the promise resolves.
|
|
108
|
+
*/
|
|
109
|
+
readonly onRemoveOrgApp?: () => Promise<void>;
|
|
110
|
+
/** `true` while a remove-org-app operation is in flight. */
|
|
111
|
+
readonly isRemovingOrgApp?: boolean;
|
|
67
112
|
}
|
|
68
113
|
/** Props for {@link McpServerConfigPanel}. */
|
|
69
114
|
export interface McpServerConfigPanelProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpServerConfigPanel.d.ts","sourceRoot":"","sources":["../../src/mcp-server/McpServerConfigPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"McpServerConfigPanel.d.ts","sourceRoot":"","sources":["../../src/mcp-server/McpServerConfigPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback } from "react";
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { getUserMessage, isRetryableError } from "@stigmer/sdk";
|
|
6
|
+
import { OAuthConnectionHealth } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
5
7
|
import { EnvVarForm, } from "../environment/EnvVarForm";
|
|
6
8
|
import { McpToolSelector } from "./McpToolSelector";
|
|
7
9
|
/**
|
|
@@ -67,28 +69,102 @@ export function McpServerConfigPanel({ mcpServer, credentials, oauthSignIn, disc
|
|
|
67
69
|
const handleCredentialSubmit = useCallback((values, options) => {
|
|
68
70
|
credentials?.onSubmit(values, options);
|
|
69
71
|
}, [credentials]);
|
|
70
|
-
return (_jsxs("div", { className: cn("space-y-3", className), role: "region", "aria-label": `Configure ${serverName}`, children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("button", { type: "button", onClick: onBack, disabled: credentials?.isSubmitting || isOAuthBusy, className: cn("mt-0.5 shrink-0 rounded p-0.5", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), "aria-label": "Back to MCP server list", children: _jsx(BackArrowIcon, {}) }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-2", children: [iconUrl && (_jsx("img", { src: iconUrl, alt: "", width: 16, height: 16, className: "mt-0.5 size-4 shrink-0 rounded-sm object-contain" })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "truncate text-xs font-medium text-foreground", children: serverName }), description && (_jsx("p", { className: "line-clamp-2 text-[0.65rem] leading-relaxed text-muted-foreground", children: description }))] })] })] }), oauthSignIn && (_jsx(InlineOAuthSignIn, { serverName: serverName, isConnected: oauthSignIn.isConnected, phase: oauthSignIn.phase, onSignIn: oauthSignIn.onSignIn, error: oauthSignIn.error, onClearError: oauthSignIn.onClearError, isVendorApprovalPending: oauthSignIn.isVendorApprovalPending, vendorApprovalDocsUrl: oauthSignIn.vendorApprovalDocsUrl, onSwitchToManual: onSwitchToManual })), !oauthSignIn && onSwitchToOAuth && (_jsx("button", { type: "button", onClick: onSwitchToOAuth, className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Sign in with OAuth instead" })), credentials && (_jsx(EnvVarForm, { variables: credentials.variables, onSubmit: handleCredentialSubmit, isSubmitting: credentials.isSubmitting, disabled: disabled || isOAuthBusy, title: "Credentials required", defaultSaveForFuture: credentials.defaultSaveForFuture, hideSaveToggle: credentials.hideSaveToggle, poolValues: credentials.poolValues, className: "w-full" })), error && (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-2 text-xs text-destructive", children: error
|
|
72
|
+
return (_jsxs("div", { className: cn("space-y-3", className), role: "region", "aria-label": `Configure ${serverName}`, children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("button", { type: "button", onClick: onBack, disabled: credentials?.isSubmitting || isOAuthBusy, className: cn("mt-0.5 shrink-0 rounded p-0.5", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), "aria-label": "Back to MCP server list", children: _jsx(BackArrowIcon, {}) }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-2", children: [iconUrl && (_jsx("img", { src: iconUrl, alt: "", width: 16, height: 16, className: "mt-0.5 size-4 shrink-0 rounded-sm object-contain" })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "truncate text-xs font-medium text-foreground", children: serverName }), description && (_jsx("p", { className: "line-clamp-2 text-[0.65rem] leading-relaxed text-muted-foreground", children: description }))] })] })] }), oauthSignIn && (_jsx(InlineOAuthSignIn, { serverName: serverName, isConnected: oauthSignIn.isConnected, connectionHealth: oauthSignIn.connectionHealth, phase: oauthSignIn.phase, onSignIn: oauthSignIn.onSignIn, onDisconnect: oauthSignIn.onDisconnect, isDisconnecting: oauthSignIn.isDisconnecting, disconnectError: oauthSignIn.disconnectError, onClearDisconnectError: oauthSignIn.onClearDisconnectError, error: oauthSignIn.error, onClearError: oauthSignIn.onClearError, isVendorApprovalPending: oauthSignIn.isVendorApprovalPending, isVendorApprovalBlocked: oauthSignIn.isVendorApprovalBlocked, vendorApprovalDocsUrl: oauthSignIn.vendorApprovalDocsUrl, canBringOwnApp: oauthSignIn.canBringOwnApp, isOrgOAuthApp: oauthSignIn.isOrgOAuthApp, onBringOwnApp: oauthSignIn.onBringOwnApp, onRemoveOrgApp: oauthSignIn.onRemoveOrgApp, isRemovingOrgApp: oauthSignIn.isRemovingOrgApp, onSwitchToManual: onSwitchToManual })), !oauthSignIn && onSwitchToOAuth && (_jsx("button", { type: "button", onClick: onSwitchToOAuth, className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Sign in with OAuth instead" })), credentials && (_jsx(EnvVarForm, { variables: credentials.variables, onSubmit: handleCredentialSubmit, isSubmitting: credentials.isSubmitting, disabled: disabled || isOAuthBusy, title: "Credentials required", defaultSaveForFuture: credentials.defaultSaveForFuture, hideSaveToggle: credentials.hideSaveToggle, poolValues: credentials.poolValues, className: "w-full" })), error && (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-2 text-xs text-destructive", children: getUserMessage(error) })), _jsx(McpToolSelector, { tools: discoveredTools, toolApprovals: toolApprovals, enabledTools: enabledTools, onChange: onEnabledToolsChange, disabled: !!isDisabled || !!credentials || isOAuthBusy })] }));
|
|
71
73
|
}
|
|
72
74
|
// ---------------------------------------------------------------------------
|
|
73
75
|
// Inline OAuth sign-in (compact, for config panel context)
|
|
74
76
|
// ---------------------------------------------------------------------------
|
|
75
|
-
|
|
77
|
+
/** Maps OAuthConnectionHealth to compact status dot + label for InlineOAuthSignIn. */
|
|
78
|
+
function inlineHealthProps(health, isConnected, isVendorApprovalPending) {
|
|
79
|
+
if (isVendorApprovalPending && !isConnected) {
|
|
80
|
+
return {
|
|
81
|
+
textClass: "text-amber-600 dark:text-amber-400",
|
|
82
|
+
dotClass: "bg-amber-500",
|
|
83
|
+
label: "Pending approval",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
switch (health) {
|
|
87
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_HEALTHY:
|
|
88
|
+
return {
|
|
89
|
+
textClass: "text-success",
|
|
90
|
+
dotClass: "bg-success",
|
|
91
|
+
label: "Signed in",
|
|
92
|
+
};
|
|
93
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED_REFRESHABLE:
|
|
94
|
+
return {
|
|
95
|
+
textClass: "text-amber-600 dark:text-amber-400",
|
|
96
|
+
dotClass: "bg-amber-500",
|
|
97
|
+
label: "Token expired",
|
|
98
|
+
};
|
|
99
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED:
|
|
100
|
+
return {
|
|
101
|
+
textClass: "text-destructive",
|
|
102
|
+
dotClass: "bg-destructive",
|
|
103
|
+
label: "Re-auth needed",
|
|
104
|
+
};
|
|
105
|
+
default:
|
|
106
|
+
return {
|
|
107
|
+
textClass: "text-muted-foreground",
|
|
108
|
+
dotClass: "bg-muted-foreground",
|
|
109
|
+
label: "Sign-in required",
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function InlineOAuthSignIn({ serverName, isConnected, connectionHealth, phase, onSignIn, onDisconnect, isDisconnecting, disconnectError, onClearDisconnectError, error, onClearError, isVendorApprovalPending, isVendorApprovalBlocked, vendorApprovalDocsUrl, canBringOwnApp, isOrgOAuthApp, onBringOwnApp, onRemoveOrgApp, isRemovingOrgApp, onSwitchToManual, }) {
|
|
114
|
+
const [disconnectPhase, setDisconnectPhase] = useState("idle");
|
|
115
|
+
const [removeOrgAppPhase, setRemoveOrgAppPhase] = useState("idle");
|
|
116
|
+
const blocked = isVendorApprovalBlocked ?? isVendorApprovalPending;
|
|
76
117
|
const isBusy = phase === "initiating" ||
|
|
77
118
|
phase === "awaiting-callback" ||
|
|
78
119
|
phase === "completing" ||
|
|
79
120
|
phase === "connecting";
|
|
80
|
-
const signInDisabled = isBusy || !!
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
121
|
+
const signInDisabled = isBusy || (!!blocked && !isOrgOAuthApp);
|
|
122
|
+
const anyBusy = isBusy || !!isDisconnecting || !!isRemovingOrgApp;
|
|
123
|
+
const needsReAuth = connectionHealth === OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED;
|
|
124
|
+
const status = inlineHealthProps(connectionHealth, isConnected, !!isVendorApprovalPending && !isOrgOAuthApp);
|
|
125
|
+
const showDisconnectLink = isConnected && onDisconnect && !anyBusy && disconnectPhase === "idle";
|
|
126
|
+
const showRemoveOrgAppLink = isOrgOAuthApp && onRemoveOrgApp && !anyBusy && removeOrgAppPhase === "idle";
|
|
127
|
+
// Inline disconnect confirmation
|
|
128
|
+
if (disconnectPhase === "confirming" || disconnectPhase === "disconnecting") {
|
|
129
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsx("p", { className: "text-[0.65rem] text-foreground", children: "Remove credentials? You can reconnect at any time." }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("button", { type: "button", disabled: !!isDisconnecting, onClick: async () => {
|
|
130
|
+
if (!onDisconnect)
|
|
131
|
+
return;
|
|
132
|
+
setDisconnectPhase("disconnecting");
|
|
133
|
+
try {
|
|
134
|
+
await onDisconnect();
|
|
135
|
+
setDisconnectPhase("idle");
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
setDisconnectPhase("confirming");
|
|
139
|
+
}
|
|
140
|
+
}, className: cn("inline-flex items-center gap-1 rounded px-2 py-0.5 text-[0.65rem] font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive/90", "disabled:pointer-events-none disabled:opacity-50"), children: [isDisconnecting && _jsx(InlineSpinner, {}), "Disconnect"] }), _jsx("button", { type: "button", disabled: !!isDisconnecting, onClick: () => {
|
|
141
|
+
setDisconnectPhase("idle");
|
|
142
|
+
onClearDisconnectError?.();
|
|
143
|
+
}, className: cn("inline-flex items-center rounded px-2 py-0.5 text-[0.65rem] font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] }), disconnectError && (_jsxs("div", { className: "flex items-start gap-1.5 text-[0.65rem] text-destructive", role: "alert", children: [_jsx("span", { className: "flex-1", children: getUserMessage(disconnectError) }), _jsx("button", { type: "button", onClick: () => onClearDisconnectError?.(), className: "shrink-0 underline underline-offset-2 hover:no-underline", children: "Dismiss" })] }))] }));
|
|
144
|
+
}
|
|
145
|
+
// Inline "remove custom app" confirmation
|
|
146
|
+
if (removeOrgAppPhase === "confirming" || removeOrgAppPhase === "removing") {
|
|
147
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsx("p", { className: "text-[0.65rem] text-foreground", children: "Remove your custom OAuth app? The server will revert to the platform's app." }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("button", { type: "button", disabled: !!isRemovingOrgApp, onClick: async () => {
|
|
148
|
+
if (!onRemoveOrgApp)
|
|
149
|
+
return;
|
|
150
|
+
setRemoveOrgAppPhase("removing");
|
|
151
|
+
try {
|
|
152
|
+
await onRemoveOrgApp();
|
|
153
|
+
setRemoveOrgAppPhase("idle");
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
setRemoveOrgAppPhase("confirming");
|
|
157
|
+
}
|
|
158
|
+
}, className: cn("inline-flex items-center gap-1 rounded px-2 py-0.5 text-[0.65rem] font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive/90", "disabled:pointer-events-none disabled:opacity-50"), children: [isRemovingOrgApp && _jsx(InlineSpinner, {}), "Remove"] }), _jsx("button", { type: "button", disabled: !!isRemovingOrgApp, onClick: () => setRemoveOrgAppPhase("idle"), className: cn("inline-flex items-center rounded px-2 py-0.5 text-[0.65rem] font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] }));
|
|
159
|
+
}
|
|
160
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: cn("inline-flex items-center gap-1 text-[0.65rem] font-medium", status.textClass), children: [_jsx("span", { className: cn("size-1.5 rounded-full", status.dotClass), "aria-hidden": "true" }), status.label] }), isOrgOAuthApp && isConnected && (_jsx("span", { className: "text-[0.6rem] text-muted-foreground", children: "Your app" })), showDisconnectLink && (_jsx("button", { type: "button", onClick: () => setDisconnectPhase("confirming"), className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Disconnect" })), showRemoveOrgAppLink && (_jsx("button", { type: "button", onClick: () => setRemoveOrgAppPhase("confirming"), className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Remove custom app" }))] }), _jsx("button", { type: "button", onClick: onSignIn, disabled: signInDisabled, className: cn("inline-flex items-center gap-1 rounded px-2 py-0.5 text-[0.65rem] font-medium", isConnected && !needsReAuth
|
|
90
161
|
? "text-muted-foreground hover:text-foreground hover:bg-accent/50"
|
|
91
|
-
: "bg-primary text-primary-foreground hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-50"), children: isBusy ? (_jsx(InlineSpinner, {})) : isConnected ? ("Re-authenticate") : (`Sign in with ${serverName}`) })] }),
|
|
162
|
+
: "bg-primary text-primary-foreground hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-50"), children: isBusy ? (_jsx(InlineSpinner, {})) : isOrgOAuthApp && !isConnected ? ("Sign in with your app") : isConnected && !needsReAuth ? ("Re-authenticate") : needsReAuth ? ("Sign in to reconnect") : (`Sign in with ${serverName}`) })] }), blocked && !isConnected && !isOrgOAuthApp && (_jsxs("div", { className: "text-[0.65rem] text-amber-700 dark:text-amber-300", children: [_jsxs("p", { children: ["OAuth sign-in is pending vendor approval.", canBringOwnApp && onBringOwnApp
|
|
163
|
+
? " You can use your own OAuth app or enter a token manually."
|
|
164
|
+
: ""] }), canBringOwnApp && onBringOwnApp && (_jsx("button", { type: "button", onClick: onBringOwnApp, className: "mt-1 inline-flex items-center gap-1 rounded bg-amber-600 px-2 py-0.5 text-[0.6rem] font-medium text-white hover:bg-amber-700 dark:bg-amber-500 dark:text-amber-950 dark:hover:bg-amber-400", children: "Use your own OAuth app" })), vendorApprovalDocsUrl && !canBringOwnApp && (_jsx("a", { href: vendorApprovalDocsUrl, target: "_blank", rel: "noopener noreferrer", className: "underline decoration-amber-600/40 underline-offset-2 hover:decoration-amber-600 dark:decoration-amber-400/40 dark:hover:decoration-amber-400", children: "Learn how to bring your own token" }))] })), isOrgOAuthApp && !isConnected && (_jsx("span", { className: "text-[0.6rem] text-muted-foreground", children: "Using your OAuth app" })), error && (_jsxs("div", { className: "flex items-start gap-1.5 text-[0.65rem] text-destructive", role: "alert", children: [_jsx("span", { className: "flex-1", children: getUserMessage(error) }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [isRetryableError(error) && (_jsx("button", { type: "button", onClick: () => {
|
|
165
|
+
onClearError();
|
|
166
|
+
onSignIn();
|
|
167
|
+
}, className: "font-medium underline underline-offset-2 hover:no-underline", children: "Try again" })), _jsx("button", { type: "button", onClick: onClearError, className: "underline underline-offset-2 hover:no-underline", children: "Dismiss" })] })] })), !isConnected && !isBusy && (_jsxs("div", { className: "flex items-center gap-2", children: [onSwitchToManual && (_jsx("button", { type: "button", onClick: onSwitchToManual, className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Enter token manually" })), canBringOwnApp && onBringOwnApp && !blocked && (_jsx("button", { type: "button", onClick: onBringOwnApp, className: "text-[0.65rem] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Use your own OAuth app" }))] }))] }));
|
|
92
168
|
}
|
|
93
169
|
function InlineSpinner() {
|
|
94
170
|
return (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", className: "animate-spin", "aria-hidden": "true", children: _jsx("path", { d: "M8 2a6 6 0 1 0 6 6" }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpServerConfigPanel.js","sourceRoot":"","sources":["../../src/mcp-server/McpServerConfigPanel.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"McpServerConfigPanel.js","sourceRoot":"","sources":["../../src/mcp-server/McpServerConfigPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpServerDetailView.d.ts","sourceRoot":"","sources":["../../src/mcp-server/McpServerDetailView.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"McpServerDetailView.d.ts","sourceRoot":"","sources":["../../src/mcp-server/McpServerDetailView.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAC;AAe/F,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAE/D,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvE;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACjE,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,aAAa,CAAC;IAC9C;;;;;;OAMG;IACH,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAC9B,GAAG,EAAE,MAAM,KACR,OAAO,cAAc,EAAE,WAAW,GAAG,SAAS,CAAC;IACpD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,IAAI,EACJ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,oBAA8B,EAC9B,yBAAiC,EACjC,oBAAoB,EACpB,SAAS,EACT,SAAS,GACV,EAAE,wBAAwB,2CA6U1B"}
|
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { getUserMessage, isRetryableError } from "@stigmer/sdk";
|
|
5
6
|
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
7
|
+
import { OAuthConnectionHealth } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
6
8
|
import { ValidationState } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
|
|
7
9
|
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
8
10
|
import { useMcpServer } from "./useMcpServer";
|
|
9
11
|
import { useMcpServerConnect } from "./useMcpServerConnect";
|
|
10
12
|
import { useMcpServerCredentials } from "./useMcpServerCredentials";
|
|
11
13
|
import { useMcpServerOAuthConnect } from "./useMcpServerOAuthConnect";
|
|
14
|
+
import { useDisconnectOAuth } from "./useDisconnectOAuth";
|
|
15
|
+
import { useOrgOAuthApp } from "./useOrgOAuthApp";
|
|
16
|
+
import { OAuthAppForm } from "./OAuthAppForm";
|
|
12
17
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
13
18
|
import { EnvVarForm } from "../environment/EnvVarForm";
|
|
14
19
|
import { VisibilityToggle } from "../library/VisibilityToggle";
|
|
@@ -42,8 +47,12 @@ export function McpServerDetailView({ org, slug, onResourceLoad, onVisibilityCha
|
|
|
42
47
|
const credentials = useMcpServerCredentials(activeOrg ?? org, mcpServer ?? null);
|
|
43
48
|
const connection = useMcpServerConnect();
|
|
44
49
|
const oauth = useMcpServerOAuthConnect();
|
|
50
|
+
const disconnectOAuth = useDisconnectOAuth();
|
|
51
|
+
const orgOAuthApp = useOrgOAuthApp(mcpServer?.metadata?.id ?? null, activeOrg ?? org);
|
|
45
52
|
const [showCredentialForm, setShowCredentialForm] = useState(defaultShowCredentialForm);
|
|
53
|
+
const [showByoaForm, setShowByoaForm] = useState(false);
|
|
46
54
|
const [capabilityTab, setCapabilityTab] = useState(defaultCapabilityTab);
|
|
55
|
+
const byoaDialogRef = useRef(null);
|
|
47
56
|
const onResourceLoadRef = useRef(onResourceLoad);
|
|
48
57
|
onResourceLoadRef.current = onResourceLoad;
|
|
49
58
|
useEffect(() => {
|
|
@@ -109,6 +118,48 @@ export function McpServerDetailView({ org, slug, onResourceLoad, onVisibilityCha
|
|
|
109
118
|
// error state is managed by the hooks
|
|
110
119
|
}
|
|
111
120
|
}, [credentials, mcpServer, connection, refetch]);
|
|
121
|
+
const handleDisconnect = useCallback(async () => {
|
|
122
|
+
if (!mcpServer?.metadata?.id)
|
|
123
|
+
return;
|
|
124
|
+
try {
|
|
125
|
+
await disconnectOAuth.disconnect(mcpServer.metadata.id, activeOrg ?? org);
|
|
126
|
+
credentials.refetch();
|
|
127
|
+
refetch();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// error state is managed by the disconnect hook
|
|
131
|
+
}
|
|
132
|
+
}, [mcpServer, disconnectOAuth, credentials, refetch, activeOrg, org]);
|
|
133
|
+
// BYOA dialog lifecycle — native <dialog> toggle
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
const dialog = byoaDialogRef.current;
|
|
136
|
+
if (!dialog)
|
|
137
|
+
return;
|
|
138
|
+
if (showByoaForm && !dialog.open) {
|
|
139
|
+
dialog.showModal();
|
|
140
|
+
}
|
|
141
|
+
else if (!showByoaForm && dialog.open) {
|
|
142
|
+
dialog.close();
|
|
143
|
+
}
|
|
144
|
+
}, [showByoaForm]);
|
|
145
|
+
const handleByoaDialogCancel = useCallback((e) => {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
setShowByoaForm(false);
|
|
148
|
+
orgOAuthApp.clearErrors();
|
|
149
|
+
}, [orgOAuthApp]);
|
|
150
|
+
const handleByoaSubmit = useCallback(async (clientId, clientSecret) => {
|
|
151
|
+
await orgOAuthApp.setOrgOAuthApp(clientId, clientSecret);
|
|
152
|
+
setShowByoaForm(false);
|
|
153
|
+
orgOAuthApp.refetch();
|
|
154
|
+
credentials.refetch();
|
|
155
|
+
refetch();
|
|
156
|
+
}, [orgOAuthApp, credentials, refetch]);
|
|
157
|
+
const handleRemoveOrgApp = useCallback(async () => {
|
|
158
|
+
await orgOAuthApp.deleteOrgOAuthApp();
|
|
159
|
+
orgOAuthApp.refetch();
|
|
160
|
+
credentials.refetch();
|
|
161
|
+
refetch();
|
|
162
|
+
}, [orgOAuthApp, credentials, refetch]);
|
|
112
163
|
const spec = mcpServer?.spec;
|
|
113
164
|
const status = mcpServer?.status;
|
|
114
165
|
const hasSource = spec && (spec.repositoryUrl || spec.githubStars > 0);
|
|
@@ -148,30 +199,95 @@ export function McpServerDetailView({ org, slug, onResourceLoad, onVisibilityCha
|
|
|
148
199
|
return (_jsxs("div", { className: cn("flex flex-col gap-6", className), children: [status?.validationState === ValidationState.invalid &&
|
|
149
200
|
status.validationMessage && (_jsx(ValidationBanner, { message: status.validationMessage })), _jsx(Header, { server: mcpServer, createdAt: specAudit?.createdAt ? timestampDate(specAudit.createdAt) : null, updatedAt: specAudit?.updatedAt ? timestampDate(specAudit.updatedAt) : null, lastDiscoveredAt: capabilities?.lastDiscoveredAt
|
|
150
201
|
? timestampDate(capabilities.lastDiscoveredAt)
|
|
151
|
-
: null, onVisibilityChange: onVisibilityChange, isVisibilityPending: isVisibilityPending }), hasSource && _jsx(SourceSection, { spec: spec }), spec?.serverType.case && (_jsx(ServerConfigSection, { serverType: spec.serverType })), spec?.env && Object.keys(spec.env).length > 0 && (_jsx(EnvSection, { data: spec.env, oauthTargetEnvVar: credentials.oauthTargetEnvVar })), _jsxs(Section, { title: "Connection", children: [_jsx(ConnectBar, { isConnecting: connection.isConnecting || oauth.isInProgress, connectionError: combinedError, onConnect: handleConnectClick, onClearConnectionError: combinedClearError, hasDiscoveredTools: hasDiscoveredTools, toolCount: tools.length, policyCount: totalPolicyCount, credentialsLoading: credentials.isLoading, oauthPhase: oauth.phase, authMode: credentials.authMode, isOAuthConnected: credentials.isOAuthConnected, accessTokenExpiresAt: credentials.accessTokenExpiresAt, tokenLifetimeHint: credentials.tokenLifetimeHint, isVendorApprovalPending: credentials.isVendorApprovalPending, vendorApprovalDocsUrl: credentials.vendorApprovalDocsUrl, manualOverride: credentials.manualOverride, onManualOverride: () => {
|
|
202
|
+
: null, onVisibilityChange: onVisibilityChange, isVisibilityPending: isVisibilityPending }), hasSource && _jsx(SourceSection, { spec: spec }), spec?.serverType.case && (_jsx(ServerConfigSection, { serverType: spec.serverType })), spec?.env && Object.keys(spec.env).length > 0 && (_jsx(EnvSection, { data: spec.env, oauthTargetEnvVar: credentials.oauthTargetEnvVar })), _jsxs(Section, { title: "Connection", children: [_jsx(ConnectBar, { isConnecting: connection.isConnecting || oauth.isInProgress, connectionError: combinedError, onConnect: handleConnectClick, onClearConnectionError: combinedClearError, hasDiscoveredTools: hasDiscoveredTools, toolCount: tools.length, policyCount: totalPolicyCount, credentialsLoading: credentials.isLoading, oauthPhase: oauth.phase, authMode: credentials.authMode, isOAuthConnected: credentials.isOAuthConnected, connectionHealth: credentials.connectionHealth, canDisconnect: credentials.canDisconnect, onDisconnect: handleDisconnect, isDisconnecting: disconnectOAuth.isDisconnecting, disconnectError: disconnectOAuth.error, onClearDisconnectError: disconnectOAuth.clearError, serverName: mcpServer?.metadata?.name ?? slug, accessTokenExpiresAt: credentials.accessTokenExpiresAt, tokenLifetimeHint: credentials.tokenLifetimeHint, isVendorApprovalPending: credentials.isVendorApprovalPending, isVendorApprovalBlocked: credentials.isVendorApprovalBlocked, vendorApprovalDocsUrl: credentials.vendorApprovalDocsUrl, canBringOwnApp: credentials.canBringOwnApp, isOrgOAuthApp: credentials.isOrgOAuthApp, onBringOwnApp: () => setShowByoaForm(true), onRemoveOrgApp: handleRemoveOrgApp, isRemovingOrgApp: orgOAuthApp.isDeleting, removeOrgAppError: orgOAuthApp.deleteError, onClearRemoveOrgAppError: orgOAuthApp.clearErrors, manualOverride: credentials.manualOverride, onManualOverride: () => {
|
|
152
203
|
credentials.setManualOverride(true);
|
|
153
204
|
setShowCredentialForm(true);
|
|
154
205
|
}, onBackToOAuth: () => {
|
|
155
206
|
credentials.setManualOverride(false);
|
|
156
207
|
setShowCredentialForm(false);
|
|
157
|
-
} }), showCredentialForm && credentials.missingVariables.length > 0 && (_jsx("div", { className: "border-b border-border p-4", "data-cursor-target": "credential-form", children: _jsx(EnvVarForm, { title: "Credentials Required", description: "Enter the credentials needed to connect to this MCP server. Toggle \"Save for future runs\" to persist them in your personal environment, or leave it off for one-time use.", variables: credentials.missingVariables, onSubmit: (values, options) => handleCredentialSubmit(values, options), onCancel: () => setShowCredentialForm(false), isSubmitting: credentials.isSaving, poolValues: credentialPoolValues, className: "w-full max-w-md" }) }))] }),
|
|
208
|
+
} }), showCredentialForm && credentials.missingVariables.length > 0 && (_jsx("div", { className: "border-b border-border p-4", "data-cursor-target": "credential-form", children: _jsx(EnvVarForm, { title: "Credentials Required", description: "Enter the credentials needed to connect to this MCP server. Toggle \"Save for future runs\" to persist them in your personal environment, or leave it off for one-time use.", variables: credentials.missingVariables, onSubmit: (values, options) => handleCredentialSubmit(values, options), onCancel: () => setShowCredentialForm(false), isSubmitting: credentials.isSaving, poolValues: credentialPoolValues, className: "w-full max-w-md" }) }))] }), _jsxs("dialog", { ref: byoaDialogRef, onCancel: handleByoaDialogCancel, className: cn("w-full max-w-md rounded-lg border border-border bg-background p-6 shadow-lg", "backdrop:bg-black/50"), children: [_jsx("h3", { className: "mb-4 text-base font-semibold text-foreground", children: "Use your own OAuth app" }), _jsx(OAuthAppForm, { providerName: mcpServer?.metadata?.name ?? slug, vendorDocsUrl: credentials.vendorApprovalDocsUrl, onSubmit: handleByoaSubmit, onCancel: () => {
|
|
209
|
+
setShowByoaForm(false);
|
|
210
|
+
orgOAuthApp.clearErrors();
|
|
211
|
+
}, isSubmitting: orgOAuthApp.isSetting, error: orgOAuthApp.setError })] }), _jsx(Section, { title: "Capabilities", children: _jsxs(Tabs, { tabs: capabilityTabs, activeTab: capabilityTab, onTabChange: (id) => setCapabilityTab(id), "aria-label": "MCP server capabilities", children: [capabilityTab === "tools" && (_jsx(ToolsTabContent, { tools: tools })), capabilityTab === "policies" && (_jsx(PoliciesTabContent, { pinnedPolicies: pinnedPolicies, classifiedPolicies: classifiedPolicies, hasDiscoveredTools: hasDiscoveredTools })), capabilityTab === "resources" && (_jsx(ResourceTemplatesList, { templates: resourceTemplates }))] }) }), spec && spec.tags.length > 0 && _jsx(TagsSection, { tags: spec.tags })] }));
|
|
158
212
|
}
|
|
159
213
|
// ---------------------------------------------------------------------------
|
|
160
214
|
// ConnectBar — single entry point for capability discovery
|
|
161
215
|
// ---------------------------------------------------------------------------
|
|
162
|
-
|
|
216
|
+
/** Maps an OAuthConnectionHealth enum to pill display properties. */
|
|
217
|
+
function healthPillProps(health, isVendorApprovalPending) {
|
|
218
|
+
if (isVendorApprovalPending) {
|
|
219
|
+
return {
|
|
220
|
+
pillClass: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
221
|
+
dotClass: "bg-amber-500",
|
|
222
|
+
label: "Pending approval",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
switch (health) {
|
|
226
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_HEALTHY:
|
|
227
|
+
return {
|
|
228
|
+
pillClass: "bg-success/10 text-success",
|
|
229
|
+
dotClass: "bg-success",
|
|
230
|
+
label: "Connected",
|
|
231
|
+
};
|
|
232
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED_REFRESHABLE:
|
|
233
|
+
return {
|
|
234
|
+
pillClass: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
235
|
+
dotClass: "bg-amber-500",
|
|
236
|
+
label: "Token expired",
|
|
237
|
+
};
|
|
238
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED:
|
|
239
|
+
return {
|
|
240
|
+
pillClass: "bg-destructive/10 text-destructive",
|
|
241
|
+
dotClass: "bg-destructive",
|
|
242
|
+
label: "Re-auth needed",
|
|
243
|
+
};
|
|
244
|
+
default:
|
|
245
|
+
return {
|
|
246
|
+
pillClass: "bg-muted text-muted-foreground",
|
|
247
|
+
dotClass: "bg-muted-foreground",
|
|
248
|
+
label: "Not connected",
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** Health-aware status detail text shown alongside the pill. */
|
|
253
|
+
function healthStatusText(health, accessTokenExpiresAt, tokenLifetimeHint) {
|
|
254
|
+
switch (health) {
|
|
255
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_HEALTHY: {
|
|
256
|
+
const expiryLabel = formatTokenExpiry(accessTokenExpiresAt);
|
|
257
|
+
if (expiryLabel)
|
|
258
|
+
return `Tokens refresh automatically \u00B7 ${expiryLabel}`;
|
|
259
|
+
const hint = tokenLifetimeHint && tokenLifetimeHint !== "never"
|
|
260
|
+
? ` \u00B7 Session lasts ~${tokenLifetimeHint}`
|
|
261
|
+
: "";
|
|
262
|
+
return `Tokens refresh automatically${hint}`;
|
|
263
|
+
}
|
|
264
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED_REFRESHABLE:
|
|
265
|
+
return "Will refresh automatically on next use";
|
|
266
|
+
case OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED:
|
|
267
|
+
return "Token expired \u2014 sign in again to reconnect";
|
|
268
|
+
default:
|
|
269
|
+
return "Not connected yet";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function ConnectBar({ isConnecting, connectionError, onConnect, onClearConnectionError, hasDiscoveredTools, toolCount, policyCount, credentialsLoading, oauthPhase, authMode, isOAuthConnected, connectionHealth, canDisconnect, onDisconnect, isDisconnecting, disconnectError, onClearDisconnectError, serverName, accessTokenExpiresAt, tokenLifetimeHint, isVendorApprovalPending, isVendorApprovalBlocked, vendorApprovalDocsUrl, canBringOwnApp, isOrgOAuthApp, onBringOwnApp, onRemoveOrgApp, isRemovingOrgApp, removeOrgAppError, onClearRemoveOrgAppError, manualOverride, onManualOverride, onBackToOAuth, }) {
|
|
273
|
+
const [disconnectPhase, setDisconnectPhase] = useState("idle");
|
|
274
|
+
const [removeOrgAppPhase, setRemoveOrgAppPhase] = useState("idle");
|
|
163
275
|
const isOAuthBusy = oauthPhase === "initiating" ||
|
|
164
276
|
oauthPhase === "awaiting-callback" ||
|
|
165
277
|
oauthPhase === "completing" ||
|
|
166
278
|
oauthPhase === "connecting";
|
|
167
279
|
const showOAuthPrimary = authMode === "oauth" && !isOAuthConnected && !manualOverride;
|
|
168
|
-
const
|
|
280
|
+
const needsReAuth = connectionHealth === OAuthConnectionHealth.OAUTH_CONNECTION_HEALTH_TOKEN_EXPIRED;
|
|
281
|
+
const oauthSignInDisabled = isVendorApprovalBlocked && showOAuthPrimary && !isOrgOAuthApp;
|
|
282
|
+
const anyBusy = isConnecting || isOAuthBusy || isDisconnecting || isRemovingOrgApp;
|
|
169
283
|
const buttonLabel = (() => {
|
|
170
284
|
if (isOAuthBusy)
|
|
171
285
|
return oauthPhaseLabel(oauthPhase);
|
|
172
286
|
if (isConnecting)
|
|
173
287
|
return "Connecting...";
|
|
174
|
-
if (showOAuthPrimary)
|
|
288
|
+
if (isOrgOAuthApp && showOAuthPrimary)
|
|
289
|
+
return "Sign in with your app";
|
|
290
|
+
if (showOAuthPrimary || needsReAuth)
|
|
175
291
|
return "Sign in to connect";
|
|
176
292
|
if (hasDiscoveredTools)
|
|
177
293
|
return "Reconnect";
|
|
@@ -180,7 +296,7 @@ function ConnectBar({ isConnecting, connectionError, onConnect, onClearConnectio
|
|
|
180
296
|
const buttonIcon = (() => {
|
|
181
297
|
if (isOAuthBusy || isConnecting)
|
|
182
298
|
return _jsx(Spinner, {});
|
|
183
|
-
if (showOAuthPrimary)
|
|
299
|
+
if (showOAuthPrimary || needsReAuth)
|
|
184
300
|
return _jsx(OAuthIcon, { className: "size-3.5" });
|
|
185
301
|
if (hasDiscoveredTools)
|
|
186
302
|
return _jsx(RefreshIcon, { className: "size-3.5" });
|
|
@@ -188,31 +304,60 @@ function ConnectBar({ isConnecting, connectionError, onConnect, onClearConnectio
|
|
|
188
304
|
})();
|
|
189
305
|
const statusText = (() => {
|
|
190
306
|
if (authMode === "oauth" && isOAuthConnected) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
return `Tokens refresh automatically \u00B7 ${expiryLabel}`;
|
|
194
|
-
const hint = tokenLifetimeHint && tokenLifetimeHint !== "never"
|
|
195
|
-
? ` \u00B7 Session lasts ~${tokenLifetimeHint}`
|
|
196
|
-
: "";
|
|
197
|
-
return `Tokens refresh automatically${hint}`;
|
|
307
|
+
const base = healthStatusText(connectionHealth, accessTokenExpiresAt, tokenLifetimeHint);
|
|
308
|
+
return isOrgOAuthApp ? `${base} \u00B7 Using your OAuth app` : base;
|
|
198
309
|
}
|
|
310
|
+
if (isOrgOAuthApp && showOAuthPrimary)
|
|
311
|
+
return "Using your OAuth app";
|
|
199
312
|
if (manualOverride)
|
|
200
313
|
return "Entering token manually";
|
|
201
314
|
if (hasDiscoveredTools)
|
|
202
315
|
return formatConnectionSummary(toolCount, policyCount);
|
|
203
316
|
return "Not connected yet";
|
|
204
317
|
})();
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
318
|
+
const pill = healthPillProps(connectionHealth, isVendorApprovalPending && !isOAuthConnected);
|
|
319
|
+
const showDisconnectLink = canDisconnect && !anyBusy && !manualOverride && disconnectPhase === "idle";
|
|
320
|
+
const showRemoveOrgAppLink = isOrgOAuthApp && !anyBusy && removeOrgAppPhase === "idle";
|
|
321
|
+
// Inline disconnect confirmation replaces the main bar content
|
|
322
|
+
if (disconnectPhase === "confirming" || disconnectPhase === "disconnecting") {
|
|
323
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [_jsx(WarningIcon, { className: "size-3.5 shrink-0 text-destructive" }), _jsxs("p", { className: "flex-1 text-xs text-foreground", children: ["Remove OAuth credentials for ", _jsx("span", { className: "font-medium", children: serverName }), "? You can reconnect at any time."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsxs("button", { type: "button", disabled: isDisconnecting, onClick: async () => {
|
|
324
|
+
setDisconnectPhase("disconnecting");
|
|
325
|
+
try {
|
|
326
|
+
await onDisconnect();
|
|
327
|
+
setDisconnectPhase("idle");
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
setDisconnectPhase("confirming");
|
|
331
|
+
}
|
|
332
|
+
}, className: cn("inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive/90", "disabled:pointer-events-none disabled:opacity-50"), children: [isDisconnecting && _jsx(Spinner, {}), "Disconnect"] }), _jsx("button", { type: "button", disabled: isDisconnecting, onClick: () => {
|
|
333
|
+
setDisconnectPhase("idle");
|
|
334
|
+
onClearDisconnectError();
|
|
335
|
+
}, className: cn("inline-flex items-center rounded-md px-2.5 py-1 text-xs font-medium", "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] }), disconnectError && (_jsxs("div", { className: "flex items-start gap-2 border-t border-destructive/20 bg-destructive/5 px-3 py-2", children: [_jsx(WarningIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }), _jsx("p", { className: "flex-1 text-xs text-destructive", children: getUserMessage(disconnectError) }), _jsx("button", { type: "button", onClick: onClearDisconnectError, className: "shrink-0 text-xs text-destructive/70 hover:text-destructive", "aria-label": "Dismiss error", children: "Dismiss" })] }))] }));
|
|
336
|
+
}
|
|
337
|
+
// Inline "remove custom app" confirmation
|
|
338
|
+
if (removeOrgAppPhase === "confirming" || removeOrgAppPhase === "removing") {
|
|
339
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [_jsx(WarningIcon, { className: "size-3.5 shrink-0 text-destructive" }), _jsxs("p", { className: "flex-1 text-xs text-foreground", children: ["Remove your custom OAuth app for", " ", _jsx("span", { className: "font-medium", children: serverName }), "? The server will revert to the platform's OAuth app."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsxs("button", { type: "button", disabled: isRemovingOrgApp, onClick: async () => {
|
|
340
|
+
setRemoveOrgAppPhase("removing");
|
|
341
|
+
try {
|
|
342
|
+
await onRemoveOrgApp();
|
|
343
|
+
setRemoveOrgAppPhase("idle");
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
setRemoveOrgAppPhase("confirming");
|
|
347
|
+
}
|
|
348
|
+
}, className: cn("inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive/90", "disabled:pointer-events-none disabled:opacity-50"), children: [isRemovingOrgApp && _jsx(Spinner, {}), "Remove"] }), _jsx("button", { type: "button", disabled: isRemovingOrgApp, onClick: () => {
|
|
349
|
+
setRemoveOrgAppPhase("idle");
|
|
350
|
+
onClearRemoveOrgAppError();
|
|
351
|
+
}, className: cn("inline-flex items-center rounded-md px-2.5 py-1 text-xs font-medium", "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] }), removeOrgAppError && (_jsxs("div", { className: "flex items-start gap-2 border-t border-destructive/20 bg-destructive/5 px-3 py-2", children: [_jsx(WarningIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }), _jsx("p", { className: "flex-1 text-xs text-destructive", children: getUserMessage(removeOrgAppError) }), _jsx("button", { type: "button", onClick: onClearRemoveOrgAppError, className: "shrink-0 text-xs text-destructive/70 hover:text-destructive", "aria-label": "Dismiss error", children: "Dismiss" })] }))] }));
|
|
352
|
+
}
|
|
353
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [authMode === "oauth" && !manualOverride && (_jsxs("span", { className: cn("inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[10px] font-medium", pill.pillClass), children: [_jsx("span", { className: cn("size-1.5 rounded-full", pill.dotClass), "aria-hidden": "true" }), pill.label] })), _jsx("span", { className: "text-xs text-muted-foreground", children: oauthSignInDisabled ? "OAuth sign-in is pending vendor approval" : statusText }), showDisconnectLink && (_jsx("button", { type: "button", onClick: () => setDisconnectPhase("confirming"), className: "text-[11px] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Disconnect" })), showRemoveOrgAppLink && (_jsx("button", { type: "button", onClick: () => setRemoveOrgAppPhase("confirming"), className: "text-[11px] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Remove custom app" }))] }), _jsxs("button", { type: "button", onClick: onConnect, disabled: anyBusy || credentialsLoading || oauthSignInDisabled, "data-cursor-target": "connect-button", className: cn("inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs font-medium", showOAuthPrimary || needsReAuth
|
|
214
354
|
? "bg-primary text-primary-foreground hover:bg-primary-hover"
|
|
215
|
-
: "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-50"), children: [buttonIcon, buttonLabel] })] }), oauthSignInDisabled && (_jsxs("div", { className: "flex items-start gap-2 border-t border-amber-500/20 bg-amber-500/5 px-3 py-2", children: [_jsx(WarningIcon, { className: "mt-0.5 size-3.5 shrink-0 text-amber-600 dark:text-amber-400" }), _jsxs("div", { className: "flex-1 text-xs text-amber-700 dark:text-amber-300", children: [
|
|
355
|
+
: "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-50"), children: [buttonIcon, buttonLabel] })] }), oauthSignInDisabled && (_jsxs("div", { className: "flex items-start gap-2 border-t border-amber-500/20 bg-amber-500/5 px-3 py-2", children: [_jsx(WarningIcon, { className: "mt-0.5 size-3.5 shrink-0 text-amber-600 dark:text-amber-400" }), _jsxs("div", { className: "flex-1 text-xs text-amber-700 dark:text-amber-300", children: [_jsxs("p", { children: ["The platform's OAuth app is awaiting vendor approval.", canBringOwnApp
|
|
356
|
+
? " You can use your own OAuth app or enter a token manually."
|
|
357
|
+
: " You can still connect by entering your own token manually."] }), canBringOwnApp && (_jsx("button", { type: "button", onClick: onBringOwnApp, className: "mt-1.5 inline-flex items-center gap-1 rounded-md bg-amber-600 px-2.5 py-1 text-[11px] font-medium text-white hover:bg-amber-700 dark:bg-amber-500 dark:text-amber-950 dark:hover:bg-amber-400", children: "Use your own OAuth app" })), vendorApprovalDocsUrl && !canBringOwnApp && (_jsxs("a", { href: vendorApprovalDocsUrl, target: "_blank", rel: "noopener noreferrer", className: "mt-1 inline-flex items-center gap-1 underline decoration-amber-600/40 underline-offset-2 hover:decoration-amber-600 dark:decoration-amber-400/40 dark:hover:decoration-amber-400", children: ["Learn how to bring your own token", _jsx(ExternalLinkIcon, { className: "size-3 shrink-0" })] }))] })] })), authMode === "oauth" && !isOAuthConnected && !isOAuthBusy && !isConnecting && (_jsx("div", { className: "flex items-center gap-3 border-t border-border px-3 py-1.5", children: manualOverride ? (_jsx("button", { type: "button", onClick: onBackToOAuth, className: "text-[11px] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: isVendorApprovalPending ? "Back to OAuth status" : "Sign in with OAuth instead" })) : (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: onManualOverride, className: "text-[11px] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Enter token manually" }), canBringOwnApp && !isVendorApprovalBlocked && (_jsx("button", { type: "button", onClick: onBringOwnApp, className: "text-[11px] text-muted-foreground underline decoration-muted-foreground/40 underline-offset-2 hover:text-foreground hover:decoration-foreground", children: "Use your own OAuth app" }))] })) })), connectionError && (_jsxs("div", { className: "flex items-start gap-2 border-t border-destructive/20 bg-destructive/5 px-3 py-2", role: "alert", children: [_jsx(WarningIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }), _jsx("p", { className: "flex-1 text-xs text-destructive", children: getUserMessage(connectionError) }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [isRetryableError(connectionError) && (_jsx("button", { type: "button", onClick: () => {
|
|
358
|
+
onClearConnectionError();
|
|
359
|
+
onConnect();
|
|
360
|
+
}, className: "text-xs font-medium text-destructive underline underline-offset-2 hover:no-underline", children: "Try again" })), _jsx("button", { type: "button", onClick: onClearConnectionError, className: "text-xs text-destructive/70 hover:text-destructive", "aria-label": "Dismiss error", children: "Dismiss" })] })] }))] }));
|
|
216
361
|
}
|
|
217
362
|
function oauthPhaseLabel(phase) {
|
|
218
363
|
switch (phase) {
|