@shuffleio/shuffle-mcps 0.0.3 → 0.0.4
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/README.md +18 -2
- package/dist/index.cjs +167 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +167 -96
- package/dist/index.js.map +1 -1
- package/dist/{singul-GZKBHJNI.css → shuffle-mcp-XZEVQXW2.css} +89 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -146,16 +146,32 @@ When `apiKey` is set, the component also fetches the user's **private apps** fro
|
|
|
146
146
|
| Prop | Type | Description |
|
|
147
147
|
|---|---|---|
|
|
148
148
|
| `authToken` | `string` | Required. Forwarded into the auth URL. |
|
|
149
|
+
| `orgId` | `string` | Optional Shuffle organization ID. When set, every API call (`/api/v1/apps/authentication`, `/api/v1/apps`) is sent with an `Org-Id: <orgId>` header, and the auth URL gets `&org_id=<orgId>` appended. Default: not sent. |
|
|
149
150
|
| `inline` | `boolean` | Inline results vs floating dropdown. |
|
|
150
151
|
| `layout` | `'list' \| 'grid'` | Result layout. Default `'list'`. |
|
|
151
152
|
| `initialFilterQuery` | `string` | Pre-filter without filling the input. |
|
|
152
|
-
| `preventDefault` | `boolean` | Skip default `window.open(authUrl)` so you can handle selection. |
|
|
153
|
-
| `onAppSelected` | `(detail) => void` | Fires on single-select pick. |
|
|
153
|
+
| `preventDefault` | `boolean` | Skip the default click behavior (built-in drawer or `window.open(authUrl)`) so you can handle selection yourself. |
|
|
154
|
+
| `onAppSelected` | `(detail) => void` | Fires on single-select pick. If provided, the built-in drawer is **not** opened — you take over. |
|
|
154
155
|
| `multiSelect` | `boolean` | Allow selecting multiple apps. |
|
|
155
156
|
| `apiKey` | `string` | Bearer token. Enables status dots and merges your private apps from `/api/v1/apps`. |
|
|
156
157
|
| `showSourceFilter` | `boolean` | Toggle the All / Public / Private filter. Default `true`. |
|
|
157
158
|
| `customStyles` | `CustomStyles` | Per-slot style overrides. |
|
|
158
159
|
|
|
160
|
+
### Default click behavior
|
|
161
|
+
|
|
162
|
+
When you do **not** pass `onAppSelected`, clicking an app opens a built-in right-side drawer that shows the app, its existing authentication entries (with Configured / Tested / Inactive chips), and a CTA that opens the Shuffle auth flow in a new tab. Pass `onAppSelected` to take over, or `preventDefault` to disable both.
|
|
163
|
+
|
|
164
|
+
### Org scoping
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<ShuffleMCP
|
|
168
|
+
authToken={token}
|
|
169
|
+
apiKey={user.apiKey}
|
|
170
|
+
orgId={currentOrg.id} // every request now scoped to this org
|
|
171
|
+
/>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
159
175
|
Full prop reference, framework setup (Next.js, Vue), styling slots, custom rendering, and publishing: [**LIBRARY.md**](./LIBRARY.md).
|
|
160
176
|
|
|
161
177
|
## Imperative handle
|
package/dist/index.cjs
CHANGED
|
@@ -37,13 +37,14 @@ module.exports = __toCommonJS(index_exports);
|
|
|
37
37
|
// ShuffleMCP.tsx
|
|
38
38
|
var import_react = __toESM(require("react"), 1);
|
|
39
39
|
var import_algoliasearch = require("algoliasearch");
|
|
40
|
-
var
|
|
40
|
+
var import_shuffle_mcp = require("./shuffle-mcp-XZEVQXW2.css");
|
|
41
41
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
42
|
var DEFAULT_ALGOLIA_APP_ID = "JNSS5CFDZZ";
|
|
43
43
|
var DEFAULT_ALGOLIA_API_KEY = "33e4e3564f4f060e96e0531957bed552";
|
|
44
44
|
var DEFAULT_ALGOLIA_INDEX = "appsearch";
|
|
45
45
|
var ShuffleMCP = import_react.default.forwardRef(({
|
|
46
46
|
authToken,
|
|
47
|
+
orgId,
|
|
47
48
|
placeholder = "Search apps...",
|
|
48
49
|
layout = "list",
|
|
49
50
|
gridColumns = 3,
|
|
@@ -89,6 +90,7 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
89
90
|
const [selectedIndex, setSelectedIndex] = (0, import_react.useState)(-1);
|
|
90
91
|
const [internalSelectedApps, setInternalSelectedApps] = (0, import_react.useState)(selectedApps);
|
|
91
92
|
const [authenticatedApps, setAuthenticatedApps] = (0, import_react.useState)(externalAuthenticatedApps || []);
|
|
93
|
+
const [drawerApp, setDrawerApp] = (0, import_react.useState)(null);
|
|
92
94
|
const hasInitialized = (0, import_react.useRef)(false);
|
|
93
95
|
const containerRef = (0, import_react.useRef)(null);
|
|
94
96
|
const inputRef = (0, import_react.useRef)(null);
|
|
@@ -100,7 +102,8 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
100
102
|
try {
|
|
101
103
|
const response = await fetch(`${apiBaseUrl}${authPath}`, {
|
|
102
104
|
headers: {
|
|
103
|
-
"Authorization": `Bearer ${apiKey}
|
|
105
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
106
|
+
...orgId ? { "Org-Id": orgId } : {}
|
|
104
107
|
}
|
|
105
108
|
});
|
|
106
109
|
if (response.ok) {
|
|
@@ -117,7 +120,7 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
117
120
|
};
|
|
118
121
|
fetchAuthenticatedApps();
|
|
119
122
|
}
|
|
120
|
-
}, [apiKey, apiBaseUrl]);
|
|
123
|
+
}, [apiKey, apiBaseUrl, orgId]);
|
|
121
124
|
(0, import_react.useEffect)(() => {
|
|
122
125
|
if (!apiKey || disablePrivateApps) {
|
|
123
126
|
setPrivateApps([]);
|
|
@@ -126,7 +129,10 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
126
129
|
const fetchPrivateApps = async () => {
|
|
127
130
|
try {
|
|
128
131
|
const response = await fetch(`${apiBaseUrl}${privateAppsPath}`, {
|
|
129
|
-
headers: {
|
|
132
|
+
headers: {
|
|
133
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
134
|
+
...orgId ? { "Org-Id": orgId } : {}
|
|
135
|
+
},
|
|
130
136
|
credentials: "include"
|
|
131
137
|
});
|
|
132
138
|
if (!response.ok) return;
|
|
@@ -158,7 +164,7 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
158
164
|
}
|
|
159
165
|
};
|
|
160
166
|
fetchPrivateApps();
|
|
161
|
-
}, [apiKey, apiBaseUrl, privateAppsPath, disablePrivateApps]);
|
|
167
|
+
}, [apiKey, apiBaseUrl, privateAppsPath, disablePrivateApps, orgId]);
|
|
162
168
|
(0, import_react.useEffect)(() => {
|
|
163
169
|
if (authenticatedApps.length > 0 && results.length > 0) {
|
|
164
170
|
const validatedApps = authenticatedApps.filter((auth) => auth.validation?.valid);
|
|
@@ -277,22 +283,24 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
277
283
|
}, 300);
|
|
278
284
|
}, [performSearch, onSearchChange]);
|
|
279
285
|
const selectApp = (0, import_react.useCallback)((app) => {
|
|
280
|
-
const authUrl = `${apiBaseUrl}${appAuthPath}?app_id=${app.objectID}&auth=${authToken}&source=shuffle`;
|
|
286
|
+
const authUrl = `${apiBaseUrl}${appAuthPath}?app_id=${app.objectID}&auth=${authToken}&source=shuffle${orgId ? `&org_id=${encodeURIComponent(orgId)}` : ""}`;
|
|
281
287
|
if (multiSelect) {
|
|
282
288
|
const isAlreadySelected = internalSelectedApps.some((a) => a.objectID === app.objectID);
|
|
283
289
|
const newSelection = isAlreadySelected ? internalSelectedApps.filter((a) => a.objectID !== app.objectID) : [...internalSelectedApps, app];
|
|
284
290
|
setInternalSelectedApps(newSelection);
|
|
285
291
|
onSelectionChange?.(newSelection);
|
|
286
292
|
} else {
|
|
287
|
-
onAppSelected
|
|
288
|
-
|
|
289
|
-
|
|
293
|
+
if (onAppSelected) {
|
|
294
|
+
onAppSelected({ app, authUrl });
|
|
295
|
+
if (!preventDefault) {
|
|
296
|
+
window.open(authUrl, "_blank");
|
|
297
|
+
}
|
|
298
|
+
} else if (!preventDefault) {
|
|
299
|
+
setDrawerApp(app);
|
|
290
300
|
}
|
|
291
301
|
setIsOpen(false);
|
|
292
|
-
setQuery("");
|
|
293
|
-
setResults([]);
|
|
294
302
|
}
|
|
295
|
-
}, [authToken, apiBaseUrl, appAuthPath, multiSelect, internalSelectedApps, onAppSelected, onSelectionChange, preventDefault]);
|
|
303
|
+
}, [authToken, apiBaseUrl, appAuthPath, orgId, multiSelect, internalSelectedApps, onAppSelected, onSelectionChange, preventDefault]);
|
|
296
304
|
const handleKeyDown = (0, import_react.useCallback)((event) => {
|
|
297
305
|
if (!isOpen) return;
|
|
298
306
|
switch (event.key) {
|
|
@@ -413,100 +421,163 @@ var ShuffleMCP = import_react.default.forwardRef(({
|
|
|
413
421
|
app.objectID
|
|
414
422
|
);
|
|
415
423
|
};
|
|
416
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
417
425
|
"div",
|
|
418
426
|
{
|
|
419
427
|
ref: containerRef,
|
|
420
428
|
className: `singul-container ${inline ? "singul-inline" : ""} ${className}`,
|
|
421
429
|
style: customStyles.container,
|
|
422
|
-
children:
|
|
423
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-search-
|
|
424
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
425
|
-
|
|
430
|
+
children: [
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-search-bar-container", children: [
|
|
432
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-search-input-wrapper", style: customStyles.inputWrapper, children: [
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
434
|
+
"input",
|
|
435
|
+
{
|
|
436
|
+
ref: inputRef,
|
|
437
|
+
type: "text",
|
|
438
|
+
className: "singul-search-input",
|
|
439
|
+
style: customStyles.input,
|
|
440
|
+
placeholder,
|
|
441
|
+
value: query,
|
|
442
|
+
onChange: handleInputChange,
|
|
443
|
+
onFocus: () => {
|
|
444
|
+
if (!inline && query.trim() && results.length > 0) {
|
|
445
|
+
setIsOpen(true);
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
onKeyDown: handleKeyDown,
|
|
449
|
+
autoComplete: "off"
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-search-icon", style: customStyles.searchIcon, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
|
|
454
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21 21-4.35-4.35" })
|
|
455
|
+
] }) }),
|
|
456
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-loading-spinner", style: customStyles.loadingSpinner, children: renderLoadingState ? renderLoadingState() : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-spinner", style: customStyles.spinner }) })
|
|
457
|
+
] }),
|
|
458
|
+
showSourceFilter && privateApps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-source-filter", role: "tablist", "aria-label": "Filter by app source", children: [
|
|
459
|
+
{ key: "all", label: "All", count: results.length + filteredPrivateApps.length },
|
|
460
|
+
{ key: "public", label: "Public", count: results.length },
|
|
461
|
+
{ key: "private", label: "Private", count: filteredPrivateApps.length }
|
|
462
|
+
].map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
463
|
+
"button",
|
|
464
|
+
{
|
|
465
|
+
type: "button",
|
|
466
|
+
role: "tab",
|
|
467
|
+
"aria-selected": sourceFilter === opt.key,
|
|
468
|
+
className: `singul-source-pill ${sourceFilter === opt.key ? "singul-source-pill-active" : ""}`,
|
|
469
|
+
onClick: () => setSourceFilter(opt.key),
|
|
470
|
+
children: [
|
|
471
|
+
opt.label,
|
|
472
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "singul-source-count", children: opt.count })
|
|
473
|
+
]
|
|
474
|
+
},
|
|
475
|
+
opt.key
|
|
476
|
+
)) }),
|
|
477
|
+
inline && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
478
|
+
"div",
|
|
426
479
|
{
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
value: query,
|
|
433
|
-
onChange: handleInputChange,
|
|
434
|
-
onFocus: () => {
|
|
435
|
-
if (!inline && query.trim() && results.length > 0) {
|
|
436
|
-
setIsOpen(true);
|
|
437
|
-
}
|
|
480
|
+
className: `singul-results-container ${layout === "grid" ? "singul-results-grid" : ""}`,
|
|
481
|
+
style: {
|
|
482
|
+
...customStyles.resultsContainer,
|
|
483
|
+
...getGridColumnsStyle,
|
|
484
|
+
...layout === "grid" ? { display: "grid" } : {}
|
|
438
485
|
},
|
|
439
|
-
|
|
440
|
-
|
|
486
|
+
children: displayResults.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
487
|
+
displayResults.map((app, index) => renderAppItem(app, index)),
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-end-of-results", style: {
|
|
489
|
+
padding: "10px 16px",
|
|
490
|
+
color: "rgba(255, 255, 255, 0.3)",
|
|
491
|
+
textAlign: "center",
|
|
492
|
+
fontSize: "11px",
|
|
493
|
+
gridColumn: "1 / -1"
|
|
494
|
+
}, children: "Can't find what you're looking for? Try a different search term." })
|
|
495
|
+
] }) : query.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-empty-state", style: customStyles.emptyState, children: renderEmptyState ? renderEmptyState() : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
496
|
+
'No integrations match "',
|
|
497
|
+
query,
|
|
498
|
+
'". Try searching for a different app or category.'
|
|
499
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-empty-state", style: customStyles.emptyState, children: "Start typing to search integrations..." })
|
|
441
500
|
}
|
|
442
501
|
),
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
502
|
+
!inline && isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
503
|
+
"div",
|
|
504
|
+
{
|
|
505
|
+
className: `singul-dropdown ${layout === "grid" ? "singul-dropdown-grid" : ""}`,
|
|
506
|
+
style: {
|
|
507
|
+
...customStyles.dropdown,
|
|
508
|
+
...getGridColumnsStyle,
|
|
509
|
+
...layout === "grid" ? { display: "grid" } : {}
|
|
510
|
+
},
|
|
511
|
+
children: displayResults.length > 0 ? displayResults.map((app, index) => renderAppItem(app, index)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-empty-state", style: customStyles.emptyState, children: renderEmptyState ? renderEmptyState() : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
512
|
+
'No apps found for "',
|
|
513
|
+
query,
|
|
514
|
+
'"'
|
|
515
|
+
] }) })
|
|
516
|
+
}
|
|
517
|
+
)
|
|
448
518
|
] }),
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
"
|
|
455
|
-
{
|
|
456
|
-
|
|
457
|
-
role: "
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
519
|
+
drawerApp && (() => {
|
|
520
|
+
const norm = (n) => (n || "").toLowerCase().replace(/[\s_\-]+/g, "_");
|
|
521
|
+
const matchingAuths = authenticatedApps.filter(
|
|
522
|
+
(a) => norm(a.app?.name || "") === norm(drawerApp.name)
|
|
523
|
+
);
|
|
524
|
+
const drawerAuthUrl = `${apiBaseUrl}${appAuthPath}?app_id=${drawerApp.objectID}&auth=${authToken}&source=shuffle${orgId ? `&org_id=${encodeURIComponent(orgId)}` : ""}`;
|
|
525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-drawer-backdrop", onClick: () => setDrawerApp(null) }),
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "singul-drawer", role: "dialog", "aria-label": `${drawerApp.name} configuration`, children: [
|
|
528
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "singul-drawer-header", children: [
|
|
529
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-drawer-title-row", children: [
|
|
530
|
+
drawerApp.image_url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: drawerApp.image_url, alt: drawerApp.name, className: "singul-drawer-icon" }),
|
|
531
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
532
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-drawer-title", children: drawerApp.name.replace(/_/g, " ") }),
|
|
533
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-drawer-subtitle", children: "App configuration" })
|
|
534
|
+
] })
|
|
535
|
+
] }),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
537
|
+
"button",
|
|
538
|
+
{
|
|
539
|
+
type: "button",
|
|
540
|
+
className: "singul-drawer-close",
|
|
541
|
+
onClick: () => setDrawerApp(null),
|
|
542
|
+
"aria-label": "Close",
|
|
543
|
+
children: "\xD7"
|
|
544
|
+
}
|
|
545
|
+
)
|
|
546
|
+
] }),
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-drawer-body", children: [
|
|
548
|
+
drawerApp.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "singul-drawer-desc", children: drawerApp.description }),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-drawer-section-title", children: [
|
|
550
|
+
"Authentication",
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "singul-drawer-count", children: [
|
|
552
|
+
matchingAuths.length,
|
|
553
|
+
" configuration",
|
|
554
|
+
matchingAuths.length === 1 ? "" : "s",
|
|
555
|
+
" found"
|
|
556
|
+
] })
|
|
557
|
+
] }),
|
|
558
|
+
matchingAuths.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "singul-drawer-auth-list", children: matchingAuths.map((a) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "singul-drawer-auth-item", children: [
|
|
559
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-drawer-auth-label", children: a.label || "Untitled" }),
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "singul-drawer-auth-chips", children: [
|
|
561
|
+
a.active && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "singul-chip singul-chip-configured", children: "Configured" }),
|
|
562
|
+
a.validation?.valid && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "singul-chip singul-chip-tested", children: "Tested" }),
|
|
563
|
+
!a.active && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "singul-chip singul-chip-inactive", children: "Inactive" })
|
|
564
|
+
] })
|
|
565
|
+
] }, a.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "singul-drawer-empty", children: "No authentications yet for this app." }),
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
567
|
+
"a",
|
|
568
|
+
{
|
|
569
|
+
href: drawerAuthUrl,
|
|
570
|
+
target: "_blank",
|
|
571
|
+
rel: "noopener noreferrer",
|
|
572
|
+
className: "singul-drawer-cta",
|
|
573
|
+
children: matchingAuths.length > 0 ? "Manage authentication" : "Add authentication"
|
|
574
|
+
}
|
|
575
|
+
)
|
|
576
|
+
] })
|
|
577
|
+
] })
|
|
578
|
+
] });
|
|
579
|
+
})()
|
|
580
|
+
]
|
|
510
581
|
}
|
|
511
582
|
);
|
|
512
583
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../ShuffleMCP.tsx"],"sourcesContent":["/**\n * Local Singul Library\n * This is a local copy for development. Changes here should be merged back to:\n * https://github.com/Shuffle/singul.js\n */\n\nexport { ShuffleMCP, default } from './ShuffleMCP';\nexport type { ShuffleMCPHandle } from './ShuffleMCP';\nexport type {\n AlgoliaSearchApp,\n AppSelectedEvent,\n AppAuthentication,\n CustomStyles,\n ShuffleMCPProps,\n} from './singul.helpers';\n","/**\n * Local Singul Library - React Component\n * This is a local copy for development. Changes here should be merged back to:\n * https://github.com/Shuffle/singul.js\n */\n\nimport React, { useState, useEffect, useRef, useCallback, useMemo, useImperativeHandle } from 'react';\nimport { algoliasearch, SearchClient } from 'algoliasearch';\nimport type { AlgoliaSearchApp, AppSelectedEvent, ShuffleMCPProps, AppAuthentication } from './singul.helpers';\nimport './singul.css';\n\nconst DEFAULT_ALGOLIA_APP_ID = 'JNSS5CFDZZ';\nconst DEFAULT_ALGOLIA_API_KEY = '33e4e3564f4f060e96e0531957bed552';\nconst DEFAULT_ALGOLIA_INDEX = 'appsearch';\n\nexport interface ShuffleMCPHandle {\n search: (query: string) => void;\n clear: () => void;\n}\n\nexport const ShuffleMCP = React.forwardRef<ShuffleMCPHandle, ShuffleMCPProps>(({\n authToken,\n placeholder = 'Search apps...',\n layout = 'list',\n gridColumns = 3,\n showDescription = false,\n showCategories = false,\n showCheckbox = false,\n multiSelect = false,\n selectedApps = [],\n preventDefault = false,\n inline = false,\n initialQuery = '',\n initialFilterQuery,\n hitsPerPage = 15,\n apiKey,\n apiBaseUrl = 'https://shuffler.io',\n authPath = '/api/v1/apps/authentication',\n appAuthPath = '/appauth',\n privateAppsPath = '/api/v1/apps',\n disablePrivateApps = false,\n showSourceFilter = true,\n singulBaseUrl = 'https://singul.io',\n hideAuthStatus = false,\n authenticatedApps: externalAuthenticatedApps,\n pinnedApps,\n algoliaAppId = DEFAULT_ALGOLIA_APP_ID,\n algoliaApiKey = DEFAULT_ALGOLIA_API_KEY,\n algoliaIndexName = DEFAULT_ALGOLIA_INDEX,\n customStyles = {},\n className = '',\n renderItem,\n renderEmptyState,\n renderLoadingState,\n onAppSelected,\n onSelectionChange,\n onSearchChange,\n}, ref) => {\n const [query, setQuery] = useState(initialQuery);\n const [results, setResults] = useState<AlgoliaSearchApp[]>([]);\n const [privateApps, setPrivateApps] = useState<AlgoliaSearchApp[]>([]);\n const [sourceFilter, setSourceFilter] = useState<'all' | 'public' | 'private'>('all');\n const [isLoading, setIsLoading] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [internalSelectedApps, setInternalSelectedApps] = useState<AlgoliaSearchApp[]>(selectedApps);\n const [authenticatedApps, setAuthenticatedApps] = useState<AppAuthentication[]>(externalAuthenticatedApps || []);\n const hasInitialized = useRef(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const searchClient = useRef<SearchClient | null>(null);\n\n // Fetch authenticated apps when apiKey is provided\n useEffect(() => {\n if (apiKey) {\n const fetchAuthenticatedApps = async () => {\n try {\n const response = await fetch(`${apiBaseUrl}${authPath}`, {\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n },\n });\n if (response.ok) {\n const result = await response.json();\n // Handle both { success: true, data: [...] } and direct array response\n const authData = result.data || result;\n if (Array.isArray(authData)) {\n console.log('Loaded authenticated apps:', authData.length, authData.map(a => a.app?.name));\n setAuthenticatedApps(authData);\n }\n }\n } catch (error) {\n console.error('Failed to fetch authenticated apps:', error);\n }\n };\n fetchAuthenticatedApps();\n }\n }, [apiKey, apiBaseUrl]);\n\n // Fetch the user's private apps from /api/v1/apps when apiKey is provided.\n // These get merged into search results so users can find their own apps too.\n useEffect(() => {\n if (!apiKey || disablePrivateApps) {\n setPrivateApps([]);\n return;\n }\n const fetchPrivateApps = async () => {\n try {\n const response = await fetch(`${apiBaseUrl}${privateAppsPath}`, {\n headers: { 'Authorization': `Bearer ${apiKey}` },\n credentials: 'include',\n });\n if (!response.ok) return;\n const data = await response.json();\n const apps = Array.isArray(data) ? data : (data?.data || []);\n // Normalize to AlgoliaSearchApp shape, tagged as 'private' source.\n const normalized: AlgoliaSearchApp[] = apps.map((a: any) => ({\n name: a.name || '',\n description: a.description || '',\n objectID: a.id || a.objectID || `private-${a.name}`,\n creator: a.owner || a.creator || '',\n app_version: a.app_version || '1.0.0',\n image_url: a.large_image || a.image_url || '',\n time_edited: a.edited || 0,\n generated: !!a.generated,\n invalid: !!a.invalid,\n priority: a.priority || 0,\n actions: Array.isArray(a.actions) ? a.actions.length : (a.actions || 0),\n tags: a.tags || [],\n accessible_by: a.accessible_by || [],\n categories: a.categories || [],\n action_labels: a.action_labels || [],\n triggers: a.triggers || [],\n verified: !!a.verified,\n source: 'private',\n }));\n setPrivateApps(normalized);\n } catch (error) {\n console.error('Failed to fetch private apps:', error);\n }\n };\n fetchPrivateApps();\n }, [apiKey, apiBaseUrl, privateAppsPath, disablePrivateApps]);\n\n // Auto-select validated apps when they're loaded (validated = tests ran successfully)\n useEffect(() => {\n if (authenticatedApps.length > 0 && results.length > 0) {\n const validatedApps = authenticatedApps.filter(auth => auth.validation?.valid);\n const appsToAutoSelect = results.filter(app => \n validatedApps.some(auth => auth.app.name.toLowerCase() === app.name.toLowerCase())\n );\n \n if (appsToAutoSelect.length > 0) {\n const newSelection = [...internalSelectedApps];\n appsToAutoSelect.forEach(app => {\n if (!newSelection.some(a => a.objectID === app.objectID)) {\n newSelection.push(app);\n }\n });\n if (newSelection.length !== internalSelectedApps.length) {\n setInternalSelectedApps(newSelection);\n onSelectionChange?.(newSelection);\n }\n }\n }\n }, [authenticatedApps, results]);\n\n // Sync external authenticatedApps\n useEffect(() => {\n if (externalAuthenticatedApps) {\n setAuthenticatedApps(externalAuthenticatedApps);\n }\n }, [externalAuthenticatedApps]);\n\n // Initialize Algolia client and run initial search\n useEffect(() => {\n searchClient.current = algoliasearch(algoliaAppId, algoliaApiKey);\n \n // Run initial search after client is ready\n if (!hasInitialized.current) {\n hasInitialized.current = true;\n const searchTerm = initialQuery || initialFilterQuery || '';\n setTimeout(() => {\n if (searchClient.current) {\n performSearch(searchTerm);\n onSearchChange?.(initialQuery); // Only report the visible query\n }\n }, 100);\n }\n }, []);\n\n // Sync external selectedApps\n useEffect(() => {\n setInternalSelectedApps(selectedApps);\n }, [selectedApps]);\n\n // Handle click outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n };\n\n document.addEventListener('click', handleClickOutside);\n return () => document.removeEventListener('click', handleClickOutside);\n }, []);\n\n // Check if an app is configured (found in authentication API with active: true)\n const isAppConfigured = useCallback((app: AlgoliaSearchApp) => {\n return authenticatedApps.some(\n auth => auth.app.name.toLowerCase() === app.name.toLowerCase() && auth.active === true\n );\n }, [authenticatedApps]);\n\n // Check if an app is validated/tested (validation.valid is true)\n const isAppValidated = useCallback((app: AlgoliaSearchApp) => {\n return authenticatedApps.some(\n auth => auth.app.name.toLowerCase() === app.name.toLowerCase() && auth.validation?.valid === true\n );\n }, [authenticatedApps]);\n\n // Get auth state for an app\n const getAppAuthState = useCallback((app: AlgoliaSearchApp) => {\n return {\n configured: isAppConfigured(app),\n validated: isAppValidated(app),\n };\n }, [isAppConfigured, isAppValidated]);\n\n // Perform search\n const performSearch = useCallback(async (searchQuery: string) => {\n if (!searchClient.current) {\n return;\n }\n\n setIsLoading(true);\n try {\n const searchResult = await searchClient.current.searchSingleIndex({\n indexName: algoliaIndexName,\n searchParams: {\n query: searchQuery || '', // Empty string gets top results\n hitsPerPage,\n },\n });\n\n const hits = (searchResult.hits as AlgoliaSearchApp[]).map(h => ({ ...h, source: 'public' as const }));\n setResults(hits);\n setIsOpen(hits.length > 0);\n setSelectedIndex(-1);\n } catch (error) {\n console.error('Search failed:', error);\n setResults([]);\n setIsOpen(false);\n } finally {\n setIsLoading(false);\n }\n }, [hitsPerPage]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n search: (searchQuery: string) => {\n setQuery(searchQuery);\n onSearchChange?.(searchQuery);\n performSearch(searchQuery);\n },\n clear: () => {\n setQuery('');\n performSearch(''); // Show top results when cleared\n },\n getQuery: () => query,\n }), [performSearch, onSearchChange, query]);\n\n // Handle input change\n const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n const value = event.target.value;\n setQuery(value);\n setSelectedIndex(-1);\n onSearchChange?.(value);\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n debounceTimer.current = setTimeout(() => {\n performSearch(value);\n }, 300);\n }, [performSearch, onSearchChange]);\n\n // Handle app selection\n const selectApp = useCallback((app: AlgoliaSearchApp) => {\n const authUrl = `${apiBaseUrl}${appAuthPath}?app_id=${app.objectID}&auth=${authToken}&source=shuffle`;\n \n if (multiSelect) {\n const isAlreadySelected = internalSelectedApps.some((a) => a.objectID === app.objectID);\n const newSelection = isAlreadySelected\n ? internalSelectedApps.filter((a) => a.objectID !== app.objectID)\n : [...internalSelectedApps, app];\n \n setInternalSelectedApps(newSelection);\n onSelectionChange?.(newSelection);\n } else {\n onAppSelected?.({ app, authUrl });\n \n if (!preventDefault) {\n window.open(authUrl, '_blank');\n }\n \n setIsOpen(false);\n setQuery('');\n setResults([]);\n }\n }, [authToken, apiBaseUrl, appAuthPath, multiSelect, internalSelectedApps, onAppSelected, onSelectionChange, preventDefault]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, displayResults.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, -1));\n break;\n case 'Enter':\n event.preventDefault();\n if (selectedIndex >= 0 && displayResults[selectedIndex]) {\n selectApp(displayResults[selectedIndex]);\n }\n break;\n case 'Escape':\n event.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.blur();\n break;\n }\n }, [isOpen, results, selectedIndex, selectApp]);\n\n // Check if app is selected\n const isAppSelected = useCallback((app: AlgoliaSearchApp) => {\n return internalSelectedApps.some((a) => a.objectID === app.objectID);\n }, [internalSelectedApps]);\n\n // Filter the user's private apps client-side by the current query.\n const filteredPrivateApps = useMemo(() => {\n if (privateApps.length === 0) return [];\n const q = query.trim().toLowerCase();\n if (!q) return privateApps;\n return privateApps.filter(a =>\n a.name.toLowerCase().includes(q) ||\n (a.description || '').toLowerCase().includes(q) ||\n (a.categories || []).some(c => c.toLowerCase().includes(q))\n );\n }, [privateApps, query]);\n\n // Merge private + public apps, apply source filter, prepend pinned, dedupe by name.\n const displayResults = useMemo(() => {\n const norm = (n: string) => (n || '').toLowerCase().replace(/[\\s_\\-]+/g, '');\n\n let merged: AlgoliaSearchApp[];\n if (sourceFilter === 'public') {\n merged = results;\n } else if (sourceFilter === 'private') {\n merged = filteredPrivateApps;\n } else {\n // 'all' — private apps first (your own tools win), then public, deduped by name\n const privateNames = new Set(filteredPrivateApps.map(a => norm(a.name)));\n const publicOnly = results.filter(a => !privateNames.has(norm(a.name)));\n merged = [...filteredPrivateApps, ...publicOnly];\n }\n\n if (!pinnedApps || pinnedApps.length === 0) return merged;\n const pinnedNames = new Set(pinnedApps.map(a => norm(a.name)));\n return [...pinnedApps, ...merged.filter(a => !pinnedNames.has(norm(a.name)))];\n }, [pinnedApps, results, filteredPrivateApps, sourceFilter]);\n\n // Get grid columns style\n const getGridColumnsStyle = useMemo(() => {\n if (layout !== 'grid') return {};\n \n const cols = typeof gridColumns === 'number' ? gridColumns : gridColumns.md || 3;\n return { '--singul-grid-columns': cols } as React.CSSProperties;\n }, [layout, gridColumns]);\n\n // Render individual app item\n const renderAppItem = (app: AlgoliaSearchApp, index: number) => {\n const selected = isAppSelected(app);\n const isHighlighted = index === selectedIndex;\n const authState = getAppAuthState(app);\n\n // Use custom render if provided\n if (renderItem) {\n return (\n <div\n key={app.objectID}\n onClick={() => selectApp(app)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n {renderItem(app, selected, () => selectApp(app), authState)}\n </div>\n );\n }\n\n // Show both chips (configured/not configured AND tested/not tested)\n return (\n <div\n key={app.objectID}\n className={`singul-dropdown-item ${selected ? 'singul-selected' : ''} ${authState.validated ? 'singul-validated' : ''} ${authState.configured ? 'singul-configured' : ''}`}\n style={{\n ...customStyles.dropdownItem,\n ...(selected ? customStyles.selectedItem : {}),\n }}\n onClick={() => selectApp(app)}\n >\n <div className=\"singul-app-info\" style={customStyles.appInfo}>\n {app.image_url && (\n <div style={{ position: 'relative', flexShrink: 0 }}>\n <img\n src={app.image_url}\n alt={app.name}\n className=\"singul-app-icon\"\n style={customStyles.appIcon}\n />\n {/* Color-coded status dot: green=tested, yellow=configured, blue=activated/selected, gray=inactive */}\n {!hideAuthStatus && (\n <span\n className={`singul-status-dot ${\n authState.validated ? 'singul-dot-validated' :\n authState.configured ? 'singul-dot-configured' :\n selected ? 'singul-dot-activated' :\n 'singul-dot-inactive'\n }`}\n />\n )}\n </div>\n )}\n <div className=\"singul-app-details\" style={customStyles.appDetails}>\n <span className=\"singul-app-name\" style={customStyles.appName}>\n {app.name.replace(/_/g, ' ')}\n {app.source === 'private' && (\n <span className=\"singul-private-badge\" title=\"From your private apps\">Private</span>\n )}\n </span>\n {showDescription && app.description && (\n <span className=\"singul-app-description\" style={customStyles.appDescription}>\n {app.description}\n </span>\n )}\n {showCategories && app.categories?.[0] && (\n <span className=\"singul-app-category\" style={customStyles.appCategory}>\n {app.categories[0]}\n </span>\n )}\n </div>\n {showCheckbox && (\n <div\n className={`singul-checkbox ${selected ? 'singul-checked' : ''}`}\n style={selected ? customStyles.checkboxChecked : customStyles.checkbox}\n >\n {selected && (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n )}\n </div>\n </div>\n );\n };\n\n return (\n <div\n ref={containerRef}\n className={`singul-container ${inline ? 'singul-inline' : ''} ${className}`}\n style={customStyles.container}\n >\n <div className=\"singul-search-bar-container\">\n <div className=\"singul-search-input-wrapper\" style={customStyles.inputWrapper}>\n <input\n ref={inputRef}\n type=\"text\"\n className=\"singul-search-input\"\n style={customStyles.input}\n placeholder={placeholder}\n value={query}\n onChange={handleInputChange}\n onFocus={() => {\n if (!inline && query.trim() && results.length > 0) {\n setIsOpen(true);\n }\n }}\n onKeyDown={handleKeyDown}\n autoComplete=\"off\"\n />\n <div className=\"singul-search-icon\" style={customStyles.searchIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n </div>\n {isLoading && (\n <div className=\"singul-loading-spinner\" style={customStyles.loadingSpinner}>\n {renderLoadingState ? (\n renderLoadingState()\n ) : (\n <div className=\"singul-spinner\" style={customStyles.spinner} />\n )}\n </div>\n )}\n </div>\n\n {/* Source filter — only shown when private apps are loaded */}\n {showSourceFilter && privateApps.length > 0 && (\n <div className=\"singul-source-filter\" role=\"tablist\" aria-label=\"Filter by app source\">\n {([\n { key: 'all', label: 'All', count: results.length + filteredPrivateApps.length },\n { key: 'public', label: 'Public', count: results.length },\n { key: 'private', label: 'Private', count: filteredPrivateApps.length },\n ] as const).map(opt => (\n <button\n key={opt.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={sourceFilter === opt.key}\n className={`singul-source-pill ${sourceFilter === opt.key ? 'singul-source-pill-active' : ''}`}\n onClick={() => setSourceFilter(opt.key)}\n >\n {opt.label}\n <span className=\"singul-source-count\">{opt.count}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Inline Results Container */}\n {inline && (\n <div\n className={`singul-results-container ${layout === 'grid' ? 'singul-results-grid' : ''}`}\n style={{\n ...customStyles.resultsContainer,\n ...getGridColumnsStyle,\n ...(layout === 'grid' ? { display: 'grid' } : {}),\n }}\n >\n {displayResults.length > 0 ? (\n <>\n {displayResults.map((app, index) => renderAppItem(app, index))}\n <div className=\"singul-end-of-results\" style={{\n padding: '10px 16px',\n color: 'rgba(255, 255, 255, 0.3)',\n textAlign: 'center' as const,\n fontSize: '11px',\n gridColumn: '1 / -1',\n }}>\n Can't find what you're looking for? Try a different search term.\n </div>\n </>\n ) : query.trim() ? (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n {renderEmptyState ? (\n renderEmptyState()\n ) : (\n <>No integrations match \"{query}\". Try searching for a different app or category.</>\n )}\n </div>\n ) : (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n Start typing to search integrations...\n </div>\n )}\n </div>\n )}\n\n {/* Dropdown Results (non-inline mode) */}\n {!inline && isOpen && (\n <div\n className={`singul-dropdown ${layout === 'grid' ? 'singul-dropdown-grid' : ''}`}\n style={{\n ...customStyles.dropdown,\n ...getGridColumnsStyle,\n ...(layout === 'grid' ? { display: 'grid' } : {}),\n }}\n >\n {displayResults.length > 0 ? (\n displayResults.map((app, index) => renderAppItem(app, index))\n ) : (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n {renderEmptyState ? (\n renderEmptyState()\n ) : (\n <>No apps found for \"{query}\"</>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n});\n\nShuffleMCP.displayName = 'ShuffleMCP';\n\nexport default ShuffleMCP;\n"],"mappings":"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","names":["React"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts","../ShuffleMCP.tsx"],"sourcesContent":["/**\n * Local Singul Library\n * This is a local copy for development. Changes here should be merged back to:\n * https://github.com/Shuffle/singul.js\n */\n\nexport { ShuffleMCP, default } from './ShuffleMCP';\nexport type { ShuffleMCPHandle } from './ShuffleMCP';\nexport type {\n AlgoliaSearchApp,\n AppSelectedEvent,\n AppAuthentication,\n CustomStyles,\n ShuffleMCPProps,\n} from './shuffle-mcp.helpers';\n","/**\n * Local Singul Library - React Component\n * This is a local copy for development. Changes here should be merged back to:\n * https://github.com/Shuffle/singul.js\n */\n\nimport React, { useState, useEffect, useRef, useCallback, useMemo, useImperativeHandle } from 'react';\nimport { algoliasearch, SearchClient } from 'algoliasearch';\nimport type { AlgoliaSearchApp, AppSelectedEvent, ShuffleMCPProps, AppAuthentication } from './shuffle-mcp.helpers';\nimport './shuffle-mcp.css';\n\nconst DEFAULT_ALGOLIA_APP_ID = 'JNSS5CFDZZ';\nconst DEFAULT_ALGOLIA_API_KEY = '33e4e3564f4f060e96e0531957bed552';\nconst DEFAULT_ALGOLIA_INDEX = 'appsearch';\n\nexport interface ShuffleMCPHandle {\n search: (query: string) => void;\n clear: () => void;\n}\n\nexport const ShuffleMCP = React.forwardRef<ShuffleMCPHandle, ShuffleMCPProps>(({\n authToken,\n orgId,\n placeholder = 'Search apps...',\n layout = 'list',\n gridColumns = 3,\n showDescription = false,\n showCategories = false,\n showCheckbox = false,\n multiSelect = false,\n selectedApps = [],\n preventDefault = false,\n inline = false,\n initialQuery = '',\n initialFilterQuery,\n hitsPerPage = 15,\n apiKey,\n apiBaseUrl = 'https://shuffler.io',\n authPath = '/api/v1/apps/authentication',\n appAuthPath = '/appauth',\n privateAppsPath = '/api/v1/apps',\n disablePrivateApps = false,\n showSourceFilter = true,\n singulBaseUrl = 'https://singul.io',\n hideAuthStatus = false,\n authenticatedApps: externalAuthenticatedApps,\n pinnedApps,\n algoliaAppId = DEFAULT_ALGOLIA_APP_ID,\n algoliaApiKey = DEFAULT_ALGOLIA_API_KEY,\n algoliaIndexName = DEFAULT_ALGOLIA_INDEX,\n customStyles = {},\n className = '',\n renderItem,\n renderEmptyState,\n renderLoadingState,\n onAppSelected,\n onSelectionChange,\n onSearchChange,\n}, ref) => {\n const [query, setQuery] = useState(initialQuery);\n const [results, setResults] = useState<AlgoliaSearchApp[]>([]);\n const [privateApps, setPrivateApps] = useState<AlgoliaSearchApp[]>([]);\n const [sourceFilter, setSourceFilter] = useState<'all' | 'public' | 'private'>('all');\n const [isLoading, setIsLoading] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [internalSelectedApps, setInternalSelectedApps] = useState<AlgoliaSearchApp[]>(selectedApps);\n const [authenticatedApps, setAuthenticatedApps] = useState<AppAuthentication[]>(externalAuthenticatedApps || []);\n const [drawerApp, setDrawerApp] = useState<AlgoliaSearchApp | null>(null);\n const hasInitialized = useRef(false);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const searchClient = useRef<SearchClient | null>(null);\n\n // Fetch authenticated apps when apiKey is provided\n useEffect(() => {\n if (apiKey) {\n const fetchAuthenticatedApps = async () => {\n try {\n const response = await fetch(`${apiBaseUrl}${authPath}`, {\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n ...(orgId ? { 'Org-Id': orgId } : {}),\n },\n });\n if (response.ok) {\n const result = await response.json();\n // Handle both { success: true, data: [...] } and direct array response\n const authData = result.data || result;\n if (Array.isArray(authData)) {\n console.log('Loaded authenticated apps:', authData.length, authData.map(a => a.app?.name));\n setAuthenticatedApps(authData);\n }\n }\n } catch (error) {\n console.error('Failed to fetch authenticated apps:', error);\n }\n };\n fetchAuthenticatedApps();\n }\n }, [apiKey, apiBaseUrl, orgId]);\n\n // Fetch the user's private apps from /api/v1/apps when apiKey is provided.\n // These get merged into search results so users can find their own apps too.\n useEffect(() => {\n if (!apiKey || disablePrivateApps) {\n setPrivateApps([]);\n return;\n }\n const fetchPrivateApps = async () => {\n try {\n const response = await fetch(`${apiBaseUrl}${privateAppsPath}`, {\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n ...(orgId ? { 'Org-Id': orgId } : {}),\n },\n credentials: 'include',\n });\n if (!response.ok) return;\n const data = await response.json();\n const apps = Array.isArray(data) ? data : (data?.data || []);\n // Normalize to AlgoliaSearchApp shape, tagged as 'private' source.\n const normalized: AlgoliaSearchApp[] = apps.map((a: any) => ({\n name: a.name || '',\n description: a.description || '',\n objectID: a.id || a.objectID || `private-${a.name}`,\n creator: a.owner || a.creator || '',\n app_version: a.app_version || '1.0.0',\n image_url: a.large_image || a.image_url || '',\n time_edited: a.edited || 0,\n generated: !!a.generated,\n invalid: !!a.invalid,\n priority: a.priority || 0,\n actions: Array.isArray(a.actions) ? a.actions.length : (a.actions || 0),\n tags: a.tags || [],\n accessible_by: a.accessible_by || [],\n categories: a.categories || [],\n action_labels: a.action_labels || [],\n triggers: a.triggers || [],\n verified: !!a.verified,\n source: 'private',\n }));\n setPrivateApps(normalized);\n } catch (error) {\n console.error('Failed to fetch private apps:', error);\n }\n };\n fetchPrivateApps();\n }, [apiKey, apiBaseUrl, privateAppsPath, disablePrivateApps, orgId]);\n\n // Auto-select validated apps when they're loaded (validated = tests ran successfully)\n useEffect(() => {\n if (authenticatedApps.length > 0 && results.length > 0) {\n const validatedApps = authenticatedApps.filter(auth => auth.validation?.valid);\n const appsToAutoSelect = results.filter(app => \n validatedApps.some(auth => auth.app.name.toLowerCase() === app.name.toLowerCase())\n );\n \n if (appsToAutoSelect.length > 0) {\n const newSelection = [...internalSelectedApps];\n appsToAutoSelect.forEach(app => {\n if (!newSelection.some(a => a.objectID === app.objectID)) {\n newSelection.push(app);\n }\n });\n if (newSelection.length !== internalSelectedApps.length) {\n setInternalSelectedApps(newSelection);\n onSelectionChange?.(newSelection);\n }\n }\n }\n }, [authenticatedApps, results]);\n\n // Sync external authenticatedApps\n useEffect(() => {\n if (externalAuthenticatedApps) {\n setAuthenticatedApps(externalAuthenticatedApps);\n }\n }, [externalAuthenticatedApps]);\n\n // Initialize Algolia client and run initial search\n useEffect(() => {\n searchClient.current = algoliasearch(algoliaAppId, algoliaApiKey);\n \n // Run initial search after client is ready\n if (!hasInitialized.current) {\n hasInitialized.current = true;\n const searchTerm = initialQuery || initialFilterQuery || '';\n setTimeout(() => {\n if (searchClient.current) {\n performSearch(searchTerm);\n onSearchChange?.(initialQuery); // Only report the visible query\n }\n }, 100);\n }\n }, []);\n\n // Sync external selectedApps\n useEffect(() => {\n setInternalSelectedApps(selectedApps);\n }, [selectedApps]);\n\n // Handle click outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n };\n\n document.addEventListener('click', handleClickOutside);\n return () => document.removeEventListener('click', handleClickOutside);\n }, []);\n\n // Check if an app is configured (found in authentication API with active: true)\n const isAppConfigured = useCallback((app: AlgoliaSearchApp) => {\n return authenticatedApps.some(\n auth => auth.app.name.toLowerCase() === app.name.toLowerCase() && auth.active === true\n );\n }, [authenticatedApps]);\n\n // Check if an app is validated/tested (validation.valid is true)\n const isAppValidated = useCallback((app: AlgoliaSearchApp) => {\n return authenticatedApps.some(\n auth => auth.app.name.toLowerCase() === app.name.toLowerCase() && auth.validation?.valid === true\n );\n }, [authenticatedApps]);\n\n // Get auth state for an app\n const getAppAuthState = useCallback((app: AlgoliaSearchApp) => {\n return {\n configured: isAppConfigured(app),\n validated: isAppValidated(app),\n };\n }, [isAppConfigured, isAppValidated]);\n\n // Perform search\n const performSearch = useCallback(async (searchQuery: string) => {\n if (!searchClient.current) {\n return;\n }\n\n setIsLoading(true);\n try {\n const searchResult = await searchClient.current.searchSingleIndex({\n indexName: algoliaIndexName,\n searchParams: {\n query: searchQuery || '', // Empty string gets top results\n hitsPerPage,\n },\n });\n\n const hits = (searchResult.hits as AlgoliaSearchApp[]).map(h => ({ ...h, source: 'public' as const }));\n setResults(hits);\n setIsOpen(hits.length > 0);\n setSelectedIndex(-1);\n } catch (error) {\n console.error('Search failed:', error);\n setResults([]);\n setIsOpen(false);\n } finally {\n setIsLoading(false);\n }\n }, [hitsPerPage]);\n\n // Expose imperative methods via ref\n useImperativeHandle(ref, () => ({\n search: (searchQuery: string) => {\n setQuery(searchQuery);\n onSearchChange?.(searchQuery);\n performSearch(searchQuery);\n },\n clear: () => {\n setQuery('');\n performSearch(''); // Show top results when cleared\n },\n getQuery: () => query,\n }), [performSearch, onSearchChange, query]);\n\n // Handle input change\n const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n const value = event.target.value;\n setQuery(value);\n setSelectedIndex(-1);\n onSearchChange?.(value);\n\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n debounceTimer.current = setTimeout(() => {\n performSearch(value);\n }, 300);\n }, [performSearch, onSearchChange]);\n\n // Handle app selection\n const selectApp = useCallback((app: AlgoliaSearchApp) => {\n const authUrl = `${apiBaseUrl}${appAuthPath}?app_id=${app.objectID}&auth=${authToken}&source=shuffle${orgId ? `&org_id=${encodeURIComponent(orgId)}` : ''}`;\n\n if (multiSelect) {\n const isAlreadySelected = internalSelectedApps.some((a) => a.objectID === app.objectID);\n const newSelection = isAlreadySelected\n ? internalSelectedApps.filter((a) => a.objectID !== app.objectID)\n : [...internalSelectedApps, app];\n\n setInternalSelectedApps(newSelection);\n onSelectionChange?.(newSelection);\n } else {\n // If consumer wired up onAppSelected, defer entirely to them.\n if (onAppSelected) {\n onAppSelected({ app, authUrl });\n if (!preventDefault) {\n window.open(authUrl, '_blank');\n }\n } else if (!preventDefault) {\n // New default: open built-in side drawer with the app + its existing\n // authentications, instead of popping a new tab to shuffler.io.\n setDrawerApp(app);\n }\n\n setIsOpen(false);\n }\n }, [authToken, apiBaseUrl, appAuthPath, orgId, multiSelect, internalSelectedApps, onAppSelected, onSelectionChange, preventDefault]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, displayResults.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, -1));\n break;\n case 'Enter':\n event.preventDefault();\n if (selectedIndex >= 0 && displayResults[selectedIndex]) {\n selectApp(displayResults[selectedIndex]);\n }\n break;\n case 'Escape':\n event.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.blur();\n break;\n }\n }, [isOpen, results, selectedIndex, selectApp]);\n\n // Check if app is selected\n const isAppSelected = useCallback((app: AlgoliaSearchApp) => {\n return internalSelectedApps.some((a) => a.objectID === app.objectID);\n }, [internalSelectedApps]);\n\n // Filter the user's private apps client-side by the current query.\n const filteredPrivateApps = useMemo(() => {\n if (privateApps.length === 0) return [];\n const q = query.trim().toLowerCase();\n if (!q) return privateApps;\n return privateApps.filter(a =>\n a.name.toLowerCase().includes(q) ||\n (a.description || '').toLowerCase().includes(q) ||\n (a.categories || []).some(c => c.toLowerCase().includes(q))\n );\n }, [privateApps, query]);\n\n // Merge private + public apps, apply source filter, prepend pinned, dedupe by name.\n const displayResults = useMemo(() => {\n const norm = (n: string) => (n || '').toLowerCase().replace(/[\\s_\\-]+/g, '');\n\n let merged: AlgoliaSearchApp[];\n if (sourceFilter === 'public') {\n merged = results;\n } else if (sourceFilter === 'private') {\n merged = filteredPrivateApps;\n } else {\n // 'all' — private apps first (your own tools win), then public, deduped by name\n const privateNames = new Set(filteredPrivateApps.map(a => norm(a.name)));\n const publicOnly = results.filter(a => !privateNames.has(norm(a.name)));\n merged = [...filteredPrivateApps, ...publicOnly];\n }\n\n if (!pinnedApps || pinnedApps.length === 0) return merged;\n const pinnedNames = new Set(pinnedApps.map(a => norm(a.name)));\n return [...pinnedApps, ...merged.filter(a => !pinnedNames.has(norm(a.name)))];\n }, [pinnedApps, results, filteredPrivateApps, sourceFilter]);\n\n // Get grid columns style\n const getGridColumnsStyle = useMemo(() => {\n if (layout !== 'grid') return {};\n \n const cols = typeof gridColumns === 'number' ? gridColumns : gridColumns.md || 3;\n return { '--singul-grid-columns': cols } as React.CSSProperties;\n }, [layout, gridColumns]);\n\n // Render individual app item\n const renderAppItem = (app: AlgoliaSearchApp, index: number) => {\n const selected = isAppSelected(app);\n const isHighlighted = index === selectedIndex;\n const authState = getAppAuthState(app);\n\n // Use custom render if provided\n if (renderItem) {\n return (\n <div\n key={app.objectID}\n onClick={() => selectApp(app)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n {renderItem(app, selected, () => selectApp(app), authState)}\n </div>\n );\n }\n\n // Show both chips (configured/not configured AND tested/not tested)\n return (\n <div\n key={app.objectID}\n className={`singul-dropdown-item ${selected ? 'singul-selected' : ''} ${authState.validated ? 'singul-validated' : ''} ${authState.configured ? 'singul-configured' : ''}`}\n style={{\n ...customStyles.dropdownItem,\n ...(selected ? customStyles.selectedItem : {}),\n }}\n onClick={() => selectApp(app)}\n >\n <div className=\"singul-app-info\" style={customStyles.appInfo}>\n {app.image_url && (\n <div style={{ position: 'relative', flexShrink: 0 }}>\n <img\n src={app.image_url}\n alt={app.name}\n className=\"singul-app-icon\"\n style={customStyles.appIcon}\n />\n {/* Color-coded status dot: green=tested, yellow=configured, blue=activated/selected, gray=inactive */}\n {!hideAuthStatus && (\n <span\n className={`singul-status-dot ${\n authState.validated ? 'singul-dot-validated' :\n authState.configured ? 'singul-dot-configured' :\n selected ? 'singul-dot-activated' :\n 'singul-dot-inactive'\n }`}\n />\n )}\n </div>\n )}\n <div className=\"singul-app-details\" style={customStyles.appDetails}>\n <span className=\"singul-app-name\" style={customStyles.appName}>\n {app.name.replace(/_/g, ' ')}\n {app.source === 'private' && (\n <span className=\"singul-private-badge\" title=\"From your private apps\">Private</span>\n )}\n </span>\n {showDescription && app.description && (\n <span className=\"singul-app-description\" style={customStyles.appDescription}>\n {app.description}\n </span>\n )}\n {showCategories && app.categories?.[0] && (\n <span className=\"singul-app-category\" style={customStyles.appCategory}>\n {app.categories[0]}\n </span>\n )}\n </div>\n {showCheckbox && (\n <div\n className={`singul-checkbox ${selected ? 'singul-checked' : ''}`}\n style={selected ? customStyles.checkboxChecked : customStyles.checkbox}\n >\n {selected && (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n )}\n </div>\n </div>\n );\n };\n\n return (\n <div\n ref={containerRef}\n className={`singul-container ${inline ? 'singul-inline' : ''} ${className}`}\n style={customStyles.container}\n >\n <div className=\"singul-search-bar-container\">\n <div className=\"singul-search-input-wrapper\" style={customStyles.inputWrapper}>\n <input\n ref={inputRef}\n type=\"text\"\n className=\"singul-search-input\"\n style={customStyles.input}\n placeholder={placeholder}\n value={query}\n onChange={handleInputChange}\n onFocus={() => {\n if (!inline && query.trim() && results.length > 0) {\n setIsOpen(true);\n }\n }}\n onKeyDown={handleKeyDown}\n autoComplete=\"off\"\n />\n <div className=\"singul-search-icon\" style={customStyles.searchIcon}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n </div>\n {isLoading && (\n <div className=\"singul-loading-spinner\" style={customStyles.loadingSpinner}>\n {renderLoadingState ? (\n renderLoadingState()\n ) : (\n <div className=\"singul-spinner\" style={customStyles.spinner} />\n )}\n </div>\n )}\n </div>\n\n {/* Source filter — only shown when private apps are loaded */}\n {showSourceFilter && privateApps.length > 0 && (\n <div className=\"singul-source-filter\" role=\"tablist\" aria-label=\"Filter by app source\">\n {([\n { key: 'all', label: 'All', count: results.length + filteredPrivateApps.length },\n { key: 'public', label: 'Public', count: results.length },\n { key: 'private', label: 'Private', count: filteredPrivateApps.length },\n ] as const).map(opt => (\n <button\n key={opt.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={sourceFilter === opt.key}\n className={`singul-source-pill ${sourceFilter === opt.key ? 'singul-source-pill-active' : ''}`}\n onClick={() => setSourceFilter(opt.key)}\n >\n {opt.label}\n <span className=\"singul-source-count\">{opt.count}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Inline Results Container */}\n {inline && (\n <div\n className={`singul-results-container ${layout === 'grid' ? 'singul-results-grid' : ''}`}\n style={{\n ...customStyles.resultsContainer,\n ...getGridColumnsStyle,\n ...(layout === 'grid' ? { display: 'grid' } : {}),\n }}\n >\n {displayResults.length > 0 ? (\n <>\n {displayResults.map((app, index) => renderAppItem(app, index))}\n <div className=\"singul-end-of-results\" style={{\n padding: '10px 16px',\n color: 'rgba(255, 255, 255, 0.3)',\n textAlign: 'center' as const,\n fontSize: '11px',\n gridColumn: '1 / -1',\n }}>\n Can't find what you're looking for? Try a different search term.\n </div>\n </>\n ) : query.trim() ? (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n {renderEmptyState ? (\n renderEmptyState()\n ) : (\n <>No integrations match \"{query}\". Try searching for a different app or category.</>\n )}\n </div>\n ) : (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n Start typing to search integrations...\n </div>\n )}\n </div>\n )}\n\n {/* Dropdown Results (non-inline mode) */}\n {!inline && isOpen && (\n <div\n className={`singul-dropdown ${layout === 'grid' ? 'singul-dropdown-grid' : ''}`}\n style={{\n ...customStyles.dropdown,\n ...getGridColumnsStyle,\n ...(layout === 'grid' ? { display: 'grid' } : {}),\n }}\n >\n {displayResults.length > 0 ? (\n displayResults.map((app, index) => renderAppItem(app, index))\n ) : (\n <div className=\"singul-empty-state\" style={customStyles.emptyState}>\n {renderEmptyState ? (\n renderEmptyState()\n ) : (\n <>No apps found for \"{query}\"</>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Built-in app auth drawer — shown when no custom onAppSelected handler is provided */}\n {drawerApp && (() => {\n const norm = (n: string) => (n || '').toLowerCase().replace(/[\\s_\\-]+/g, '_');\n const matchingAuths = authenticatedApps.filter(\n a => norm(a.app?.name || '') === norm(drawerApp.name)\n );\n const drawerAuthUrl = `${apiBaseUrl}${appAuthPath}?app_id=${drawerApp.objectID}&auth=${authToken}&source=shuffle${orgId ? `&org_id=${encodeURIComponent(orgId)}` : ''}`;\n return (\n <>\n <div className=\"singul-drawer-backdrop\" onClick={() => setDrawerApp(null)} />\n <aside className=\"singul-drawer\" role=\"dialog\" aria-label={`${drawerApp.name} configuration`}>\n <header className=\"singul-drawer-header\">\n <div className=\"singul-drawer-title-row\">\n {drawerApp.image_url && (\n <img src={drawerApp.image_url} alt={drawerApp.name} className=\"singul-drawer-icon\" />\n )}\n <div>\n <div className=\"singul-drawer-title\">{drawerApp.name.replace(/_/g, ' ')}</div>\n <div className=\"singul-drawer-subtitle\">App configuration</div>\n </div>\n </div>\n <button\n type=\"button\"\n className=\"singul-drawer-close\"\n onClick={() => setDrawerApp(null)}\n aria-label=\"Close\"\n >×</button>\n </header>\n\n <div className=\"singul-drawer-body\">\n {drawerApp.description && (\n <p className=\"singul-drawer-desc\">{drawerApp.description}</p>\n )}\n\n <div className=\"singul-drawer-section-title\">\n Authentication\n <span className=\"singul-drawer-count\">\n {matchingAuths.length} configuration{matchingAuths.length === 1 ? '' : 's'} found\n </span>\n </div>\n\n {matchingAuths.length > 0 ? (\n <ul className=\"singul-drawer-auth-list\">\n {matchingAuths.map(a => (\n <li key={a.id} className=\"singul-drawer-auth-item\">\n <div className=\"singul-drawer-auth-label\">{a.label || 'Untitled'}</div>\n <div className=\"singul-drawer-auth-chips\">\n {a.active && <span className=\"singul-chip singul-chip-configured\">Configured</span>}\n {a.validation?.valid && <span className=\"singul-chip singul-chip-tested\">Tested</span>}\n {!a.active && <span className=\"singul-chip singul-chip-inactive\">Inactive</span>}\n </div>\n </li>\n ))}\n </ul>\n ) : (\n <div className=\"singul-drawer-empty\">No authentications yet for this app.</div>\n )}\n\n <a\n href={drawerAuthUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"singul-drawer-cta\"\n >\n {matchingAuths.length > 0 ? 'Manage authentication' : 'Add authentication'}\n </a>\n </div>\n </aside>\n </>\n );\n })()}\n </div>\n );\n});\n\nShuffleMCP.displayName = 'ShuffleMCP';\n\nexport default ShuffleMCP;\n"],"mappings":"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","names":["React"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -84,6 +84,12 @@ interface AppAuthentication {
|
|
|
84
84
|
}
|
|
85
85
|
interface ShuffleMCPProps {
|
|
86
86
|
authToken: string;
|
|
87
|
+
/**
|
|
88
|
+
* Optional Shuffle organization ID. When provided, every API call this
|
|
89
|
+
* component makes (Shuffle backend + Singul gateway) will include an
|
|
90
|
+
* `Org-Id: <orgId>` header so the request is scoped to that org.
|
|
91
|
+
*/
|
|
92
|
+
orgId?: string;
|
|
87
93
|
placeholder?: string;
|
|
88
94
|
layout?: 'list' | 'grid';
|
|
89
95
|
gridColumns?: number | {
|
package/dist/index.d.ts
CHANGED
|
@@ -84,6 +84,12 @@ interface AppAuthentication {
|
|
|
84
84
|
}
|
|
85
85
|
interface ShuffleMCPProps {
|
|
86
86
|
authToken: string;
|
|
87
|
+
/**
|
|
88
|
+
* Optional Shuffle organization ID. When provided, every API call this
|
|
89
|
+
* component makes (Shuffle backend + Singul gateway) will include an
|
|
90
|
+
* `Org-Id: <orgId>` header so the request is scoped to that org.
|
|
91
|
+
*/
|
|
92
|
+
orgId?: string;
|
|
87
93
|
placeholder?: string;
|
|
88
94
|
layout?: 'list' | 'grid';
|
|
89
95
|
gridColumns?: number | {
|