@iblai/web-containers 1.57.0 → 1.58.1
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/dist/cjs/_virtual/index2.js +2 -2
- package/dist/cjs/_virtual/index3.js +2 -2
- package/dist/cjs/components/chat/chat-download-dialog.js.map +1 -1
- package/dist/cjs/components/chat/ui/button.js +4 -4
- package/dist/cjs/components/chat/ui/button.js.map +1 -1
- package/dist/cjs/components/chat-input-form/composer-plus-menu.js +94 -17
- package/dist/cjs/components/chat-input-form/composer-plus-menu.js.map +1 -1
- package/dist/cjs/components/chat-input-form/mcp-connect-explainer-dialog.js +29 -0
- package/dist/cjs/components/chat-input-form/mcp-connect-explainer-dialog.js.map +1 -0
- package/dist/cjs/components/chat-input-form/mcp-servers-menu.js +199 -0
- package/dist/cjs/components/chat-input-form/mcp-servers-menu.js.map +1 -0
- package/dist/cjs/components/chat-input-form/use-mcp-active-count.js +56 -0
- package/dist/cjs/components/chat-input-form/use-mcp-active-count.js.map +1 -0
- package/dist/cjs/components/chat-input-form.js +17 -4
- package/dist/cjs/components/chat-input-form.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab/create-api-modal.js +29 -13
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab/create-api-modal.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab/labels.js +8 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab/labels.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab.js +23 -13
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/api-tab.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-dialogs.js +755 -90
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-dialogs.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-management-content.js +386 -984
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-management-content.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/field-info.js +16 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/field-info.js.map +1 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/index.js +6 -3
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/index.js.map +1 -1
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/mcp-connector-helpers.js +463 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/mcp-connector-helpers.js.map +1 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/oauth-app-fields.js +329 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/oauth-app-fields.js.map +1 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/remove-connector-dialog.js +20 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/remove-connector-dialog.js.map +1 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/use-mcp-server-actions.js +744 -0
- package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/use-mcp-server-actions.js.map +1 -0
- package/dist/cjs/components/modals/user-profile-modal.js +2 -0
- package/dist/cjs/components/modals/user-profile-modal.js.map +1 -1
- package/dist/cjs/components/profile/integration/api-tab/create-api-modal.js +17 -10
- package/dist/cjs/components/profile/integration/api-tab/create-api-modal.js.map +1 -1
- package/dist/cjs/components/ui/accordion.js +40 -0
- package/dist/cjs/components/ui/accordion.js.map +1 -0
- package/dist/cjs/i18n/messages/en.json.js +156 -19
- package/dist/cjs/i18n/messages/en.json.js.map +1 -1
- package/dist/cjs/i18n/messages/es.json.js +156 -19
- package/dist/cjs/i18n/messages/es.json.js.map +1 -1
- package/dist/cjs/i18n/messages/fr.json.js +156 -19
- package/dist/cjs/i18n/messages/fr.json.js.map +1 -1
- package/dist/cjs/i18n/messages/zh.json.js +156 -19
- package/dist/cjs/i18n/messages/zh.json.js.map +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-accordion@1.2.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types_re_b91476821b9fe8f172a947f727875267/node_modules/@radix-ui/react-accordion/dist/index.js +317 -0
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-accordion@1.2.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types_re_b91476821b9fe8f172a947f727875267/node_modules/@radix-ui/react-accordion/dist/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-collapsible@1.1.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types__d84e28844e8116e61b459b615fab358a/node_modules/@radix-ui/react-collapsible/dist/index.js +173 -0
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-collapsible@1.1.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types__d84e28844e8116e61b459b615fab358a/node_modules/@radix-ui/react-collapsible/dist/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-collection@1.1.4_@types_react-dom@19.2.1_@types_react@19.1.17__@types_r_7047fbfe61c39c77a2126486502acdb6/node_modules/@radix-ui/react-collection/dist/index.js +73 -0
- package/dist/cjs/node_modules/.pnpm/@radix-ui_react-collection@1.1.4_@types_react-dom@19.2.1_@types_react@19.1.17__@types_r_7047fbfe61c39c77a2126486502acdb6/node_modules/@radix-ui/react-collection/dist/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/css-mediaquery@0.1.2/node_modules/css-mediaquery/index.js +1 -1
- package/dist/cjs/node_modules/.pnpm/matchmediaquery@0.4.2/node_modules/matchmediaquery/index.js +1 -1
- package/dist/cjs/node_modules/.pnpm/prop-types@15.8.1/node_modules/prop-types/index.js +1 -1
- package/dist/cjs/web-containers/tsconfig.build.tsbuildinfo +1 -0
- package/dist/esm/_virtual/index2.js +2 -2
- package/dist/esm/_virtual/index3.js +2 -2
- package/dist/esm/components/chat/chat-download-dialog.js.map +1 -1
- package/dist/esm/components/chat-input-form/composer-plus-menu.js +94 -17
- package/dist/esm/components/chat-input-form/composer-plus-menu.js.map +1 -1
- package/dist/esm/components/chat-input-form/mcp-connect-explainer-dialog.js +27 -0
- package/dist/esm/components/chat-input-form/mcp-connect-explainer-dialog.js.map +1 -0
- package/dist/esm/components/chat-input-form/mcp-servers-menu.js +197 -0
- package/dist/esm/components/chat-input-form/mcp-servers-menu.js.map +1 -0
- package/dist/esm/components/chat-input-form/use-mcp-active-count.js +54 -0
- package/dist/esm/components/chat-input-form/use-mcp-active-count.js.map +1 -0
- package/dist/esm/components/chat-input-form.js +17 -4
- package/dist/esm/components/chat-input-form.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab/create-api-modal.js +30 -14
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab/create-api-modal.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab/labels.js +8 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab/labels.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab.js +25 -15
- package/dist/esm/components/modals/edit-mentor-modal/tabs/api-tab.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-dialogs.js +755 -92
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-dialogs.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-management-content.js +361 -968
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-management-content.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/field-info.js +14 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/field-info.js.map +1 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/index.js +6 -3
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/index.js.map +1 -1
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/mcp-connector-helpers.js +431 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/mcp-connector-helpers.js.map +1 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/oauth-app-fields.js +313 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/oauth-app-fields.js.map +1 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/remove-connector-dialog.js +18 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/remove-connector-dialog.js.map +1 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/use-mcp-server-actions.js +742 -0
- package/dist/esm/components/modals/edit-mentor-modal/tabs/mcp-tab/use-mcp-server-actions.js.map +1 -0
- package/dist/esm/components/modals/user-profile-modal.js +2 -0
- package/dist/esm/components/modals/user-profile-modal.js.map +1 -1
- package/dist/esm/components/profile/integration/api-tab/create-api-modal.js +17 -10
- package/dist/esm/components/profile/integration/api-tab/create-api-modal.js.map +1 -1
- package/dist/esm/components/ui/accordion.js +16 -0
- package/dist/esm/components/ui/accordion.js.map +1 -0
- package/dist/esm/i18n/messages/en.json.js +154 -20
- package/dist/esm/i18n/messages/en.json.js.map +1 -1
- package/dist/esm/i18n/messages/es.json.js +154 -20
- package/dist/esm/i18n/messages/es.json.js.map +1 -1
- package/dist/esm/i18n/messages/fr.json.js +154 -20
- package/dist/esm/i18n/messages/fr.json.js.map +1 -1
- package/dist/esm/i18n/messages/zh.json.js +154 -20
- package/dist/esm/i18n/messages/zh.json.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-accordion@1.2.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types_re_b91476821b9fe8f172a947f727875267/node_modules/@radix-ui/react-accordion/dist/index.js +306 -0
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-accordion@1.2.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types_re_b91476821b9fe8f172a947f727875267/node_modules/@radix-ui/react-accordion/dist/index.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-collapsible@1.1.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types__d84e28844e8116e61b459b615fab358a/node_modules/@radix-ui/react-collapsible/dist/index.js +146 -0
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-collapsible@1.1.8_@types_react-dom@19.2.1_@types_react@19.1.17__@types__d84e28844e8116e61b459b615fab358a/node_modules/@radix-ui/react-collapsible/dist/index.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-collection@1.1.4_@types_react-dom@19.2.1_@types_react@19.1.17__@types_r_7047fbfe61c39c77a2126486502acdb6/node_modules/@radix-ui/react-collection/dist/index.js +71 -0
- package/dist/esm/node_modules/.pnpm/@radix-ui_react-collection@1.1.4_@types_react-dom@19.2.1_@types_react@19.1.17__@types_r_7047fbfe61c39c77a2126486502acdb6/node_modules/@radix-ui/react-collection/dist/index.js.map +1 -0
- package/dist/esm/node_modules/.pnpm/css-mediaquery@0.1.2/node_modules/css-mediaquery/index.js +1 -1
- package/dist/esm/node_modules/.pnpm/matchmediaquery@0.4.2/node_modules/matchmediaquery/index.js +1 -1
- package/dist/esm/node_modules/.pnpm/prop-types@15.8.1/node_modules/prop-types/index.js +1 -1
- package/dist/esm/web-containers/tsconfig.build.tsbuildinfo +1 -0
- package/dist/index.d.ts +31 -2
- package/dist/next/index.d.ts +6 -0
- package/dist/package.json +1 -1
- package/package.json +3 -3
- package/dist/cjs/web-containers/tsconfig.tsbuildinfo +0 -1
- package/dist/esm/web-containers/tsconfig.tsbuildinfo +0 -1
package/dist/cjs/components/modals/edit-mentor-modal/tabs/mcp-tab/connector-management-content.js
CHANGED
|
@@ -3,350 +3,68 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var dateFns = require('date-fns');
|
|
6
|
+
var sonner = require('sonner');
|
|
6
7
|
var button = require('../../../../ui/button.js');
|
|
7
|
-
var dialog = require('../../../../ui/dialog.js');
|
|
8
8
|
var input = require('../../../../ui/input.js');
|
|
9
9
|
var _switch = require('../../../../ui/switch.js');
|
|
10
|
+
var tabs = require('../../../../ui/tabs.js');
|
|
10
11
|
var popover = require('../../../../ui/popover.js');
|
|
11
12
|
var calendar$1 = require('../../../../ui/calendar.js');
|
|
12
13
|
var command = require('../../../../ui/command.js');
|
|
13
14
|
var connectorDialogs = require('./connector-dialogs.js');
|
|
14
|
-
var
|
|
15
|
+
var mcpConnectorHelpers = require('./mcp-connector-helpers.js');
|
|
16
|
+
var removeConnectorDialog = require('./remove-connector-dialog.js');
|
|
15
17
|
var dataLayer = require('@iblai/data-layer');
|
|
16
|
-
var iblaiApi = require('@iblai/iblai-api');
|
|
17
|
-
var sonner = require('sonner');
|
|
18
18
|
var index = require('../../../../spinner/index.js');
|
|
19
|
+
var tooltip = require('../../../../ui/tooltip.js');
|
|
19
20
|
var utils = require('../../../../../lib/utils.js');
|
|
20
21
|
var iblPagination = require('../../../../ibl-pagination.js');
|
|
21
22
|
var webUtils = require('@iblai/web-utils');
|
|
22
|
-
var agentSettingsContext = require('../../agent-settings-context.js');
|
|
23
23
|
var context = require('../../../../../i18n/context.js');
|
|
24
24
|
require('../../../../../packages/i18n/dist/index.esm.js');
|
|
25
|
+
var useMcpServerActions = require('./use-mcp-server-actions.js');
|
|
26
|
+
var plus = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/plus.js');
|
|
27
|
+
var plug = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/plug.js');
|
|
25
28
|
var calendar = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/calendar.js');
|
|
26
29
|
var chevronsUpDown = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/chevrons-up-down.js');
|
|
27
30
|
var check = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/check.js');
|
|
28
|
-
var
|
|
29
|
-
var
|
|
30
|
-
var
|
|
31
|
-
var
|
|
32
|
-
var squarePen = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/square-pen.js');
|
|
31
|
+
var building2 = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/building-2.js');
|
|
32
|
+
var bot = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/bot.js');
|
|
33
|
+
var userRound = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/user-round.js');
|
|
34
|
+
var settings = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/settings.js');
|
|
33
35
|
var trash2 = require('../../../../../node_modules/.pnpm/lucide-react@0.528.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/trash-2.js');
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
[iblaiApi.TransportEnum.STREAMABLE_HTTP]: 'mcpTabConnectorManagementContent.transportLabelStreamableHTTP',
|
|
47
|
-
};
|
|
48
|
-
const getTransportLabelKey = (value) => { var _a; return (_a = TRANSPORT_LABEL_KEYS[value]) !== null && _a !== void 0 ? _a : 'mcpTabConnectorManagementContent.transportLabelStreamableHTTP'; };
|
|
49
|
-
const getTransportLabel = (transport) => {
|
|
50
|
-
const normalized = transport === null || transport === void 0 ? void 0 : transport.toString().toLowerCase();
|
|
51
|
-
const option = TRANSPORT_OPTIONS.find((opt) => {
|
|
52
|
-
const optVal = opt.value ? opt.value.toString().toLowerCase() : '';
|
|
53
|
-
return optVal === '' ? !normalized : optVal === normalized;
|
|
54
|
-
});
|
|
55
|
-
return (option === null || option === void 0 ? void 0 : option.label) || (transport === null || transport === void 0 ? void 0 : transport.toString()) || 'Streamable HTTP';
|
|
56
|
-
};
|
|
57
|
-
const normalizeTransportValue = (transport) => {
|
|
58
|
-
const normalized = transport === null || transport === void 0 ? void 0 : transport.toString().toLowerCase();
|
|
59
|
-
if (normalized === iblaiApi.TransportEnum.SSE)
|
|
60
|
-
return iblaiApi.TransportEnum.SSE;
|
|
61
|
-
if (normalized === iblaiApi.TransportEnum.WEBSOCKET)
|
|
62
|
-
return iblaiApi.TransportEnum.WEBSOCKET;
|
|
63
|
-
return iblaiApi.TransportEnum.STREAMABLE_HTTP;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Finds the active MCP server connection for a given server, accounting for scope rules.
|
|
67
|
-
* - tenant scope: any connection for this server ID means connected
|
|
68
|
-
* - user scope: connection must match the current user
|
|
69
|
-
* - mentor scope: connection must match the current mentor being edited
|
|
70
|
-
*/
|
|
71
|
-
const findMCPServerConnection = (connections, serverId, currentUser, currentMentorId) => {
|
|
72
|
-
if (!(connections === null || connections === void 0 ? void 0 : connections.length))
|
|
73
|
-
return null;
|
|
74
|
-
const active = connections.filter((c) => c.server === serverId && c.is_active);
|
|
75
|
-
for (const conn of active) {
|
|
76
|
-
if (conn.scope === 'tenant')
|
|
77
|
-
return conn;
|
|
78
|
-
if (conn.scope === 'user' && conn.user === currentUser)
|
|
79
|
-
return conn;
|
|
80
|
-
if (conn.scope === 'mentor' && conn.mentor === currentMentorId)
|
|
81
|
-
return conn;
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
};
|
|
85
|
-
// Helper to create FormData for MCP server
|
|
86
|
-
const createMCPServerFormData = (data) => {
|
|
87
|
-
var _a;
|
|
88
|
-
const formData = new FormData();
|
|
89
|
-
formData.append('name', data.name);
|
|
90
|
-
formData.append('url', data.url);
|
|
91
|
-
formData.append('transport', data.transport);
|
|
92
|
-
if (data.description)
|
|
93
|
-
formData.append('description', data.description);
|
|
94
|
-
if (data.auth_type)
|
|
95
|
-
formData.append('auth_type', data.auth_type);
|
|
96
|
-
if (data.auth_scope)
|
|
97
|
-
formData.append('auth_scope', data.auth_scope);
|
|
98
|
-
if (data.credentials)
|
|
99
|
-
formData.append('credentials', data.credentials);
|
|
100
|
-
if (data.image)
|
|
101
|
-
formData.append('image', data.image);
|
|
102
|
-
if (data.mentor !== undefined)
|
|
103
|
-
formData.append('mentor', (_a = data.mentor) !== null && _a !== void 0 ? _a : '');
|
|
104
|
-
return formData;
|
|
105
|
-
};
|
|
106
|
-
// Helper to validate and create OAuth connection
|
|
107
|
-
const createOAuthConnection = async (params, onSuccess, onError) => {
|
|
108
|
-
var _a;
|
|
109
|
-
const { connectedServiceId, isCreatingConnection, createMCPServerConnection, tenantKey, username, serverId, authScope, mentorId, oauthDisplayName, refetchFeatured, refetchMy, refetchConnected, refetchMCPServerConnections, refetchMentorSettings, } = params;
|
|
110
|
-
if (isCreatingConnection || !connectedServiceId || !Number.isFinite(connectedServiceId)) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
const scope = authScope || 'user';
|
|
114
|
-
try {
|
|
115
|
-
await createMCPServerConnection({
|
|
116
|
-
org: tenantKey,
|
|
117
|
-
userId: username,
|
|
118
|
-
server: serverId,
|
|
119
|
-
scope,
|
|
120
|
-
auth_type: 'oauth2',
|
|
121
|
-
...(scope !== 'mentor' ? { user: username } : {}),
|
|
122
|
-
connected_service: connectedServiceId,
|
|
123
|
-
...(scope === 'mentor' && mentorId ? { mentor: mentorId } : {}),
|
|
124
|
-
}).unwrap();
|
|
125
|
-
await Promise.all([
|
|
126
|
-
refetchFeatured(),
|
|
127
|
-
refetchMy(),
|
|
128
|
-
refetchConnected(),
|
|
129
|
-
refetchMCPServerConnections(),
|
|
130
|
-
refetchMentorSettings(),
|
|
131
|
-
]);
|
|
132
|
-
sonner.toast.success(`${oauthDisplayName} connected successfully`);
|
|
133
|
-
onSuccess();
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
const err = error;
|
|
138
|
-
sonner.toast.error(`Failed to create connection: ${((_a = err === null || err === void 0 ? void 0 : err.data) === null || _a === void 0 ? void 0 : _a.detail) || 'Unknown error'}`);
|
|
139
|
-
onError(error);
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
// Helper to process OAuth storage events
|
|
144
|
-
const processOAuthStorageEvent = (event, expectedProvider, expectedServiceName) => {
|
|
145
|
-
if (event.key !== 'oauth_connection_complete') {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
try {
|
|
149
|
-
const data = JSON.parse(event.newValue || '{}');
|
|
150
|
-
if (data.connectedServiceId) {
|
|
151
|
-
const isMatch = data.provider === expectedProvider && data.serviceName === expectedServiceName;
|
|
152
|
-
return { connectedServiceId: data.connectedServiceId, isMatch };
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
catch (_a) {
|
|
156
|
-
// Invalid JSON, return null to trigger fallback
|
|
157
|
-
}
|
|
158
|
-
return null;
|
|
159
|
-
};
|
|
160
|
-
// Helper to process OAuth message events
|
|
161
|
-
const processOAuthMessageEvent = (event, expectedOrigin, expectedProvider, expectedServiceName) => {
|
|
162
|
-
var _a, _b;
|
|
163
|
-
if (event.origin !== expectedOrigin) {
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'GOOGLE_AUTH_SUCCESS' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.connectedServiceId)) {
|
|
167
|
-
if (event.data.provider === expectedProvider &&
|
|
168
|
-
event.data.serviceName === expectedServiceName) {
|
|
169
|
-
return event.data.connectedServiceId;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return null;
|
|
173
|
-
};
|
|
174
|
-
// Helper to check if OAuth connection is complete
|
|
175
|
-
const checkOAuthConnectionComplete = async (refetchConnected, provider, serviceName) => {
|
|
176
|
-
try {
|
|
177
|
-
const updated = await refetchConnected();
|
|
178
|
-
if (updated === null || updated === void 0 ? void 0 : updated.data) {
|
|
179
|
-
const connService = updated.data.find((cs) => cs.provider === provider && cs.service === serviceName);
|
|
180
|
-
if (connService === null || connService === void 0 ? void 0 : connService.id) {
|
|
181
|
-
return connService.id;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (_a) {
|
|
186
|
-
// Continue polling on error
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
189
|
-
};
|
|
190
|
-
// Helper to handle OAuth message event result and determine if connection should be created
|
|
191
|
-
const handleOAuthMessageResult = (event, expectedOrigin, expectedProvider, expectedServiceName) => {
|
|
192
|
-
const connectedServiceId = processOAuthMessageEvent(event, expectedOrigin, expectedProvider, expectedServiceName);
|
|
193
|
-
return {
|
|
194
|
-
shouldCreate: connectedServiceId !== null && connectedServiceId > 0,
|
|
195
|
-
connectedServiceId,
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
|
-
const validateDisconnectOAuthParams = (tenantKey, username, connectedServiceId) => {
|
|
199
|
-
if (!tenantKey || !username) {
|
|
200
|
-
return {
|
|
201
|
-
isValid: false,
|
|
202
|
-
error: 'Missing required parameters',
|
|
203
|
-
connectedServiceId: null,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
if (!connectedServiceId) {
|
|
207
|
-
return {
|
|
208
|
-
isValid: false,
|
|
209
|
-
error: 'No connected service to disconnect',
|
|
210
|
-
connectedServiceId: null,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
isValid: true,
|
|
215
|
-
error: null,
|
|
216
|
-
connectedServiceId,
|
|
217
|
-
};
|
|
218
|
-
};
|
|
219
|
-
// Determines the action to take in checkConnection based on the current state
|
|
220
|
-
const determineCheckConnectionAction = (isCreatingConnection, connectedServiceId, createConnectionSuccess, pollCount, maxPolls) => {
|
|
221
|
-
if (isCreatingConnection) {
|
|
222
|
-
return { action: 'skip', connectedServiceId: null };
|
|
223
|
-
}
|
|
224
|
-
if (pollCount >= maxPolls) {
|
|
225
|
-
return { action: 'max_polls_cleanup', connectedServiceId: null };
|
|
226
|
-
}
|
|
227
|
-
return { action: 'continue_polling', connectedServiceId };
|
|
228
|
-
};
|
|
229
|
-
// Determines the action to take after processing a message event
|
|
230
|
-
const determineMessageEventAction = (shouldCreate, connectedServiceId) => {
|
|
231
|
-
if (shouldCreate && connectedServiceId) {
|
|
232
|
-
return { action: 'create_and_cleanup', connectedServiceId };
|
|
233
|
-
}
|
|
234
|
-
return { action: 'ignore', connectedServiceId: null };
|
|
235
|
-
};
|
|
236
|
-
// Helper to check if message event should trigger cleanup and create
|
|
237
|
-
const shouldExecuteMessageAction = (actionResult) => {
|
|
238
|
-
return actionResult.action === 'create_and_cleanup' && actionResult.connectedServiceId !== null;
|
|
239
|
-
};
|
|
240
|
-
// Execute the check connection flow logic - returns what action was taken
|
|
241
|
-
const executeCheckConnectionFlowLogic = (connectedServiceId, createConnectionSuccess, pollCount, maxPolls) => {
|
|
242
|
-
// Determine if we should create and cleanup
|
|
243
|
-
if (connectedServiceId && createConnectionSuccess) {
|
|
244
|
-
return {
|
|
245
|
-
executed: true,
|
|
246
|
-
action: 'create_and_cleanup',
|
|
247
|
-
connectedServiceId,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
// Check if max polls reached
|
|
251
|
-
if (pollCount >= maxPolls) {
|
|
252
|
-
return {
|
|
253
|
-
executed: true,
|
|
254
|
-
action: 'max_polls_cleanup',
|
|
255
|
-
connectedServiceId: null,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
return {
|
|
259
|
-
executed: false,
|
|
260
|
-
action: 'continue_polling',
|
|
261
|
-
connectedServiceId: null,
|
|
262
|
-
};
|
|
263
|
-
};
|
|
264
|
-
// Execute the message event flow logic - returns what action was taken
|
|
265
|
-
const executeMessageEventFlowLogic = (event, expectedOrigin, expectedProvider, expectedServiceName) => {
|
|
266
|
-
const { shouldCreate, connectedServiceId } = handleOAuthMessageResult(event, expectedOrigin, expectedProvider, expectedServiceName);
|
|
267
|
-
const actionResult = determineMessageEventAction(shouldCreate, connectedServiceId);
|
|
268
|
-
if (shouldExecuteMessageAction(actionResult)) {
|
|
269
|
-
return {
|
|
270
|
-
executed: true,
|
|
271
|
-
action: 'create_and_cleanup',
|
|
272
|
-
connectedServiceId: actionResult.connectedServiceId,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
return {
|
|
276
|
-
executed: false,
|
|
277
|
-
action: 'ignore',
|
|
278
|
-
connectedServiceId: null,
|
|
279
|
-
};
|
|
280
|
-
};
|
|
281
|
-
const executeHandleMessageCallback = async (params) => {
|
|
282
|
-
const flowResult = executeMessageEventFlowLogic(params.event, params.expectedOrigin, params.provider, params.serviceName);
|
|
283
|
-
if (flowResult.executed && flowResult.connectedServiceId) {
|
|
284
|
-
params.cleanup();
|
|
285
|
-
await params.doCreateConnection(flowResult.connectedServiceId);
|
|
286
|
-
return {
|
|
287
|
-
executed: true,
|
|
288
|
-
connectedServiceId: flowResult.connectedServiceId,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
return { executed: false, connectedServiceId: null };
|
|
292
|
-
};
|
|
293
|
-
const executeMaxPollsCleanup = (params) => {
|
|
294
|
-
const maxPollsFlowResult = executeCheckConnectionFlowLogic(null, false, params.pollCount, params.maxPolls);
|
|
295
|
-
if (maxPollsFlowResult.executed) {
|
|
296
|
-
params.cleanup();
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
return false;
|
|
300
|
-
};
|
|
301
|
-
const executeConnectionFoundCleanup = async (params) => {
|
|
302
|
-
const success = await params.doCreateConnection(params.connectedServiceId);
|
|
303
|
-
const flowResult = executeCheckConnectionFlowLogic(params.connectedServiceId, success, params.pollCount, params.maxPolls);
|
|
304
|
-
if (flowResult.executed) {
|
|
305
|
-
params.cleanup();
|
|
306
|
-
return { cleaned: true, success };
|
|
307
|
-
}
|
|
308
|
-
return { cleaned: false, success };
|
|
309
|
-
};
|
|
310
|
-
function ConnectorManagementContent({ tenantKey, username, mentorId, rbacPermissions, onSelect, }) {
|
|
311
|
-
var _a, _b, _c;
|
|
37
|
+
// The agent settings tabs' own sub-tab look (Settings, Memory, ...).
|
|
38
|
+
const SUB_TAB_TRIGGER_CLASS = 'px-3 py-1.5 text-sm font-medium text-gray-700 data-[state=active]:bg-white data-[state=active]:text-gray-900';
|
|
39
|
+
// A connector seeded from the MCP directory: the organization cannot edit or
|
|
40
|
+
// delete it; the one thing an agent may change is how it signs in (guide §5.9).
|
|
41
|
+
const isDirectoryServer = (server) => { var _a; return ((_a = server.registry) === null || _a === void 0 ? void 0 : _a.source) === 'registry'; };
|
|
42
|
+
// Only a sign-in (OAuth) connector has a way of signing in to choose.
|
|
43
|
+
const isOAuthServer = (server) => { var _a; return ((_a = server.auth_type) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'oauth2' && !!server.oauth_service_data; };
|
|
44
|
+
// Featured and directory connectors cannot be edited by the organization:
|
|
45
|
+
// Configure opens the form with only the settings for this agent enabled.
|
|
46
|
+
const isLockedServer = (server) => !!server.is_featured || isDirectoryServer(server);
|
|
47
|
+
function ConnectorManagementContent({ tenantKey, username, mentorId, rbacPermissions, enableRbac = false, onSelect, }) {
|
|
312
48
|
const t = context.useT();
|
|
313
|
-
// Outside an agent-settings host (e.g. a standalone picker) there is no RBAC
|
|
314
|
-
// flag, so permissions are not enforced, as before.
|
|
315
|
-
const enableRBAC = (_b = (_a = agentSettingsContext.useAgentSettingsOptional()) === null || _a === void 0 ? void 0 : _a.enableRBAC) !== null && _b !== void 0 ? _b : false;
|
|
316
49
|
const itemsPerPage = 12;
|
|
317
|
-
// Filter state
|
|
318
50
|
const [searchQuery, setSearchQuery] = React.useState('');
|
|
319
51
|
const [dateRange, setDateRange] = React.useState(undefined);
|
|
320
52
|
const [selectedTransport, setSelectedTransport] = React.useState('');
|
|
321
|
-
|
|
53
|
+
const [section, setSection] = React.useState('featured');
|
|
322
54
|
const [featuredPage, setFeaturedPage] = React.useState(1);
|
|
323
55
|
const [myConnectorsPage, setMyConnectorsPage] = React.useState(1);
|
|
324
|
-
// Dialog state
|
|
325
56
|
const [showAddConnectorDialog, setShowAddConnectorDialog] = React.useState(false);
|
|
326
|
-
const [deletingServerId, setDeletingServerId] = React.useState(null);
|
|
327
57
|
const [connectorToDelete, setConnectorToDelete] = React.useState(null);
|
|
328
58
|
const [editingServer, setEditingServer] = React.useState(null);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const [
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
// Tracks in-flight OAuth cleanup callbacks so they fire on unmount, not just
|
|
335
|
-
// on successful completion / timeout / popup-closed paths inside
|
|
336
|
-
// `handleConnectOAuth`. Without this, navigating away mid-flow would leak
|
|
337
|
-
// the `storage` / `message` / `focus` window listeners until the 5-minute
|
|
338
|
-
// safety timer eventually fires.
|
|
339
|
-
const oauthCleanupsRef = React.useRef(new Set());
|
|
340
|
-
React.useEffect(() => () => {
|
|
341
|
-
oauthCleanupsRef.current.forEach((fn) => fn());
|
|
342
|
-
oauthCleanupsRef.current.clear();
|
|
343
|
-
}, []);
|
|
344
|
-
// Reset to first page when filters change
|
|
59
|
+
// A connector the organization cannot edit: the form opens with only its
|
|
60
|
+
// settings for this agent (and its sign-in app) enabled.
|
|
61
|
+
const [restricted, setRestricted] = React.useState(false);
|
|
62
|
+
const [openOnSignInApp, setOpenOnSignInApp] = React.useState(false);
|
|
63
|
+
const canSetUpOAuthApp = webUtils.checkRbacPermission(rbacPermissions !== null && rbacPermissions !== void 0 ? rbacPermissions : {}, '/mcpservers/#create', enableRbac);
|
|
345
64
|
React.useEffect(() => {
|
|
346
65
|
setFeaturedPage(1);
|
|
347
66
|
setMyConnectorsPage(1);
|
|
348
67
|
}, [searchQuery, dateRange, selectedTransport]);
|
|
349
|
-
// Build query params
|
|
350
68
|
const buildQueryParams = React.useCallback((page, isFeatured) => ({
|
|
351
69
|
org: tenantKey,
|
|
352
70
|
userId: username,
|
|
@@ -358,86 +76,235 @@ function ConnectorManagementContent({ tenantKey, username, mentorId, rbacPermiss
|
|
|
358
76
|
...(searchQuery && { search: searchQuery }),
|
|
359
77
|
...(selectedTransport && { transport: selectedTransport }),
|
|
360
78
|
}), [tenantKey, username, mentorId, searchQuery, selectedTransport]);
|
|
361
|
-
// API hooks
|
|
362
79
|
const { data: featuredServers, isLoading: isLoadingFeatured, error: featuredError, refetch: refetchFeatured, } = dataLayer.useGetMCPServersQuery(buildQueryParams(featuredPage, true), {
|
|
363
80
|
skip: !tenantKey || !username,
|
|
364
81
|
});
|
|
365
82
|
const { data: myServers, isLoading: isLoadingMy, error: myError, refetch: refetchMy, } = dataLayer.useGetMCPServersQuery(buildQueryParams(myConnectorsPage, false), {
|
|
366
83
|
skip: !tenantKey || !username,
|
|
367
84
|
});
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (!Array.isArray(maybeServers))
|
|
390
|
-
return [];
|
|
391
|
-
return maybeServers
|
|
392
|
-
.map((entry) => {
|
|
393
|
-
if (typeof entry === 'number' && Number.isFinite(entry))
|
|
394
|
-
return entry;
|
|
395
|
-
if (typeof entry === 'object' && entry !== null && 'id' in entry) {
|
|
396
|
-
const id = entry.id;
|
|
397
|
-
if (typeof id === 'number')
|
|
398
|
-
return id;
|
|
85
|
+
const refetchServers = React.useCallback(() => Promise.all([refetchFeatured(), refetchMy()]), [refetchFeatured, refetchMy]);
|
|
86
|
+
const serverDisplayName = React.useCallback((server) => {
|
|
87
|
+
var _a;
|
|
88
|
+
return server.name ||
|
|
89
|
+
((_a = server.oauth_service_data) === null || _a === void 0 ? void 0 : _a.display_name) ||
|
|
90
|
+
t('mcpTabConnectorManagementContent.unknownConnector');
|
|
91
|
+
}, [t]);
|
|
92
|
+
const { activeMcpServerIds, fieldPermissions, attachmentsKnown, isOAuthServerConnected, hasConnectionForScope, refetchMCPServerConnections, getConnectedServiceId, getSignedInServiceId, ownsConnectedService, getConnectionId, handleToggleConnector, saveConnector, deleteServer, deletingServerId, handleConnectOAuth, handleDisconnectOAuth, refetchAfterOAuth: handleOAuthComplete, togglingServerIds, connectingServiceIds, disconnectingServiceIds, } = useMcpServerActions.useMcpServerActions({
|
|
93
|
+
tenantKey,
|
|
94
|
+
username,
|
|
95
|
+
mentorId,
|
|
96
|
+
refetchServers,
|
|
97
|
+
softUserScopeConnectFailure: true,
|
|
98
|
+
// No sign-in app for this organization yet: open the setup dialog for
|
|
99
|
+
// whoever may add connectors, instead of the error.
|
|
100
|
+
onConnectNotConfigured: (server) => {
|
|
101
|
+
var _a, _b, _c;
|
|
102
|
+
// Said the same way as in the chat panel, for whoever cannot set it up.
|
|
103
|
+
if (!canSetUpOAuthApp) {
|
|
104
|
+
sonner.toast.info(t('mcpServersMenu.notSetUp', { name: serverDisplayName(server) }));
|
|
105
|
+
return true;
|
|
399
106
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
107
|
+
const canEdit = (_c = (_b = (_a = server.permissions) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.write) !== null && _c !== void 0 ? _c : !enableRbac;
|
|
108
|
+
setRestricted(isLockedServer(server) || !canEdit);
|
|
109
|
+
setOpenOnSignInApp(true);
|
|
110
|
+
// Connect passes the server already carrying the choice in force for this
|
|
111
|
+
// agent, so the form opens on it.
|
|
112
|
+
setEditingServer(server);
|
|
113
|
+
setShowAddConnectorDialog(true);
|
|
114
|
+
return true;
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
const canManage = mcpConnectorHelpers.canManageMcpServers({ attachmentsKnown, fieldPermissions, enableRbac });
|
|
118
|
+
// A sign-in choice made in the form is saved at once for a connector the agent
|
|
119
|
+
// uses; otherwise it is kept and stored when the connector is turned on. The
|
|
120
|
+
// choice shown stays the chosen one until the list reflects it.
|
|
121
|
+
const chosenScopes = React.useRef(new Map());
|
|
122
|
+
const pendingScopes = React.useRef(new Map());
|
|
123
|
+
const [setMentorAuthScope] = dataLayer.useSetMCPServerMentorAuthScopeMutation();
|
|
124
|
+
const [patchServer] = dataLayer.usePartialUpdateMCPServerMutation();
|
|
125
|
+
// Only for a server as the list has it: on a copy that already carries the
|
|
126
|
+
// choice it would drop a kept choice the list never got.
|
|
127
|
+
const shownScope = React.useCallback((server) => {
|
|
128
|
+
const listed = mcpConnectorHelpers.currentSignInScope(server);
|
|
129
|
+
const chosen = chosenScopes.current.get(server.id);
|
|
130
|
+
if (chosen === undefined)
|
|
131
|
+
return listed;
|
|
132
|
+
// The list now reflects the choice: from here on the list is the source.
|
|
133
|
+
if (chosen === listed)
|
|
134
|
+
chosenScopes.current.delete(server.id);
|
|
135
|
+
return chosen;
|
|
136
|
+
}, []);
|
|
137
|
+
// Unlike shownScope, never settles a kept choice against `server`, so it is
|
|
138
|
+
// safe on a copy that already carries the choice.
|
|
139
|
+
const scopeInForce = React.useCallback((server) => { var _a; return (_a = chosenScopes.current.get(server.id)) !== null && _a !== void 0 ? _a : mcpConnectorHelpers.currentSignInScope(server); }, []);
|
|
140
|
+
const storeScope = React.useCallback(async (server, scope) => {
|
|
141
|
+
await setMentorAuthScope({
|
|
142
|
+
org: tenantKey,
|
|
143
|
+
userId: username,
|
|
144
|
+
id: server.id,
|
|
145
|
+
mentor: mentorId,
|
|
146
|
+
// The connector's own scope is stored as "no override".
|
|
147
|
+
authScope: scope === (server.auth_scope || 'user') ? null : scope,
|
|
148
|
+
}).unwrap();
|
|
149
|
+
pendingScopes.current.delete(server.id);
|
|
150
|
+
}, [setMentorAuthScope, tenantKey, username, mentorId]);
|
|
151
|
+
// The form and a sign-in use the choice in force for this agent, kept ones included.
|
|
152
|
+
const withShownScope = React.useCallback((server) => isOAuthServer(server) ? { ...server, effective_auth_scope: shownScope(server) } : server, [shownScope]);
|
|
153
|
+
const openEdit = React.useCallback((server, restrictedEdit) => {
|
|
154
|
+
setRestricted(restrictedEdit);
|
|
155
|
+
setEditingServer(withShownScope(server));
|
|
156
|
+
setShowAddConnectorDialog(true);
|
|
157
|
+
}, [withShownScope]);
|
|
158
|
+
// The organization edited the connector's own scope, so the agent's override
|
|
159
|
+
// no longer applies; best-effort, like the connection patch.
|
|
160
|
+
const clearAgentScopeOverride = React.useCallback(async (server) => {
|
|
161
|
+
try {
|
|
162
|
+
await setMentorAuthScope({
|
|
163
|
+
org: tenantKey,
|
|
164
|
+
userId: username,
|
|
165
|
+
id: server.id,
|
|
166
|
+
mentor: mentorId,
|
|
167
|
+
authScope: null,
|
|
168
|
+
}).unwrap();
|
|
169
|
+
}
|
|
170
|
+
catch (_a) {
|
|
171
|
+
// The connector's own scope was saved; the override clears on the next edit.
|
|
172
|
+
}
|
|
173
|
+
chosenScopes.current.delete(server.id);
|
|
174
|
+
pendingScopes.current.delete(server.id);
|
|
175
|
+
}, [setMentorAuthScope, tenantKey, username, mentorId]);
|
|
176
|
+
// A connector that signs in once for everyone (agent or organization) and has
|
|
177
|
+
// no such sign-in yet: turning it on also opens that sign-in.
|
|
178
|
+
const needsSharedSignIn = React.useCallback((server) => {
|
|
179
|
+
const scope = shownScope(server);
|
|
180
|
+
return isOAuthServer(server) && scope !== 'user' && !hasConnectionForScope(server.id, scope);
|
|
181
|
+
}, [shownScope, hasConnectionForScope]);
|
|
182
|
+
// Turning on also stores a sign-in choice made while the connector was off.
|
|
183
|
+
const turnOn = React.useCallback(async (server) => {
|
|
184
|
+
const name = serverDisplayName(server);
|
|
185
|
+
const attached = await handleToggleConnector(server.id, name, true);
|
|
186
|
+
if (!attached)
|
|
187
|
+
return;
|
|
188
|
+
const pending = pendingScopes.current.get(server.id);
|
|
189
|
+
if (pending === undefined)
|
|
190
|
+
return;
|
|
191
|
+
try {
|
|
192
|
+
await storeScope(server, pending);
|
|
193
|
+
}
|
|
194
|
+
catch (_a) {
|
|
195
|
+
sonner.toast.error(t('mcpTabConnectorManagementContent.saveFailed', { name }));
|
|
196
|
+
}
|
|
197
|
+
}, [serverDisplayName, handleToggleConnector, storeScope, t]);
|
|
198
|
+
// The sign-in starts in the same click, so its tab opens at once.
|
|
199
|
+
const turnOnAndSignIn = React.useCallback((server) => {
|
|
200
|
+
if (needsSharedSignIn(server))
|
|
201
|
+
void handleConnectOAuth(withShownScope(server));
|
|
202
|
+
return turnOn(server);
|
|
203
|
+
}, [needsSharedSignIn, handleConnectOAuth, withShownScope, turnOn]);
|
|
204
|
+
const requestToggle = React.useCallback((server, checked) => {
|
|
205
|
+
if (checked)
|
|
206
|
+
void turnOnAndSignIn(server);
|
|
207
|
+
else
|
|
208
|
+
void handleToggleConnector(server.id, serverDisplayName(server), false);
|
|
209
|
+
}, [turnOnAndSignIn, handleToggleConnector, serverDisplayName]);
|
|
210
|
+
// Picking closes the workflow editor's connector panel, and with it a sign-in
|
|
211
|
+
// still open in its tab, so a connector waiting for one is picked once it lands.
|
|
212
|
+
const pendingSelectRef = React.useRef(null);
|
|
213
|
+
const selectConnector = React.useCallback(async (server) => {
|
|
214
|
+
if (activeMcpServerIds.includes(server.id)) {
|
|
215
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(server);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const waitsForSignIn = needsSharedSignIn(server);
|
|
219
|
+
if (waitsForSignIn)
|
|
220
|
+
pendingSelectRef.current = { server, scope: shownScope(server) };
|
|
221
|
+
await turnOnAndSignIn(server);
|
|
222
|
+
if (!waitsForSignIn)
|
|
223
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(server);
|
|
224
|
+
}, [activeMcpServerIds, needsSharedSignIn, shownScope, turnOnAndSignIn, onSelect]);
|
|
225
|
+
React.useEffect(() => {
|
|
226
|
+
const pending = pendingSelectRef.current;
|
|
227
|
+
if (!pending)
|
|
228
|
+
return;
|
|
229
|
+
if (hasConnectionForScope(pending.server.id, pending.scope)) {
|
|
230
|
+
pendingSelectRef.current = null;
|
|
231
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(pending.server);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// The sign-in ended without a connection (tab closed, refused): nothing to pick.
|
|
235
|
+
if (!connectingServiceIds.has(`server-${pending.server.id}`))
|
|
236
|
+
pendingSelectRef.current = null;
|
|
237
|
+
}, [connectingServiceIds, hasConnectionForScope, onSelect]);
|
|
238
|
+
// A connector edited to sign in for everyone, while on for this agent with no
|
|
239
|
+
// such sign-in yet, goes off by itself until it is turned on again.
|
|
240
|
+
const handleAuthScopeChanged = React.useCallback(async (server, authScope) => {
|
|
241
|
+
if (authScope === 'user' || !activeMcpServerIds.includes(server.id))
|
|
242
|
+
return;
|
|
243
|
+
const { data } = await refetchMCPServerConnections();
|
|
244
|
+
if (mcpConnectorHelpers.connectionForScopeExists(data === null || data === void 0 ? void 0 : data.results, server.id, authScope, username, mentorId))
|
|
245
|
+
return;
|
|
246
|
+
const name = serverDisplayName(server);
|
|
247
|
+
await handleToggleConnector(server.id, name, false, { quiet: true });
|
|
248
|
+
sonner.toast.info(t('mcpTabConnectorManagementContent.turnedOffUntilConnected', { name }));
|
|
249
|
+
}, [
|
|
250
|
+
activeMcpServerIds,
|
|
251
|
+
refetchMCPServerConnections,
|
|
252
|
+
username,
|
|
253
|
+
mentorId,
|
|
254
|
+
serverDisplayName,
|
|
255
|
+
handleToggleConnector,
|
|
256
|
+
t,
|
|
257
|
+
]);
|
|
258
|
+
// The settings for this agent of a connector the organization cannot edit,
|
|
259
|
+
// saved from the form's restricted mode. The failure is said here and
|
|
260
|
+
// rethrown, so the form stays open.
|
|
261
|
+
const handleRestrictedSave = React.useCallback(async (server, { scope, userCanDisable }) => {
|
|
262
|
+
const name = serverDisplayName(server);
|
|
263
|
+
const attached = activeMcpServerIds.includes(server.id);
|
|
264
|
+
const scopeChanged = isOAuthServer(server) && scope !== scopeInForce(server);
|
|
265
|
+
const disableChanged = userCanDisable !== (server.user_can_disable !== false);
|
|
266
|
+
try {
|
|
267
|
+
// First, since the organization may be refused it for a featured or
|
|
268
|
+
// directory connector: nothing else is stored when it is.
|
|
269
|
+
if (disableChanged) {
|
|
270
|
+
await patchServer({
|
|
271
|
+
id: server.id,
|
|
272
|
+
org: tenantKey,
|
|
273
|
+
userId: username,
|
|
274
|
+
body: { user_can_disable: userCanDisable },
|
|
275
|
+
}).unwrap();
|
|
418
276
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}, [
|
|
440
|
-
|
|
277
|
+
if (scopeChanged) {
|
|
278
|
+
// The override can only be stored for a connector the agent uses.
|
|
279
|
+
if (attached)
|
|
280
|
+
await storeScope(server, scope);
|
|
281
|
+
else
|
|
282
|
+
pendingScopes.current.set(server.id, scope);
|
|
283
|
+
chosenScopes.current.set(server.id, scope);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch (failure) {
|
|
287
|
+
// The API's prose stays out of the toast: a refused change has one sentence.
|
|
288
|
+
const status = failure === null || failure === void 0 ? void 0 : failure.status;
|
|
289
|
+
sonner.toast.error(status === 403 || status === 404
|
|
290
|
+
? t('mcpTabConnectorManagementContent.cannotChangeSetting', { name })
|
|
291
|
+
: t('mcpTabConnectorManagementContent.saveFailed', { name }));
|
|
292
|
+
throw failure;
|
|
293
|
+
}
|
|
294
|
+
sonner.toast.success(t('mcpTabConnectorDialogs.connectorUpdatedSuccess'));
|
|
295
|
+
if (scopeChanged)
|
|
296
|
+
await handleAuthScopeChanged(server, scope);
|
|
297
|
+
}, [
|
|
298
|
+
serverDisplayName,
|
|
299
|
+
activeMcpServerIds,
|
|
300
|
+
scopeInForce,
|
|
301
|
+
patchServer,
|
|
302
|
+
tenantKey,
|
|
303
|
+
username,
|
|
304
|
+
storeScope,
|
|
305
|
+
t,
|
|
306
|
+
handleAuthScopeChanged,
|
|
307
|
+
]);
|
|
441
308
|
const filterByDate = React.useCallback((servers) => {
|
|
442
309
|
if (!(dateRange === null || dateRange === void 0 ? void 0 : dateRange.from) || !(dateRange === null || dateRange === void 0 ? void 0 : dateRange.to))
|
|
443
310
|
return servers;
|
|
@@ -447,7 +314,6 @@ function ConnectorManagementContent({ tenantKey, username, mentorId, rbacPermiss
|
|
|
447
314
|
return created >= dateRange.from && created <= dateRange.to;
|
|
448
315
|
});
|
|
449
316
|
}, [dateRange]);
|
|
450
|
-
// Filtered servers
|
|
451
317
|
const filteredFeaturedServers = React.useMemo(() => filterByDate((featuredServers === null || featuredServers === void 0 ? void 0 : featuredServers.results) || []), [featuredServers, filterByDate]);
|
|
452
318
|
const featuredOAuthServers = React.useMemo(() => filteredFeaturedServers.filter((s) => {
|
|
453
319
|
var _a;
|
|
@@ -471,621 +337,157 @@ function ConnectorManagementContent({ tenantKey, username, mentorId, rbacPermiss
|
|
|
471
337
|
}, [myServers, filterByDate]);
|
|
472
338
|
const featuredTotalPages = featuredServers ? Math.ceil(featuredServers.count / itemsPerPage) : 0;
|
|
473
339
|
const myConnectorsTotalPages = myServers ? Math.ceil(myServers.count / itemsPerPage) : 0;
|
|
474
|
-
// Update MCP servers in mentor settings with optional tool_slugs and can_use_tools
|
|
475
|
-
const updateMCPServers = React.useCallback(async (serverIds, options) => {
|
|
476
|
-
if (!mentorId)
|
|
477
|
-
throw new Error('Invalid mentor ID');
|
|
478
|
-
const uniqueIds = [...new Set(serverIds.filter((id) => Number.isFinite(id) && id > 0))];
|
|
479
|
-
const requestBody = { mcp_servers: uniqueIds };
|
|
480
|
-
// Include tool_slugs if provided
|
|
481
|
-
if ((options === null || options === void 0 ? void 0 : options.toolSlugs) !== undefined) {
|
|
482
|
-
requestBody.tool_slugs = options.toolSlugs;
|
|
483
|
-
}
|
|
484
|
-
// Always set can_use_tools to true when enabling MCP connectors
|
|
485
|
-
if ((options === null || options === void 0 ? void 0 : options.canUseTools) !== undefined) {
|
|
486
|
-
requestBody.can_use_tools = options.canUseTools;
|
|
487
|
-
}
|
|
488
|
-
await editMentorJson({
|
|
489
|
-
mentorId,
|
|
490
|
-
org: tenantKey,
|
|
491
|
-
requestBody,
|
|
492
|
-
userId: username,
|
|
493
|
-
}).unwrap();
|
|
494
|
-
}, [mentorId, tenantKey, username, editMentorJson]);
|
|
495
|
-
// Handle toggle for activating/deactivating connectors
|
|
496
|
-
const handleToggleConnector = React.useCallback(async (serverId, serverName, isActive) => {
|
|
497
|
-
var _a, _b;
|
|
498
|
-
if (!Number.isFinite(serverId) || serverId <= 0) {
|
|
499
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.invalidServerId'));
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
setTogglingServerIds((prev) => new Set(prev).add(serverId));
|
|
503
|
-
try {
|
|
504
|
-
const currentIds = Array.isArray(activeMcpServerIds) ? activeMcpServerIds : [];
|
|
505
|
-
const updatedIds = isActive
|
|
506
|
-
? currentIds.includes(serverId)
|
|
507
|
-
? currentIds
|
|
508
|
-
: [...currentIds, serverId]
|
|
509
|
-
: currentIds.filter((id) => id !== serverId);
|
|
510
|
-
/* istanbul ignore next -- @preserve optimization path, tested via toggle tests */
|
|
511
|
-
if (updatedIds.length === currentIds.length && isActive && currentIds.includes(serverId)) {
|
|
512
|
-
return; // Already in desired state
|
|
513
|
-
}
|
|
514
|
-
// Prepare options for tool_slugs and can_use_tools updates
|
|
515
|
-
const hasMcpInToolSlugs = currentToolSlugs.includes('mcp');
|
|
516
|
-
if (isActive) {
|
|
517
|
-
// When enabling a connector:
|
|
518
|
-
// - If tool_slugs doesn't have 'mcp', add it
|
|
519
|
-
// - Always set can_use_tools to true
|
|
520
|
-
if (!hasMcpInToolSlugs) {
|
|
521
|
-
const updatedToolSlugs = [...currentToolSlugs, 'mcp'];
|
|
522
|
-
await updateMCPServers(updatedIds, {
|
|
523
|
-
toolSlugs: updatedToolSlugs,
|
|
524
|
-
canUseTools: true,
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
// mcp already in tool_slugs, just update mcp_servers and can_use_tools
|
|
529
|
-
await updateMCPServers(updatedIds, {
|
|
530
|
-
canUseTools: true,
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
// When disabling a connector:
|
|
536
|
-
// - If this is the last connector being disabled, remove 'mcp' from tool_slugs
|
|
537
|
-
const isLastConnector = updatedIds.length === 0;
|
|
538
|
-
if (isLastConnector && hasMcpInToolSlugs) {
|
|
539
|
-
const updatedToolSlugs = currentToolSlugs.filter((slug) => slug !== 'mcp');
|
|
540
|
-
await updateMCPServers(updatedIds, {
|
|
541
|
-
toolSlugs: updatedToolSlugs,
|
|
542
|
-
// Set can_use_tools based on whether there are other tools
|
|
543
|
-
canUseTools: updatedToolSlugs.length > 0,
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
// Not the last connector, just update mcp_servers
|
|
548
|
-
await updateMCPServers(updatedIds);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
await refetchMentorSettings();
|
|
552
|
-
sonner.toast.success(isActive
|
|
553
|
-
? t('mcpTabConnectorManagementContent.serverActivated', { serverName })
|
|
554
|
-
: t('mcpTabConnectorManagementContent.serverDeactivated', { serverName }));
|
|
555
|
-
}
|
|
556
|
-
catch (error) {
|
|
557
|
-
const err = error;
|
|
558
|
-
const msg = ((_a = err === null || err === void 0 ? void 0 : err.data) === null || _a === void 0 ? void 0 : _a.detail) || ((_b = err === null || err === void 0 ? void 0 : err.data) === null || _b === void 0 ? void 0 : _b.error) || (err === null || err === void 0 ? void 0 : err.message) || '';
|
|
559
|
-
if (msg.includes('does not exist') || msg.includes('not accessible')) {
|
|
560
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.serverNotAccessible', { serverName }));
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
sonner.toast.error(isActive
|
|
564
|
-
? t('mcpTabConnectorManagementContent.failedToActivate', { serverName, msg })
|
|
565
|
-
: t('mcpTabConnectorManagementContent.failedToDeactivate', { serverName, msg }));
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
finally {
|
|
569
|
-
setTogglingServerIds((prev) => {
|
|
570
|
-
const next = new Set(prev);
|
|
571
|
-
next.delete(serverId);
|
|
572
|
-
return next;
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
}, [activeMcpServerIds, currentToolSlugs, updateMCPServers, refetchMentorSettings]);
|
|
576
|
-
// Handle add/edit connector
|
|
577
340
|
const handleAddConnectorClick = React.useCallback(async (connector) => {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
const authType = (_b = connector.authType) !== null && _b !== void 0 ? _b : (trimmedCredentials ? 'token' : 'none');
|
|
587
|
-
const resolvedTransport = normalizeTransportValue(connector.transport);
|
|
588
|
-
const basePayload = {
|
|
589
|
-
name: connector.name,
|
|
590
|
-
url: connector.url || `https://api.${connector.name.toLowerCase()}.com/mcp`,
|
|
591
|
-
transport: resolvedTransport,
|
|
592
|
-
auth_type: authType,
|
|
593
|
-
description: connector.description || '',
|
|
594
|
-
// Only include credentials if provided (for edits, undefined means keep existing)
|
|
595
|
-
...(trimmedCredentials !== undefined && {
|
|
596
|
-
credentials: trimmedCredentials,
|
|
597
|
-
}),
|
|
598
|
-
...(connector.authScope && { auth_scope: connector.authScope }),
|
|
599
|
-
...(connector.mentor !== undefined && { mentor: connector.mentor }),
|
|
600
|
-
};
|
|
601
|
-
/* istanbul ignore next -- @preserve update path tested via ConnectorDialogs integration */
|
|
602
|
-
if (editingServer) {
|
|
603
|
-
// Update existing server
|
|
604
|
-
const args = {
|
|
605
|
-
id: editingServer.id,
|
|
606
|
-
org: tenantKey,
|
|
607
|
-
userId: username,
|
|
608
|
-
...(hasFileImage
|
|
609
|
-
? {
|
|
610
|
-
formData: createMCPServerFormData({
|
|
611
|
-
...basePayload,
|
|
612
|
-
image: connector.image,
|
|
613
|
-
}),
|
|
614
|
-
}
|
|
615
|
-
: { body: basePayload }),
|
|
616
|
-
};
|
|
617
|
-
await updateMCPServer(args).unwrap();
|
|
618
|
-
sonner.toast.success(t('mcpTabConnectorManagementContent.connectorUpdated', { name: connector.name }));
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
// Create new server
|
|
622
|
-
const args = {
|
|
623
|
-
org: tenantKey,
|
|
624
|
-
userId: username,
|
|
625
|
-
...(hasFileImage
|
|
626
|
-
? {
|
|
627
|
-
formData: createMCPServerFormData({
|
|
628
|
-
...basePayload,
|
|
629
|
-
image: connector.image,
|
|
630
|
-
}),
|
|
631
|
-
}
|
|
632
|
-
: { body: basePayload }),
|
|
633
|
-
};
|
|
634
|
-
const newServer = await createMCPServer(args).unwrap();
|
|
635
|
-
sonner.toast.success(t('mcpTabConnectorManagementContent.connectorAdded', { name: connector.name }));
|
|
636
|
-
// Auto-activate new connector
|
|
637
|
-
try {
|
|
638
|
-
const newId = Number(newServer.id);
|
|
639
|
-
if (Number.isFinite(newId)) {
|
|
640
|
-
const updatedIds = [...activeMcpServerIds, newId];
|
|
641
|
-
const hasMcpInToolSlugs = currentToolSlugs.includes('mcp');
|
|
642
|
-
// When auto-activating, also add 'mcp' to tool_slugs if not present
|
|
643
|
-
if (!hasMcpInToolSlugs) {
|
|
644
|
-
const updatedToolSlugs = [...currentToolSlugs, 'mcp'];
|
|
645
|
-
await updateMCPServers(updatedIds, {
|
|
646
|
-
toolSlugs: updatedToolSlugs,
|
|
647
|
-
canUseTools: true,
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
else {
|
|
651
|
-
await updateMCPServers(updatedIds, {
|
|
652
|
-
canUseTools: true,
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
await refetchMentorSettings();
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
catch (_c) {
|
|
659
|
-
sonner.toast.warning(t('mcpTabConnectorManagementContent.connectorNotActivated', { name: connector.name }));
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
setShowAddConnectorDialog(false);
|
|
663
|
-
setEditingServer(null);
|
|
664
|
-
await Promise.all([refetchFeatured(), refetchMy()]);
|
|
665
|
-
}
|
|
666
|
-
catch (_d) {
|
|
667
|
-
sonner.toast.error(editingServer
|
|
668
|
-
? t('mcpTabConnectorManagementContent.failedToUpdateConnector', {
|
|
669
|
-
name: connector.name,
|
|
670
|
-
})
|
|
671
|
-
: t('mcpTabConnectorManagementContent.failedToAddConnector', { name: connector.name }));
|
|
672
|
-
}
|
|
673
|
-
}, [
|
|
674
|
-
tenantKey,
|
|
675
|
-
username,
|
|
676
|
-
editingServer,
|
|
677
|
-
activeMcpServerIds,
|
|
678
|
-
currentToolSlugs,
|
|
679
|
-
createMCPServer,
|
|
680
|
-
updateMCPServer,
|
|
681
|
-
updateMCPServers,
|
|
682
|
-
refetchFeatured,
|
|
683
|
-
refetchMy,
|
|
684
|
-
refetchMentorSettings,
|
|
685
|
-
]);
|
|
686
|
-
// Handle delete connector
|
|
341
|
+
await saveConnector(connector, {
|
|
342
|
+
editingServer,
|
|
343
|
+
onSaved: () => {
|
|
344
|
+
setShowAddConnectorDialog(false);
|
|
345
|
+
setEditingServer(null);
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}, [saveConnector, editingServer]);
|
|
687
349
|
const handleDeleteConnector = React.useCallback(async (serverId, serverName) => {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const updatedIds = activeMcpServerIds.filter((id) => id !== serverId);
|
|
703
|
-
await updateMCPServers(updatedIds);
|
|
704
|
-
await refetchMentorSettings();
|
|
705
|
-
}
|
|
706
|
-
catch (_a) {
|
|
707
|
-
sonner.toast.warning(t('mcpTabConnectorManagementContent.connectorDeletedStillActive', { serverName }));
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
catch (_b) {
|
|
711
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.failedToRemoveConnector', { serverName }));
|
|
712
|
-
}
|
|
713
|
-
finally {
|
|
714
|
-
setDeletingServerId(null);
|
|
715
|
-
setConnectorToDelete(null);
|
|
716
|
-
}
|
|
717
|
-
}, [
|
|
718
|
-
tenantKey,
|
|
719
|
-
username,
|
|
720
|
-
activeMcpServerIds,
|
|
721
|
-
deleteMCPServer,
|
|
722
|
-
updateMCPServers,
|
|
723
|
-
refetchFeatured,
|
|
724
|
-
refetchMy,
|
|
725
|
-
refetchMentorSettings,
|
|
726
|
-
]);
|
|
727
|
-
// Handle OAuth connect
|
|
728
|
-
const handleConnectOAuth = React.useCallback(async (server) => {
|
|
729
|
-
if (!tenantKey || !username || !server.oauth_service_data) {
|
|
730
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.missingOAuthParams'));
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
const oauthData = server.oauth_service_data;
|
|
734
|
-
const { oauth_provider: provider, name } = oauthData;
|
|
735
|
-
const serverId = server.id;
|
|
736
|
-
const serviceKey = `server-${serverId}`;
|
|
737
|
-
const oauthDisplayName = oauthData.display_name || name;
|
|
738
|
-
setPendingOAuthServer({
|
|
739
|
-
serverId,
|
|
740
|
-
provider,
|
|
741
|
-
service: name,
|
|
742
|
-
timestamp: Date.now(),
|
|
350
|
+
await deleteServer(serverId, serverName);
|
|
351
|
+
setConnectorToDelete(null);
|
|
352
|
+
}, [deleteServer]);
|
|
353
|
+
// Read as is: `editingServer` already carries the scope in force (openEdit),
|
|
354
|
+
// and shownScope on such a copy would settle a kept choice against itself.
|
|
355
|
+
const describeConnection = (server) => {
|
|
356
|
+
const { isConnected, showConnect, showDisconnect, disconnectOptions } = mcpConnectorHelpers.getMcpConnectionState(server, {
|
|
357
|
+
canManage,
|
|
358
|
+
attachmentsKnown,
|
|
359
|
+
activeMcpServerIds,
|
|
360
|
+
isOAuthServerConnected,
|
|
361
|
+
getConnectedServiceId,
|
|
362
|
+
getSignedInServiceId,
|
|
363
|
+
ownsConnectedService,
|
|
743
364
|
});
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
let isCreatingConnection = false;
|
|
753
|
-
// Listener handlers — reassigned with real implementations once the
|
|
754
|
-
// OAuth URL resolves. Default noops let cleanup safely call
|
|
755
|
-
// removeEventListener even if we never reached addEventListener (e.g.
|
|
756
|
-
// unmount before startOAuthFlow resolves).
|
|
757
|
-
let handleFocus = () => { };
|
|
758
|
-
let handleStorageChange = () => { };
|
|
759
|
-
let handleMessage = () => { };
|
|
760
|
-
// Cleanup function to remove listeners and reset state. Idempotent —
|
|
761
|
-
// tracked in `oauthCleanupsRef` so component unmount can also drive it.
|
|
762
|
-
let cleanedUp = false;
|
|
763
|
-
const cleanup = () => {
|
|
764
|
-
if (cleanedUp)
|
|
765
|
-
return;
|
|
766
|
-
cleanedUp = true;
|
|
767
|
-
oauthCleanupsRef.current.delete(cleanup);
|
|
768
|
-
if (pollInterval)
|
|
769
|
-
clearInterval(pollInterval);
|
|
770
|
-
if (popupCheckInterval)
|
|
771
|
-
clearInterval(popupCheckInterval);
|
|
772
|
-
window.removeEventListener('focus', handleFocus);
|
|
773
|
-
window.removeEventListener('storage', handleStorageChange);
|
|
774
|
-
window.removeEventListener('message', handleMessage);
|
|
775
|
-
setConnectingServiceIds((prev) => {
|
|
776
|
-
const next = new Set(prev);
|
|
777
|
-
next.delete(serviceKey);
|
|
778
|
-
return next;
|
|
779
|
-
});
|
|
780
|
-
removePendingOAuthServer();
|
|
781
|
-
isCreatingConnection = false;
|
|
365
|
+
return {
|
|
366
|
+
connected: isConnected,
|
|
367
|
+
canConnect: showConnect,
|
|
368
|
+
canDisconnect: showDisconnect,
|
|
369
|
+
connecting: connectingServiceIds.has(`server-${server.id}`),
|
|
370
|
+
disconnecting: disconnectingServiceIds.has(server.id),
|
|
371
|
+
onConnect: () => void handleConnectOAuth(server),
|
|
372
|
+
onDisconnect: () => void handleDisconnectOAuth(server, disconnectOptions),
|
|
782
373
|
};
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
const result = await createOAuthConnection({
|
|
804
|
-
connectedServiceId,
|
|
805
|
-
isCreatingConnection,
|
|
806
|
-
createMCPServerConnection,
|
|
807
|
-
tenantKey,
|
|
808
|
-
username,
|
|
809
|
-
serverId,
|
|
810
|
-
authScope: server.auth_scope,
|
|
811
|
-
mentorId,
|
|
812
|
-
oauthDisplayName,
|
|
813
|
-
refetchFeatured,
|
|
814
|
-
refetchMy,
|
|
815
|
-
refetchConnected,
|
|
816
|
-
refetchMCPServerConnections,
|
|
817
|
-
refetchMentorSettings,
|
|
818
|
-
},
|
|
819
|
-
/* istanbul ignore next -- @preserve success callback, tested via createOAuthConnection */
|
|
820
|
-
() => {
|
|
821
|
-
isCreatingConnection = false;
|
|
822
|
-
},
|
|
823
|
-
/* istanbul ignore next -- @preserve error callback, tested via createOAuthConnection */
|
|
824
|
-
() => {
|
|
825
|
-
isCreatingConnection = false;
|
|
826
|
-
});
|
|
827
|
-
if (result) {
|
|
828
|
-
isCreatingConnection = true;
|
|
829
|
-
}
|
|
830
|
-
return result;
|
|
831
|
-
};
|
|
832
|
-
// Check for OAuth connection using helper
|
|
833
|
-
const checkConnection = async () => {
|
|
834
|
-
// Early check using helper
|
|
835
|
-
const earlyCheck = determineCheckConnectionAction(isCreatingConnection, null, false, pollCount, maxPolls);
|
|
836
|
-
if (earlyCheck.action === 'skip')
|
|
837
|
-
return;
|
|
838
|
-
try {
|
|
839
|
-
const connectedServiceId = await checkOAuthConnectionComplete(refetchConnected, provider, name);
|
|
840
|
-
// If we found a connected service, try to create connection using helper
|
|
841
|
-
// Logic tested via executeConnectionFoundCleanup unit tests
|
|
842
|
-
/* istanbul ignore next -- @preserve callback wrapper, logic tested via helper */
|
|
843
|
-
if (connectedServiceId) {
|
|
844
|
-
const result = await executeConnectionFoundCleanup({
|
|
845
|
-
connectedServiceId,
|
|
846
|
-
doCreateConnection,
|
|
847
|
-
pollCount,
|
|
848
|
-
maxPolls,
|
|
849
|
-
cleanup,
|
|
850
|
-
});
|
|
851
|
-
if (result.cleaned) {
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
await Promise.all([refetchFeatured(), refetchMy()]);
|
|
856
|
-
pollCount++;
|
|
857
|
-
// Check if max polls reached using extracted helper function
|
|
858
|
-
executeMaxPollsCleanup({ pollCount, maxPolls, cleanup });
|
|
859
|
-
}
|
|
860
|
-
catch (_a) {
|
|
861
|
-
// Continue polling
|
|
862
|
-
}
|
|
863
|
-
};
|
|
864
|
-
handleFocus = () => checkConnection();
|
|
865
|
-
// Handle OAuth message events using extracted helper function
|
|
866
|
-
// Logic tested via executeHandleMessageCallback unit tests
|
|
867
|
-
/* istanbul ignore next -- @preserve callback wrapper, logic tested via helper */
|
|
868
|
-
handleMessage = async (event) => {
|
|
869
|
-
await executeHandleMessageCallback({
|
|
870
|
-
event,
|
|
871
|
-
expectedOrigin: window.location.origin,
|
|
872
|
-
provider,
|
|
873
|
-
serviceName: name,
|
|
874
|
-
cleanup,
|
|
875
|
-
doCreateConnection,
|
|
876
|
-
});
|
|
877
|
-
};
|
|
878
|
-
// Handle OAuth storage events using helper
|
|
879
|
-
handleStorageChange = async (e) => {
|
|
880
|
-
const result = processOAuthStorageEvent(e, provider, name);
|
|
881
|
-
if (result) {
|
|
882
|
-
if (result.isMatch) {
|
|
883
|
-
cleanup();
|
|
884
|
-
await doCreateConnection(result.connectedServiceId);
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
await checkConnection();
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
else if (e.key === 'oauth_connection_complete') {
|
|
891
|
-
/* istanbul ignore next */ // Fallback for parse errors or missing data
|
|
892
|
-
await checkConnection();
|
|
893
|
-
}
|
|
894
|
-
};
|
|
895
|
-
window.addEventListener('storage', handleStorageChange);
|
|
896
|
-
window.addEventListener('message', handleMessage);
|
|
897
|
-
window.addEventListener('focus', handleFocus);
|
|
898
|
-
pollInterval = setInterval(checkConnection, 5000);
|
|
899
|
-
setTimeout(cleanup, 5 * 60 * 1000);
|
|
900
|
-
// Detect if user closed the OAuth popup without completing
|
|
901
|
-
if (popup) {
|
|
902
|
-
popupCheckInterval = setInterval(() => {
|
|
903
|
-
if (popup.closed) {
|
|
904
|
-
if (popupCheckInterval)
|
|
905
|
-
clearInterval(popupCheckInterval);
|
|
906
|
-
popupCheckInterval = null;
|
|
907
|
-
// Grace period for OAuth callback/redirect to complete
|
|
908
|
-
setTimeout(() => {
|
|
909
|
-
if (!isCreatingConnection) {
|
|
910
|
-
cleanup();
|
|
911
|
-
}
|
|
912
|
-
}, 10000);
|
|
913
|
-
}
|
|
914
|
-
}, 2000);
|
|
915
|
-
}
|
|
916
|
-
} /* istanbul ignore next */
|
|
917
|
-
catch (_a) {
|
|
918
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.failedToConnect', {
|
|
919
|
-
name: oauthData.display_name || name,
|
|
920
|
-
}));
|
|
921
|
-
setConnectingServiceIds((prev) => {
|
|
922
|
-
const next = new Set(prev);
|
|
923
|
-
next.delete(serviceKey);
|
|
924
|
-
return next;
|
|
925
|
-
});
|
|
926
|
-
removePendingOAuthServer();
|
|
927
|
-
}
|
|
928
|
-
}, [
|
|
929
|
-
tenantKey,
|
|
930
|
-
username,
|
|
931
|
-
startOAuthFlow,
|
|
932
|
-
createMCPServerConnection,
|
|
933
|
-
refetchFeatured,
|
|
934
|
-
refetchMy,
|
|
935
|
-
refetchConnected,
|
|
936
|
-
refetchMCPServerConnections,
|
|
937
|
-
refetchMentorSettings,
|
|
938
|
-
mentorId,
|
|
939
|
-
setPendingOAuthServer,
|
|
940
|
-
removePendingOAuthServer,
|
|
941
|
-
]);
|
|
942
|
-
// Handle OAuth disconnect
|
|
943
|
-
const handleDisconnectOAuth = React.useCallback(async (server) => {
|
|
944
|
-
const serverConnectedServiceId = getConnectedServiceId(server);
|
|
945
|
-
const validation = validateDisconnectOAuthParams(tenantKey, username, serverConnectedServiceId);
|
|
946
|
-
/* istanbul ignore next -- @preserve validation error branch */
|
|
947
|
-
if (!validation.isValid) {
|
|
948
|
-
sonner.toast.error(validation.error || 'Validation failed');
|
|
949
|
-
return;
|
|
950
|
-
}
|
|
951
|
-
const connectedServiceId = validation.connectedServiceId;
|
|
952
|
-
setDisconnectingServiceIds((prev) => new Set(prev).add(server.id));
|
|
953
|
-
try {
|
|
954
|
-
const updatedIds = activeMcpServerIds.filter((id) => id !== server.id);
|
|
955
|
-
await updateMCPServers(updatedIds);
|
|
956
|
-
await disconnectService({
|
|
957
|
-
org: tenantKey,
|
|
958
|
-
userId: username,
|
|
959
|
-
id: connectedServiceId,
|
|
960
|
-
}).unwrap();
|
|
961
|
-
await Promise.all([
|
|
962
|
-
refetchFeatured(),
|
|
963
|
-
refetchMy(),
|
|
964
|
-
refetchConnected(),
|
|
965
|
-
refetchMCPServerConnections(),
|
|
966
|
-
refetchMentorSettings(),
|
|
967
|
-
]);
|
|
968
|
-
sonner.toast.success(t('mcpTabConnectorManagementContent.serviceDisconnected'));
|
|
969
|
-
}
|
|
970
|
-
catch (_a) {
|
|
971
|
-
sonner.toast.error(t('mcpTabConnectorManagementContent.failedToDisconnect'));
|
|
972
|
-
}
|
|
973
|
-
finally {
|
|
974
|
-
setDisconnectingServiceIds((prev) => {
|
|
975
|
-
const next = new Set(prev);
|
|
976
|
-
next.delete(server.id);
|
|
977
|
-
return next;
|
|
978
|
-
});
|
|
979
|
-
}
|
|
980
|
-
}, [
|
|
981
|
-
tenantKey,
|
|
982
|
-
username,
|
|
983
|
-
activeMcpServerIds,
|
|
984
|
-
getConnectedServiceId,
|
|
985
|
-
updateMCPServers,
|
|
986
|
-
disconnectService,
|
|
987
|
-
refetchFeatured,
|
|
988
|
-
refetchMy,
|
|
989
|
-
refetchConnected,
|
|
990
|
-
refetchMCPServerConnections,
|
|
991
|
-
refetchMentorSettings,
|
|
992
|
-
]);
|
|
993
|
-
// Handle OAuth completion from ConnectorDialogs
|
|
994
|
-
const handleOAuthComplete = React.useCallback(async () => {
|
|
995
|
-
await Promise.all([
|
|
996
|
-
refetchFeatured(),
|
|
997
|
-
refetchMy(),
|
|
998
|
-
refetchMCPServerConnections(),
|
|
999
|
-
refetchMentorSettings(),
|
|
1000
|
-
]);
|
|
1001
|
-
}, [refetchFeatured, refetchMy, refetchMCPServerConnections, refetchMentorSettings]);
|
|
1002
|
-
// Render server card
|
|
374
|
+
};
|
|
375
|
+
const editingConnection = editingServer ? describeConnection(editingServer) : null;
|
|
376
|
+
// Read-only: the Authentication Scope in force for this agent, changed in Configure.
|
|
377
|
+
const renderScopePill = (server, displayName) => {
|
|
378
|
+
const scope = shownScope(server);
|
|
379
|
+
const ScopeIcon = scope === 'platform' ? building2.default : scope === 'mentor' ? bot.default : userRound.default;
|
|
380
|
+
const scopeName = t(scope === 'platform'
|
|
381
|
+
? 'mcpTabConnectorManagementContent.scopeTenant'
|
|
382
|
+
: scope === 'mentor'
|
|
383
|
+
? 'mcpTabConnectorManagementContent.scopeAgent'
|
|
384
|
+
: 'mcpTabConnectorManagementContent.scopeUser');
|
|
385
|
+
const scopeHint = t(scope === 'platform'
|
|
386
|
+
? 'mcpTabConnectorManagementContent.scopeHintOrganization'
|
|
387
|
+
: scope === 'mentor'
|
|
388
|
+
? 'mcpTabConnectorManagementContent.scopeHintAgent'
|
|
389
|
+
: 'mcpTabConnectorManagementContent.scopeHintUser', { name: displayName });
|
|
390
|
+
const scopeLabel = t('mcpTabConnectorDialogs.authScopeLabel');
|
|
391
|
+
return (jsxRuntime.jsx(tooltip.TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(tooltip.Tooltip, { children: [jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: jsxRuntime.jsxs("span", { tabIndex: 0, "data-testid": `mcp-connector-scope-${server.id}`, className: "inline-flex cursor-default items-center gap-1 rounded bg-gray-100 px-2 py-0.5 text-xs text-gray-600", children: [jsxRuntime.jsxs("span", { className: "sr-only", children: [scopeLabel, ": "] }), jsxRuntime.jsx(ScopeIcon, { className: "h-3 w-3", "aria-hidden": "true" }), scopeName] }) }), jsxRuntime.jsxs(tooltip.TooltipContent, { className: "ibl-tooltip-content z-50 max-w-[300px]", children: [jsxRuntime.jsx("p", { className: "font-medium", children: scopeLabel }), jsxRuntime.jsx("p", { children: scopeHint })] })] }) }));
|
|
392
|
+
};
|
|
393
|
+
const renderIconAction = ({ label, icon: Icon, testId, onClick, disabled, className, }) => (jsxRuntime.jsx(tooltip.TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(tooltip.Tooltip, { children: [jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: jsxRuntime.jsx(button.Button, { type: "button", variant: "ghost", size: "icon", "aria-label": label, "data-testid": testId, className: utils.cn('h-8 w-8 text-gray-500', className), onClick: onClick, disabled: disabled, children: jsxRuntime.jsx(Icon, { className: "h-4 w-4", "aria-hidden": "true" }) }) }), jsxRuntime.jsx(tooltip.TooltipContent, { className: "ibl-tooltip-content z-50", children: label })] }) }));
|
|
1003
394
|
const renderServerCard = (server, isFeatured) => {
|
|
1004
395
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1005
396
|
const oauthData = server.oauth_service_data;
|
|
1006
|
-
const displayName = server
|
|
1007
|
-
(oauthData === null || oauthData === void 0 ? void 0 : oauthData.display_name) ||
|
|
1008
|
-
t('mcpTabConnectorManagementContent.unknownConnector');
|
|
1009
|
-
const authType = (_a = server.auth_type) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
1010
|
-
const isOAuth2 = authType === 'oauth2';
|
|
1011
|
-
const isToken = authType === 'token';
|
|
1012
|
-
const isConnected = isOAuth2 && isOAuthServerConnected(server);
|
|
1013
|
-
const connectedServiceId = getConnectedServiceId(server);
|
|
1014
|
-
const serviceKey = `server-${server.id}`;
|
|
1015
|
-
const isConnecting = connectingServiceIds.has(serviceKey);
|
|
1016
|
-
const isDisconnecting = disconnectingServiceIds.has(server.id);
|
|
397
|
+
const displayName = serverDisplayName(server);
|
|
1017
398
|
const isActive = activeMcpServerIds.includes(server.id);
|
|
1018
|
-
|
|
1019
|
-
const
|
|
399
|
+
const locked = isFeatured || isLockedServer(server);
|
|
400
|
+
const description = (oauthData === null || oauthData === void 0 ? void 0 : oauthData.description) || server.description || server.url;
|
|
1020
401
|
const objectPermissions = {
|
|
1021
|
-
write: (
|
|
1022
|
-
delete: (
|
|
402
|
+
write: (_c = (_b = (_a = server.permissions) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.write) !== null && _c !== void 0 ? _c : true,
|
|
403
|
+
delete: (_f = (_e = (_d = server.permissions) === null || _d === void 0 ? void 0 : _d.object) === null || _e === void 0 ? void 0 : _e.delete) !== null && _f !== void 0 ? _f : true,
|
|
1023
404
|
};
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
405
|
+
// A connector the organization cannot edit still has settings for this
|
|
406
|
+
// agent, so Configure opens the form with only those enabled, for whoever
|
|
407
|
+
// may change what the agent uses.
|
|
408
|
+
const restrictedEdit = locked || !objectPermissions.write;
|
|
409
|
+
const configureButton = renderIconAction({
|
|
410
|
+
label: t('mcpTabConnectorManagementContent.configure'),
|
|
411
|
+
icon: settings.default,
|
|
412
|
+
testId: `mcp-connector-configure-${server.id}`,
|
|
413
|
+
onClick: () => openEdit(server, restrictedEdit),
|
|
414
|
+
className: 'hover:text-gray-700',
|
|
415
|
+
});
|
|
416
|
+
// The card's actions are icons because its on/off is a switch: one style per
|
|
417
|
+
// card, never a switch beside words (#2725 review). The name wraps, never truncates.
|
|
418
|
+
return (jsxRuntime.jsxs("div", { "data-testid": `mcp-connector-${server.id}`, role: "group", "aria-label": displayName, className: "flex flex-col gap-3 rounded-lg border p-4", children: [jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [jsxRuntime.jsx("div", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg border border-gray-100 bg-white", children: mcpConnectorHelpers.connectorImage(server) ? (jsxRuntime.jsx("img", { src: mcpConnectorHelpers.connectorImage(server), alt: displayName, className: "h-6 w-6 object-contain" })) : (jsxRuntime.jsx(plug.default, { className: "h-5 w-5 text-gray-400" })) }), jsxRuntime.jsxs("div", { className: "min-w-0", children: [jsxRuntime.jsx("h4", { className: "text-sm font-medium break-words text-gray-900", children: displayName }), (isOAuthServer(server) || !isFeatured) && (jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1", children: [isOAuthServer(server) && renderScopePill(server, displayName), !isFeatured && (
|
|
419
|
+
// The same word the transport filter above uses; no transport means Streamable HTTP.
|
|
420
|
+
jsxRuntime.jsx("span", { className: "inline-block rounded bg-gray-100 px-2 py-0.5 text-xs text-gray-600", children: t(mcpConnectorHelpers.getTransportLabelKey(mcpConnectorHelpers.normalizeTransportValue((_g = server.transport) !== null && _g !== void 0 ? _g : undefined))) }))] }))] })] }), jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-1", children: [!locked && (jsxRuntime.jsx(webUtils.WithFormPermissions, { name: mcpConnectorHelpers.MCP_SERVER_PERMISSION_NAME, permissions: { [mcpConnectorHelpers.MCP_SERVER_PERMISSION_NAME]: objectPermissions }, enableRBAC: enableRbac, children: ({ canDelete }) => canDelete
|
|
421
|
+
? renderIconAction({
|
|
422
|
+
label: t('mcpTabConnectorManagementContent.delete'),
|
|
423
|
+
icon: trash2.default,
|
|
424
|
+
testId: `mcp-connector-delete-${server.id}`,
|
|
425
|
+
onClick: () => setConnectorToDelete({ id: server.id, name: server.name }),
|
|
426
|
+
disabled: deletingServerId === server.id,
|
|
427
|
+
className: 'hover:bg-red-50 hover:text-red-600',
|
|
428
|
+
})
|
|
429
|
+
: null })), restrictedEdit ? (jsxRuntime.jsx(webUtils.WithFormPermissions, { name: "mcp_servers", permissions: fieldPermissions !== null && fieldPermissions !== void 0 ? fieldPermissions : {}, enableRBAC: enableRbac, children: ({ disabled }) => (disabled ? null : configureButton) })) : (jsxRuntime.jsx(webUtils.WithFormPermissions, { name: mcpConnectorHelpers.MCP_SERVER_PERMISSION_NAME, permissions: { [mcpConnectorHelpers.MCP_SERVER_PERMISSION_NAME]: objectPermissions }, enableRBAC: enableRbac, children: ({ disabled }) => (disabled ? null : configureButton) })), jsxRuntime.jsx(webUtils.WithFormPermissions, { name: "mcp_servers", permissions: fieldPermissions !== null && fieldPermissions !== void 0 ? fieldPermissions : {}, enableRBAC: enableRbac, children: ({ disabled }) => disabled ? null : (
|
|
430
|
+
// The state reads on hover (title) and to screen readers (aria-label).
|
|
431
|
+
jsxRuntime.jsx("span", { className: "flex flex-shrink-0 items-center", title: isActive
|
|
432
|
+
? t('mcpTabConnectorManagementContent.onForThisAgent')
|
|
433
|
+
: t('mcpTabConnectorManagementContent.offForThisAgent'), children: jsxRuntime.jsx(_switch.Switch, { "data-testid": `mcp-connector-toggle-${server.id}`, checked: isActive, onCheckedChange: (checked) => requestToggle(server, checked), disabled: togglingServerIds.has(server.id), "aria-label": isActive
|
|
1027
434
|
? t('mcpTabConnectorManagementContent.ariaEnabled', { displayName })
|
|
1028
|
-
: t('mcpTabConnectorManagementContent.ariaDisabled', { displayName }) })
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
: t('mcpTabConnectorManagementContent.scopeTenant') })), isToken && (jsxRuntime.jsx("span", { className: "rounded bg-purple-100 px-2 py-1 text-xs text-purple-600", children: "Token" })), isFeatured && (oauthData === null || oauthData === void 0 ? void 0 : oauthData.oauth_provider) && (jsxRuntime.jsx("span", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-600", children: oauthData.oauth_provider })), !isFeatured && (jsxRuntime.jsx("span", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-600", children: getTransportLabel(server.transport) }))] }), jsxRuntime.jsx("div", { className: "mt-auto", children: !isFeatured ? (
|
|
1033
|
-
// Custom (non-featured) servers: Show Edit/Delete based on object permissions, and Connect/Disconnect if OAuth
|
|
1034
|
-
jsxRuntime.jsxs("div", { className: "space-y-2", children: [isOAuth2 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConnected && connectedServiceId ? (jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", className: "h-8 w-full text-red-600 hover:bg-red-50 hover:text-red-700", onClick: () => handleDisconnectOAuth(server), disabled: isDisconnecting, children: isDisconnecting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(index.Spinner, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.disconnecting')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(unlink.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.disconnect')] })) })) : /* istanbul ignore next -- @preserve JSX branch */ needsOAuthConnection ? (jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", className: "h-8 w-full border-[#38A1E5] bg-[#38A1E5] text-white hover:bg-[#2d8bc7] hover:text-white", onClick: () => handleConnectOAuth(server), disabled: isConnecting, children: isConnecting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(index.Spinner, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.connecting')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(link2.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.connect')] })) })) : null })), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(webUtils.WithFormPermissions, { name: MCP_SERVER_PERMISSION_NAME, enableRBAC: enableRBAC, permissions: {
|
|
1035
|
-
[MCP_SERVER_PERMISSION_NAME]: objectPermissions,
|
|
1036
|
-
}, children: ({ disabled }) => !disabled ? (jsxRuntime.jsxs(button.Button, { variant: "outline", size: "sm", className: "h-8 flex-1", onClick: () => {
|
|
1037
|
-
setEditingServer(server);
|
|
1038
|
-
setShowAddConnectorDialog(true);
|
|
1039
|
-
}, children: [jsxRuntime.jsx(squarePen.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.edit')] })) : null }), jsxRuntime.jsx(webUtils.WithFormPermissions, { name: MCP_SERVER_PERMISSION_NAME, enableRBAC: enableRBAC, permissions: {
|
|
1040
|
-
[MCP_SERVER_PERMISSION_NAME]: objectPermissions,
|
|
1041
|
-
}, children: ({ canDelete }) => canDelete ? (jsxRuntime.jsxs(button.Button, { variant: "outline", size: "sm", className: "h-8 flex-1 text-red-600 hover:bg-red-50 hover:text-red-700", onClick: () => setConnectorToDelete({
|
|
1042
|
-
id: server.id,
|
|
1043
|
-
name: server.name,
|
|
1044
|
-
}), disabled: deletingServerId === server.id, children: [jsxRuntime.jsx(trash2.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.delete')] })) : null })] })] })) : (
|
|
1045
|
-
// Featured servers: Only show Connect/Disconnect for OAuth
|
|
1046
|
-
jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConnected && connectedServiceId ? (jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", className: "h-8 w-full text-red-600 hover:bg-red-50 hover:text-red-700", onClick: () => handleDisconnectOAuth(server), disabled: isDisconnecting, children: isDisconnecting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(index.Spinner, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.disconnecting')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(unlink.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.disconnect')] })) })) : needsOAuthConnection ? (jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", className: "h-8 w-full border-[#38A1E5] bg-[#38A1E5] text-white hover:bg-[#2d8bc7] hover:text-white", onClick: () => handleConnectOAuth(server), disabled: isConnecting, children: isConnecting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(index.Spinner, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.connecting')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(link2.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.connect')] })) })) : null })) }), onSelect && !needsOAuthConnection && (jsxRuntime.jsxs(button.Button, { variant: "default", size: "sm", className: "mt-2 h-8 w-full border-0 bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", onClick: async (e) => {
|
|
1047
|
-
e.stopPropagation();
|
|
1048
|
-
if (!isActive) {
|
|
1049
|
-
await handleToggleConnector(server.id, displayName, true);
|
|
1050
|
-
}
|
|
1051
|
-
onSelect(server);
|
|
1052
|
-
}, children: [jsxRuntime.jsx(check.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.select')] })), jsxRuntime.jsx("div", { className: "mt-2 text-xs text-gray-500", children: t('mcpTabConnectorManagementContent.createdDate', {
|
|
1053
|
-
date: new Date(server.created_at).toLocaleDateString(),
|
|
1054
|
-
}) })] })] }, server.id));
|
|
435
|
+
: t('mcpTabConnectorManagementContent.ariaDisabled', { displayName }), className: "data-[state=checked]:bg-[#38A1E5] data-[state=unchecked]:bg-gray-200" }) })) })] })] }), description && (jsxRuntime.jsx("p", { className: "truncate text-xs text-gray-500", title: description, children: description })), onSelect && (jsxRuntime.jsx("div", { className: "mt-auto flex gap-2", children: jsxRuntime.jsxs(button.Button, { variant: "default", size: "sm", className: "h-8 border-0 bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", onClick: (e) => {
|
|
436
|
+
e.stopPropagation();
|
|
437
|
+
void selectConnector(server);
|
|
438
|
+
}, children: [jsxRuntime.jsx(check.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.select')] }) }))] }, server.id));
|
|
1055
439
|
};
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
440
|
+
const hasFeatured = featuredOAuthServers.length > 0 || featuredRegularServers.length > 0;
|
|
441
|
+
// Decided before the featured page answers: the sub-tabs show from the first
|
|
442
|
+
// render (with the Featured panel's own spinner or error), never swapping the
|
|
443
|
+
// Connectors list away from under the person once it has arrived.
|
|
444
|
+
const showTabs = isLoadingFeatured || !!featuredError || hasFeatured;
|
|
445
|
+
const addButton = (jsxRuntime.jsx(webUtils.WithPermissions, { rbacResource: "/mcpservers/#create", rbacPermissions: rbacPermissions !== null && rbacPermissions !== void 0 ? rbacPermissions : {}, children: ({ hasPermission }) => hasPermission ? (jsxRuntime.jsxs(button.Button, { onClick: () => setShowAddConnectorDialog(true), variant: "outline", className: "ibl-button-primary shrink-0", children: [jsxRuntime.jsx(plus.default, { className: "mr-2 h-4 w-4" }), t('mcpTabConnectorManagementContent.addConnector')] })) : null }));
|
|
446
|
+
const featuredList = isLoadingFeatured ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [jsxRuntime.jsx(index.Spinner, { className: "mb-4 h-8 w-8" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: t('mcpTabConnectorManagementContent.loadingFeaturedConnectors') })] })) : featuredError ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [jsxRuntime.jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-red-100", children: jsxRuntime.jsx(plug.default, { className: "h-8 w-8 text-red-400" }) }), jsxRuntime.jsx("p", { className: "mb-2 text-sm text-red-600", children: t('mcpTabConnectorManagementContent.failedToLoadFeatured') }), jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", onClick: () => refetchFeatured(), className: "text-sm", children: t('mcpTabConnectorManagementContent.retry') })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [featuredOAuthServers.map((server) => renderServerCard(server, true)), featuredRegularServers.map((server) => renderServerCard(server, true))] }), featuredTotalPages > 1 && (jsxRuntime.jsx("div", { className: "flex justify-center pt-4", children: jsxRuntime.jsx(iblPagination.IblPagination, { currentPage: featuredPage, totalPages: featuredTotalPages, onPageChange: setFeaturedPage, disabled: isLoadingFeatured }) }))] }));
|
|
447
|
+
const connectorsList = isLoadingMy ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [jsxRuntime.jsx(index.Spinner, { className: "mb-4 h-8 w-8" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: t('mcpTabConnectorManagementContent.loadingConnectors') })] })) : myError ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [jsxRuntime.jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-red-100", children: jsxRuntime.jsx(plug.default, { className: "h-8 w-8 text-red-400" }) }), jsxRuntime.jsx("p", { className: "mb-2 text-sm text-red-600", children: t('mcpTabConnectorManagementContent.failedToLoadConnectors') }), jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", onClick: () => refetchMy(), className: "text-sm", children: t('mcpTabConnectorManagementContent.retry') })] })) : !filteredMyServers.length ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [jsxRuntime.jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-200", children: jsxRuntime.jsx(plug.default, { className: "h-8 w-8 text-gray-400" }) }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: t('mcpTabConnectorManagementContent.noConnectorsConfigured') })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "grid gap-3 md:grid-cols-2", children: filteredMyServers.map((server) => renderServerCard(server, false)) }), myConnectorsTotalPages > 1 && (jsxRuntime.jsx("div", { className: "flex justify-center pt-4", children: jsxRuntime.jsx(iblPagination.IblPagination, { currentPage: myConnectorsPage, totalPages: myConnectorsTotalPages, onPageChange: setMyConnectorsPage, disabled: isLoadingMy }) }))] }));
|
|
448
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "space-y-6", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 lg:flex-row", children: [jsxRuntime.jsx("div", { className: "relative min-w-[200px] flex-1", children: jsxRuntime.jsx(input.Input, { type: "text", placeholder: t('mcpTabConnectorManagementContent.searchByName'), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "h-10 w-full bg-transparent" }) }), jsxRuntime.jsxs(popover.Popover, { children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { variant: "outline", className: "flex w-full items-center gap-2 bg-transparent font-normal whitespace-nowrap lg:w-auto", children: [jsxRuntime.jsx(calendar.default, { className: "h-4 w-4" }),
|
|
449
|
+
/* istanbul ignore next */ (dateRange === null || dateRange === void 0 ? void 0 : dateRange.from) && (dateRange === null || dateRange === void 0 ? void 0 : dateRange.to)
|
|
450
|
+
? `${dateFns.format(dateRange.from, 'MMM dd')} - ${dateFns.format(dateRange.to, 'MMM dd')}`
|
|
451
|
+
: t('mcpTabConnectorManagementContent.pickDateRange')] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-auto p-0", align: "start", children: jsxRuntime.jsx(calendar$1.Calendar, { mode: "range", selected: dateRange, onSelect: setDateRange, numberOfMonths: 2, initialFocus: true }) })] }), jsxRuntime.jsxs(popover.Popover, { children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { variant: "outline", role: "combobox", "aria-label": t('mcpTabConnectorManagementContent.ariaSelectTransport'), className: "w-full justify-between bg-transparent font-normal lg:w-[200px]", children: [selectedTransport
|
|
452
|
+
? t(mcpConnectorHelpers.getTransportLabelKey(selectedTransport))
|
|
453
|
+
: t('mcpTabConnectorManagementContent.allTransports'), jsxRuntime.jsx(chevronsUpDown.default, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-full p-0", align: "start", children: jsxRuntime.jsxs(command.Command, { children: [jsxRuntime.jsx(command.CommandInput, { placeholder: t('mcpTabConnectorManagementContent.searchTransport') }), jsxRuntime.jsxs(command.CommandList, { children: [jsxRuntime.jsx(command.CommandEmpty, { children: t('mcpTabConnectorManagementContent.noTransportFound') }), jsxRuntime.jsx(command.CommandGroup, { children: mcpConnectorHelpers.TRANSPORT_OPTIONS.map((option) => (jsxRuntime.jsxs(command.CommandItem, { value: String(option.value), onSelect: () => setSelectedTransport(option.value), children: [jsxRuntime.jsx(check.default, { className: utils.cn('mr-2 h-4 w-4', selectedTransport === option.value ? 'opacity-100' : 'opacity-0') }), t(mcpConnectorHelpers.getTransportLabelKey(option.value))] }, option.value || 'all'))) })] })] }) })] })] }), showTabs ? (jsxRuntime.jsxs(tabs.Tabs, { value: section, onValueChange: (value) => setSection(value), className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsxRuntime.jsxs(tabs.TabsList, { className: "inline-flex h-auto max-w-full justify-start overflow-x-auto rounded-md bg-gray-100 p-1", "aria-label": t('mcpTabConnectorManagementContent.connectors'), children: [jsxRuntime.jsx(tabs.TabsTrigger, { value: "featured", "data-testid": "mcp-tab-featured", className: SUB_TAB_TRIGGER_CLASS, children: t('mcpTabConnectorManagementContent.featured') }), jsxRuntime.jsx(tabs.TabsTrigger, { value: "custom", "data-testid": "mcp-tab-custom", className: SUB_TAB_TRIGGER_CLASS, children: t('mcpTabConnectorManagementContent.directory') })] }), addButton] }), jsxRuntime.jsx(tabs.TabsContent, { value: "featured", forceMount: true, className: "m-0 data-[state=inactive]:hidden", children: featuredList }), jsxRuntime.jsx(tabs.TabsContent, { value: "custom", forceMount: true, className: "m-0 data-[state=inactive]:hidden", children: connectorsList })] })) : (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsx("h3", { className: "text-base font-medium text-gray-900", children: t('mcpTabConnectorManagementContent.connectors') }), addButton] }), connectorsList] }))] }), jsxRuntime.jsx(connectorDialogs.ConnectorDialogs, { open: showAddConnectorDialog, restricted: restricted, openOnSignInApp: openOnSignInApp, onClose: () => {
|
|
454
|
+
setRestricted(false);
|
|
455
|
+
setOpenOnSignInApp(false);
|
|
1062
456
|
setShowAddConnectorDialog(false);
|
|
1063
457
|
setEditingServer(null);
|
|
1064
|
-
}, onAddConnector: handleAddConnectorClick, editingServer: editingServer, editingConnectionId: editingServer ? getConnectionId(editingServer) : null, tenantKey: tenantKey, username: username, mentorId: mentorId, onOAuthComplete: handleOAuthComplete
|
|
1065
|
-
? t('mcpTabConnectorManagementContent.deleting')
|
|
1066
|
-
: t('mcpTabConnectorManagementContent.delete') })] })] })] }) }))] }));
|
|
458
|
+
}, onAddConnector: handleAddConnectorClick, onRestrictedSave: handleRestrictedSave, clearAgentScopeOverride: clearAgentScopeOverride, editingServer: editingServer, editingConnectionId: editingServer ? getConnectionId(editingServer) : null, tenantKey: tenantKey, username: username, mentorId: mentorId, onOAuthComplete: handleOAuthComplete, onAuthScopeChanged: handleAuthScopeChanged, connection: editingConnection }), jsxRuntime.jsx(removeConnectorDialog.RemoveConnectorDialog, { connector: connectorToDelete, deletingServerId: deletingServerId, onCancel: () => setConnectorToDelete(null), onConfirm: (connector) => handleDeleteConnector(connector.id, connector.name) })] }));
|
|
1067
459
|
}
|
|
1068
460
|
|
|
461
|
+
exports.MCP_RADIO_ITEM_CLASS = mcpConnectorHelpers.MCP_RADIO_ITEM_CLASS;
|
|
462
|
+
exports.MCP_SERVER_PERMISSION_NAME = mcpConnectorHelpers.MCP_SERVER_PERMISSION_NAME;
|
|
463
|
+
exports.TRANSPORT_OPTIONS = mcpConnectorHelpers.TRANSPORT_OPTIONS;
|
|
464
|
+
exports.attachedMcpServers = mcpConnectorHelpers.attachedMcpServers;
|
|
465
|
+
exports.canManageMcpServers = mcpConnectorHelpers.canManageMcpServers;
|
|
466
|
+
exports.checkOAuthConnectionComplete = mcpConnectorHelpers.checkOAuthConnectionComplete;
|
|
467
|
+
exports.connectionForScopeExists = mcpConnectorHelpers.connectionForScopeExists;
|
|
468
|
+
exports.connectionHasSignIn = mcpConnectorHelpers.connectionHasSignIn;
|
|
469
|
+
exports.connectorImage = mcpConnectorHelpers.connectorImage;
|
|
470
|
+
exports.createMCPServerFormData = mcpConnectorHelpers.createMCPServerFormData;
|
|
471
|
+
exports.createOAuthConnection = mcpConnectorHelpers.createOAuthConnection;
|
|
472
|
+
exports.currentSignInScope = mcpConnectorHelpers.currentSignInScope;
|
|
473
|
+
exports.determineCheckConnectionAction = mcpConnectorHelpers.determineCheckConnectionAction;
|
|
474
|
+
exports.determineMessageEventAction = mcpConnectorHelpers.determineMessageEventAction;
|
|
475
|
+
exports.executeCheckConnectionFlowLogic = mcpConnectorHelpers.executeCheckConnectionFlowLogic;
|
|
476
|
+
exports.executeConnectionFoundCleanup = mcpConnectorHelpers.executeConnectionFoundCleanup;
|
|
477
|
+
exports.executeHandleMessageCallback = mcpConnectorHelpers.executeHandleMessageCallback;
|
|
478
|
+
exports.executeMaxPollsCleanup = mcpConnectorHelpers.executeMaxPollsCleanup;
|
|
479
|
+
exports.executeMessageEventFlowLogic = mcpConnectorHelpers.executeMessageEventFlowLogic;
|
|
480
|
+
exports.findMCPServerConnection = mcpConnectorHelpers.findMCPServerConnection;
|
|
481
|
+
exports.getMcpConnectionState = mcpConnectorHelpers.getMcpConnectionState;
|
|
482
|
+
exports.getTransportLabelKey = mcpConnectorHelpers.getTransportLabelKey;
|
|
483
|
+
exports.handleOAuthMessageResult = mcpConnectorHelpers.handleOAuthMessageResult;
|
|
484
|
+
exports.mcpServerSignedIn = mcpConnectorHelpers.mcpServerSignedIn;
|
|
485
|
+
exports.normalizeTransportValue = mcpConnectorHelpers.normalizeTransportValue;
|
|
486
|
+
exports.oauthCallbackUrl = mcpConnectorHelpers.oauthCallbackUrl;
|
|
487
|
+
exports.processOAuthMessageEvent = mcpConnectorHelpers.processOAuthMessageEvent;
|
|
488
|
+
exports.processOAuthStorageEvent = mcpConnectorHelpers.processOAuthStorageEvent;
|
|
489
|
+
exports.readAttachedMcpServerIds = mcpConnectorHelpers.readAttachedMcpServerIds;
|
|
490
|
+
exports.shouldExecuteMessageAction = mcpConnectorHelpers.shouldExecuteMessageAction;
|
|
491
|
+
exports.validateDisconnectOAuthParams = mcpConnectorHelpers.validateDisconnectOAuthParams;
|
|
1069
492
|
exports.ConnectorManagementContent = ConnectorManagementContent;
|
|
1070
|
-
exports.MCP_SERVER_PERMISSION_NAME = MCP_SERVER_PERMISSION_NAME;
|
|
1071
|
-
exports.TRANSPORT_OPTIONS = TRANSPORT_OPTIONS;
|
|
1072
|
-
exports.checkOAuthConnectionComplete = checkOAuthConnectionComplete;
|
|
1073
|
-
exports.createMCPServerFormData = createMCPServerFormData;
|
|
1074
|
-
exports.createOAuthConnection = createOAuthConnection;
|
|
1075
|
-
exports.determineCheckConnectionAction = determineCheckConnectionAction;
|
|
1076
|
-
exports.determineMessageEventAction = determineMessageEventAction;
|
|
1077
|
-
exports.executeCheckConnectionFlowLogic = executeCheckConnectionFlowLogic;
|
|
1078
|
-
exports.executeConnectionFoundCleanup = executeConnectionFoundCleanup;
|
|
1079
|
-
exports.executeHandleMessageCallback = executeHandleMessageCallback;
|
|
1080
|
-
exports.executeMaxPollsCleanup = executeMaxPollsCleanup;
|
|
1081
|
-
exports.executeMessageEventFlowLogic = executeMessageEventFlowLogic;
|
|
1082
|
-
exports.findMCPServerConnection = findMCPServerConnection;
|
|
1083
|
-
exports.getTransportLabel = getTransportLabel;
|
|
1084
|
-
exports.getTransportLabelKey = getTransportLabelKey;
|
|
1085
|
-
exports.handleOAuthMessageResult = handleOAuthMessageResult;
|
|
1086
|
-
exports.normalizeTransportValue = normalizeTransportValue;
|
|
1087
|
-
exports.processOAuthMessageEvent = processOAuthMessageEvent;
|
|
1088
|
-
exports.processOAuthStorageEvent = processOAuthStorageEvent;
|
|
1089
|
-
exports.shouldExecuteMessageAction = shouldExecuteMessageAction;
|
|
1090
|
-
exports.validateDisconnectOAuthParams = validateDisconnectOAuthParams;
|
|
1091
493
|
//# sourceMappingURL=connector-management-content.js.map
|