@shuffleio/shuffle-mcps 0.0.3 → 0.0.5
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 +170 -17
- package/dist/index.cjs +5332 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +341 -5
- package/dist/index.d.ts +341 -5
- package/dist/index.js +5364 -169
- package/dist/index.js.map +1 -1
- package/dist/{singul-GZKBHJNI.css → shuffle-mcp-JQWKQNUP.css} +357 -21
- package/package.json +18 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../ShuffleMCP.tsx"],"sourcesContent":["/**\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":";AAMA,OAAO,SAAS,UAAU,WAAW,QAAQ,aAAa,SAAS,2BAA2B;AAC9F,SAAS,qBAAmC;AAE5C,OAAO;AAuYC,SAyJM,UAzJN,KAuBI,YAvBJ;AArYR,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAOvB,IAAM,aAAa,MAAM,WAA8C,CAAC;AAAA,EAC7E;AAAA,EACA,cAAc;AAAA,EACd,SAAS;AAAA,EACT,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,eAAe,CAAC;AAAA,EAChB,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,eAAe;AAAA,EACf;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,aAAa;AAAA,EACb,WAAW;AAAA,EACX,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB;AAAA,EACA,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,eAAe,CAAC;AAAA,EAChB,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAG,QAAQ;AACT,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,YAAY;AAC/C,QAAM,CAAC,SAAS,UAAU,IAAI,SAA6B,CAAC,CAAC;AAC7D,QAAM,CAAC,aAAa,cAAc,IAAI,SAA6B,CAAC,CAAC;AACrE,QAAM,CAAC,cAAc,eAAe,IAAI,SAAuC,KAAK;AACpF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,EAAE;AACrD,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,SAA6B,YAAY;AACjG,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAA8B,6BAA6B,CAAC,CAAC;AAC/G,QAAM,iBAAiB,OAAO,KAAK;AAEnC,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,WAAW,OAAyB,IAAI;AAC9C,QAAM,gBAAgB,OAA6C,IAAI;AACvE,QAAM,eAAe,OAA4B,IAAI;AAGrD,YAAU,MAAM;AACd,QAAI,QAAQ;AACV,YAAM,yBAAyB,YAAY;AACzC,YAAI;AACF,gBAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,QAAQ,IAAI;AAAA,YACvD,SAAS;AAAA,cACP,iBAAiB,UAAU,MAAM;AAAA,YACnC;AAAA,UACF,CAAC;AACD,cAAI,SAAS,IAAI;AACf,kBAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,kBAAM,WAAW,OAAO,QAAQ;AAChC,gBAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,sBAAQ,IAAI,8BAA8B,SAAS,QAAQ,SAAS,IAAI,OAAK,EAAE,KAAK,IAAI,CAAC;AACzF,mCAAqB,QAAQ;AAAA,YAC/B;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AACd,kBAAQ,MAAM,uCAAuC,KAAK;AAAA,QAC5D;AAAA,MACF;AACA,6BAAuB;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,CAAC;AAIvB,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,oBAAoB;AACjC,qBAAe,CAAC,CAAC;AACjB;AAAA,IACF;AACA,UAAM,mBAAmB,YAAY;AACnC,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,eAAe,IAAI;AAAA,UAC9D,SAAS,EAAE,iBAAiB,UAAU,MAAM,GAAG;AAAA,UAC/C,aAAa;AAAA,QACf,CAAC;AACD,YAAI,CAAC,SAAS,GAAI;AAClB,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,cAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAQ,MAAM,QAAQ,CAAC;AAE1D,cAAM,aAAiC,KAAK,IAAI,CAAC,OAAY;AAAA,UAC3D,MAAM,EAAE,QAAQ;AAAA,UAChB,aAAa,EAAE,eAAe;AAAA,UAC9B,UAAU,EAAE,MAAM,EAAE,YAAY,WAAW,EAAE,IAAI;AAAA,UACjD,SAAS,EAAE,SAAS,EAAE,WAAW;AAAA,UACjC,aAAa,EAAE,eAAe;AAAA,UAC9B,WAAW,EAAE,eAAe,EAAE,aAAa;AAAA,UAC3C,aAAa,EAAE,UAAU;AAAA,UACzB,WAAW,CAAC,CAAC,EAAE;AAAA,UACf,SAAS,CAAC,CAAC,EAAE;AAAA,UACb,UAAU,EAAE,YAAY;AAAA,UACxB,SAAS,MAAM,QAAQ,EAAE,OAAO,IAAI,EAAE,QAAQ,SAAU,EAAE,WAAW;AAAA,UACrE,MAAM,EAAE,QAAQ,CAAC;AAAA,UACjB,eAAe,EAAE,iBAAiB,CAAC;AAAA,UACnC,YAAY,EAAE,cAAc,CAAC;AAAA,UAC7B,eAAe,EAAE,iBAAiB,CAAC;AAAA,UACnC,UAAU,EAAE,YAAY,CAAC;AAAA,UACzB,UAAU,CAAC,CAAC,EAAE;AAAA,UACd,QAAQ;AAAA,QACV,EAAE;AACF,uBAAe,UAAU;AAAA,MAC3B,SAAS,OAAO;AACd,gBAAQ,MAAM,iCAAiC,KAAK;AAAA,MACtD;AAAA,IACF;AACA,qBAAiB;AAAA,EACnB,GAAG,CAAC,QAAQ,YAAY,iBAAiB,kBAAkB,CAAC;AAG5D,YAAU,MAAM;AACd,QAAI,kBAAkB,SAAS,KAAK,QAAQ,SAAS,GAAG;AACtD,YAAM,gBAAgB,kBAAkB,OAAO,UAAQ,KAAK,YAAY,KAAK;AAC7E,YAAM,mBAAmB,QAAQ;AAAA,QAAO,SACtC,cAAc,KAAK,UAAQ,KAAK,IAAI,KAAK,YAAY,MAAM,IAAI,KAAK,YAAY,CAAC;AAAA,MACnF;AAEA,UAAI,iBAAiB,SAAS,GAAG;AAC/B,cAAM,eAAe,CAAC,GAAG,oBAAoB;AAC7C,yBAAiB,QAAQ,SAAO;AAC9B,cAAI,CAAC,aAAa,KAAK,OAAK,EAAE,aAAa,IAAI,QAAQ,GAAG;AACxD,yBAAa,KAAK,GAAG;AAAA,UACvB;AAAA,QACF,CAAC;AACD,YAAI,aAAa,WAAW,qBAAqB,QAAQ;AACvD,kCAAwB,YAAY;AACpC,8BAAoB,YAAY;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,mBAAmB,OAAO,CAAC;AAG/B,YAAU,MAAM;AACd,QAAI,2BAA2B;AAC7B,2BAAqB,yBAAyB;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,yBAAyB,CAAC;AAG9B,YAAU,MAAM;AACd,iBAAa,UAAU,cAAc,cAAc,aAAa;AAGhE,QAAI,CAAC,eAAe,SAAS;AAC3B,qBAAe,UAAU;AACzB,YAAM,aAAa,gBAAgB,sBAAsB;AACzD,iBAAW,MAAM;AACf,YAAI,aAAa,SAAS;AACxB,wBAAc,UAAU;AACxB,2BAAiB,YAAY;AAAA,QAC/B;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACd,4BAAwB,YAAY;AAAA,EACtC,GAAG,CAAC,YAAY,CAAC;AAGjB,YAAU,MAAM;AACd,UAAM,qBAAqB,CAAC,UAAsB;AAChD,UAAI,aAAa,WAAW,CAAC,aAAa,QAAQ,SAAS,MAAM,MAAc,GAAG;AAChF,kBAAU,KAAK;AACf,yBAAiB,EAAE;AAAA,MACrB;AAAA,IACF;AAEA,aAAS,iBAAiB,SAAS,kBAAkB;AACrD,WAAO,MAAM,SAAS,oBAAoB,SAAS,kBAAkB;AAAA,EACvE,GAAG,CAAC,CAAC;AAGL,QAAM,kBAAkB,YAAY,CAAC,QAA0B;AAC7D,WAAO,kBAAkB;AAAA,MACvB,UAAQ,KAAK,IAAI,KAAK,YAAY,MAAM,IAAI,KAAK,YAAY,KAAK,KAAK,WAAW;AAAA,IACpF;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAGtB,QAAM,iBAAiB,YAAY,CAAC,QAA0B;AAC5D,WAAO,kBAAkB;AAAA,MACvB,UAAQ,KAAK,IAAI,KAAK,YAAY,MAAM,IAAI,KAAK,YAAY,KAAK,KAAK,YAAY,UAAU;AAAA,IAC/F;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAGtB,QAAM,kBAAkB,YAAY,CAAC,QAA0B;AAC7D,WAAO;AAAA,MACL,YAAY,gBAAgB,GAAG;AAAA,MAC/B,WAAW,eAAe,GAAG;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAGpC,QAAM,gBAAgB,YAAY,OAAO,gBAAwB;AAC/D,QAAI,CAAC,aAAa,SAAS;AACzB;AAAA,IACF;AAEA,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,eAAe,MAAM,aAAa,QAAQ,kBAAkB;AAAA,QAChE,WAAW;AAAA,QACX,cAAc;AAAA,UACZ,OAAO,eAAe;AAAA;AAAA,UACtB;AAAA,QACF;AAAA,MACF,CAAC;AAED,YAAM,OAAQ,aAAa,KAA4B,IAAI,QAAM,EAAE,GAAG,GAAG,QAAQ,SAAkB,EAAE;AACrG,iBAAW,IAAI;AACf,gBAAU,KAAK,SAAS,CAAC;AACzB,uBAAiB,EAAE;AAAA,IACrB,SAAS,OAAO;AACd,cAAQ,MAAM,kBAAkB,KAAK;AACrC,iBAAW,CAAC,CAAC;AACb,gBAAU,KAAK;AAAA,IACjB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAGhB,sBAAoB,KAAK,OAAO;AAAA,IAC9B,QAAQ,CAAC,gBAAwB;AAC/B,eAAS,WAAW;AACpB,uBAAiB,WAAW;AAC5B,oBAAc,WAAW;AAAA,IAC3B;AAAA,IACA,OAAO,MAAM;AACX,eAAS,EAAE;AACX,oBAAc,EAAE;AAAA,IAClB;AAAA,IACA,UAAU,MAAM;AAAA,EAClB,IAAI,CAAC,eAAe,gBAAgB,KAAK,CAAC;AAG1C,QAAM,oBAAoB,YAAY,CAAC,UAA+C;AACpF,UAAM,QAAQ,MAAM,OAAO;AAC3B,aAAS,KAAK;AACd,qBAAiB,EAAE;AACnB,qBAAiB,KAAK;AAEtB,QAAI,cAAc,SAAS;AACzB,mBAAa,cAAc,OAAO;AAAA,IACpC;AAEA,kBAAc,UAAU,WAAW,MAAM;AACvC,oBAAc,KAAK;AAAA,IACrB,GAAG,GAAG;AAAA,EACR,GAAG,CAAC,eAAe,cAAc,CAAC;AAGlC,QAAM,YAAY,YAAY,CAAC,QAA0B;AACvD,UAAM,UAAU,GAAG,UAAU,GAAG,WAAW,WAAW,IAAI,QAAQ,SAAS,SAAS;AAEpF,QAAI,aAAa;AACf,YAAM,oBAAoB,qBAAqB,KAAK,CAAC,MAAM,EAAE,aAAa,IAAI,QAAQ;AACtF,YAAM,eAAe,oBACjB,qBAAqB,OAAO,CAAC,MAAM,EAAE,aAAa,IAAI,QAAQ,IAC9D,CAAC,GAAG,sBAAsB,GAAG;AAEjC,8BAAwB,YAAY;AACpC,0BAAoB,YAAY;AAAA,IAClC,OAAO;AACL,sBAAgB,EAAE,KAAK,QAAQ,CAAC;AAEhC,UAAI,CAAC,gBAAgB;AACnB,eAAO,KAAK,SAAS,QAAQ;AAAA,MAC/B;AAEA,gBAAU,KAAK;AACf,eAAS,EAAE;AACX,iBAAW,CAAC,CAAC;AAAA,IACf;AAAA,EACF,GAAG,CAAC,WAAW,YAAY,aAAa,aAAa,sBAAsB,eAAe,mBAAmB,cAAc,CAAC;AAG5H,QAAM,gBAAgB,YAAY,CAAC,UAA+B;AAChE,QAAI,CAAC,OAAQ;AAEb,YAAQ,MAAM,KAAK;AAAA,MACjB,KAAK;AACH,cAAM,eAAe;AACrB,yBAAiB,CAAC,SAAS,KAAK,IAAI,OAAO,GAAG,eAAe,SAAS,CAAC,CAAC;AACxE;AAAA,MACF,KAAK;AACH,cAAM,eAAe;AACrB,yBAAiB,CAAC,SAAS,KAAK,IAAI,OAAO,GAAG,EAAE,CAAC;AACjD;AAAA,MACF,KAAK;AACH,cAAM,eAAe;AACrB,YAAI,iBAAiB,KAAK,eAAe,aAAa,GAAG;AACvD,oBAAU,eAAe,aAAa,CAAC;AAAA,QACzC;AACA;AAAA,MACF,KAAK;AACH,cAAM,eAAe;AACrB,kBAAU,KAAK;AACf,yBAAiB,EAAE;AACnB,iBAAS,SAAS,KAAK;AACvB;AAAA,IACJ;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,eAAe,SAAS,CAAC;AAG9C,QAAM,gBAAgB,YAAY,CAAC,QAA0B;AAC3D,WAAO,qBAAqB,KAAK,CAAC,MAAM,EAAE,aAAa,IAAI,QAAQ;AAAA,EACrE,GAAG,CAAC,oBAAoB,CAAC;AAGzB,QAAM,sBAAsB,QAAQ,MAAM;AACxC,QAAI,YAAY,WAAW,EAAG,QAAO,CAAC;AACtC,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,YAAY;AAAA,MAAO,OACxB,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,MAC9B,EAAE,eAAe,IAAI,YAAY,EAAE,SAAS,CAAC,MAC7C,EAAE,cAAc,CAAC,GAAG,KAAK,OAAK,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF,GAAG,CAAC,aAAa,KAAK,CAAC;AAGvB,QAAM,iBAAiB,QAAQ,MAAM;AACnC,UAAM,OAAO,CAAC,OAAe,KAAK,IAAI,YAAY,EAAE,QAAQ,aAAa,EAAE;AAE3E,QAAI;AACJ,QAAI,iBAAiB,UAAU;AAC7B,eAAS;AAAA,IACX,WAAW,iBAAiB,WAAW;AACrC,eAAS;AAAA,IACX,OAAO;AAEL,YAAM,eAAe,IAAI,IAAI,oBAAoB,IAAI,OAAK,KAAK,EAAE,IAAI,CAAC,CAAC;AACvE,YAAM,aAAa,QAAQ,OAAO,OAAK,CAAC,aAAa,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC;AACtE,eAAS,CAAC,GAAG,qBAAqB,GAAG,UAAU;AAAA,IACjD;AAEA,QAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;AACnD,UAAM,cAAc,IAAI,IAAI,WAAW,IAAI,OAAK,KAAK,EAAE,IAAI,CAAC,CAAC;AAC7D,WAAO,CAAC,GAAG,YAAY,GAAG,OAAO,OAAO,OAAK,CAAC,YAAY,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,EAC9E,GAAG,CAAC,YAAY,SAAS,qBAAqB,YAAY,CAAC;AAG3D,QAAM,sBAAsB,QAAQ,MAAM;AACxC,QAAI,WAAW,OAAQ,QAAO,CAAC;AAE/B,UAAM,OAAO,OAAO,gBAAgB,WAAW,cAAc,YAAY,MAAM;AAC/E,WAAO,EAAE,yBAAyB,KAAK;AAAA,EACzC,GAAG,CAAC,QAAQ,WAAW,CAAC;AAGxB,QAAM,gBAAgB,CAAC,KAAuB,UAAkB;AAC9D,UAAM,WAAW,cAAc,GAAG;AAClC,UAAM,gBAAgB,UAAU;AAChC,UAAM,YAAY,gBAAgB,GAAG;AAGrC,QAAI,YAAY;AACd,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM,UAAU,GAAG;AAAA,UAC5B,cAAc,MAAM,iBAAiB,KAAK;AAAA,UAEzC,qBAAW,KAAK,UAAU,MAAM,UAAU,GAAG,GAAG,SAAS;AAAA;AAAA,QAJrD,IAAI;AAAA,MAKX;AAAA,IAEJ;AAGA,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,wBAAwB,WAAW,oBAAoB,EAAE,IAAI,UAAU,YAAY,qBAAqB,EAAE,IAAI,UAAU,aAAa,sBAAsB,EAAE;AAAA,QACxK,OAAO;AAAA,UACL,GAAG,aAAa;AAAA,UAChB,GAAI,WAAW,aAAa,eAAe,CAAC;AAAA,QAC9C;AAAA,QACA,SAAS,MAAM,UAAU,GAAG;AAAA,QAE5B,+BAAC,SAAI,WAAU,mBAAkB,OAAO,aAAa,SAClD;AAAA,cAAI,aACH,qBAAC,SAAI,OAAO,EAAE,UAAU,YAAY,YAAY,EAAE,GAChD;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK,IAAI;AAAA,gBACT,KAAK,IAAI;AAAA,gBACT,WAAU;AAAA,gBACV,OAAO,aAAa;AAAA;AAAA,YACtB;AAAA,YAEC,CAAC,kBACA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,qBACT,UAAU,YAAY,yBACtB,UAAU,aAAa,0BACvB,WAAW,yBACX,qBACF;AAAA;AAAA,YACF;AAAA,aAEJ;AAAA,UAEF,qBAAC,SAAI,WAAU,sBAAqB,OAAO,aAAa,YACtD;AAAA,iCAAC,UAAK,WAAU,mBAAkB,OAAO,aAAa,SACnD;AAAA,kBAAI,KAAK,QAAQ,MAAM,GAAG;AAAA,cAC1B,IAAI,WAAW,aACd,oBAAC,UAAK,WAAU,wBAAuB,OAAM,0BAAyB,qBAAO;AAAA,eAEjF;AAAA,YACC,mBAAmB,IAAI,eACtB,oBAAC,UAAK,WAAU,0BAAyB,OAAO,aAAa,gBAC1D,cAAI,aACP;AAAA,YAED,kBAAkB,IAAI,aAAa,CAAC,KACnC,oBAAC,UAAK,WAAU,uBAAsB,OAAO,aAAa,aACvD,cAAI,WAAW,CAAC,GACnB;AAAA,aAEJ;AAAA,UACC,gBACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,mBAAmB,WAAW,mBAAmB,EAAE;AAAA,cAC9D,OAAO,WAAW,aAAa,kBAAkB,aAAa;AAAA,cAE7D,sBACC,oBAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KACrE,8BAAC,cAAS,QAAO,kBAAiB,GACpC;AAAA;AAAA,UAEJ;AAAA,WAEJ;AAAA;AAAA,MA5DK,IAAI;AAAA,IA6DX;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,oBAAoB,SAAS,kBAAkB,EAAE,IAAI,SAAS;AAAA,MACzE,OAAO,aAAa;AAAA,MAEpB,+BAAC,SAAI,WAAU,+BACb;AAAA,6BAAC,SAAI,WAAU,+BAA8B,OAAO,aAAa,cAC/D;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,WAAU;AAAA,cACV,OAAO,aAAa;AAAA,cACpB;AAAA,cACA,OAAO;AAAA,cACP,UAAU;AAAA,cACV,SAAS,MAAM;AACb,oBAAI,CAAC,UAAU,MAAM,KAAK,KAAK,QAAQ,SAAS,GAAG;AACjD,4BAAU,IAAI;AAAA,gBAChB;AAAA,cACF;AAAA,cACA,WAAW;AAAA,cACX,cAAa;AAAA;AAAA,UACf;AAAA,UACA,oBAAC,SAAI,WAAU,sBAAqB,OAAO,aAAa,YACtD,+BAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAC5F;AAAA,gCAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,YAC9B,oBAAC,UAAK,GAAE,oBAAmB;AAAA,aAC7B,GACF;AAAA,UACC,aACC,oBAAC,SAAI,WAAU,0BAAyB,OAAO,aAAa,gBACzD,+BACC,mBAAmB,IAEnB,oBAAC,SAAI,WAAU,kBAAiB,OAAO,aAAa,SAAS,GAEjE;AAAA,WAEJ;AAAA,QAGC,oBAAoB,YAAY,SAAS,KACxC,oBAAC,SAAI,WAAU,wBAAuB,MAAK,WAAU,cAAW,wBAC5D;AAAA,UACA,EAAE,KAAK,OAAO,OAAO,OAAO,OAAO,QAAQ,SAAS,oBAAoB,OAAO;AAAA,UAC/E,EAAE,KAAK,UAAU,OAAO,UAAU,OAAO,QAAQ,OAAO;AAAA,UACxD,EAAE,KAAK,WAAW,OAAO,WAAW,OAAO,oBAAoB,OAAO;AAAA,QACxE,EAAY,IAAI,SACd;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,iBAAe,iBAAiB,IAAI;AAAA,YACpC,WAAW,sBAAsB,iBAAiB,IAAI,MAAM,8BAA8B,EAAE;AAAA,YAC5F,SAAS,MAAM,gBAAgB,IAAI,GAAG;AAAA,YAErC;AAAA,kBAAI;AAAA,cACL,oBAAC,UAAK,WAAU,uBAAuB,cAAI,OAAM;AAAA;AAAA;AAAA,UAR5C,IAAI;AAAA,QASX,CACD,GACH;AAAA,QAID,UACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,4BAA4B,WAAW,SAAS,wBAAwB,EAAE;AAAA,YACrF,OAAO;AAAA,cACL,GAAG,aAAa;AAAA,cAChB,GAAG;AAAA,cACH,GAAI,WAAW,SAAS,EAAE,SAAS,OAAO,IAAI,CAAC;AAAA,YACjD;AAAA,YAEC,yBAAe,SAAS,IACvB,iCACG;AAAA,6BAAe,IAAI,CAAC,KAAK,UAAU,cAAc,KAAK,KAAK,CAAC;AAAA,cAC7D,oBAAC,SAAI,WAAU,yBAAwB,OAAO;AAAA,gBAC5C,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP,WAAW;AAAA,gBACX,UAAU;AAAA,gBACV,YAAY;AAAA,cACd,GAAG,8EAEH;AAAA,eACF,IACE,MAAM,KAAK,IACb,oBAAC,SAAI,WAAU,sBAAqB,OAAO,aAAa,YACrD,6BACC,iBAAiB,IAEjB,iCAAE;AAAA;AAAA,cAAwB;AAAA,cAAM;AAAA,eAAiD,GAErF,IAEA,oBAAC,SAAI,WAAU,sBAAqB,OAAO,aAAa,YAAY,oDAEpE;AAAA;AAAA,QAEJ;AAAA,QAID,CAAC,UAAU,UACV;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,mBAAmB,WAAW,SAAS,yBAAyB,EAAE;AAAA,YAC7E,OAAO;AAAA,cACL,GAAG,aAAa;AAAA,cAChB,GAAG;AAAA,cACH,GAAI,WAAW,SAAS,EAAE,SAAS,OAAO,IAAI,CAAC;AAAA,YACjD;AAAA,YAEC,yBAAe,SAAS,IACvB,eAAe,IAAI,CAAC,KAAK,UAAU,cAAc,KAAK,KAAK,CAAC,IAE5D,oBAAC,SAAI,WAAU,sBAAqB,OAAO,aAAa,YACrD,6BACC,iBAAiB,IAEjB,iCAAE;AAAA;AAAA,cAAoB;AAAA,cAAM;AAAA,eAAC,GAEjC;AAAA;AAAA,QAEJ;AAAA,SAEJ;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,WAAW,cAAc;AAEzB,IAAO,qBAAQ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../ShuffleMCP.tsx","../AppDetailDrawer.tsx","../api.ts","../datastore.ts","../useAppAuth.ts","../IntegrationStatus.tsx","../authenticatedApps.ts","../auth-utils.ts","../AppDetailContext.tsx","../ingestionDetection.ts","../AppTitleHeader.tsx","../AppAuthSection.tsx","../AppAuthConfig.tsx","../toast.ts","../TryMcpSection.tsx","../AppMcpChat.tsx","../AgentIcon.tsx","../SingulActionsPreview.tsx","../AppSearchDrawer.tsx","../ShufflePipelinesBanner.tsx","../useAppLookup.ts"],"sourcesContent":["/**\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 AppDetailDrawer from './AppDetailDrawer';\nimport './shuffle-mcp.css';\n\nconst DEFAULT_ALGOLIA_APP_ID = 'JNSS5CFDZZ';\nconst DEFAULT_ALGOLIA_API_KEY = '33e4e3564f4f060e96e0531957bed552';\nconst DEFAULT_ALGOLIA_INDEX = 'appsearch';\nconst EMPTY_SELECTED_APPS: AlgoliaSearchApp[] = [];\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 = EMPTY_SELECTED_APPS,\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 const fetchAuthenticatedApps = useCallback(async () => {\n if (!apiKey) return;\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 const authData = result.data || result;\n if (Array.isArray(authData)) {\n setAuthenticatedApps(authData);\n }\n }\n } catch (error) {\n console.error('Failed to fetch authenticated apps:', error);\n }\n }, [apiKey, apiBaseUrl, authPath, orgId]);\n\n useEffect(() => {\n fetchAuthenticatedApps();\n }, [fetchAuthenticatedApps]);\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 (disablePrivateApps) {\n setPrivateApps([]);\n return;\n }\n const fetchPrivateApps = async () => {\n try {\n const response = await fetch(`${apiBaseUrl}${privateAppsPath}`, {\n headers: {\n // apiKey is optional — if omitted we rely on the browser session\n // cookie (credentials: 'include'), which is how prod usually auths.\n ...(apiKey ? { 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 // Open dropdown if we got Algolia hits OR we have private apps to show\n setIsOpen(hits.length > 0 || privateApps.length > 0);\n setSelectedIndex(-1);\n } catch (error) {\n // Algolia rate-limit (429) or network error: don't blank out the dropdown\n // if we still have private apps to show from /api/v1/apps.\n console.error('Search failed:', error);\n setResults([]);\n setIsOpen(privateApps.length > 0);\n } finally {\n setIsLoading(false);\n }\n }, [hitsPerPage, algoliaIndexName, privateApps.length]);\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 handoffToken = apiKey || authToken || '';\n const authUrl = `${apiBaseUrl}${appAuthPath}?app_id=${app.objectID}&auth=${handoffToken}&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, apiKey, 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 config drawer — same drawer used by /incidents Add ingestion source */}\n {drawerApp && (\n <AppDetailDrawer\n open={true}\n appName={drawerApp.name}\n anchor=\"right\"\n width={560}\n onClose={() => setDrawerApp(null)}\n onRefresh={fetchAuthenticatedApps}\n />\n )}\n </div>\n );\n});\n\nShuffleMCP.displayName = 'ShuffleMCP';\n\nexport default ShuffleMCP;\n","/**\n * AppDetailDrawer — Shows app detail content (header, auth, MCP chat, API viewer)\n * inside a drawer. Used from alluvial diagrams and the app search drawer.\n *\n * Accepts either an app name (fetches data) or pre-loaded app info.\n */\n\nimport { useState, useEffect, useMemo, useCallback, useRef } from 'react';\nimport { toast } from 'sonner';\nimport { Download, Forward } from 'lucide-react';\nimport { getDatastoreByCategory, DATASTORE_CATEGORIES } from '@/Shuffle-MCPs/datastore';\nimport {\n Box,\n Typography,\n Avatar,\n Chip,\n IconButton,\n Skeleton,\n Button,\n Divider,\n Drawer,\n Autocomplete,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n} from '@mui/material';\nimport CloseIcon from '@mui/icons-material/Close';\nimport PlayArrowIcon from '@mui/icons-material/PlayArrow';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { motion } from 'framer-motion';\nimport { AppAuthCard } from '@/Shuffle-MCPs/AppAuthConfig';\nimport AppMcpChat from '@/Shuffle-MCPs/AppMcpChat';\nimport ApiCallViewer from '@/Shuffle-MCPs/ApiCallViewer';\nimport type { AlgoliaSearchApp } from './shuffle-mcp.helpers';\nimport { useAppAuth } from '@/Shuffle-MCPs/useAppAuth';\nimport { API_CONFIG, getApiUrl, getAuthHeader, getTrackedOrgId } from '@/Shuffle-MCPs/api';\nimport AppTitleHeader from './AppTitleHeader';\nimport AppAuthSection from './AppAuthSection';\nimport TryMcpSection from './TryMcpSection';\nimport SingulActionsPreview from './SingulActionsPreview';\n// AuthContext detached — consumers can pass `isAuthenticated` as a prop. Defaults to true.\n\ninterface AppInfo {\n name: string;\n description: string;\n large_image?: string;\n categories?: string[];\n authentication?: {\n type?: string;\n parameters?: { id: string; name: string; description: string; example: string; required: boolean }[];\n };\n}\n\n/** Collapsible markdown description */\nconst CollapsibleDescription = ({ description }: { description: string }) => {\n const [expanded, setExpanded] = useState(false);\n return (\n <Box\n onClick={() => setExpanded(prev => !prev)}\n sx={{\n cursor: 'pointer',\n position: 'relative',\n ...(!expanded && {\n maxHeight: '5em',\n overflow: 'hidden',\n '&::after': {\n content: '\"\"',\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: 32,\n background: 'linear-gradient(transparent, hsl(var(--card)))',\n pointerEvents: 'none',\n },\n }),\n '& p': { fontSize: '0.78rem', lineHeight: 1.5, color: 'hsl(var(--muted-foreground))', m: 0, '&:not(:last-child)': { mb: 1 } },\n '& a': { color: 'hsl(var(--primary))', textDecoration: 'underline' },\n '& code': { fontSize: '0.7rem', fontFamily: \"'JetBrains Mono', monospace\", bgcolor: 'hsl(var(--muted))', px: 0.5, borderRadius: 0.5 },\n '& ul, & ol': { pl: 2, fontSize: '0.78rem', color: 'hsl(var(--muted-foreground))' },\n }}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{description}</ReactMarkdown>\n {!expanded && (\n <Typography sx={{ fontSize: '0.68rem', color: 'hsl(var(--primary))', mt: 0.5, fontWeight: 500 }}>Show more…</Typography>\n )}\n </Box>\n );\n};\n\n/**\n * Singul standard actions catalog, keyed by lowercase category fragment.\n * Mirrors the canonical action names exposed by https://singul.io —\n * each name becomes the `{action}` segment in `POST /api/{action}`.\n * Fields shown here are starter parameters; the full schema lives on\n * the Singul side and is editable in the curl preview below.\n */\n\ninterface AppDetailDrawerProps {\n open: boolean;\n onClose: () => void;\n /** App name to load */\n appName: string | null;\n /** Anchor side */\n anchor?: 'left' | 'right';\n /** Width in px */\n width?: number;\n /** Called when drawer closes so parent can refresh data */\n onRefresh?: () => void;\n /** When set, replaces the Activate button with \"+ Add\" and calls this on click */\n onAddToCanvas?: (appInfo: { name: string; icon: string; algoliaId: string | null }) => void;\n /** Whether the current user is authenticated. Defaults to true. */\n isAuthenticated?: boolean;\n /** Host app's currently active org id. If different from the library's tracked org,\n * an `Org-Id` header is injected into the Singul curl preview. */\n activeOrgId?: string | null;\n}\n\nexport default function AppDetailDrawer({\n open,\n onClose,\n appName,\n anchor = 'right',\n width = 520,\n onRefresh,\n onAddToCanvas,\n isAuthenticated = true,\n activeOrgId,\n}: AppDetailDrawerProps) {\n const [appInfo, setAppInfo] = useState<AppInfo | null>(null);\n const [appLoading, setAppLoading] = useState(false);\n const [isActivated, setIsActivated] = useState<boolean | null>(null);\n const [activatedAppId, setActivatedAppId] = useState<string | null>(null);\n const [activateLoading, setActivateLoading] = useState(false);\n const [resolvedAlgoliaId, setResolvedAlgoliaId] = useState<string | null>(null);\n const [authExpanded, setAuthExpanded] = useState(true);\n // Auto-collapse Authentication section when a valid auth exists; expand otherwise.\n // Only fires when validity flips, so user manual toggles are preserved.\n const lastValidAuthRef = useRef<boolean | null>(null);\n const [incidentStats, setIncidentStats] = useState<{ ingested: number; forwarded: number } | null>(null);\n\n const {\n authStates,\n authenticatedApps,\n loading: appAuthLoading,\n handleAuthChange,\n handleTestConnection,\n handleSaveAuth,\n refreshAuth,\n } = useAppAuth();\n\n // Fetch app info and refresh auth when opened with a new app\n useEffect(() => {\n if (!open || !appName) return;\n setAppLoading(true);\n setAppInfo(null);\n setIsActivated(null);\n setResolvedAlgoliaId(null);\n // Always refresh auth when opening a different app\n refreshAuth();\n\n const normalizedName = appName.toLowerCase().replace(/[\\s_\\-]+/g, '_');\n const searchName = appName.replace(/_/g, ' ');\n\n (async () => {\n // Algolia lookup (best-effort — may fail with 429 or be unavailable)\n let algoliaId: string | null = null;\n try {\n const { algoliasearch } = await import('algoliasearch');\n const client = algoliasearch('JNSS5CFDZZ', '33e4e3564f4f060e96e0531957bed552');\n const res = await client.search({\n requests: [{ indexName: 'appsearch', query: searchName, hitsPerPage: 10 }],\n });\n const hits = (res as any)?.results?.[0]?.hits || [];\n const match = hits.find((h: any) =>\n h.name?.toLowerCase().replace(/[\\s_\\-]+/g, '_') === normalizedName\n ) || (hits.length > 0 ? hits[0] : null);\n\n if (match) {\n algoliaId = match.objectID;\n setResolvedAlgoliaId(algoliaId);\n setAppInfo({\n name: match.name || searchName,\n description: match.description || '',\n large_image: match.image_url || '',\n categories: match.categories || [],\n });\n }\n } catch {}\n\n // Fallback: if Algolia didn't resolve an id, look it up via /api/v1/apps\n // This also doubles as our activation check below.\n let appsList: any[] | null = null;\n if (API_CONFIG.apiKey) {\n try {\n const res = await fetch(getApiUrl('/api/v1/apps'), {\n credentials: 'include',\n headers: { ...getAuthHeader() },\n });\n if (res.ok) {\n const apps = await res.json();\n if (Array.isArray(apps)) appsList = apps;\n }\n } catch {}\n }\n\n if (!algoliaId && appsList) {\n const localMatch = appsList.find((a: any) =>\n (a.name || '').toLowerCase().replace(/[\\s_\\-]+/g, '_') === normalizedName\n );\n if (localMatch?.id) {\n algoliaId = localMatch.id;\n setResolvedAlgoliaId(localMatch.id);\n setAppInfo(prev => prev ?? {\n name: localMatch.name || searchName,\n description: localMatch.description || '',\n large_image: localMatch.large_image || '',\n categories: localMatch.categories || [],\n authentication: localMatch.authentication,\n });\n }\n }\n\n // Config API — only available when we have an id\n if (API_CONFIG.apiKey && algoliaId) {\n try {\n const response = await fetch(\n getApiUrl(`/api/v1/apps/${encodeURIComponent(algoliaId)}/config`),\n { credentials: 'include', headers: { ...getAuthHeader() } }\n );\n if (response.ok) {\n const data = await response.json();\n if (data?.name) {\n setAppInfo(prev => ({ ...prev, ...data, large_image: data.large_image || prev?.large_image || '' }));\n }\n }\n } catch {}\n }\n\n // Activation status from the same /api/v1/apps response\n if (appsList) {\n const activeMatch = appsList.find((a: any) =>\n (a.name || '').toLowerCase().replace(/[\\s_\\-]+/g, '_') === normalizedName && a.activated\n );\n setIsActivated(!!activeMatch);\n setActivatedAppId(activeMatch?.id || null);\n } else {\n setIsActivated(false);\n }\n\n // Last-resort: if we still have no appInfo, seed from the name so the drawer renders\n setAppInfo(prev => prev ?? {\n name: searchName,\n description: '',\n large_image: '',\n categories: [],\n });\n\n setAppLoading(false);\n })();\n }, [open, appName]);\n\n // Fetch incident stats for this app\n useEffect(() => {\n if (!open || !appName || !isAuthenticated) {\n setIncidentStats(null);\n return;\n }\n\n (async () => {\n try {\n const result = await getDatastoreByCategory(DATASTORE_CATEGORIES.INCIDENTS);\n if (!result.success || !result.data) {\n setIncidentStats({ ingested: 0, forwarded: 0 });\n return;\n }\n\n const normalizedAppName = appName.toLowerCase().replace(/[\\s_\\-]+/g, '');\n let ingested = 0;\n let forwarded = 0;\n\n for (const item of result.data) {\n try {\n const parsed = JSON.parse(item.value);\n const productName = (parsed.metadata?.product?.name || '').toLowerCase().replace(/[\\s_\\-]+/g, '');\n if (productName && productName === normalizedAppName) {\n ingested++;\n }\n // Check if forwarded to this app (via finding_info dest or similar)\n const forwardDest = (parsed.metadata?.product?.forward_name || parsed.forward_target || '').toLowerCase().replace(/[\\s_\\-]+/g, '');\n if (forwardDest && forwardDest === normalizedAppName) {\n forwarded++;\n }\n } catch {}\n }\n\n setIncidentStats({ ingested, forwarded });\n } catch {\n setIncidentStats({ ingested: 0, forwarded: 0 });\n }\n })();\n }, [open, appName, isAuthenticated]);\n\n const handleClose = () => {\n onRefresh?.();\n onClose();\n };\n\n // Matching auth entries\n const matchingEntries = useMemo(() => {\n if (!appName || !isAuthenticated) return [];\n return authenticatedApps.filter(\n auth => auth.app?.name?.toLowerCase().replace(/[\\s_\\-]+/g, '_') === appName.toLowerCase().replace(/[\\s_\\-]+/g, '_')\n );\n }, [appName, authenticatedApps, isAuthenticated]);\n\n const resolvedImage = useMemo(() => {\n if (appInfo?.large_image) return appInfo.large_image;\n for (const entry of matchingEntries) {\n const img = (entry as any).app?.large_image || (entry as any).large_image;\n if (img) return img;\n }\n return '';\n }, [appInfo, matchingEntries]);\n\n const algoliaApp: AlgoliaSearchApp | null = useMemo(() => {\n if (!appName) return null;\n return {\n objectID: resolvedAlgoliaId || appName,\n name: appName,\n image_url: resolvedImage,\n description: appInfo?.description || '',\n categories: appInfo?.categories || [],\n } as AlgoliaSearchApp;\n }, [appName, appInfo, resolvedImage, resolvedAlgoliaId]);\n\n const authState = authStates[appName || ''] || { systemId: appName || '', status: 'pending' as const, credentials: {} };\n const hasValidAuth = matchingEntries.some(e => e.validation?.valid === true);\n const hasAnyAuth = matchingEntries.length > 0;\n const authCount = matchingEntries.length;\n const displayName = (appInfo?.name || appName || '').replace(/_/g, ' ');\n\n // Auto-collapse when valid auth appears, auto-expand when it disappears.\n useEffect(() => {\n if (lastValidAuthRef.current === hasValidAuth) return;\n lastValidAuthRef.current = hasValidAuth;\n setAuthExpanded(!hasValidAuth);\n }, [hasValidAuth]);\n\n // Reset tracker when switching apps so the new app starts from current state.\n useEffect(() => {\n lastValidAuthRef.current = null;\n }, [appName]);\n\n const handleActivateToggle = async () => {\n if (!appName || activateLoading) return;\n const wasActivated = isActivated;\n const prevAppId = activatedAppId;\n setIsActivated(!wasActivated);\n setActivateLoading(true);\n try {\n if (wasActivated && prevAppId) {\n const res = await fetch(getApiUrl(`/api/v1/apps/${prevAppId}/deactivate`), {\n method: 'POST', credentials: 'include', headers: { ...getAuthHeader() },\n });\n if (!res.ok) throw new Error('Deactivate failed');\n setActivatedAppId(null);\n toast.success(`${displayName} deactivated`);\n } else {\n const appId = resolvedAlgoliaId;\n if (!appId) throw new Error('App ID not resolved yet');\n const activateRes = await fetch(getApiUrl(`/api/v1/apps/${appId}/activate`), {\n method: 'GET', credentials: 'include', headers: { ...getAuthHeader() },\n });\n if (!activateRes.ok) throw new Error(`Activate failed (${activateRes.status})`);\n setActivatedAppId(appId);\n toast.success(`${displayName} activated`);\n }\n } catch (err: any) {\n console.error('[Activate] Error:', err);\n toast.error(err?.message || 'Activation failed');\n setIsActivated(wasActivated);\n setActivatedAppId(prevAppId);\n } finally {\n setActivateLoading(false);\n }\n };\n\n const isLoadingAll = appLoading || (isAuthenticated && appAuthLoading);\n\n return (\n <Drawer\n anchor={anchor}\n open={open}\n onClose={handleClose}\n sx={{\n '& .MuiDrawer-paper': {\n width,\n maxWidth: '100vw',\n background: 'linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)',\n borderLeft: anchor === 'right' ? '1px solid hsl(var(--border))' : 'none',\n borderRight: anchor === 'left' ? '1px solid hsl(var(--border))' : 'none',\n },\n }}\n >\n {/* Header bar */}\n <Box\n sx={{\n px: 3,\n py: 2,\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n borderBottom: '1px solid hsl(var(--border))',\n flexShrink: 0,\n }}\n >\n <Box sx={{ flex: 1 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 700, fontSize: '1rem', lineHeight: 1.2, textTransform: 'capitalize' }}>\n {isLoadingAll ? <Skeleton width={140} /> : displayName}\n </Typography>\n <Typography sx={{ color: 'hsl(var(--muted-foreground))', fontSize: '0.75rem' }}>\n App configuration\n </Typography>\n </Box>\n <IconButton\n component=\"a\"\n href={`/apps/${encodeURIComponent(appName || '')}`}\n size=\"small\"\n sx={{ color: 'hsl(var(--muted-foreground))', '&:hover': { color: 'hsl(var(--foreground))' } }}\n >\n <OpenInNewIcon fontSize=\"small\" />\n </IconButton>\n <IconButton\n size=\"small\"\n onClick={handleClose}\n sx={{ color: 'hsl(var(--muted-foreground))', '&:hover': { color: 'hsl(var(--foreground))' } }}\n >\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n </Box>\n\n {/* Content */}\n <Box sx={{ flex: 1, overflowY: 'auto', p: 3 }}>\n {isLoadingAll ? (\n <Box>\n <Box sx={{ display: 'flex', gap: 2, mb: 3 }}>\n <Skeleton variant=\"circular\" width={56} height={56} />\n <Box sx={{ flex: 1 }}>\n <Skeleton width={180} height={28} />\n <Skeleton width={260} height={18} sx={{ mt: 0.5 }} />\n </Box>\n </Box>\n <Skeleton variant=\"rectangular\" height={160} sx={{ borderRadius: 2 }} />\n </Box>\n ) : (\n <>\n {/* App header */}\n <AppTitleHeader\n name={displayName}\n image={resolvedImage}\n hasValidAuth={hasValidAuth}\n hasAnyAuth={hasAnyAuth}\n isAuthenticated={isAuthenticated}\n categories={appInfo?.categories}\n isActivated={onAddToCanvas ? null : isActivated}\n activateLoading={activateLoading}\n onActivateToggle={handleActivateToggle}\n onAdd={onAddToCanvas && appName ? () => {\n onAddToCanvas({ name: appName, icon: resolvedImage || '', algoliaId: resolvedAlgoliaId });\n onClose();\n } : undefined}\n />\n\n {/* Incident stats */}\n {isAuthenticated && incidentStats && incidentStats.ingested > 0 && (\n <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.08 }}>\n <Box sx={{\n display: 'flex',\n gap: 2,\n mb: 3,\n p: 2,\n borderRadius: 2,\n border: '1px solid hsl(var(--border))',\n bgcolor: 'hsl(var(--muted) / 0.3)',\n }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Download size={14} style={{ color: 'hsl(var(--primary))' }} />\n <Box>\n <Typography sx={{ fontSize: '1.1rem', fontWeight: 700, color: 'hsl(var(--foreground))', lineHeight: 1 }}>\n {incidentStats.ingested}\n </Typography>\n <Typography sx={{ fontSize: '0.65rem', color: 'hsl(var(--muted-foreground))', fontWeight: 500 }}>\n Incidents ingested\n </Typography>\n </Box>\n </Box>\n {incidentStats.forwarded > 0 && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, ml: 2, pl: 2, borderLeft: '1px solid hsl(var(--border))' }}>\n <Forward size={14} style={{ color: 'hsl(var(--severity-low))' }} />\n <Box>\n <Typography sx={{ fontSize: '1.1rem', fontWeight: 700, color: 'hsl(var(--foreground))', lineHeight: 1 }}>\n {incidentStats.forwarded}\n </Typography>\n <Typography sx={{ fontSize: '0.65rem', color: 'hsl(var(--muted-foreground))', fontWeight: 500 }}>\n Forwarded\n </Typography>\n </Box>\n </Box>\n )}\n </Box>\n </motion.div>\n )}\n\n {/* Authentication section */}\n <AppAuthSection\n displayName={displayName}\n algoliaApp={algoliaApp}\n resolvedAlgoliaId={resolvedAlgoliaId}\n authState={authState}\n expanded={authExpanded}\n onToggle={() => setAuthExpanded(prev => !prev)}\n authCount={authCount}\n isAuthenticated={isAuthenticated}\n matchingEntries={matchingEntries}\n onAuthChange={handleAuthChange}\n onTestConnection={(appId, authId) => handleTestConnection(appName || appId, authId)}\n onSaveAuth={(appId, creds) => handleSaveAuth(appId, creds, appName || undefined)}\n onRefreshAuth={refreshAuth}\n />\n\n {/* MCP Chat + individual actions */}\n {isAuthenticated && (\n <>\n <TryMcpSection\n appName={appName || ''}\n appIcon={resolvedImage}\n appId={matchingEntries[0]?.app?.id || matchingEntries[0]?.id || appName || ''}\n categories={appInfo?.categories}\n />\n <SingulActionsPreview appName={appName || ''} categories={appInfo?.categories} activeOrgId={activeOrgId} />\n </>\n )}\n </>\n )}\n </Box>\n </Drawer>\n );\n}\n","/**\n * API Configuration\n * \n * Configure the base URL based on your deployment:\n * - Shuffle Cloud (EU): https://shuffler.io\n * - Shuffle Cloud (US): https://us.shuffler.io \n * - Self-hosted: Your own backend URL (e.g., https://shuffle.yourdomain.com)\n *\n * The region URL is dynamically resolved from /api/v1/getinfo's `region_url` field.\n * If the user switches orgs, it resets to the default until getinfo is called again.\n */\n\nconst DEV_BACKEND = 'https://tunnel.schemaless.org';\nconst PROD_BACKEND = 'https://shuffler.io';\n\n// Base URL for Shuffle Automation dashboard (used in tool switcher)\nexport const SHUFFLE_AUTOMATION_URL = 'https://shuffler.io/new-dashboard';\n\n// Known cloud domains that should always use shuffler.io as the default backend\nconst CLOUD_DOMAINS = ['security.shuffler.io', 'shutdown.no'];\n\n// Safely read Vite-style env vars without depending on `vite/client` types\n// (the published library should not require Vite to be installed).\nconst getEnvVar = (key: string): string | undefined => {\n try {\n const meta = import.meta as unknown as { env?: Record<string, string | undefined> };\n return meta?.env?.[key];\n } catch {\n return undefined;\n }\n};\n\n// Determine if we're in Lovable preview (dev) or published (prod)\nexport const isDevEnvironment = (): boolean => {\n if (getEnvVar('VITE_SHUFFLE_API_URL')) return false;\n const hostname = typeof window !== 'undefined' ? window.location.hostname : '';\n return hostname.includes('lovableproject.com') || hostname.includes('id-preview--');\n};\n\n/** Check if running on a known Shuffle Cloud domain */\nexport const isCloudDomain = (): boolean => {\n const hostname = typeof window !== 'undefined' ? window.location.hostname : '';\n return CLOUD_DOMAINS.includes(hostname);\n};\n\n/**\n * True when running on Shuffle Cloud (a known *.shuffler.io / shutdown.no domain).\n * Use this to gate cloud-only features like Google Analytics (ReactGA).\n *\n * isCloud() → cloud deployment, GA allowed, telemetry OK\n * !isCloud() → either Lovable preview (dev) OR self-hosted onprem; do NOT call GA\n */\nexport const isCloud = (): boolean => isCloudDomain();\n\n/**\n * True when running self-hosted (onprem) — i.e. NOT in Lovable preview AND NOT on a known cloud domain.\n */\nexport const isOnprem = (): boolean => !isDevEnvironment() && !isCloudDomain();\n\nconst getDefaultBaseUrl = (): string => {\n const envUrl = getEnvVar('VITE_SHUFFLE_API_URL');\n if (envUrl) {\n return envUrl;\n }\n if (isDevEnvironment()) return DEV_BACKEND;\n // Cloud domains always default to shuffler.io; region_url from getinfo may override later\n if (isCloudDomain()) return PROD_BACKEND;\n // Self-hosted / on-prem: use current domain (nginx proxies /api/* to backend)\n if (typeof window !== 'undefined') {\n return window.location.origin;\n }\n return PROD_BACKEND;\n};\n\n// Dynamic region URL state (only applies in production, not dev)\nlet _regionUrl: string | null = null;\nlet _trackedOrgId: string | null = null;\n\n/** Check if a URL is a valid shuffler.io subdomain */\nconst isShufflerSubdomain = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return parsed.hostname.endsWith('.shuffler.io') || parsed.hostname === 'shuffler.io';\n } catch {\n return false;\n }\n};\n\n/**\n * Set the dynamic region URL from getinfo response.\n * Only applies if the URL is a shuffler.io subdomain and different from default.\n */\nexport const setRegionUrl = (regionUrl: string | undefined | null, orgId: string | undefined | null) => {\n // In dev environments, don't override — always use dev backend\n if (isDevEnvironment()) {\n _trackedOrgId = orgId || null;\n return;\n }\n\n _trackedOrgId = orgId || null;\n\n if (regionUrl && isShufflerSubdomain(regionUrl)) {\n // Normalize: strip trailing slash\n const normalized = regionUrl.replace(/\\/+$/, '');\n if (normalized !== PROD_BACKEND) {\n _regionUrl = normalized;\n console.log(`[API] Region URL set to: ${_regionUrl}`);\n return;\n }\n }\n\n // No valid region override — use default\n _regionUrl = null;\n};\n\n/**\n * Called when org changes. Resets region URL to default until next getinfo.\n */\nexport const resetRegionUrl = () => {\n if (_regionUrl) {\n console.log(`[API] Region URL reset to default (org changed)`);\n }\n _regionUrl = null;\n};\n\n/** Get the currently tracked org ID */\nexport const getTrackedOrgId = (): string | null => _trackedOrgId;\n\nexport const API_CONFIG = {\n // Shuffle backend URL - uses region URL if set, otherwise default\n get baseUrl(): string {\n return _regionUrl || getDefaultBaseUrl();\n },\n \n // API version\n version: 'v1',\n \n // Get API key from localStorage (for local development)\n get apiKey(): string | null {\n return localStorage.getItem('shuffle_api_key');\n },\n \n // Set API key in localStorage\n setApiKey(key: string | null) {\n if (key) {\n localStorage.setItem('shuffle_api_key', key);\n } else {\n localStorage.removeItem('shuffle_api_key');\n }\n },\n};\n\n// Computed API endpoint - pass full path including /api/v1 or /api/v2\nexport const getApiUrl = (endpoint: string): string => {\n return `${API_CONFIG.baseUrl}${endpoint}`;\n};\n\n/**\n * Resolve an agent approval / form URL (typically `/forms/{id}`) to the\n * original Shuffle Core where the form actually lives. On Cloud this is\n * always https://shuffler.io (regardless of the active region URL — forms\n * are served from core), and onprem / dev fall back to the configured\n * backend baseUrl. Absolute URLs are returned unchanged.\n */\nexport const getShuffleCoreFormUrl = (refUrl: string): string => {\n if (!refUrl) return refUrl;\n // Already absolute — trust it.\n if (/^https?:\\/\\//i.test(refUrl)) return refUrl;\n const path = refUrl.startsWith('/') ? refUrl : `/${refUrl}`;\n // Cloud always points at shuffler.io for forms.\n if (isCloud()) return `https://shuffler.io${path}`;\n // Self-hosted / dev — use the active backend.\n return `${API_CONFIG.baseUrl}${path}`;\n};\n\n/** True when a notification.reference_url points at an agent approval form. */\nexport const isAgentApprovalFormUrl = (refUrl: string | undefined | null): boolean => {\n if (!refUrl) return false;\n try {\n // Strip an optional origin so we can match the path consistently.\n const path = /^https?:\\/\\//i.test(refUrl) ? new URL(refUrl).pathname : refUrl;\n return /^\\/forms\\/[^/?#]+/.test(path);\n } catch {\n return false;\n }\n};\n\n/**\n * Central fetch wrapper that ALWAYS includes credentials and auth headers.\n * Use this instead of raw fetch() for all Shuffle API calls.\n */\nexport const shuffleFetch = (url: string, init?: RequestInit): Promise<Response> => {\n const { headers: extraHeaders, ...rest } = init || {};\n return fetch(url, {\n credentials: 'include',\n ...rest,\n headers: {\n ...getAuthHeader(),\n ...extraHeaders,\n },\n });\n};\n\n// Common endpoints\nexport const API_ENDPOINTS = {\n login: '/login',\n logout: '/logout',\n me: '/me',\n getinfo: '/getinfo',\n alerts: '/alerts',\n cases: '/cases',\n workflows: '/workflows',\n apps: '/apps',\n};\n\n// Get authorization header - uses API key if available, otherwise session token.\n// Always scopes the request to the currently-active org via Org-Id when known,\n// so a user in a sub-org reads/writes against that sub-org rather than their\n// default home org. Pass `overrideOrgId` to force a different org (e.g. when\n// reading data from another tenant in a multi-tenant view).\nexport const getAuthHeader = (overrideOrgId?: string | null): Record<string, string> => {\n const headers: Record<string, string> = {};\n\n // Only send Authorization header for API key auth.\n // Session-based (cookie) auth is handled by credentials: 'include' — never both.\n const apiKey = API_CONFIG.apiKey;\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`;\n }\n\n // Scope to the active org. Explicit override beats the tracked org.\n const orgId = overrideOrgId ?? _trackedOrgId;\n if (orgId) {\n headers['Org-Id'] = orgId;\n }\n\n return headers;\n};\n\n","/**\n * Shuffle Datastore Service\n * \n * Provides reusable functions for interacting with the Shuffle datastore API.\n * Uses the correct Shuffle cache API endpoints.\n */\n\nimport { API_CONFIG, getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\n\nexport interface DatastoreItem {\n key: string;\n value: string;\n category: string;\n created?: number;\n edited?: number;\n public_authorization?: string;\n enrichments?: Array<{ type: string; value?: string; data?: string }>;\n}\n\nexport interface CategoryAutomation {\n id?: string;\n name: string;\n type?: 'workflow' | 'webhook' | 'ai_agent' | 'enrich' | 'send_message' | 'security_rules';\n trigger?: 'on_create' | 'on_edit' | 'on_delete';\n workflow_id?: string;\n webhook_url?: string;\n enabled: boolean;\n description?: string;\n options?: { key: string; value: string }[];\n}\n\nexport interface CategoryConfig {\n id: string;\n org_id: string;\n category: string;\n automations: CategoryAutomation[] | null;\n settings: {\n timeout: number;\n public: boolean;\n };\n}\n\nexport interface DatastoreResponse {\n success: boolean;\n data?: DatastoreItem[];\n categoryConfig?: CategoryConfig;\n cursor?: string;\n totalAmount?: number;\n error?: string;\n diagnostics?: DatastoreDiagnostics;\n}\n\nexport interface DatastoreDiagnostics {\n operation: string;\n category?: string;\n orgId?: string | null;\n url?: string;\n cursor?: string;\n status?: number;\n statusText?: string;\n contentType?: string | null;\n responseShape?: 'array' | 'keys' | 'data' | 'unknown';\n itemCount?: number;\n totalAmount?: number | null;\n bodyPreview?: string;\n errorStage?: 'request' | 'response' | 'parse' | 'unknown';\n timestamp: string;\n}\n\n/**\n * Runtime-injected active org ID. AuthContext sets this synchronously when\n * /api/v1/getinfo resolves, so callers don't need to wait for the\n * `shuffle_user_info` localStorage write to land. Falls back to localStorage\n * for cases where the service is imported before AuthContext mounts.\n */\nlet _runtimeOrgId: string | null = null;\n\nexport const setRuntimeOrgId = (orgId: string | null) => {\n _runtimeOrgId = orgId || null;\n};\n\n/**\n * Get current org ID. Prefers the runtime value set by AuthContext, then\n * falls back to localStorage so legacy callers keep working.\n */\nconst getOrgId = (): string | null => {\n if (_runtimeOrgId) return _runtimeOrgId;\n try {\n const userInfo = localStorage.getItem('shuffle_user_info');\n if (userInfo) {\n const parsed = JSON.parse(userInfo);\n return parsed.active_org?.id || null;\n }\n } catch {\n // Ignore parsing errors\n }\n return null;\n};\n\nconst normalizeDatastoreKey = (key: string): string => {\n if (!key?.includes('::')) return key;\n const parts = key.split('::').filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : key;\n};\n\nconst truncateResponsePreview = (value: string | null | undefined, maxLength = 280): string | undefined => {\n if (!value) return undefined;\n const normalized = value.replace(/\\s+/g, ' ').trim();\n if (!normalized) return undefined;\n return normalized.length > maxLength ? `${normalized.slice(0, maxLength)}…` : normalized;\n};\n\n/**\n * Set a single item in the datastore\n */\nexport const setDatastoreItem = async (\n key: string,\n value: string | object,\n category: string,\n overrideOrgId?: string\n): Promise<DatastoreResponse> => {\n const orgId = overrideOrgId || getOrgId();\n if (!orgId) {\n return { success: false, error: 'No organization ID found' };\n }\n\n const rawKey = normalizeDatastoreKey(key);\n const payload = {\n key: rawKey,\n value: typeof value === 'string' ? value : JSON.stringify(value),\n category,\n ignore_security_rules: true,\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n };\n if (overrideOrgId) {\n headers['Org-Id'] = overrideOrgId;\n }\n\n const response = await fetch(getApiUrl(`/api/v1/orgs/${orgId}/set_cache`), {\n method: 'POST',\n credentials: 'include',\n headers,\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n return { success: false, error: `Failed to set datastore item: ${response.statusText}` };\n }\n\n return { success: true };\n};\n\n/**\n * Set multiple items in the datastore (bulk create) using v2 API\n */\nexport const setDatastoreItems = async (\n items: { key: string; value: string | object }[],\n category: string\n): Promise<DatastoreResponse> => {\n const orgId = getOrgId();\n if (!orgId) {\n return { success: false, error: 'No organization ID found' };\n }\n\n // Use v2 API for bulk operations - send as array\n const payload = items.map(item => ({\n key: item.key,\n value: typeof item.value === 'string' ? item.value : JSON.stringify(item.value),\n category,\n }));\n\n const response = await fetch(getApiUrl('/api/v2/datastore'), {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n 'Org-Id': orgId,\n ...getAuthHeader(),\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const fallbackResults = await Promise.all(items.map(item =>\n setDatastoreItem(item.key, item.value, category)\n ));\n const failedWrites = fallbackResults.filter(result => !result.success);\n if (failedWrites.length > 0) {\n return {\n success: false,\n error: failedWrites[0]?.error || `Failed to set datastore items: ${response.statusText}`,\n };\n }\n return { success: true };\n }\n\n return { success: true };\n};\n\n/**\n * Get a single item from the datastore\n */\nexport const getDatastoreItem = async (\n key: string,\n category: string,\n overrideOrgId?: string\n): Promise<DatastoreResponse & { item?: DatastoreItem }> => {\n const orgId = overrideOrgId || getOrgId();\n if (!orgId) {\n return { success: false, error: 'No organization ID found' };\n }\n\n const rawKey = normalizeDatastoreKey(key);\n const payload: Record<string, string> = {\n key: rawKey,\n org_id: orgId,\n };\n \n if (category) {\n payload.category = category;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n };\n if (overrideOrgId) {\n headers['Org-Id'] = overrideOrgId;\n }\n\n const response = await fetch(getApiUrl(`/api/v1/orgs/${orgId}/get_cache`), {\n method: 'POST',\n credentials: 'include',\n headers,\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n // 404 means key doesn't exist - not an error, just empty\n if (response.status === 404) {\n return { success: true, item: undefined };\n }\n return { success: false, error: `Failed to get datastore item: ${response.statusText}` };\n }\n\n const data = await response.json();\n \n // API returns success: false if key not found\n if (data.success === false && !data.value) {\n return { success: true, item: undefined };\n }\n \n return { success: true, item: data };\n};\n\n/**\n * Get a single item from the datastore using public authorization (no login required)\n */\nexport const getDatastoreItemPublic = async (\n key: string,\n orgId: string,\n authorization: string,\n): Promise<DatastoreResponse & { item?: DatastoreItem }> => {\n const response = await fetch(\n getApiUrl(`/api/v1/orgs/${orgId}/cache/${key}?authorization=${authorization}`),\n { method: 'GET' },\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n return { success: true, item: undefined };\n }\n return { success: false, error: `Failed to get public datastore item: ${response.statusText}` };\n }\n\n const data = await response.json();\n if (data.success === false && !data.value) {\n return { success: true, item: undefined };\n }\n return { success: true, item: data };\n};\n\n/**\n * Try to extract valid datastore items from a response body string,\n * even if the HTTP status was non-2xx (some backend servers return 400 with valid data).\n */\nconst tryExtractItemsFromBody = (rawBody: string): { items: DatastoreItem[]; categoryConfig?: CategoryConfig; cursor?: string; totalAmount?: number; shape: DatastoreDiagnostics['responseShape'] } | null => {\n try {\n const data = rawBody ? JSON.parse(rawBody) : null;\n if (!data || typeof data !== 'object') return null;\n\n const items = Array.isArray(data) ? data : data.keys || data.data || [];\n if (!Array.isArray(items) || items.length === 0) return null;\n\n // Basic validation: at least one item should have a key\n if (!items.some((i: any) => i && typeof i === 'object' && typeof i.key === 'string')) return null;\n\n const shape: DatastoreDiagnostics['responseShape'] = Array.isArray(data)\n ? 'array'\n : Array.isArray(data?.keys) ? 'keys'\n : Array.isArray(data?.data) ? 'data'\n : 'unknown';\n\n return {\n items,\n categoryConfig: data.category_config,\n cursor: data.cursor,\n totalAmount: data.total_amount,\n shape,\n };\n } catch {\n return null;\n }\n};\n\n/**\n * Get all items in a category with optional cursor-based pagination\n */\nexport const getDatastoreByCategory = async (\n category: string,\n cursor?: string\n): Promise<DatastoreResponse> => {\n const orgId = getOrgId();\n if (!orgId) {\n return {\n success: false,\n error: 'No organization ID found',\n diagnostics: {\n operation: 'list',\n category,\n orgId: null,\n cursor,\n errorStage: 'request',\n timestamp: new Date().toISOString(),\n },\n };\n }\n\n // Cap page size at 50 — large `top` values can blow up payloads (especially\n // for incidents). Pagination via cursor handles the rest.\n const limit = 50;\n let url = `/api/v1/orgs/${orgId}/list_cache?category=${encodeURIComponent(category)}&top=${limit}`;\n if (cursor) {\n url += `&cursor=${encodeURIComponent(cursor)}`;\n }\n\n const requestUrl = getApiUrl(url);\n const baseDiagnostics: DatastoreDiagnostics = {\n operation: 'list',\n category,\n orgId,\n url: requestUrl,\n cursor,\n timestamp: new Date().toISOString(),\n };\n\n let response: Response;\n\n try {\n response = await fetch(\n requestUrl,\n {\n method: 'GET',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n },\n }\n );\n } catch (error) {\n // Network error — retry once\n try {\n response = await fetch(\n requestUrl,\n {\n method: 'GET',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n },\n }\n );\n } catch (retryError) {\n return {\n success: false,\n error: retryError instanceof Error ? retryError.message : 'Failed to request datastore items',\n diagnostics: {\n ...baseDiagnostics,\n errorStage: 'request',\n },\n };\n }\n }\n\n const contentType = response.headers.get('content-type');\n const rawBody = await response.text();\n\n if (!response.ok) {\n // Some backend servers return 400 but still include valid data in the body.\n // Try to extract items before treating as a hard failure.\n const extracted = tryExtractItemsFromBody(rawBody);\n if (extracted && extracted.items.length > 0) {\n console.warn(`[Datastore] ${response.status} response for category=${category} but body contained ${extracted.items.length} valid items — treating as success`);\n return {\n success: true,\n data: extracted.items,\n categoryConfig: extracted.categoryConfig,\n cursor: extracted.cursor,\n totalAmount: extracted.totalAmount,\n diagnostics: {\n ...baseDiagnostics,\n status: response.status,\n statusText: response.statusText,\n contentType,\n responseShape: extracted.shape,\n itemCount: extracted.items.length,\n totalAmount: extracted.totalAmount ?? null,\n },\n };\n }\n\n // No valid data in body — retry once for transient server errors\n if (response.status >= 400 && response.status < 500) {\n try {\n const retryResponse = await fetch(\n requestUrl,\n {\n method: 'GET',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n },\n }\n );\n const retryBody = await retryResponse.text();\n const retryExtracted = tryExtractItemsFromBody(retryBody);\n if (retryResponse.ok || (retryExtracted && retryExtracted.items.length > 0)) {\n const items = retryExtracted?.items || [];\n console.warn(`[Datastore] Retry succeeded for category=${category} (status=${retryResponse.status}, items=${items.length})`);\n return {\n success: true,\n data: items,\n categoryConfig: retryExtracted?.categoryConfig,\n cursor: retryExtracted?.cursor,\n totalAmount: retryExtracted?.totalAmount,\n diagnostics: {\n ...baseDiagnostics,\n status: retryResponse.status,\n statusText: retryResponse.statusText,\n contentType: retryResponse.headers.get('content-type'),\n responseShape: retryExtracted?.shape || 'unknown',\n itemCount: items.length,\n totalAmount: retryExtracted?.totalAmount ?? null,\n },\n };\n }\n } catch { /* retry failed, fall through to error */ }\n }\n\n return {\n success: false,\n error: `Failed to get datastore items: ${response.status} ${response.statusText}`.trim(),\n diagnostics: {\n ...baseDiagnostics,\n status: response.status,\n statusText: response.statusText,\n contentType,\n bodyPreview: truncateResponsePreview(rawBody),\n errorStage: 'response',\n },\n };\n }\n\n try {\n const data = rawBody ? JSON.parse(rawBody) : {};\n const responseShape: DatastoreDiagnostics['responseShape'] = Array.isArray(data)\n ? 'array'\n : Array.isArray(data?.keys)\n ? 'keys'\n : Array.isArray(data?.data)\n ? 'data'\n : 'unknown';\n const items = Array.isArray(data) ? data : data.keys || data.data || [];\n const totalAmount = data.total_amount ?? data.total ?? data.amount;\n\n return {\n success: true,\n data: items,\n categoryConfig: data.category_config,\n cursor: data.cursor,\n totalAmount,\n diagnostics: {\n ...baseDiagnostics,\n status: response.status,\n statusText: response.statusText,\n contentType,\n responseShape,\n itemCount: Array.isArray(items) ? items.length : 0,\n totalAmount: totalAmount ?? null,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? `Failed to parse datastore response: ${error.message}` : 'Failed to parse datastore response',\n diagnostics: {\n ...baseDiagnostics,\n status: response.status,\n statusText: response.statusText,\n contentType,\n bodyPreview: truncateResponsePreview(rawBody),\n errorStage: 'parse',\n },\n };\n }\n};\n\n/**\n * Delete a single item from the datastore\n */\nexport const deleteDatastoreItem = async (\n key: string,\n category: string,\n overrideOrgId?: string\n): Promise<DatastoreResponse> => {\n const orgId = overrideOrgId || getOrgId();\n if (!orgId) {\n return { success: false, error: 'No organization ID found' };\n }\n\n const rawKey = normalizeDatastoreKey(key);\n const payload: Record<string, string> = {\n key: rawKey,\n org_id: orgId,\n };\n \n if (category) {\n payload.category = category;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n };\n if (overrideOrgId) {\n headers['Org-Id'] = overrideOrgId;\n }\n\n const response = await fetch(getApiUrl(`/api/v1/orgs/${orgId}/delete_cache`), {\n method: 'POST',\n credentials: 'include',\n headers,\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n return { success: false, error: `Failed to delete datastore item: ${response.statusText}` };\n }\n\n return { success: true };\n};\n\n/**\n * Delete multiple items from the datastore (bulk delete)\n */\nexport const deleteDatastoreItems = async (\n keys: string[],\n category: string\n): Promise<{ success: boolean; deleted: number; failed: string[]; error?: string }> => {\n const orgId = getOrgId();\n if (!orgId) {\n return { success: false, deleted: 0, failed: keys, error: 'No organization ID found' };\n }\n\n const results = await Promise.allSettled(\n keys.map(key => deleteDatastoreItem(key, category))\n );\n\n const failed: string[] = [];\n let deleted = 0;\n\n results.forEach((result, index) => {\n if (result.status === 'fulfilled' && result.value.success) {\n deleted++;\n } else {\n failed.push(keys[index]);\n }\n });\n\n return {\n success: failed.length === 0,\n deleted,\n failed,\n };\n};\n\n// Category constants for consistency\nexport const DATASTORE_CATEGORIES = {\n INCIDENTS: 'shuffle-security_incidents',\n ASSETS: 'shuffle-security_assets',\n TEMPLATES: 'shuffle-security_templates',\n CONFIGURATION: 'shuffle-security_configuration',\n IOCS: 'shuffle-security_ioc-config',\n CUSTOM_FIELDS: 'shuffle-security_custom-fields',\n THREAT_FEEDS: 'shuffle-security_threat-feeds',\n INFRASTRUCTURE: 'shuffle-security_infrastructure',\n USERS: 'shuffle-security_users',\n REPORTS: 'shuffle-security_reports',\n // Legacy - for migration purposes\n LEGACY_ALERTS: 'shuffle-security_alerts',\n LEGACY_CASES: 'shuffle-security_cases',\n} as const;\n","import { useState, useCallback, useEffect } from 'react';\nimport { API_CONFIG, getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\nimport type { AppAuthState, AuthStatus, ApiAuthEntry } from '@/Shuffle-MCPs/AppAuthConfig';\nimport { refreshAllIntegrationStatus } from '@/Shuffle-MCPs/IntegrationStatus';\n\n// Helper to process auth data and invalidate entries older than 30 days\nconst processAuthData = (authData: ApiAuthEntry[]): ApiAuthEntry[] => {\n const thirtyDaysAgoMs = Date.now() - (30 * 24 * 60 * 60 * 1000);\n \n return authData.map(entry => {\n if (entry.validation?.valid === true && entry.validation?.last_valid) {\n const lastValidMs = entry.validation.last_valid > 1e12 \n ? entry.validation.last_valid \n : entry.validation.last_valid * 1000;\n \n if (lastValidMs < thirtyDaysAgoMs) {\n return {\n ...entry,\n validation: {\n ...entry.validation,\n valid: false,\n error: 'Validation expired (older than 30 days)',\n },\n };\n }\n }\n return entry;\n });\n};\n\n// Human-readable error descriptions for HTTP status codes\nconst getStatusDescription = (status: number | string): string => {\n const statusDescriptions: Record<number, string> = {\n 400: 'Bad Request – The request was malformed or missing required parameters',\n 401: 'Unauthorized – Invalid or expired API key/credentials',\n 403: 'Forbidden – Access denied. Check your permissions',\n 404: 'Not Found – The API endpoint or resource doesn\\'t exist',\n 429: 'Too Many Requests – Rate limit exceeded. Try again later',\n 500: 'Internal Server Error – Something went wrong on the server',\n 502: 'Bad Gateway – The server received an invalid response',\n 503: 'Service Unavailable – The service is temporarily down',\n };\n const num = Number(status);\n if (statusDescriptions[num]) return statusDescriptions[num];\n if (num >= 400 && num < 500) return 'Client Error – Check your request parameters';\n if (num >= 500 && num < 600) return 'Server Error – The remote service may be unavailable';\n return '';\n};\n\nconst parseResultData = (data: any) => {\n const rawData = data.result || data.raw_response;\n if (!rawData) return null;\n try {\n return typeof rawData === 'string' ? JSON.parse(rawData) : rawData;\n } catch {\n return null;\n }\n};\n\nexport function useAppAuth() {\n const [authStates, setAuthStates] = useState<Record<string, AppAuthState>>({});\n const [authenticatedApps, setAuthenticatedApps] = useState<ApiAuthEntry[]>([]);\n const [loading, setLoading] = useState(true);\n\n // Load authenticated apps on mount\n const fetchAuthenticatedApps = useCallback(async () => {\n \n try {\n const response = await fetch(getApiUrl('/api/v1/apps/authentication'), {\n credentials: 'include',\n headers: { ...getAuthHeader() },\n });\n if (response.ok) {\n const result = await response.json();\n const authData = result.data || result;\n if (Array.isArray(authData)) {\n setAuthenticatedApps(processAuthData(authData));\n }\n }\n } catch (error) {\n console.error('Failed to fetch auth data:', error);\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n fetchAuthenticatedApps();\n }, [fetchAuthenticatedApps]);\n\n const handleAuthChange = useCallback((systemId: string, credentials: Record<string, string>) => {\n setAuthStates((prev) => ({\n ...prev,\n [systemId]: {\n systemId,\n status: 'pending' as AuthStatus,\n credentials,\n },\n }));\n }, []);\n\n const handleTestConnection = useCallback(async (systemId: string, authenticationId?: string) => {\n setAuthStates((prev) => ({\n ...prev,\n [systemId]: {\n ...prev[systemId],\n systemId,\n status: 'testing' as AuthStatus,\n credentials: prev[systemId]?.credentials || {},\n },\n }));\n\n try {\n const requestBody: Record<string, string | boolean> = {\n action: 'test_api',\n app: systemId,\n skip_workflow: true,\n };\n \n if (authenticationId) {\n requestBody.authentication_id = authenticationId;\n }\n\n const response = await fetch(getApiUrl('/api/v1/apps/categories/run'), {\n method: 'POST',\n credentials: 'include',\n headers: {\n ...getAuthHeader(),\n 'Content-Type': 'application/json',\n 'Accept-Encoding': 'identity',\n },\n body: JSON.stringify(requestBody),\n });\n\n const result = await response.json();\n \n let isValid = false;\n let errorMessage = 'Failed to connect. Please check your credentials.';\n let successMessage = '';\n let warningMessage = '';\n let errorCode: number | undefined;\n let workflowId = result.workflow_id || '';\n let executionId = result.execution_id || '';\n\n const validActions = ['done', 'app_validation'];\n if (response.ok && validActions.includes(result.action) && result.success === true) {\n try {\n const resultData = parseResultData(result);\n \n const hasErrorInBody = resultData && (\n resultData.error !== undefined || \n resultData.ok === false\n );\n \n if (hasErrorInBody) {\n const errorDetail = resultData.error || resultData.reason || 'unknown error';\n isValid = true;\n successMessage = `Connection likely working, but API returned: ${typeof errorDetail === 'string' ? errorDetail : JSON.stringify(errorDetail)}`;\n warningMessage = 'The API responded but included an error field.';\n } else if (resultData && resultData.status) {\n const parsedStatus = resultData.status;\n const statusLower = String(parsedStatus).toLowerCase();\n const statusNum = Number(parsedStatus);\n\n const isErrorStatus = (statusNum >= 400 && statusNum < 600) ||\n statusLower === 'error' || statusLower === 'failed' ||\n statusLower === 'unauthorized' || statusLower === 'forbidden';\n \n if (statusNum === 401 || statusNum === 403 || statusLower === 'unauthorized' || statusLower === 'forbidden') {\n errorCode = statusNum || 401;\n }\n \n const isGoodStatus = !isErrorStatus && (\n statusLower === 'ok' || statusLower === 'success' || statusLower === 'healthy' ||\n statusLower === 'connected' || statusLower === '200' || statusNum === 200\n );\n \n if (isErrorStatus) {\n const statusDesc = getStatusDescription(parsedStatus);\n const reason = resultData.reason ? ` • ${resultData.reason}` : '';\n errorMessage = statusDesc ? `${statusDesc}${reason}` : `Connection failed • Status: ${parsedStatus}${reason}`;\n } else if (isGoodStatus) {\n isValid = true;\n successMessage = `Connection verified • Status: ${parsedStatus}`;\n } else {\n const statusDesc = getStatusDescription(parsedStatus);\n errorMessage = statusDesc || `Connection failed • Unexpected status: ${parsedStatus}`;\n }\n } else if (resultData?.success !== undefined) {\n if (resultData.success === true) {\n isValid = true;\n successMessage = 'Connection verified';\n } else {\n errorMessage = resultData.reason || 'Connection failed';\n }\n }\n } catch {\n errorMessage = 'Connection failed – Unable to parse response.';\n }\n } else if (result.status !== undefined) {\n const statusDesc = getStatusDescription(result.status);\n errorMessage = statusDesc || `Connection failed • Status: ${result.status}`;\n const sn = Number(result.status);\n if (sn === 401 || sn === 403) errorCode = sn;\n }\n\n // Refresh auth list & notify all IntegrationStatus instances\n await fetchAuthenticatedApps();\n refreshAllIntegrationStatus();\n\n setAuthStates((prev) => ({\n ...prev,\n [systemId]: {\n ...prev[systemId],\n systemId,\n credentials: prev[systemId]?.credentials || {},\n status: isValid ? 'connected' : 'error',\n errorMessage: isValid ? undefined : errorMessage,\n successMessage: isValid ? (successMessage || 'Connection verified') : undefined,\n warningMessage: isValid ? warningMessage : undefined,\n workflowId: isValid ? undefined : workflowId,\n executionId: isValid ? undefined : executionId,\n errorCode: isValid ? undefined : errorCode,\n },\n }));\n } catch (error) {\n await new Promise(resolve => setTimeout(resolve, 3000));\n await fetchAuthenticatedApps();\n refreshAllIntegrationStatus();\n\n setAuthStates((prev) => ({\n ...prev,\n [systemId]: {\n ...prev[systemId],\n systemId,\n credentials: prev[systemId]?.credentials || {},\n status: 'error',\n errorMessage: error instanceof Error ? error.message : 'Connection test failed.',\n },\n }));\n }\n }, [fetchAuthenticatedApps]);\n\n const handleSaveAuth = useCallback(async (appId: string, credentials: Record<string, string>, appName?: string): Promise<boolean> => {\n const fields = Object.entries(credentials)\n .filter(([key, value]) => key?.trim() && value?.trim())\n .map(([key, value]) => ({ key, value }));\n\n const payload = {\n label: `Auth for ${(appName || appId).replace(/_/g, ' ')}`,\n app: {\n name: appName || appId,\n id: appId,\n app_version: '1.0.0',\n },\n fields,\n active: true,\n };\n\n try {\n const response = await fetch(getApiUrl('/api/v1/apps/authentication'), {\n method: 'PUT',\n credentials: 'include',\n headers: {\n ...getAuthHeader(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (response.ok) {\n await fetchAuthenticatedApps();\n refreshAllIntegrationStatus();\n return true;\n }\n return false;\n } catch (error) {\n console.error('Failed to save authentication:', error);\n return false;\n }\n }, [fetchAuthenticatedApps]);\n\n return {\n authStates,\n authenticatedApps,\n loading,\n handleAuthChange,\n handleTestConnection,\n handleSaveAuth,\n refreshAuth: fetchAuthenticatedApps,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n Box,\n Typography,\n Tooltip,\n IconButton,\n Avatar,\n CircularProgress,\n} from '@mui/material';\nimport AddIcon from '@mui/icons-material/Add';\nimport { API_CONFIG, getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\nimport { fetchAuthenticatedApps } from '@/Shuffle-MCPs/authenticatedApps';\nimport { deduplicateAuthApps, backfillAppImages, type AuthAppEntry } from '@/Shuffle-MCPs/auth-utils';\nimport { useAppDetailOptional } from '@/Shuffle-MCPs/AppDetailContext';\nimport { SIEM_PATTERNS, CASES_PATTERNS, EDR_PATTERNS, EMAIL_APP_PATTERNS } from '@/Shuffle-MCPs/ingestionDetection';\n\ninterface Integration {\n id: string;\n name: string;\n icon: string;\n category: string;\n hasValidAuth: boolean;\n authInstances: { label: string; isValidated: boolean }[];\n isActiveOnly?: boolean;\n}\n\ninterface IntegrationStatusProps {\n collapsed: boolean;\n /** When provided, only show integrations whose name is in this list */\n filterApps?: string[];\n /** When provided, the Add button calls this instead of navigating to /onboarding */\n onAddClick?: () => void;\n /** Icon size override (default: 26) */\n iconSize?: number;\n /** When provided, hovering an icon shows a cross-out button that calls this with the app name */\n onDisable?: (name: string) => void;\n /** Set of app names that are currently disabled */\n disabledApps?: Set<string>;\n /** Show all integrations without truncation */\n showAll?: boolean;\n /** Hide the Add Integration button */\n hideAddButton?: boolean;\n /** Hide the \"Integrations\" section header */\n hideHeader?: boolean;\n /** When set, apps matching this category are sorted to the top */\n priorityCategory?: string;\n}\n\nconst PRIORITY_CATEGORY_PATTERNS: Record<string, string[]> = {\n siem: SIEM_PATTERNS,\n case_management: CASES_PATTERNS,\n edr: EDR_PATTERNS,\n email: EMAIL_APP_PATTERNS,\n};\n\nfunction matchesPriorityCategory(appName: string, categoryId: string): boolean {\n const patterns = PRIORITY_CATEGORY_PATTERNS[categoryId];\n if (!patterns) return false;\n const lower = appName.toLowerCase();\n return patterns.some(p => lower.includes(p));\n}\n\n/** Fire this event from anywhere to make all IntegrationStatus instances re-fetch. */\nexport const refreshAllIntegrationStatus = () => {\n window.dispatchEvent(new CustomEvent('integrations-changed'));\n};\n\nexport const IntegrationStatus = ({ collapsed, filterApps, onAddClick, iconSize = 26, onDisable, disabledApps, showAll, hideAddButton, hideHeader, priorityCategory }: IntegrationStatusProps) => {\n const [allIntegrations, setAllIntegrations] = useState<Integration[]>([]);\n const [loading, setLoading] = useState(false);\n const [expanded, setExpanded] = useState(false);\n const [failedImages, setFailedImages] = useState<Set<string>>(new Set());\n const [hoveredId, setHoveredId] = useState<string | null>(null);\n const appDetail = useAppDetailOptional();\n\n // Apply filter if provided (case-insensitive name match)\n const integrations = filterApps\n ? allIntegrations.filter(i => filterApps.some(f => f.toLowerCase() === i.name.toLowerCase()))\n : allIntegrations;\n\n const defaultLimit = showAll ? integrations.length : (collapsed ? 3 : 7);\n const displayLimit = showAll ? integrations.length : (expanded ? integrations.length : defaultLimit);\n const hasMore = !showAll && integrations.length > defaultLimit;\n\n // Fetch enabled integrations from API\n const fetchIntegrations = useCallback(async () => {\n setLoading(true);\n try {\n // Use the coalesced shared fetcher so we share a single in-flight\n // request with other consumers (e.g. the incident header source-app\n // logo). Without this, every detail-page navigation triggered 3+\n // identical /apps/authentication requests.\n const authData = (await fetchAuthenticatedApps().catch(() => [])) as unknown as AuthAppEntry[];\n\n let dedupedIntegrations: Integration[] = [];\n const authNameSet = new Set<string>();\n\n if (Array.isArray(authData) && authData.length > 0) {\n const dedupedApps = deduplicateAuthApps(authData);\n await backfillAppImages(dedupedApps);\n\n dedupedIntegrations = dedupedApps\n .map(({ app, instances, hasValidAuth, bestImage }) => {\n authNameSet.add(app.name.toLowerCase());\n return {\n id: app.id,\n name: app.name,\n icon: bestImage || app.large_image || '',\n category: app.categories?.[0] || 'Integration',\n hasValidAuth,\n authInstances: instances,\n isActiveOnly: false,\n };\n });\n }\n\n if (dedupedIntegrations.length < 10) {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const appsResponse = await fetch(getApiUrl('/api/v1/apps'), {\n credentials: 'include',\n headers: { ...getAuthHeader() },\n signal: controller.signal,\n });\n clearTimeout(timeout);\n if (appsResponse.ok) {\n const appsData = await appsResponse.json();\n if (Array.isArray(appsData)) {\n const activatedApps = appsData.filter((app: any) => app.activated);\n const slotsRemaining = 10 - dedupedIntegrations.length;\n let added = 0;\n for (const app of activatedApps) {\n if (added >= slotsRemaining) break;\n if (!authNameSet.has((app.name || '').toLowerCase())) {\n authNameSet.add((app.name || '').toLowerCase());\n dedupedIntegrations.push({\n id: app.id || app.name,\n name: app.name,\n icon: app.large_image || '',\n category: app.categories?.[0] || 'Integration',\n hasValidAuth: false,\n authInstances: [],\n isActiveOnly: true,\n });\n added++;\n }\n }\n }\n }\n } catch (_) {\n // Non-critical, ignore\n }\n }\n\n dedupedIntegrations.sort((a, b) => {\n // Priority category apps first\n if (priorityCategory) {\n const aMatch = matchesPriorityCategory(a.name, priorityCategory);\n const bMatch = matchesPriorityCategory(b.name, priorityCategory);\n if (aMatch && !bMatch) return -1;\n if (!aMatch && bMatch) return 1;\n }\n if (a.hasValidAuth && !b.hasValidAuth) return -1;\n if (!a.hasValidAuth && b.hasValidAuth) return 1;\n if (!a.isActiveOnly && b.isActiveOnly) return -1;\n if (a.isActiveOnly && !b.isActiveOnly) return 1;\n return a.name.localeCompare(b.name);\n });\n \n setAllIntegrations(dedupedIntegrations);\n } catch (error) {\n console.error('Failed to fetch integrations:', error);\n } finally {\n setLoading(false);\n }\n }, [priorityCategory]);\n\n // Fetch on mount\n useEffect(() => {\n fetchIntegrations();\n }, [fetchIntegrations]);\n\n // Re-fetch whenever any integration auth changes globally\n useEffect(() => {\n const handler = () => fetchIntegrations();\n window.addEventListener('integrations-changed', handler);\n return () => window.removeEventListener('integrations-changed', handler);\n }, [fetchIntegrations]);\n\n const getStatusColor = (integration: Integration) => {\n if (integration.isActiveOnly) return 'hsl(var(--destructive))';\n return integration.hasValidAuth ? 'hsl(var(--severity-low))' : 'hsl(var(--severity-medium))';\n };\n\n // Icon-only view for both collapsed and expanded states\n const sz = iconSize;\n return (\n <Box sx={{ px: collapsed ? 0 : 1, py: 1 }}>\n {/* Header - only show when expanded */}\n {!collapsed && !hideHeader && (\n <Typography \n sx={{ \n color: 'hsl(var(--muted-foreground))', \n fontSize: '0.7rem', \n fontWeight: 600, \n textTransform: 'uppercase', \n letterSpacing: '0.05em',\n px: 1.5,\n mb: 1,\n }}\n >\n Integrations\n </Typography>\n )}\n \n {/* Icon grid */}\n <Box sx={{ \n display: 'flex', \n flexWrap: 'wrap',\n gap: 0.5,\n justifyContent: collapsed ? 'center' : 'flex-start',\n px: collapsed ? 0 : 1,\n maxHeight: expanded ? 'none' : 80,\n overflow: 'hidden',\n }}>\n {loading ? (\n <CircularProgress size={20} sx={{ color: 'hsl(var(--muted-foreground))' }} />\n ) : (\n <>\n {integrations.slice(0, displayLimit).map((integration) => {\n const isDisabled = disabledApps?.has(integration.name) ?? false;\n const isHovered = hoveredId === integration.id;\n return (\n <Tooltip \n key={integration.id} \n title={onDisable && isHovered ? '' : (\n <Box sx={{ textAlign: 'left', minWidth: 160, p: 0.5 }}>\n <Typography sx={{ fontWeight: 600, fontSize: '0.85rem', color: 'hsl(var(--foreground))' }}>\n {integration.name}\n {isDisabled && <Typography component=\"span\" sx={{ ml: 1, fontSize: '0.7rem', color: 'hsl(var(--muted-foreground))' }}>(disabled)</Typography>}\n </Typography>\n <Typography sx={{ fontSize: '0.7rem', color: 'hsl(var(--muted-foreground))', mb: 1, textTransform: 'capitalize' }}>\n {integration.category}\n </Typography>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>\n {integration.authInstances.map((instance, idx) => (\n <Box key={idx} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box \n sx={{ \n width: 7, \n height: 7, \n borderRadius: '50%', \n backgroundColor: instance.isValidated \n ? 'hsl(var(--severity-low))' \n : 'hsl(var(--severity-medium))',\n flexShrink: 0,\n }} \n />\n <Typography sx={{ fontSize: '0.75rem', color: 'hsl(var(--foreground))', opacity: 0.9 }}>\n {instance.label}\n </Typography>\n <Typography sx={{ fontSize: '0.65rem', color: instance.isValidated ? 'hsl(var(--severity-low))' : 'hsl(var(--muted-foreground))', ml: 'auto' }}>\n {instance.isValidated ? 'Valid' : 'Pending'}\n </Typography>\n </Box>\n ))}\n </Box>\n </Box>\n )}\n placement=\"bottom\"\n arrow\n >\n <Box\n onMouseEnter={() => onDisable && setHoveredId(integration.id)}\n onMouseLeave={() => onDisable && setHoveredId(null)}\n sx={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: onDisable ? 'default' : 'pointer',\n textDecoration: 'none',\n opacity: isDisabled ? 0.35 : 1,\n transition: 'opacity 0.15s ease',\n '&:hover': onDisable ? {} : {\n transform: 'scale(1.1)',\n transition: 'transform 0.15s ease',\n },\n }}\n >\n {/* Icon — rendered as link only when not in disable mode */}\n <Box\n onClick={!onDisable && appDetail ? () => appDetail.openApp(integration.name) : undefined}\n sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', textDecoration: 'none', cursor: !onDisable && appDetail ? 'pointer' : 'default' }}\n >\n {integration.icon && !failedImages.has(integration.id) ? (\n <Box\n component=\"img\"\n src={integration.icon}\n alt={integration.name}\n sx={{\n width: sz,\n height: sz,\n borderRadius: '50%',\n objectFit: 'contain',\n backgroundColor: 'hsl(var(--muted))',\n p: 0.25,\n filter: isDisabled ? 'grayscale(1)' : 'none',\n transition: 'filter 0.15s ease',\n }}\n onError={() => {\n setFailedImages(prev => new Set(prev).add(integration.id));\n }}\n />\n ) : (\n <Avatar\n sx={{\n width: sz,\n height: sz,\n backgroundColor: 'hsl(var(--muted))',\n fontSize: sz * 0.4 + 'px',\n color: 'hsl(var(--foreground))',\n filter: isDisabled ? 'grayscale(1)' : 'none',\n }}\n >\n {integration.name.charAt(0).toUpperCase()}\n </Avatar>\n )}\n </Box>\n\n {/* Status dot */}\n {!isDisabled && (\n <Box\n sx={{\n position: 'absolute',\n bottom: -1,\n right: -1,\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: getStatusColor(integration),\n border: '1.5px solid hsl(var(--card))',\n pointerEvents: 'none',\n }}\n />\n )}\n\n {/* Hover cross-out overlay */}\n {onDisable && isHovered && (\n <Box\n onClick={() => onDisable(integration.name)}\n sx={{\n position: 'absolute',\n inset: 0,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: isDisabled\n ? 'hsla(var(--severity-low) / 0.25)'\n : 'hsla(var(--destructive) / 0.75)',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n >\n {isDisabled ? (\n /* Re-enable: checkmark */\n <svg width={sz * 0.45} height={sz * 0.45} viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M2 6l3 3 5-5\" stroke=\"hsl(var(--severity-low))\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n ) : (\n /* Disable: X */\n <svg width={sz * 0.45} height={sz * 0.45} viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M2 2l8 8M10 2l-8 8\" stroke=\"white\" strokeWidth=\"1.8\" strokeLinecap=\"round\"/>\n </svg>\n )}\n </Box>\n )}\n </Box>\n </Tooltip>\n );\n })}\n \n {hasMore && !expanded && (\n <Tooltip title={`Show all ${integrations.length} integrations`} placement=\"bottom\">\n <Avatar\n onClick={() => setExpanded(true)}\n sx={{\n width: 26,\n height: 26,\n backgroundColor: 'hsl(var(--muted))',\n fontSize: '0.65rem',\n color: 'hsl(var(--muted-foreground))',\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: 'hsl(var(--accent))',\n },\n }}\n >\n +{integrations.length - defaultLimit}\n </Avatar>\n </Tooltip>\n )}\n \n {expanded && hasMore && (\n <Tooltip title=\"Show less\" placement=\"bottom\">\n <Avatar\n onClick={() => setExpanded(false)}\n sx={{\n width: 26,\n height: 26,\n backgroundColor: 'hsl(var(--muted))',\n fontSize: '0.65rem',\n color: 'hsl(var(--muted-foreground))',\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: 'hsl(var(--accent))',\n },\n }}\n >\n −\n </Avatar>\n </Tooltip>\n )}\n \n {/* Add button */}\n {!hideAddButton && (\n <Tooltip title=\"Add Integration\" placement=\"bottom\">\n {onAddClick ? (\n <IconButton\n size=\"small\"\n onClick={onAddClick}\n sx={{ \n width: 26,\n height: 26,\n color: 'hsl(var(--muted-foreground))',\n border: '1px dashed hsl(var(--border))',\n borderRadius: '50%',\n '&:hover': {\n backgroundColor: 'hsl(var(--muted))',\n borderStyle: 'solid',\n },\n }}\n >\n <AddIcon sx={{ fontSize: 14 }} />\n </IconButton>\n ) : (\n <IconButton\n size=\"small\"\n component=\"a\"\n href=\"/onboarding\"\n sx={{ \n width: 26,\n height: 26,\n color: 'hsl(var(--muted-foreground))',\n border: '1px dashed hsl(var(--border))',\n borderRadius: '50%',\n '&:hover': {\n backgroundColor: 'hsl(var(--muted))',\n borderStyle: 'solid',\n },\n }}\n >\n <AddIcon sx={{ fontSize: 14 }} />\n </IconButton>\n )}\n </Tooltip>\n )}\n </>\n )}\n </Box>\n </Box>\n );\n};\n","/**\n * Shared, request-coalescing fetcher for `/api/v1/apps/authentication`.\n *\n * Multiple components on a single page (sidebar `IntegrationStatus`, the\n * incident header source-app logo, the Forward dialog, the Automations\n * dialog, etc.) all need the authenticated-apps list. Without coordination\n * they each fired their own HTTP request on mount, producing 3+ identical\n * requests on every incident detail load.\n *\n * This helper:\n * 1. Coalesces concurrent in-flight calls into a single Promise so\n * simultaneous mounts only trigger one network round-trip.\n * 2. Caches the resolved JSON for a short TTL so a follow-up mount within\n * that window can read the result synchronously instead of refetching.\n * 3. Exposes an `invalidateAuthenticatedAppsCache()` so code paths that\n * mutate authentications (delete, reauth, etc.) can force a refresh.\n *\n * The cache key includes the optional `Org-Id` header value so cross-org\n * lookups stay isolated from the active org's data.\n */\n\nimport { getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\n\nexport interface AuthenticatedAppRaw {\n id?: string;\n active?: boolean;\n label?: string;\n app?: {\n name?: string;\n id?: string;\n large_image?: string;\n small_image?: string;\n categories?: string[];\n [key: string]: unknown;\n };\n validation?: { valid?: boolean; [key: string]: unknown };\n fields?: Array<{ key: string; value: string }>;\n [key: string]: unknown;\n}\n\ninterface CacheEntry {\n promise?: Promise<AuthenticatedAppRaw[]>;\n data?: AuthenticatedAppRaw[];\n fetchedAt?: number;\n}\n\nconst TTL_MS = 30_000;\nconst cache = new Map<string, CacheEntry>();\n\nconst cacheKey = (crossOrgId?: string | null): string => crossOrgId || '';\n\nconst doFetch = async (crossOrgId?: string | null): Promise<AuthenticatedAppRaw[]> => {\n // getAuthHeader() now scopes to the active org by default; pass crossOrgId\n // explicitly to override when reading from a different tenant.\n const headers: Record<string, string> = {\n ...getAuthHeader(crossOrgId ?? undefined),\n };\n const response = await fetch(getApiUrl('/api/v1/apps/authentication'), {\n credentials: 'include',\n headers,\n });\n if (!response.ok) return [];\n const result = await response.json();\n const data = result?.data || result;\n return Array.isArray(data) ? data : [];\n};\n\n/**\n * Get the raw authenticated-apps list. Returns the cached value if it is\n * still within the TTL; otherwise fires (or joins) a single network request.\n */\nexport const fetchAuthenticatedApps = (crossOrgId?: string | null): Promise<AuthenticatedAppRaw[]> => {\n const key = cacheKey(crossOrgId);\n const entry = cache.get(key) || {};\n\n // Fresh cache hit — return it without touching the network.\n if (entry.data && entry.fetchedAt && Date.now() - entry.fetchedAt < TTL_MS) {\n return Promise.resolve(entry.data);\n }\n // In-flight request — join it instead of firing a duplicate.\n if (entry.promise) return entry.promise;\n\n const promise = doFetch(crossOrgId)\n .then((data) => {\n cache.set(key, { data, fetchedAt: Date.now() });\n return data;\n })\n .catch((err) => {\n // On failure, drop the in-flight promise so the next caller can retry.\n cache.delete(key);\n throw err;\n });\n\n cache.set(key, { ...entry, promise });\n return promise;\n};\n\n/**\n * Invalidate the cached entry for one (or all) cross-org keys. Call after\n * mutating authentications (delete, create, reauth) so the next read fires\n * a fresh request.\n */\nexport const invalidateAuthenticatedAppsCache = (crossOrgId?: string | null) => {\n if (crossOrgId === undefined) {\n cache.clear();\n return;\n }\n cache.delete(cacheKey(crossOrgId));\n};\n","/**\n * Auth-app dedup + image backfill utilities.\n * Inlined into the Shuffle-MCPs library so it has no host-app dependency.\n * (Mirror copy of the helpers in src/lib/utils.ts — keep in sync.)\n */\n\nexport interface AuthAppEntry {\n app: {\n id: string;\n name: string;\n large_image?: string;\n categories?: string[];\n };\n active?: boolean;\n validation?: {\n valid: boolean;\n error?: string;\n };\n label?: string;\n id?: string;\n}\n\nexport interface DeduplicatedApp {\n app: AuthAppEntry['app'];\n hasValidAuth: boolean;\n bestImage: string;\n instances: { label: string; isValidated: boolean }[];\n}\n\nexport function deduplicateAuthApps(apps: AuthAppEntry[]): DeduplicatedApp[] {\n const appMap = new Map<string, DeduplicatedApp>();\n\n apps.forEach(auth => {\n if (!auth.active && !auth.validation?.valid) return;\n const normalizedName = auth.app.name.toLowerCase().trim().replace(/[\\s_\\-]+/g, '_');\n const existing = appMap.get(normalizedName);\n const isValidated = auth.validation?.valid === true;\n const entryImage = auth.app.large_image || '';\n const instance = {\n label: auth.label || auth.id || 'Default',\n isValidated,\n };\n\n if (!existing) {\n appMap.set(normalizedName, {\n app: auth.app,\n hasValidAuth: isValidated,\n bestImage: entryImage,\n instances: [instance],\n });\n } else {\n existing.instances.push(instance);\n if (isValidated) existing.hasValidAuth = true;\n if (!existing.bestImage && entryImage) existing.bestImage = entryImage;\n if (isValidated && !existing.app.large_image && entryImage) {\n existing.app = { ...existing.app, large_image: entryImage };\n }\n }\n });\n\n return Array.from(appMap.values());\n}\n\nconst _imageCache = new Map<string, string>();\nconst _pendingLookups = new Map<string, Promise<string | null>>();\nconst _normalize = (n: string) => n.toLowerCase().replace(/[\\s_\\-]+/g, '_');\n\nexport function seedImageCache(appName: string, imageUrl: string) {\n if (appName && imageUrl) _imageCache.set(_normalize(appName), imageUrl);\n}\n\nexport async function backfillAppImages(dedupedApps: DeduplicatedApp[]): Promise<DeduplicatedApp[]> {\n for (const d of dedupedApps) {\n const norm = _normalize(d.app.name);\n const existingImg = d.bestImage || d.app.large_image;\n if (existingImg) {\n _imageCache.set(norm, existingImg);\n } else if (_imageCache.has(norm)) {\n d.bestImage = _imageCache.get(norm)!;\n d.app = { ...d.app, large_image: d.bestImage };\n }\n }\n\n const missing = dedupedApps.filter(d => !d.bestImage && !d.app.large_image);\n if (missing.length === 0) return dedupedApps;\n\n try {\n const { algoliasearch } = await import('algoliasearch');\n const client = algoliasearch('JNSS5CFDZZ', '33e4e3564f4f060e96e0531957bed552');\n\n await Promise.all(missing.map(async (entry) => {\n const norm = _normalize(entry.app.name);\n if (!_pendingLookups.has(norm)) {\n _pendingLookups.set(norm, (async () => {\n try {\n const result = await client.searchSingleIndex({\n indexName: 'appsearch',\n searchParams: { query: entry.app.name, hitsPerPage: 3 },\n });\n const match = (result.hits as any[]).find(\n h => _normalize(h.name || '') === norm\n );\n const url = match?.image_url || null;\n if (url) _imageCache.set(norm, url);\n return url;\n } catch {\n return null;\n } finally {\n _pendingLookups.delete(norm);\n }\n })());\n }\n const url = await _pendingLookups.get(norm);\n if (url) {\n entry.bestImage = url;\n entry.app = { ...entry.app, large_image: url };\n }\n }));\n } catch {\n // ignore\n }\n\n return dedupedApps;\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react';\n\ninterface AppDetailContextType {\n openApp: (appName: string) => void;\n closeApp: () => void;\n currentAppName: string | null;\n isOpen: boolean;\n}\n\nconst AppDetailContext = createContext<AppDetailContextType | undefined>(undefined);\n\nexport const AppDetailProvider = ({ children }: { children: ReactNode }) => {\n const [currentAppName, setCurrentAppName] = useState<string | null>(null);\n\n const openApp = useCallback((appName: string) => {\n setCurrentAppName(appName);\n }, []);\n\n const closeApp = useCallback(() => {\n setCurrentAppName(null);\n }, []);\n\n return (\n <AppDetailContext.Provider value={{ openApp, closeApp, currentAppName, isOpen: currentAppName !== null }}>\n {children}\n </AppDetailContext.Provider>\n );\n};\n\nexport const useAppDetail = () => {\n const context = useContext(AppDetailContext);\n if (!context) {\n throw new Error('useAppDetail must be used within an AppDetailProvider');\n }\n return context;\n};\n\n/** Safe variant: returns null if no provider is mounted. Useful for components used both inside and outside the dashboard. */\nexport const useAppDetailOptional = () => {\n return useContext(AppDetailContext) ?? null;\n};\n","/**\n * Shared app category detection utilities.\n * Used by onboarding (AutomationConfig) and incident automations (CategoryAutomationsDialog).\n */\n\nimport { AuthAppEntry, deduplicateAuthApps } from '@/Shuffle-MCPs/auth-utils';\n\n// ============================================================================\n// Category patterns\n// ============================================================================\nexport const EMAIL_APP_PATTERNS = ['gmail', 'outlook', 'email', 'microsoft_graph', 'office365', 'exchange', 'imap', 'smtp'];\nexport const CASES_PATTERNS = ['jira', 'servicenow', 'zendesk', 'freshdesk', 'pagerduty', 'opsgenie', 'ticket', 'itsm', 'salesforce', 'thehive', 'cortex'];\nexport const EDR_PATTERNS = ['crowdstrike', 'sentinelone', 'carbon black', 'defender', 'cylance', 'sophos', 'trellix', 'vmware', 'tanium', 'falcon', 'edr'];\nexport const SIEM_PATTERNS = ['splunk', 'elastic', 'qradar', 'sentinel', 'chronicle', 'logrhythm', 'sumo logic', 'graylog', 'wazuh', 'siem', 'arcsight'];\nexport const THREAT_INTEL_PATTERNS = ['virustotal', 'shodan', 'alienvault', 'otx', 'threatcrowd', 'urlscan', 'hybrid-analysis', 'abuseipdb', 'greynoise', 'urlhaus', 'malwarebazaar', 'threatfox', 'misp', 'opencti', 'recorded future', 'mandiant', 'crowdstrike intel', 'intel471', 'flashpoint', 'domaintools'];\nexport const COMMUNICATION_PATTERNS_NAMES = ['slack', 'teams', 'discord', 'mattermost', 'telegram', 'webhook'];\nexport const VULN_SCANNER_PATTERNS = ['qualys', 'tenable', 'nessus', 'rapid7', 'nexpose', 'snyk', 'sonarqube', 'trivy', 'grype', 'anchore', 'dependabot', 'aws_inspector', 'azure_defender', 'gcp_scc', 'scout', 'prowler', 'checkov', 'wiz', 'orca', 'lacework', 'prisma'];\n\n// ============================================================================\n// Detection helpers\n// ============================================================================\nexport const isEmailApp = (appName: string): boolean =>\n EMAIL_APP_PATTERNS.some(pattern => appName.toLowerCase().includes(pattern));\n\nexport const isThreatIntelApp = (appName: string): boolean =>\n THREAT_INTEL_PATTERNS.some(pattern => appName.toLowerCase().includes(pattern));\n\nexport const isVulnScannerApp = (appName: string): boolean =>\n VULN_SCANNER_PATTERNS.some(pattern => appName.toLowerCase().includes(pattern));\n\nexport const isIngestionApp = (appName: string): boolean => {\n const name = appName.toLowerCase();\n return isEmailApp(appName) ||\n CASES_PATTERNS.some(p => name.includes(p)) ||\n EDR_PATTERNS.some(p => name.includes(p)) ||\n SIEM_PATTERNS.some(p => name.includes(p));\n};\n\nexport type IngestionCategory = 'email' | 'cases' | 'edr' | 'siem' | 'other';\n\nexport const normalizeAppName = (name: string): string =>\n name.toLowerCase().trim().replace(/[\\s_\\-]+/g, '_');\n\nexport const getIngestionCategory = (appName: string, appCategories?: string[]): IngestionCategory | null => {\n const name = appName.toLowerCase();\n const categories = (appCategories || []).map(c => c.toLowerCase());\n \n if (isEmailApp(name)) return 'email';\n if (CASES_PATTERNS.some(p => name.includes(p)) || categories.includes('cases') || categories.includes('itsm')) return 'cases';\n if (EDR_PATTERNS.some(p => name.includes(p)) || categories.includes('edr') || categories.includes('endpoint')) return 'edr';\n if (SIEM_PATTERNS.some(p => name.includes(p)) || categories.includes('siem')) return 'siem';\n \n return null;\n};\n\n// ============================================================================\n// Workflow-based ingestion detection\n// ============================================================================\n\n/** Name of the workflow that powers automatic ingestion */\nexport const INGEST_TICKETS_WORKFLOW_NAME = 'Ingest Tickets';\n\n/** Name of the workflow that powers forward tickets */\nexport const FORWARD_TICKETS_WORKFLOW_NAME = 'Forward Tickets';\n\n/**\n * Extract normalized app names from a workflow's actions.\n * Returns a Set of normalized app names found in the workflow.\n */\nexport function extractWorkflowAppNames(workflow: any): Set<string> {\n const names = new Set<string>();\n if (!workflow?.actions || !Array.isArray(workflow.actions)) return names;\n\n for (const action of workflow.actions) {\n if (action.app_name) {\n names.add(normalizeAppName(action.app_name));\n }\n if (action.app_id) {\n names.add(normalizeAppName(action.app_id));\n }\n // Handle Singul-type actions with nested app_name in parameters\n if (action.parameters) {\n for (const param of action.parameters) {\n if (param.name === 'app_name' && param.value) {\n names.add(normalizeAppName(param.value));\n }\n }\n }\n }\n return names;\n}\n\n/**\n * Find the 'Ingest Tickets' workflow from a list of workflows.\n * Returns the workflow object or null.\n */\nexport function findIngestTicketsWorkflow(workflows: any[]): any | null {\n return workflows.find(w => w.name === INGEST_TICKETS_WORKFLOW_NAME) || null;\n}\n\n/**\n * Check if a workflow's schedule/trigger is stopped.\n * Returns true if all triggers are stopped or the workflow has no triggers.\n */\nexport function isWorkflowScheduleStopped(workflow: any): boolean {\n if (!workflow) return true;\n const triggers = workflow.triggers;\n if (!Array.isArray(triggers) || triggers.length === 0) return true;\n // If every trigger is explicitly stopped, the workflow is effectively disabled\n return triggers.every(\n (t: any) => (t.status || '').toLowerCase() === 'stopped'\n );\n}\n\n/**\n * Find the 'Forward Tickets' workflow from a list of workflows.\n * Returns the workflow object or null.\n */\nexport function findForwardTicketsWorkflow(workflows: any[]): any | null {\n return workflows.find(w => w.name === FORWARD_TICKETS_WORKFLOW_NAME) || null;\n}\n\n// ============================================================================\n// Validated ingestion app extraction from raw API data\n// ============================================================================\nexport interface ValidatedIngestionApp {\n id: string;\n name: string;\n image?: string;\n validated: boolean;\n enabled: boolean;\n category: IngestionCategory;\n}\n\n/**\n * Extract validated apps from the raw /api/v1/apps/authentication response.\n * Returns deduplicated apps that have valid authentication.\n *\n * Enablement is determined by whether the app appears in the\n * 'Ingest Tickets' workflow's actions (workflows are the source of truth).\n *\n * @param authApiResponse - Raw response from /api/v1/apps/authentication\n * @param workflowAppNames - Set of normalized app names from the Ingest Tickets workflow actions\n */\nexport function extractValidatedIngestionApps(\n authApiResponse: any[],\n workflowAppNames?: Set<string>,\n): ValidatedIngestionApp[] {\n const dedupedApps = deduplicateAuthApps(\n authApiResponse.filter(auth => auth.active || auth.validation?.valid)\n );\n\n const enabledNames = workflowAppNames || new Set<string>();\n\n const apps: ValidatedIngestionApp[] = [];\n\n for (const { app, bestImage, hasValidAuth } of dedupedApps) {\n const category = getIngestionCategory(app.name, app.categories) || 'other';\n const enabled = enabledNames.has(normalizeAppName(app.name));\n\n apps.push({\n id: app.id,\n name: app.name,\n image: bestImage || app.large_image,\n validated: hasValidAuth,\n enabled,\n category,\n });\n }\n\n // Sort: Enabled+Validated > Enabled+Unvalidated > Disabled+Validated > Disabled+Unvalidated, then alphabetically\n apps.sort((a, b) => {\n const aScore = (a.enabled ? 2 : 0) + (a.validated ? 1 : 0);\n const bScore = (b.enabled ? 2 : 0) + (b.validated ? 1 : 0);\n if (aScore !== bScore) return bScore - aScore;\n return a.name.localeCompare(b.name);\n });\n\n return apps;\n}\n","/**\n * AppTitleHeader — Standalone title/header card for an app.\n *\n * Shows avatar (with valid-auth border), name, Verified/Pending chip,\n * categories, and either an \"Activate/Deactivate\" or \"+ Add\" action.\n *\n * Pure presentational component — pass in already-resolved props.\n */\n\nimport { Box, Typography, Avatar, Chip, Button } from '@mui/material';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';\nimport { motion } from 'framer-motion';\n\nexport interface AppTitleHeaderProps {\n /** Display name of the app (will be capitalized via CSS). */\n name: string;\n /** Image URL for the app icon. */\n image?: string;\n /** Whether at least one valid authentication exists. */\n hasValidAuth?: boolean;\n /** Whether at least one auth entry exists (valid or not). */\n hasAnyAuth?: boolean;\n /** Whether the host is authenticated — controls Verified/Pending chip + Activate button visibility. */\n isAuthenticated?: boolean;\n /** App categories to display as chips. */\n categories?: string[];\n /** Activation state — `null` hides the Activate button. */\n isActivated?: boolean | null;\n /** Whether activation toggle is in-flight. */\n activateLoading?: boolean;\n /** Called when user clicks Activate/Deactivate. */\n onActivateToggle?: () => void;\n /** When provided, replaces the Activate button with \"+ Add\". */\n onAdd?: () => void;\n}\n\nexport default function AppTitleHeader({\n name,\n image,\n hasValidAuth = false,\n hasAnyAuth = false,\n isAuthenticated = true,\n categories,\n isActivated = null,\n activateLoading = false,\n onActivateToggle,\n onAdd,\n}: AppTitleHeaderProps) {\n return (\n <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3 }}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n mb: 3,\n p: 2.5,\n borderRadius: 3,\n background: 'linear-gradient(135deg, hsl(var(--foreground) / 0.03) 0%, hsl(var(--foreground) / 0.01) 100%)',\n border: '1px solid hsl(var(--border))',\n }}\n >\n <Avatar\n src={image}\n alt={name}\n sx={{\n width: 56,\n height: 56,\n borderRadius: '14px',\n backgroundColor: 'hsl(var(--muted))',\n border: '2px solid',\n borderColor: hasValidAuth\n ? 'hsl(var(--severity-low))'\n : hasAnyAuth\n ? 'hsl(142 76% 36% / 0.3)'\n : 'hsl(var(--border))',\n p: 0.5,\n '& img': { objectFit: 'contain', borderRadius: '10px' },\n }}\n >\n <Typography sx={{ fontSize: '1.2rem', fontWeight: 700 }}>{name.charAt(0).toUpperCase()}</Typography>\n </Avatar>\n\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 700, fontSize: '1rem', textTransform: 'capitalize' }}>\n {name}\n </Typography>\n {isAuthenticated && hasValidAuth && (\n <Chip\n icon={<CheckCircleIcon sx={{ fontSize: 14 }} />}\n label=\"Verified\"\n size=\"small\"\n sx={{ height: 22, backgroundColor: 'hsla(142, 76%, 36%, 0.15)', color: 'hsl(var(--severity-low))', fontWeight: 600, fontSize: '0.7rem', '& .MuiChip-icon': { color: 'hsl(var(--severity-low))' } }}\n />\n )}\n {isAuthenticated && !hasValidAuth && hasAnyAuth && (\n <Chip\n icon={<ErrorOutlineIcon sx={{ fontSize: 14 }} />}\n label=\"Pending\"\n size=\"small\"\n sx={{ height: 22, backgroundColor: 'hsla(38, 92%, 50%, 0.15)', color: 'hsl(var(--severity-medium))', fontWeight: 600, fontSize: '0.7rem', '& .MuiChip-icon': { color: 'hsl(var(--severity-medium))' } }}\n />\n )}\n </Box>\n\n {categories && categories.length > 0 && (\n <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>\n {categories.slice(0, 3).map(cat => (\n <Chip\n key={cat}\n label={cat}\n size=\"small\"\n sx={{ height: 18, fontSize: '0.6rem', fontWeight: 500, backgroundColor: 'hsl(var(--muted))', color: 'hsl(var(--muted-foreground))', textTransform: 'capitalize' }}\n />\n ))}\n </Box>\n )}\n </Box>\n\n {onAdd && (\n <Button\n onClick={onAdd}\n variant=\"contained\"\n size=\"small\"\n sx={{\n textTransform: 'none', fontWeight: 600, fontSize: '0.72rem', borderRadius: 2, px: 1.5, py: 0.5, minHeight: 0, flexShrink: 0,\n bgcolor: '#FF6600', '&:hover': { bgcolor: '#e55c00' },\n }}\n >\n + Add\n </Button>\n )}\n\n {!onAdd && isAuthenticated && isActivated !== null && onActivateToggle && (\n <Button\n onClick={onActivateToggle}\n disabled={activateLoading}\n variant={isActivated ? 'outlined' : 'contained'}\n size=\"small\"\n sx={{\n textTransform: 'none', fontWeight: 600, fontSize: '0.72rem', borderRadius: 2, px: 1.5, py: 0.5, minHeight: 0, flexShrink: 0,\n ...(isActivated\n ? { color: 'hsl(var(--muted-foreground))', borderColor: 'hsl(var(--border))', '&:hover': { borderColor: 'hsl(var(--destructive))', color: 'hsl(var(--destructive))', bgcolor: 'hsla(var(--destructive) / 0.08)' } }\n : { bgcolor: '#FF6600', '&:hover': { bgcolor: '#e55c00' } }),\n }}\n >\n {activateLoading ? '…' : isActivated ? 'Deactivate' : 'Activate'}\n </Button>\n )}\n </Box>\n </motion.div>\n );\n}\n","/**\n * AppAuthSection — Standalone Authentication block for an app.\n *\n * Wraps the heading/description + AppAuthCard. Pass in the resolved\n * algoliaApp and auth state so this remains presentational.\n */\n\nimport { Box, Typography } from '@mui/material';\nimport { motion } from 'framer-motion';\nimport { AppAuthCard } from '@/Shuffle-MCPs/AppAuthConfig';\nimport type { AlgoliaSearchApp } from './shuffle-mcp.helpers';\n\nexport interface AppAuthSectionProps {\n /** Display name (used in copy when no auth exists). */\n displayName: string;\n /** Algolia app object — required to render the AuthCard. */\n algoliaApp: AlgoliaSearchApp | null;\n /** Resolved app id (Algolia objectID). When missing the card is hidden. */\n resolvedAlgoliaId: string | null;\n /** Auth state object from useAppAuth. */\n authState: any;\n /** Whether the card is expanded. */\n expanded: boolean;\n onToggle: () => void;\n /** Number of matching auth entries — drives the subtitle copy. */\n authCount: number;\n /** Whether the host is authenticated (no Cloud session = hide form). */\n isAuthenticated?: boolean;\n /** Auth entries already filtered to this app. */\n matchingEntries: any[];\n onAuthChange: any;\n onTestConnection: (appId: string, authId?: string) => any;\n onSaveAuth: (appId: string, credentials: Record<string, string>) => Promise<boolean>;\n onRefreshAuth: () => void;\n}\n\nexport default function AppAuthSection({\n displayName,\n algoliaApp,\n resolvedAlgoliaId,\n authState,\n expanded,\n onToggle,\n authCount,\n isAuthenticated = true,\n matchingEntries,\n onAuthChange,\n onTestConnection,\n onSaveAuth,\n onRefreshAuth,\n}: AppAuthSectionProps) {\n return (\n <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.1 }}>\n <Box sx={{ mb: 3 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 600, fontSize: '0.95rem', mb: 0.5 }}>\n Authentication\n </Typography>\n <Typography variant=\"body2\" sx={{ color: 'hsl(var(--muted-foreground))', mb: 1.5 }}>\n {isAuthenticated\n ? authCount > 0\n ? `${authCount} configuration${authCount > 1 ? 's' : ''} found`\n : 'No authentication configured yet'\n : `Connect your ${displayName} account`}\n </Typography>\n {isAuthenticated && algoliaApp && resolvedAlgoliaId && (\n <AppAuthCard\n app={algoliaApp}\n authState={authState}\n isExpanded={expanded}\n onToggle={onToggle}\n onAuthChange={onAuthChange}\n onTestConnection={onTestConnection}\n onSaveAuth={onSaveAuth}\n apiAuthEntries={matchingEntries}\n onRefreshAuth={onRefreshAuth}\n />\n )}\n </Box>\n </motion.div>\n );\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { toast } from '@/Shuffle-MCPs/toast';\nimport {\n Box,\n Typography,\n TextField,\n Button,\n Card,\n CardContent,\n Collapse,\n Alert,\n CircularProgress,\n Chip,\n IconButton,\n Link,\n Divider,\n FormControl,\n Select,\n MenuItem,\n Checkbox,\n ListItemText,\n OutlinedInput,\n Tooltip,\n Dialog,\n DialogTitle,\n DialogContent,\n} from '@mui/material';\nimport { motion } from 'framer-motion';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport EditIcon from '@mui/icons-material/Edit';\nimport DeleteOutlineIcon from '@mui/icons-material/DeleteOutlined';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport LockIcon from '@mui/icons-material/Lock';\nimport MenuBookIcon from '@mui/icons-material/MenuBook';\nimport CloseIcon from '@mui/icons-material/Close';\nimport type { AlgoliaSearchApp } from '@/Shuffle-MCPs';\nimport { API_CONFIG, getApiUrl, getAuthHeader, isDevEnvironment, isCloudDomain } from '@/Shuffle-MCPs/api';\nimport { getIngestionCategory } from '@/Shuffle-MCPs/ingestionDetection';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nexport type AuthStatus = 'pending' | 'testing' | 'connected' | 'error';\n\nexport interface AppAuthState {\n systemId: string;\n status: AuthStatus;\n credentials: Record<string, string>;\n errorMessage?: string;\n successMessage?: string;\n warningMessage?: string;\n workflowId?: string;\n executionId?: string;\n errorCode?: number; // HTTP status code for credential errors (401, 403, etc.)\n}\n\n// Helper to check if auth type is OAuth2 (includes oauth2-app variant)\nconst isOAuth2Type = (type: string | undefined): boolean => {\n if (!type) return false;\n const lowerType = type.toLowerCase();\n return lowerType === 'oauth2' || lowerType === 'oauth2-app';\n};\n\n// Helper to check if auth type indicates no authentication required\n// Returns true for explicit \"no auth\" types OR apps with no parameters/OAuth config\nconst isNoAuthRequired = (auth: AppAuthentication | undefined): boolean => {\n if (!auth) return false; // No auth object loaded yet = unknown\n const type = auth.type?.toLowerCase() || '';\n // Explicit \"no auth\" types\n if (type === 'none' || type === 'no_auth' || type === 'no authentication' || type === 'no_key') return true;\n // Check if there's nothing to configure (not OAuth, no parameters)\n const isOAuth = type === 'oauth2' || type === 'oauth2-app';\n const hasParameters = auth.parameters && auth.parameters.length > 0;\n const hasOAuthConfig = auth.client_id || auth.client_secret || auth.token_uri;\n // If no OAuth and no parameters, auth is not required\n if (!isOAuth && !hasParameters && !hasOAuthConfig) return true;\n return false;\n};\n\n// URL validation helper\nconst isValidUrl = (value: string): boolean => {\n if (!value) return false;\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n};\n\ninterface AuthParameter {\n description: string;\n example: string;\n id: string;\n name: string;\n required: boolean;\n schema: {\n type: string;\n };\n}\n\ninterface AppAuthentication {\n type: string;\n description?: string;\n redirect_uri?: string;\n token_uri?: string;\n refresh_uri?: string;\n authorization_url?: string;\n // Common alternative field names for the authorization endpoint\n auth_uri?: string;\n authorize_url?: string;\n scope?: string[];\n client_id?: string;\n client_secret?: string;\n parameters?: AuthParameter[];\n}\n\n// API authentication entry (from /api/v1/apps/authentication)\nexport interface ApiAuthEntry {\n id?: string;\n label?: string;\n app: {\n id: string;\n name: string;\n large_image?: string;\n };\n active?: boolean;\n created?: number;\n edited?: number;\n validation?: {\n valid: boolean;\n error?: string;\n last_valid?: number;\n };\n}\n\ninterface DecodedApp {\n name: string;\n description: string;\n authentication: AppAuthentication;\n large_image?: string;\n}\n\ninterface AppAuthConfigProps {\n apps: AlgoliaSearchApp[];\n authStates: Record<string, AppAuthState>;\n authenticatedApps?: ApiAuthEntry[];\n onAuthChange: (appId: string, credentials: Record<string, string>) => void;\n onTestConnection: (appId: string, authenticationId?: string) => void;\n onSaveAuth: (appId: string, credentials: Record<string, string>) => Promise<boolean>;\n onSelectAuth?: (appId: string, authId: string) => void;\n onRefreshAuth?: () => Promise<void> | void;\n}\n\nexport interface AppAuthCardProps {\n app: AlgoliaSearchApp;\n authState: AppAuthState;\n isExpanded: boolean;\n onToggle: () => void;\n onAuthChange: (appId: string, credentials: Record<string, string>) => void;\n onTestConnection: (appId: string, authenticationId?: string) => void;\n onSaveAuth: (appId: string, credentials: Record<string, string>) => Promise<boolean>;\n apiAuthEntries: ApiAuthEntry[];\n onSelectAuth?: (appId: string, authId: string) => void;\n /** Called to refresh auth entries (e.g. after OAuth popup closes) */\n onRefreshAuth?: () => Promise<void> | void;\n /** When true, do NOT auto-fill URL fields with the param.example value. */\n disableUrlPrefill?: boolean;\n}\n\nconst containerVariants = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: { staggerChildren: 0.1 },\n },\n};\n\nconst itemVariants = {\n hidden: { opacity: 0, y: 20 },\n visible: { opacity: 1, y: 0, transition: { duration: 0.4 } },\n};\n\nconst ADD_NEW_AUTH = '__add_new__';\n\nexport const AppAuthCard = ({\n app,\n authState,\n isExpanded,\n onToggle,\n onAuthChange,\n onTestConnection,\n onSaveAuth,\n apiAuthEntries,\n onSelectAuth,\n onRefreshAuth,\n disableUrlPrefill,\n}: AppAuthCardProps) => {\n // Helper to get best default auth: prioritize validated, otherwise last entry\n const getBestDefaultAuth = (entries: ApiAuthEntry[]): string => {\n if (entries.length === 0) return ADD_NEW_AUTH;\n \n // First, find a validated entry\n const validatedEntry = entries.find(e => e.validation?.valid === true);\n if (validatedEntry) {\n return validatedEntry.id || validatedEntry.label || '0';\n }\n \n // Otherwise, use the last entry (assuming API returns in chronological order)\n const lastEntry = entries[entries.length - 1];\n return lastEntry.id || lastEntry.label || '0';\n };\n\n // Track selected auth from dropdown\n const [selectedAuthId, setSelectedAuthId] = useState<string>(() => {\n return getBestDefaultAuth(apiAuthEntries);\n });\n\n // Track if user has made an explicit selection (to prevent auto-override on refresh)\n const [userHasSelected, setUserHasSelected] = useState(false);\n \n // Track test status PER authentication ID for this session\n // This ensures switching between auths shows each one's test result correctly\n type TestStatusValue = 'untested' | 'testing' | 'success' | 'pending_validation' | 'error';\n const [testStatusPerAuth, setTestStatusPerAuth] = useState<Record<string, TestStatusValue>>({});\n \n // Track test messages per auth (error message, success message, warning message)\n const [testMessagesPerAuth, setTestMessagesPerAuth] = useState<Record<string, {\n errorMessage?: string;\n successMessage?: string;\n warningMessage?: string;\n workflowId?: string;\n executionId?: string;\n errorCode?: number;\n }>>({});\n \n // Track which auth ID is currently being tested (to avoid updating wrong auth on switch)\n const [testingAuthId, setTestingAuthId] = useState<string | null>(null);\n \n // Delete auth state\n const [deleteConfirmAuthId, setDeleteConfirmAuthId] = useState<string | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n const handleDeleteAuth = async (authId: string) => {\n setDeleting(true);\n try {\n const response = await fetch(getApiUrl(`/api/v1/apps/authentication/${authId}`), {\n method: 'DELETE',\n credentials: 'include',\n headers: { ...getAuthHeader() },\n });\n if (response.ok) {\n // If we deleted the selected auth, reset selection\n if (selectedAuthId === authId) {\n setSelectedAuthId(ADD_NEW_AUTH);\n setUserHasSelected(false);\n }\n if (onRefreshAuth) await onRefreshAuth();\n }\n } catch (err) {\n console.error('Failed to delete auth:', err);\n } finally {\n setDeleting(false);\n setDeleteConfirmAuthId(null);\n }\n };\n\n const localTestStatus = testStatusPerAuth[selectedAuthId] || 'untested';\n \n // Track if the selected auth was already validated BEFORE we started testing\n // This is used to determine if we should trust the 200 response as source of truth\n const [wasPreValidatedPerAuth, setWasPreValidatedPerAuth] = useState<Record<string, boolean>>({});\n\n // Track previous entry count to detect new auths added (e.g. from OAuth popup)\n const prevEntryCountRef = useRef(apiAuthEntries.length);\n // Guard to prevent multiple auto-tests firing\n const autoTestFiredRef = useRef<string | null>(null);\n\n // Update selection when apiAuthEntries changes\n useEffect(() => {\n if (apiAuthEntries.length > 0) {\n // If a new entry was added (count increased), auto-select the newest one\n if (apiAuthEntries.length > prevEntryCountRef.current) {\n const sorted = [...apiAuthEntries].sort((a, b) => {\n const aTime = a.created || a.edited || 0;\n const bTime = b.created || b.edited || 0;\n return bTime - aTime;\n });\n const newestId = sorted[0]?.id || sorted[0]?.label || '0';\n setSelectedAuthId(newestId);\n \n // Auto-test the new auth if not already validated and not already auto-tested\n const newestEntry = sorted[0];\n const alreadyValid = newestEntry?.validation?.valid === true;\n if (!alreadyValid && newestId !== autoTestFiredRef.current) {\n autoTestFiredRef.current = newestId;\n // Small delay to let state settle before firing test\n setTimeout(() => {\n toast({\n title: 'Auto-testing new authentication',\n description: `Verifying connection for ${app.name.replace(/_/g, ' ')}...`,\n });\n setTestingAuthId(newestId);\n onTestConnection(app.objectID, newestId);\n }, 500);\n }\n } else if (!userHasSelected) {\n setSelectedAuthId(getBestDefaultAuth(apiAuthEntries));\n }\n }\n prevEntryCountRef.current = apiAuthEntries.length;\n }, [apiAuthEntries, userHasSelected]);\n \n // Track pre-validation state when auth selection changes (for first-time tests)\n useEffect(() => {\n // Only set pre-validated state if we haven't tracked this auth yet\n if (wasPreValidatedPerAuth[selectedAuthId] === undefined) {\n const currentAuth = apiAuthEntries.find(\n auth => (auth.id || auth.label || '') === selectedAuthId\n );\n setWasPreValidatedPerAuth(prev => ({\n ...prev,\n [selectedAuthId]: currentAuth?.validation?.valid === true\n }));\n }\n }, [selectedAuthId, apiAuthEntries]);\n \n // Get the currently selected auth entry (needed for validation check)\n const selectedAuth = apiAuthEntries.find(\n auth => (auth.id || auth.label || '') === selectedAuthId\n );\n \n // Helper to update test status for a specific auth\n const setTestStatusForAuth = (authId: string, status: TestStatusValue) => {\n setTestStatusPerAuth(prev => ({ ...prev, [authId]: status }));\n };\n \n // Helper to update test messages for a specific auth\n const setTestMessagesForAuth = (authId: string, messages: {\n errorMessage?: string;\n successMessage?: string;\n warningMessage?: string;\n workflowId?: string;\n executionId?: string;\n errorCode?: number;\n }) => {\n setTestMessagesPerAuth(prev => ({ ...prev, [authId]: messages }));\n };\n \n // Get test messages for current auth\n const localTestMessages = testMessagesPerAuth[selectedAuthId] || {};\n const wasPreValidated = wasPreValidatedPerAuth[selectedAuthId] || false;\n \n // Sync test status with authState when test completes, checking backend validation status\n // IMPORTANT: Only update the auth that was being tested, not the currently selected auth\n useEffect(() => {\n // Only process if we have a testingAuthId (a test was initiated)\n if (!testingAuthId) return;\n \n if (authState.status === 'testing') {\n setTestStatusForAuth(testingAuthId, 'testing');\n // Clear previous messages when starting a new test\n setTestMessagesForAuth(testingAuthId, {});\n } else if (authState.status === 'connected') {\n // Get the auth entry that was being tested\n const testedAuth = apiAuthEntries.find(\n auth => (auth.id || auth.label || '') === testingAuthId\n );\n const wasTestedAuthPreValidated = wasPreValidatedPerAuth[testingAuthId] || false;\n \n // If auth was already validated before testing, trust the 200 response\n // (Re-tests don't always update the backend validation status)\n if (wasTestedAuthPreValidated) {\n setTestStatusForAuth(testingAuthId, 'success');\n } else {\n // For newly tested auths, check if backend has validated\n const isBackendValidated = testedAuth?.validation?.valid === true;\n setTestStatusForAuth(testingAuthId, isBackendValidated ? 'success' : 'pending_validation');\n }\n // Store the success/warning messages for this auth\n setTestMessagesForAuth(testingAuthId, {\n successMessage: authState.successMessage,\n warningMessage: authState.warningMessage,\n });\n // Clear testingAuthId after processing completed status\n setTestingAuthId(null);\n } else if (authState.status === 'error') {\n setTestStatusForAuth(testingAuthId, 'error');\n // Store the error details for this auth\n setTestMessagesForAuth(testingAuthId, {\n errorMessage: authState.errorMessage,\n workflowId: authState.workflowId,\n executionId: authState.executionId,\n errorCode: authState.errorCode,\n });\n // Clear testingAuthId after processing completed status\n setTestingAuthId(null);\n }\n }, [authState.status, authState.errorMessage, authState.successMessage, authState.warningMessage, testingAuthId, apiAuthEntries, wasPreValidatedPerAuth]);\n \n // Track credential errors (401/403) to show warning but don't auto-switch\n // User can manually switch back to other auths or add new one\n const isCredentialError = localTestMessages.errorCode === 401 || localTestMessages.errorCode === 403;\n\n const showAddNewForm = selectedAuthId === ADD_NEW_AUTH;\n\n // Compute configured/tested status for the SELECTED auth entry only (not any auth)\n const isConfigured = selectedAuth?.active === true;\n const isTested = selectedAuth?.validation?.valid === true;\n \n // Get last validation timestamp (prefer selected auth, fallback to any validated entry)\n const getLastValidTimestamp = (): number | undefined => {\n if (selectedAuth?.validation?.last_valid) return selectedAuth.validation.last_valid;\n const validEntry = apiAuthEntries.find(a => a.validation?.valid === true && a.validation?.last_valid);\n return validEntry?.validation?.last_valid;\n };\n \n const formatLastValidDate = (): string => {\n const timestamp = getLastValidTimestamp();\n if (!timestamp) return 'Unknown';\n // Detect if timestamp is in seconds or milliseconds\n // If > 10^12, it's likely milliseconds; otherwise seconds\n const ms = timestamp > 1e12 ? timestamp : timestamp * 1000;\n const date = new Date(ms);\n return date.toLocaleDateString(undefined, { \n year: 'numeric', \n month: 'short', \n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n };\n\n // Local credentials state for the form\n const [localCredentials, setLocalCredentials] = useState<Record<string, string>>(authState.credentials || {});\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n // App config fetching for dynamic fields\n const [loading, setLoading] = useState(false);\n const [saving, setSaving] = useState(false);\n const [saveSuccess, setSaveSuccess] = useState<boolean | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [appConfig, setAppConfig] = useState<DecodedApp | null>(null);\n\n // Refresh auth entries every time the card is expanded\n useEffect(() => {\n if (isExpanded && onRefreshAuth) {\n onRefreshAuth();\n }\n }, [isExpanded]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n const fetchAppConfig = async () => {\n if (!isExpanded || appConfig) return;\n \n setLoading(true);\n setError(null);\n \n try {\n const response = await fetch(getApiUrl(`/api/v1/apps/${app.objectID}/config`), {\n credentials: 'include',\n headers: {\n ...getAuthHeader(),\n },\n });\n \n if (!response.ok) {\n throw new Error('Failed to fetch app configuration');\n }\n \n const data = await response.json();\n \n if (data.success && data.app) {\n const decodedAppString = atob(data.app);\n const decodedApp = JSON.parse(decodedAppString) as DecodedApp;\n console.log('[AppAuthCard] Decoded auth config for', decodedApp.name, ':', JSON.stringify(decodedApp.authentication, null, 2));\n setAppConfig(decodedApp);\n } else {\n throw new Error('Invalid response format');\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load configuration');\n } finally {\n setLoading(false);\n }\n };\n \n fetchAppConfig();\n }, [isExpanded, app.objectID, appConfig]);\n\n const auth = appConfig?.authentication;\n const isOAuth2 = isOAuth2Type(auth?.type);\n\n const [selectedScopes, setSelectedScopes] = useState<string[]>([]);\n\n // Update scopes when auth loads\n useEffect(() => {\n if (auth?.scope) {\n setSelectedScopes(auth.scope);\n }\n }, [auth?.scope]);\n \n // Auto-populate URL fields with example values when auth config loads\n useEffect(() => {\n if (disableUrlPrefill) return;\n if (!auth?.parameters || auth.parameters.length === 0) return;\n \n const urlDefaults: Record<string, string> = {};\n auth.parameters.forEach((param, index) => {\n const fieldKey = param.id || param.name || `param_${index}`;\n const nameOrId = (param.name || param.id || '').toLowerCase();\n \n // Check if this is a URL field and has an example that looks like a URL\n const isUrlField = nameOrId.includes('url') || nameOrId.includes('endpoint') || nameOrId.includes('host');\n const hasUrlExample = param.example && (\n param.example.startsWith('http://') || \n param.example.startsWith('https://')\n );\n \n // Only pre-fill if field is empty and has a URL example\n if (isUrlField && hasUrlExample && !localCredentials[fieldKey]) {\n urlDefaults[fieldKey] = param.example;\n }\n });\n \n // Update credentials with URL defaults if any\n if (Object.keys(urlDefaults).length > 0) {\n setLocalCredentials(prev => ({ ...urlDefaults, ...prev }));\n }\n }, [auth?.parameters, disableUrlPrefill]);\n\n const [docsOpen, setDocsOpen] = useState(false);\n const [docsContent, setDocsContent] = useState<string>('');\n const [docsLoading, setDocsLoading] = useState(false);\n const [editingLabel, setEditingLabel] = useState(false);\n const [editLabelValue, setEditLabelValue] = useState('');\n const [savingLabel, setSavingLabel] = useState(false);\n\n const handleRenameAuth = async () => {\n if (!selectedAuth || !editLabelValue.trim()) return;\n setSavingLabel(true);\n try {\n // Build the auth body with all fields but replaced label\n // Fill any sensitive fields with placeholder\n const placeholder = 'Secret. Replaced during app execution!';\n const authBody: Record<string, any> = {\n ...selectedAuth,\n label: editLabelValue.trim(),\n };\n // Ensure fields array values are placeholders\n if (authBody.fields) {\n const newFields: Record<string, any> = {};\n for (const [key, val] of Object.entries(authBody.fields)) {\n newFields[key] = typeof val === 'string' ? placeholder : val;\n }\n authBody.fields = newFields;\n }\n\n const response = await fetch(getApiUrl('/api/v1/apps/authentication'), {\n method: 'PUT',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...getAuthHeader(),\n },\n body: JSON.stringify(authBody),\n });\n\n if (response.ok) {\n setEditingLabel(false);\n if (onRefreshAuth) await onRefreshAuth();\n toast({ title: 'Label updated', description: `Renamed to \"${editLabelValue.trim()}\"` });\n } else {\n toast({ title: 'Failed to rename', description: 'Could not update the authentication label', variant: 'destructive' });\n }\n } catch (err) {\n toast({ title: 'Error', description: 'Failed to rename authentication', variant: 'destructive' });\n } finally {\n setSavingLabel(false);\n }\n };\n\n const fetchDocs = async () => {\n setDocsLoading(true);\n try {\n const encodedName = encodeURIComponent(app.name);\n const response = await fetch(getApiUrl(`/api/v1/docs/${encodedName}?location=openapi`), {\n credentials: 'include',\n headers: {\n ...getAuthHeader(),\n },\n });\n if (response.ok) {\n const data = await response.json();\n setDocsContent(data.reason || data.data || data.content || 'No documentation available.');\n } else {\n setDocsContent('Failed to load documentation.');\n }\n } catch (error) {\n setDocsContent('Error loading documentation.');\n } finally {\n setDocsLoading(false);\n }\n };\n\n const handleOpenDocs = () => {\n setDocsOpen(true);\n fetchDocs();\n };\n\n // Render OAuth2 fields - only for OAuth2 apps\n const renderOAuth2Fields = () => {\n if (!auth || !isOAuth2) return null;\n\n const availableScopes = auth.scope || [];\n\n const isCloudOrDev = isDevEnvironment() || isCloudDomain();\n const hasManualCredentials = !!localCredentials['client_id']?.trim() && !!localCredentials['client_secret']?.trim();\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>\n {/* Quick Connect Button - OAuth2 only, cloud/dev only, auto-collapses when manual creds filled */}\n {isCloudOrDev && (\n <>\n <Collapse in={!hasManualCredentials}>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>\n <Button\n variant=\"outlined\"\n fullWidth\n startIcon={\n app.image_url ? (\n <Box\n component=\"img\"\n src={app.image_url}\n alt={app.name}\n sx={{ width: 24, height: 24, borderRadius: 1, objectFit: 'contain' }}\n />\n ) : <LockIcon />\n }\n onClick={() => {\n const authUrl = `https://shuffler.io/appauth?app_id=${app.objectID}&source=shuffle`;\n const popup = window.open(authUrl, '_blank', 'width=600,height=700');\n if (popup && onRefreshAuth) {\n const authPollTimer = setInterval(() => {\n onRefreshAuth();\n }, 3000);\n const closePollTimer = setInterval(() => {\n if (popup.closed) {\n clearInterval(closePollTimer);\n clearInterval(authPollTimer);\n onRefreshAuth();\n }\n }, 500);\n }\n }}\n sx={{\n py: 1.5,\n borderColor: 'hsl(var(--primary) / 0.4)',\n color: 'hsl(var(--foreground))',\n fontWeight: 600,\n textTransform: 'none',\n fontSize: '1rem',\n '&:hover': {\n borderColor: 'hsl(var(--primary))',\n backgroundColor: 'hsl(var(--primary) / 0.08)',\n },\n }}\n >\n Quick Connect with {app.name.replace(/_/g, ' ')}\n </Button>\n\n {/* OR Divider */}\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n <Divider sx={{ flex: 1, borderColor: 'hsl(var(--border))' }} />\n <Typography sx={{ color: 'hsl(var(--muted-foreground))', fontSize: '0.875rem' }}>OR configure manually</Typography>\n <Divider sx={{ flex: 1, borderColor: 'hsl(var(--border))' }} />\n </Box>\n </Box>\n </Collapse>\n {hasManualCredentials && (\n <Button\n variant=\"text\"\n size=\"small\"\n onClick={() => {\n setLocalCredentials({});\n onAuthChange(app.objectID, {});\n }}\n sx={{\n color: 'hsl(var(--muted-foreground))',\n textTransform: 'none',\n fontSize: '0.8rem',\n alignSelf: 'flex-start',\n p: 0,\n minWidth: 0,\n '&:hover': { color: 'hsl(var(--foreground))', backgroundColor: 'transparent' },\n }}\n >\n ← Use Quick Connect instead\n </Button>\n )}\n </>\n )}\n\n {/* Manual OAuth2 Fields */}\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" sx={{ color: 'hsl(var(--muted-foreground))' }}>\n Redirect URL: <Typography component=\"span\" sx={{ color: 'hsl(var(--primary))', fontWeight: 600 }}>\n {auth.redirect_uri || 'https://shuffler.io/set_authentication'}\n </Typography>\n </Typography>\n\n <TextField\n label=\"Client ID\"\n placeholder=\"Enter your Client ID\"\n value={localCredentials['client_id'] || ''}\n onChange={(e) => handleCredentialChange('client_id', e.target.value)}\n fullWidth\n size=\"small\"\n sx={{\n '& .MuiOutlinedInput-root': {\n backgroundColor: 'hsl(var(--background))',\n borderRadius: 2,\n '& fieldset': { borderColor: 'hsl(var(--border))' },\n '&:hover fieldset': { borderColor: 'hsl(var(--border) / 0.8)' },\n '&.Mui-focused fieldset': { borderColor: 'hsl(var(--primary))' },\n },\n '& .MuiInputBase-input': { color: 'hsl(var(--foreground))' },\n '& .MuiInputLabel-root': { color: 'hsl(var(--muted-foreground))' },\n }}\n />\n\n <TextField\n label=\"Client Secret\"\n type=\"password\"\n placeholder=\"Enter your Client Secret\"\n value={localCredentials['client_secret'] || ''}\n onChange={(e) => handleCredentialChange('client_secret', e.target.value)}\n fullWidth\n size=\"small\"\n sx={{\n '& .MuiOutlinedInput-root': {\n backgroundColor: 'hsl(var(--background))',\n borderRadius: 2,\n '& fieldset': { borderColor: 'hsl(var(--border))' },\n '&:hover fieldset': { borderColor: 'hsl(var(--border) / 0.8)' },\n '&.Mui-focused fieldset': { borderColor: 'hsl(var(--primary))' },\n },\n '& .MuiInputBase-input': { color: 'hsl(var(--foreground))' },\n '& .MuiInputLabel-root': { color: 'hsl(var(--muted-foreground))' },\n }}\n />\n\n {/* Scopes */}\n {availableScopes.length > 0 && (\n <FormControl fullWidth size=\"small\">\n <Select\n multiple\n value={selectedScopes}\n onChange={(e) => {\n const value = e.target.value as string[];\n setSelectedScopes(value);\n handleCredentialChange('scopes', value.join(' '));\n }}\n input={<OutlinedInput />}\n renderValue={(selected) => selected.length === 0 ? 'Select Scopes' : `${selected.length} scope(s) selected`}\n displayEmpty\n sx={{\n backgroundColor: 'action.hover',\n borderRadius: 2,\n color: 'text.primary',\n '& .MuiOutlinedInput-notchedOutline': { borderColor: 'divider' },\n '&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'text.disabled' },\n '&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: 'primary.main' },\n '& .MuiSvgIcon-root': { color: 'text.secondary' },\n }}\n MenuProps={{\n slotProps: {\n paper: {\n sx: {\n backgroundColor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n maxHeight: 300,\n },\n },\n },\n }}\n >\n {availableScopes.map((scope) => (\n <MenuItem key={scope} value={scope} sx={{ color: 'hsl(var(--foreground))' }}>\n <Checkbox \n checked={selectedScopes.indexOf(scope) > -1}\n sx={{ color: 'hsl(var(--muted-foreground))', '&.Mui-checked': { color: 'hsl(var(--primary))' } }}\n />\n <ListItemText primary={scope} sx={{ '& .MuiTypography-root': { color: 'hsl(var(--foreground))' } }} />\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n )}\n </Box>\n </Box>\n );\n };\n\n // Render parameter fields - for non-OAuth2 apps with parameters\n const renderParameterFields = () => {\n if (isOAuth2) return null;\n if (!auth?.parameters || auth.parameters.length === 0) return null;\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n {auth.parameters.map((param, index) => {\n // Use param.id if available, otherwise fallback to name or index\n const fieldKey = param.id || param.name || `param_${index}`;\n return (\n <TextField\n key={fieldKey}\n label={\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n {param.name}\n {param.required && (\n <Typography component=\"span\" sx={{ color: '#ef4444', fontSize: '0.8rem' }}>*</Typography>\n )}\n </Box>\n }\n type={param.name.toLowerCase().includes('password') || param.name.toLowerCase().includes('secret') || param.name.toLowerCase().includes('key') ? 'password' : 'text'}\n placeholder={param.example || `Enter ${param.name}`}\n value={localCredentials[fieldKey] || ''}\n onChange={(e) => handleCredentialChange(fieldKey, e.target.value)}\n error={!!fieldErrors[fieldKey]}\n helperText={fieldErrors[fieldKey] || param.description}\n fullWidth\n size=\"small\"\n sx={{\n '& .MuiOutlinedInput-root': {\n backgroundColor: 'hsl(var(--muted))',\n borderRadius: 2,\n '& fieldset': { borderColor: fieldErrors[fieldKey] ? '#ef4444' : 'hsl(var(--border))' },\n '&:hover fieldset': { borderColor: fieldErrors[fieldKey] ? '#ef4444' : 'hsl(var(--border))' },\n '&.Mui-focused fieldset': { borderColor: fieldErrors[fieldKey] ? '#ef4444' : 'hsl(var(--primary))' },\n },\n '& .MuiInputBase-input': { color: 'hsl(var(--foreground))' },\n '& .MuiInputLabel-root': { color: 'hsl(var(--muted-foreground))' },\n '& .MuiFormHelperText-root': { color: fieldErrors[fieldKey] ? '#ef4444' : 'hsl(var(--muted-foreground))' },\n }}\n />\n );\n })}\n </Box>\n );\n };\n\n // No longer rendering fallback API key field - apps without parameters don't need auth config\n\n // Validate a single field\n const validateField = (key: string, value: string): string | null => {\n const lowerKey = key.toLowerCase();\n if (lowerKey.includes('url') || lowerKey === 'url') {\n if (!value) return 'URL is required';\n if (!isValidUrl(value)) return 'Please enter a valid URL (e.g., https://example.com)';\n }\n return null;\n };\n\n // Check if all required fields are valid for saving\n const isFormValid = (): boolean => {\n // Check for any field errors\n if (Object.values(fieldErrors).some(err => err)) return false;\n \n // Validate all current credentials\n for (const [key, value] of Object.entries(localCredentials)) {\n const error = validateField(key, value);\n if (error) return false;\n }\n \n // Check required parameters are filled\n if (auth?.parameters && auth.parameters.length > 0) {\n for (let i = 0; i < auth.parameters.length; i++) {\n const param = auth.parameters[i];\n const fieldKey = param.id || param.name || `param_${i}`;\n if (param.required && !localCredentials[fieldKey]?.trim()) return false;\n }\n // At least one parameter must have a value\n const hasAnyValue = auth.parameters.some((param, index) => {\n const fieldKey = param.id || param.name || `param_${index}`;\n return localCredentials[fieldKey]?.trim();\n });\n if (!hasAnyValue) return false;\n }\n // Apps without parameters don't need validation - they work without auth\n \n return true;\n };\n\n const handleSave = async () => {\n setSaving(true);\n setSaveSuccess(null);\n const success = await onSaveAuth(app.objectID, localCredentials);\n setSaving(false);\n setSaveSuccess(success);\n if (success) {\n setUserHasSelected(false); // Allow auto-selection to pick up new auth\n setLocalCredentials({}); // Clear form after success\n setFieldErrors({}); // Clear errors\n }\n };\n\n // Helper to update local credentials and notify parent\n const handleCredentialChange = (key: string, value: string) => {\n // Ignore empty keys\n if (!key || key.trim() === '') return;\n \n const updated = { ...localCredentials, [key]: value };\n setLocalCredentials(updated);\n onAuthChange(app.objectID, updated);\n \n // Validate the field\n const error = validateField(key, value);\n setFieldErrors(prev => ({\n ...prev,\n [key]: error || '',\n }));\n };\n\n return (\n <motion.div variants={itemVariants} style={{ width: '100%', maxWidth: '100%' }}>\n <Card\n sx={{\n background: 'hsl(var(--card) / 0.9)',\n border: '2px solid',\n borderColor: isTested\n ? 'hsl(var(--severity-low) / 0.5)'\n : authState.status === 'error'\n ? 'hsl(var(--destructive) / 0.3)'\n : 'hsl(var(--severity-medium) / 0.3)',\n borderRadius: 3,\n backdropFilter: 'blur(10px)',\n overflow: 'hidden',\n transition: 'all 0.3s ease',\n width: '100%',\n maxWidth: '100%',\n }}\n >\n <CardContent\n onClick={onToggle}\n sx={{\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n alignItems: { xs: 'flex-start', sm: 'center' },\n gap: { xs: 1.5, sm: 2 },\n cursor: 'pointer',\n p: { xs: 2, sm: 3 },\n '&:last-child': { pb: { xs: 2, sm: 3 } },\n '&:hover': { backgroundColor: 'hsl(var(--muted) / 0.35)' },\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, flex: 1, minWidth: 0 }}>\n {app.image_url ? (\n <Box\n component=\"img\"\n src={app.image_url}\n alt={app.name}\n sx={{\n width: { xs: 40, sm: 48 },\n height: { xs: 40, sm: 48 },\n borderRadius: 2,\n objectFit: 'contain',\n backgroundColor: 'hsl(var(--muted) / 0.5)',\n p: 1,\n flexShrink: 0,\n }}\n />\n ) : (\n <Box\n sx={{\n width: { xs: 40, sm: 48 },\n height: { xs: 40, sm: 48 },\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'hsl(var(--muted) / 0.5)',\n borderRadius: 2,\n fontSize: '1.5rem',\n flexShrink: 0,\n }}\n >\n 🔗\n </Box>\n )}\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Typography \n sx={{ \n color: 'hsl(var(--foreground))', \n fontWeight: 600, \n fontSize: { xs: '0.9rem', sm: '1rem' },\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {app.name.replace(/_/g, ' ')}\n </Typography>\n {app.description && (\n <Typography \n variant=\"caption\" \n sx={{ \n color: 'hsl(var(--muted-foreground))',\n display: { xs: 'none', md: 'block' },\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n maxWidth: '100%',\n }}\n >\n {app.description}\n </Typography>\n )}\n </Box>\n </Box>\n <Box sx={{ \n display: 'flex', \n alignItems: 'center', \n gap: { xs: 1, sm: 1.5 }, \n flexWrap: 'wrap',\n width: { xs: '100%', sm: 'auto' },\n justifyContent: { xs: 'flex-start', sm: 'flex-end' },\n }}>\n {/* Auth status chip - show \"Auth not required\" for no-auth apps */}\n {isNoAuthRequired(auth) ? (\n <Chip\n label=\"Auth not required\"\n size=\"small\"\n sx={{\n backgroundColor: 'hsl(var(--severity-info) / 0.15)',\n color: 'hsl(var(--severity-info))',\n fontWeight: 500,\n fontSize: { xs: '0.6rem', sm: '0.65rem' },\n height: { xs: 22, sm: 24 },\n }}\n />\n ) : (\n <>\n {/* Configured status chip */}\n <Chip\n label={isConfigured ? 'Configured' : 'Not configured'}\n size=\"small\"\n sx={{\n backgroundColor: isConfigured ? 'hsl(var(--severity-medium) / 0.15)' : 'hsl(var(--destructive) / 0.15)',\n color: isConfigured ? 'hsl(var(--severity-medium))' : 'hsl(var(--destructive))',\n fontWeight: 500,\n fontSize: { xs: '0.6rem', sm: '0.65rem' },\n height: { xs: 22, sm: 24 },\n }}\n />\n {/* Tested status chip */}\n <Tooltip \n title={isTested ? `Last validated: ${formatLastValidDate()}` : ''} \n arrow\n disableHoverListener={!isTested}\n >\n <Chip\n label={isTested ? 'Tested' : 'Not tested'}\n size=\"small\"\n sx={{\n backgroundColor: isTested ? 'hsl(var(--severity-low) / 0.15)' : 'hsl(var(--muted) / 0.8)',\n color: isTested ? 'hsl(var(--severity-low))' : 'hsl(var(--muted-foreground))',\n fontWeight: 500,\n fontSize: { xs: '0.6rem', sm: '0.65rem' },\n height: { xs: 22, sm: 24 },\n cursor: isTested ? 'help' : 'default',\n }}\n />\n </Tooltip>\n </>\n )}\n <Tooltip title=\"View documentation\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenDocs();\n }}\n sx={{\n color: 'hsl(var(--muted-foreground))',\n '&:hover': { \n color: 'hsl(var(--severity-info))',\n backgroundColor: 'hsl(var(--severity-info) / 0.1)',\n },\n }}\n >\n <MenuBookIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <IconButton\n size=\"small\"\n sx={{\n color: 'hsl(var(--muted-foreground))',\n transform: isExpanded ? 'rotate(180deg)' : 'none',\n transition: 'transform 0.3s ease',\n }}\n >\n <ExpandMoreIcon />\n </IconButton>\n </Box>\n </CardContent>\n\n <Collapse in={isExpanded}>\n <Box\n sx={{\n px: { xs: 2, sm: 3 },\n pb: { xs: 2, sm: 3 },\n pt: 2,\n borderTop: '1px solid hsl(var(--border))',\n }}\n >\n {/* Auth Selection Dropdown - always at top */}\n {apiAuthEntries.length > 0 && (\n <Box sx={{ mb: 3 }}>\n <Typography variant=\"body2\" sx={{ color: 'hsl(var(--muted-foreground))', mb: 1 }}>\n Select authentication\n </Typography>\n <FormControl fullWidth size=\"small\">\n <Select\n value={selectedAuthId}\n onChange={(e) => {\n const value = e.target.value as string;\n setSelectedAuthId(value);\n // Track that user has made an explicit selection\n setUserHasSelected(true);\n if (value !== ADD_NEW_AUTH && onSelectAuth) {\n onSelectAuth(app.objectID, value);\n }\n }}\n sx={{\n backgroundColor: 'hsl(var(--background))',\n borderRadius: 2,\n color: 'hsl(var(--foreground))',\n '& .MuiOutlinedInput-notchedOutline': { borderColor: 'hsl(var(--border))' },\n '&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'hsl(var(--border) / 0.8)' },\n '&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: 'hsl(var(--primary))' },\n '& .MuiSvgIcon-root': { color: 'hsl(var(--muted-foreground))' },\n }}\n MenuProps={{\n slotProps: {\n paper: {\n sx: {\n backgroundColor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n },\n },\n },\n }}\n >\n {/* Sort by created date - most recent first */}\n {[...apiAuthEntries]\n .sort((a, b) => {\n const aTime = a.created || a.edited || 0;\n const bTime = b.created || b.edited || 0;\n return bTime - aTime; // Descending (newest first)\n })\n .map((authEntry, index) => {\n const isLatest = index === 0 && apiAuthEntries.length > 1;\n const entryId = authEntry.id || authEntry.label || index.toString();\n const entryLabel = authEntry.label || `Auth ${index + 1}`;\n const isActive = authEntry.active === true;\n const isValid = authEntry.validation?.valid === true;\n \n // Format timestamp for tooltips\n const formatTimestamp = (ts?: number): string => {\n if (!ts) return 'Unknown';\n const date = ts > 1e12 ? new Date(ts) : new Date(ts * 1000);\n return date.toLocaleString();\n };\n \n const configuredDate = authEntry.created || authEntry.edited;\n const lastValidDate = authEntry.validation?.last_valid;\n \n return (\n <MenuItem key={entryId} value={entryId} sx={{ color: 'hsl(var(--foreground))', py: 1 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', minWidth: 0 }}>\n <Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>\n <Tooltip \n title={isActive ? `Created: ${formatTimestamp(configuredDate)}` : 'Not configured'}\n arrow\n placement=\"top\"\n >\n <Chip\n label={isActive ? 'Configured' : 'Not configured'}\n size=\"small\"\n sx={{\n height: 20,\n fontSize: '0.6rem',\n backgroundColor: isActive ? 'hsl(var(--severity-medium) / 0.15)' : 'hsl(var(--destructive) / 0.15)',\n color: isActive ? 'hsl(var(--severity-medium))' : 'hsl(var(--destructive))',\n }}\n />\n </Tooltip>\n <Tooltip \n title={lastValidDate ? `Last valid: ${formatTimestamp(lastValidDate)}` : 'Never validated'}\n arrow\n placement=\"top\"\n >\n <Chip\n label={isValid ? 'Tested' : 'Not tested'}\n size=\"small\"\n sx={{\n height: 20,\n fontSize: '0.6rem',\n backgroundColor: isValid ? 'hsl(var(--severity-low) / 0.15)' : 'hsl(var(--muted) / 0.8)',\n color: isValid ? 'hsl(var(--severity-low))' : 'hsl(var(--muted-foreground))',\n }}\n />\n </Tooltip>\n {isLatest && (\n <Chip\n label=\"Latest\"\n size=\"small\"\n sx={{\n height: 20,\n fontSize: '0.6rem',\n fontWeight: 700,\n backgroundColor: 'hsl(var(--infra-email) / 0.15)',\n color: 'hsl(var(--infra-email))',\n }}\n />\n )}\n </Box>\n <Typography sx={{ \n flex: 1, \n overflow: 'hidden', \n textOverflow: 'ellipsis', \n whiteSpace: 'nowrap',\n minWidth: 0,\n }}>\n {entryLabel}\n </Typography>\n {/* Delete button for non-validated entries */}\n {!isValid && (\n <Tooltip title=\"Delete authentication\" arrow placement=\"top\">\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n e.preventDefault();\n setDeleteConfirmAuthId(entryId);\n }}\n sx={{\n color: 'hsl(var(--muted-foreground))',\n p: 0.5,\n ml: 0.5,\n flexShrink: 0,\n '&:hover': {\n color: 'hsl(var(--destructive))',\n backgroundColor: 'hsl(var(--destructive) / 0.1)',\n },\n }}\n >\n <DeleteOutlineIcon sx={{ fontSize: 16 }} />\n </IconButton>\n </Tooltip>\n )}\n </Box>\n </MenuItem>\n );\n })}\n <Divider sx={{ borderColor: 'hsl(var(--border))', my: 1 }} />\n <MenuItem value={ADD_NEW_AUTH} sx={{ color: 'hsl(var(--primary))', fontWeight: 600 }}>\n + Add new authentication\n </MenuItem>\n </Select>\n </FormControl>\n\n {/* Delete confirmation dialog */}\n <Dialog\n open={!!deleteConfirmAuthId}\n onClose={() => setDeleteConfirmAuthId(null)}\n slotProps={{\n paper: {\n sx: {\n backgroundColor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 3,\n minWidth: 360,\n },\n },\n }}\n >\n <DialogTitle sx={{ color: 'hsl(var(--foreground))', fontWeight: 600, pb: 1 }}>\n Delete Authentication\n </DialogTitle>\n <DialogContent>\n <Typography sx={{ color: 'hsl(var(--muted-foreground))', mb: 3 }}>\n Are you sure you want to delete this authentication? This action cannot be undone.\n </Typography>\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 1.5 }}>\n <Button\n variant=\"outlined\"\n size=\"small\"\n onClick={() => setDeleteConfirmAuthId(null)}\n disabled={deleting}\n sx={{\n borderColor: 'hsl(var(--border))',\n color: 'hsl(var(--muted-foreground))',\n textTransform: 'none',\n '&:hover': {\n borderColor: 'hsl(var(--border) / 0.8)',\n backgroundColor: 'hsl(var(--muted) / 0.5)',\n },\n }}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n size=\"small\"\n onClick={() => {\n if (deleteConfirmAuthId) handleDeleteAuth(deleteConfirmAuthId);\n }}\n disabled={deleting}\n sx={{\n backgroundColor: 'hsl(var(--destructive))',\n color: 'hsl(var(--destructive-foreground))',\n textTransform: 'none',\n fontWeight: 600,\n '&:hover': { backgroundColor: 'hsl(var(--destructive) / 0.9)' },\n '&.Mui-disabled': {\n backgroundColor: 'hsl(var(--destructive) / 0.3)',\n color: 'hsl(var(--destructive-foreground) / 0.5)',\n },\n }}\n >\n {deleting ? 'Deleting...' : 'Delete'}\n </Button>\n </Box>\n </DialogContent>\n </Dialog>\n\n {/* Show selected auth info if not adding new */}\n {!showAddNewForm && selectedAuth && (\n <Box sx={{ \n mt: 2, \n p: 0,\n backgroundColor: 'hsl(var(--muted))',\n borderRadius: 3,\n border: '1px solid hsl(var(--border))',\n overflow: 'hidden',\n }}>\n {/* Active authentication header */}\n <Box sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n px: { xs: 2, sm: 2.5 },\n py: 1.5,\n borderBottom: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--background-surface))',\n }}>\n <Box sx={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: localTestStatus === 'success' \n ? '#22c55e' \n : localTestStatus === 'pending_validation'\n ? '#f59e0b'\n : localTestStatus === 'error'\n ? '#ef4444'\n : '#9ca3af',\n boxShadow: localTestStatus === 'success' \n ? '0 0 8px rgba(34, 197, 94, 0.6)'\n : localTestStatus === 'pending_validation'\n ? '0 0 8px rgba(245, 158, 11, 0.6)'\n : localTestStatus === 'error'\n ? '0 0 8px rgba(239, 68, 68, 0.6)'\n : '0 0 8px rgba(156, 163, 175, 0.4)',\n }} />\n <Typography sx={{ \n color: 'hsl(var(--muted-foreground))', \n fontSize: '0.75rem',\n fontWeight: 500,\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}>\n {localTestStatus === 'success' \n ? 'Verified Authentication' \n : localTestStatus === 'pending_validation'\n ? 'Awaiting Backend Validation'\n : localTestStatus === 'error'\n ? 'Test Failed'\n : 'Pending Verification'}\n </Typography>\n </Box>\n\n {/* Main content area — always stacked vertically for drawer contexts */}\n <Box sx={{ \n display: 'flex', \n flexDirection: 'column',\n alignItems: 'stretch', \n gap: 2,\n p: { xs: 2, sm: 2.5 },\n }}>\n {/* Auth name with icon */}\n <Box sx={{ \n display: 'flex', \n alignItems: 'center', \n gap: 1.5, \n minWidth: 0,\n flex: 1,\n }}>\n <Box sx={{\n width: 36,\n height: 36,\n borderRadius: 2,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: localTestStatus === 'success' \n ? 'rgba(34, 197, 94, 0.1)' \n : localTestStatus === 'error'\n ? 'rgba(239, 68, 68, 0.1)'\n : localTestStatus === 'pending_validation'\n ? 'rgba(245, 158, 11, 0.1)'\n : isTested\n ? 'rgba(34, 197, 94, 0.1)'\n : isConfigured\n ? 'rgba(245, 158, 11, 0.1)' // Yellow for configured but not tested\n : 'rgba(156, 163, 175, 0.1)',\n border: `1px solid ${\n localTestStatus === 'success' \n ? 'rgba(34, 197, 94, 0.2)' \n : localTestStatus === 'pending_validation'\n ? 'rgba(245, 158, 11, 0.2)'\n : localTestStatus === 'error'\n ? 'rgba(239, 68, 68, 0.2)'\n : isTested\n ? 'rgba(34, 197, 94, 0.2)'\n : isConfigured\n ? 'rgba(245, 158, 11, 0.2)' // Yellow for configured but not tested\n : 'rgba(156, 163, 175, 0.2)'\n }`,\n flexShrink: 0,\n }}>\n <CheckCircleIcon sx={{ \n color: localTestStatus === 'success' \n ? '#22c55e' \n : localTestStatus === 'pending_validation'\n ? '#f59e0b'\n : localTestStatus === 'error'\n ? '#ef4444'\n : isTested\n ? '#22c55e'\n : isConfigured\n ? '#f59e0b' // Yellow for configured but not tested\n : '#9ca3af', \n fontSize: 20 \n }} />\n </Box>\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n {editingLabel ? (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }} onClick={e => e.stopPropagation()}>\n <TextField\n value={editLabelValue}\n onChange={e => setEditLabelValue(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') handleRenameAuth();\n if (e.key === 'Escape') setEditingLabel(false);\n }}\n size=\"small\"\n autoFocus\n sx={{\n '& .MuiOutlinedInput-root': {\n height: 28,\n fontSize: '0.85rem',\n fontWeight: 600,\n color: 'hsl(var(--foreground))',\n '& fieldset': { borderColor: 'hsl(var(--border))' },\n '&.Mui-focused fieldset': { borderColor: 'hsl(var(--primary))' },\n },\n '& .MuiOutlinedInput-input': { py: 0.25, px: 1 },\n }}\n />\n <Button\n size=\"small\"\n variant=\"contained\"\n onClick={handleRenameAuth}\n disabled={savingLabel || !editLabelValue.trim()}\n sx={{\n minWidth: 0,\n px: 1.5,\n py: 0.25,\n fontSize: '0.7rem',\n textTransform: 'none',\n bgcolor: 'hsl(var(--primary))',\n '&:hover': { bgcolor: 'hsl(var(--primary) / 0.9)' },\n }}\n >\n {savingLabel ? <CircularProgress size={12} sx={{ color: 'inherit' }} /> : 'Save'}\n </Button>\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => setEditingLabel(false)}\n sx={{\n minWidth: 0,\n px: 1,\n py: 0.25,\n fontSize: '0.7rem',\n textTransform: 'none',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n Cancel\n </Button>\n </Box>\n ) : (\n <>\n <Typography sx={{ \n color: 'hsl(var(--foreground))', \n fontWeight: 600, \n fontSize: { xs: '0.9rem', sm: '0.95rem' },\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n lineHeight: 1.3,\n }}>\n {selectedAuth.label || 'Selected authentication'}\n </Typography>\n <Tooltip title=\"Rename authentication\" arrow>\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n setEditLabelValue(selectedAuth.label || '');\n setEditingLabel(true);\n }}\n sx={{\n p: 0.3,\n color: 'hsl(var(--muted-foreground))',\n '&:hover': { color: 'hsl(var(--primary))' },\n }}\n >\n <EditIcon sx={{ fontSize: 14 }} />\n </IconButton>\n </Tooltip>\n </>\n )}\n </Box>\n <Typography sx={{ \n color: localTestStatus === 'success' \n ? '#22c55e' \n : localTestStatus === 'pending_validation'\n ? '#f59e0b'\n : localTestStatus === 'error'\n ? '#ef4444'\n : isTested\n ? '#22c55e'\n : isConfigured\n ? '#f59e0b' // Yellow for configured but not tested\n : 'hsl(var(--muted-foreground))', \n fontSize: '0.75rem',\n mt: 0.25,\n fontWeight: (localTestStatus !== 'untested' || isTested || isConfigured) ? 500 : 400,\n }}>\n {localTestStatus === 'success' \n ? '✓ Connection verified' \n : localTestStatus === 'pending_validation'\n ? '⏳ Test passed, awaiting backend validation'\n : localTestStatus === 'error'\n ? '✗ Test failed'\n : localTestStatus === 'testing'\n ? 'Testing...'\n : 'Not tested in this session'}\n </Typography>\n </Box>\n </Box>\n\n {/* Test Connection button */}\n <Button\n variant={authState.status === 'testing' ? 'contained' : 'outlined'}\n size=\"medium\"\n onClick={(e) => {\n e.stopPropagation();\n // Track which auth is being tested so results go to the right auth\n setTestingAuthId(selectedAuthId);\n onTestConnection(app.objectID, selectedAuthId !== ADD_NEW_AUTH ? selectedAuthId : undefined);\n }}\n disabled={authState.status === 'testing'}\n startIcon={\n authState.status === 'testing' \n ? <CircularProgress size={16} sx={{ color: 'inherit' }} />\n : <CheckCircleIcon sx={{ fontSize: 18 }} />\n }\n sx={{\n borderColor: authState.status === 'testing' ? 'transparent' : 'rgba(255, 102, 0, 0.5)',\n color: authState.status === 'testing' ? 'hsl(var(--foreground))' : 'hsl(var(--primary))',\n background: authState.status === 'testing' \n ? 'linear-gradient(90deg, rgba(255, 102, 0, 0.3) 0%, rgba(255, 102, 0, 0.5) 50%, rgba(255, 102, 0, 0.3) 100%)'\n : 'transparent',\n backgroundSize: authState.status === 'testing' ? '200% 100%' : 'auto',\n animation: authState.status === 'testing' ? 'shimmer 1.5s infinite linear' : 'none',\n fontWeight: 600,\n textTransform: 'none',\n px: 3,\n py: 1,\n borderRadius: 2,\n flexShrink: 0,\n minWidth: 160,\n width: '100%',\n transition: 'all 0.3s ease',\n '@keyframes shimmer': {\n '0%': { backgroundPosition: '200% 0' },\n '100%': { backgroundPosition: '-200% 0' },\n },\n '&:hover': {\n borderColor: 'hsl(var(--primary))',\n backgroundColor: authState.status === 'testing' ? undefined : 'rgba(255, 102, 0, 0.08)',\n },\n '&.Mui-disabled': {\n color: authState.status === 'testing' ? 'hsl(var(--foreground))' : 'hsl(var(--muted-foreground))',\n borderColor: authState.status === 'testing' ? 'transparent' : 'hsl(var(--border))',\n },\n }}\n >\n {authState.status === 'testing' ? 'Testing Connection...' : 'Test Connection'}\n </Button>\n </Box>\n\n {/* Status messages - only show for current test session */}\n {localTestStatus === 'error' && localTestMessages.errorMessage && (\n <Box sx={{ \n px: { xs: 2, sm: 2.5 }, \n pb: { xs: 2, sm: 2.5 },\n }}>\n <Alert\n severity=\"error\"\n sx={{\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n color: '#ef4444',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n borderRadius: 2,\n '& .MuiAlert-icon': { color: '#ef4444' },\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2, width: '100%' }}>\n <Typography sx={{ fontSize: '0.875rem', flex: 1 }}>\n {localTestMessages.errorMessage}\n </Typography>\n {localTestMessages.workflowId && localTestMessages.executionId && (\n <Button\n variant=\"outlined\"\n size=\"small\"\n href={`https://shuffler.io/workflows/${localTestMessages.workflowId}?execution_id=${localTestMessages.executionId}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n sx={{\n borderColor: 'rgba(239, 68, 68, 0.5)',\n color: '#ef4444',\n textTransform: 'none',\n fontSize: '0.75rem',\n py: 0.5,\n px: 1.5,\n flexShrink: 0,\n '&:hover': {\n borderColor: '#ef4444',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n },\n }}\n >\n View Execution\n </Button>\n )}\n </Box>\n </Alert>\n </Box>\n )}\n {localTestStatus === 'success' && (\n <Box sx={{ \n px: { xs: 2, sm: 2.5 }, \n pb: { xs: 2, sm: 2.5 },\n }}>\n <Alert\n severity={localTestMessages.warningMessage ? \"warning\" : \"success\"}\n sx={{\n backgroundColor: localTestMessages.warningMessage \n ? 'rgba(245, 158, 11, 0.1)' \n : 'rgba(34, 197, 94, 0.1)',\n color: localTestMessages.warningMessage ? '#f59e0b' : '#22c55e',\n border: localTestMessages.warningMessage \n ? '1px solid rgba(245, 158, 11, 0.2)' \n : '1px solid rgba(34, 197, 94, 0.2)',\n borderRadius: 2,\n '& .MuiAlert-icon': { \n color: localTestMessages.warningMessage ? '#f59e0b' : '#22c55e' \n },\n }}\n >\n {localTestMessages.warningMessage ? (\n <Box>\n <Typography sx={{ fontWeight: 600, mb: 0.5 }}>\n {localTestMessages.successMessage || 'Connection probably working'}\n </Typography>\n <Typography sx={{ fontSize: '0.85rem', opacity: 0.9 }}>\n {localTestMessages.warningMessage}\n </Typography>\n </Box>\n ) : (\n localTestMessages.successMessage || 'Connection verified successfully'\n )}\n </Alert>\n </Box>\n )}\n {localTestStatus === 'pending_validation' && (\n <Box sx={{ \n px: { xs: 2, sm: 2.5 }, \n pb: { xs: 2, sm: 2.5 },\n }}>\n <Alert\n severity=\"warning\"\n sx={{\n backgroundColor: 'rgba(245, 158, 11, 0.1)',\n color: '#f59e0b',\n border: '1px solid rgba(245, 158, 11, 0.2)',\n borderRadius: 2,\n '& .MuiAlert-icon': { color: '#f59e0b' },\n }}\n >\n <Box>\n <Typography sx={{ fontWeight: 600, mb: 0.5 }}>\n Test passed (Status 200), but not marked as validated\n </Typography>\n <Typography sx={{ fontSize: '0.85rem', opacity: 0.9, mb: 1 }}>\n The API returned success, but Shuffle hasn't confirmed the validation yet. This could mean credentials are correct but the app needs additional setup.\n </Typography>\n <Link \n href={`${API_CONFIG.baseUrl}/admin?tab=app_auth`}\n target=\"_blank\"\n sx={{ \n color: '#f59e0b', \n fontWeight: 500,\n fontSize: '0.85rem',\n textDecoration: 'underline',\n '&:hover': { opacity: 0.8 }\n }}\n >\n Check status in Admin → App Authentication\n </Link>\n </Box>\n </Alert>\n </Box>\n )}\n </Box>\n )}\n </Box>\n )}\n\n {/* Show form when no auths exist or \"Add new\" is selected */}\n {(apiAuthEntries.length === 0 || showAddNewForm) && (\n <Box sx={{ \n p: 3, \n backgroundColor: 'hsl(var(--muted))', \n borderRadius: 2,\n border: '1px solid hsl(var(--border))',\n }}>\n {/* Show credential error notice if switched due to 401/403 */}\n {isCredentialError && (\n <Alert\n severity=\"warning\"\n sx={{\n backgroundColor: 'rgba(245, 158, 11, 0.1)',\n color: '#f59e0b',\n border: '1px solid rgba(245, 158, 11, 0.2)',\n borderRadius: 2,\n mb: 2,\n '& .MuiAlert-icon': { color: '#f59e0b' },\n }}\n >\n <Typography sx={{ fontSize: '0.875rem' }}>\n {localTestMessages.errorCode === 401 \n ? 'Previous credentials were invalid or expired. Please enter new credentials.'\n : 'Access was denied with the previous credentials. Please re-authenticate with valid permissions.'}\n </Typography>\n </Alert>\n )}\n <Typography variant=\"subtitle2\" sx={{ color: 'hsl(var(--primary))', fontWeight: 600, mb: 2 }}>\n {apiAuthEntries.length === 0 ? 'Configure Authentication' : 'Add New Authentication'}\n </Typography>\n \n {loading ? (\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', py: 4 }}>\n <CircularProgress size={32} sx={{ color: 'hsl(var(--primary))' }} />\n <Typography sx={{ ml: 2, color: 'hsl(var(--muted-foreground))' }}>\n Loading configuration...\n </Typography>\n </Box>\n ) : error ? (\n <Alert\n severity=\"error\"\n sx={{\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n color: '#ef4444',\n border: '1px solid rgba(239, 68, 68, 0.3)',\n borderRadius: 2,\n }}\n >\n {error}\n </Alert>\n ) : isNoAuthRequired(auth) ? (\n <Alert\n severity=\"info\"\n sx={{\n backgroundColor: 'rgba(59, 130, 246, 0.1)',\n color: '#3b82f6',\n border: '1px solid rgba(59, 130, 246, 0.2)',\n borderRadius: 2,\n '& .MuiAlert-icon': { color: '#3b82f6' },\n }}\n >\n <Box>\n <Typography sx={{ fontWeight: 600, mb: 0.5 }}>\n No authentication required\n </Typography>\n <Typography sx={{ fontSize: '0.85rem', opacity: 0.9 }}>\n This app works without credentials. You can use it directly.\n </Typography>\n </Box>\n </Alert>\n ) : (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>\n {/* Render dynamic fields based on auth type */}\n {renderOAuth2Fields()}\n {renderParameterFields()}\n\n {authState.status === 'error' && authState.errorMessage && (\n <Alert\n severity=\"error\"\n sx={{\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n color: '#ef4444',\n border: '1px solid rgba(239, 68, 68, 0.3)',\n borderRadius: 2,\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2, width: '100%' }}>\n <Typography sx={{ fontSize: '0.875rem', flex: 1 }}>\n {authState.errorMessage}\n </Typography>\n {authState.workflowId && authState.executionId && (\n <Button\n variant=\"outlined\"\n size=\"small\"\n href={`https://shuffler.io/workflows/${authState.workflowId}?execution_id=${authState.executionId}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n sx={{\n borderColor: 'rgba(239, 68, 68, 0.5)',\n color: '#ef4444',\n textTransform: 'none',\n fontSize: '0.75rem',\n py: 0.5,\n px: 1.5,\n flexShrink: 0,\n '&:hover': {\n borderColor: '#ef4444',\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n },\n }}\n >\n View Execution\n </Button>\n )}\n </Box>\n </Alert>\n )}\n\n {/* Success message removed per user request */}\n\n {saveSuccess === false && (\n <Alert\n severity=\"error\"\n sx={{\n backgroundColor: 'rgba(239, 68, 68, 0.1)',\n color: '#ef4444',\n border: '1px solid rgba(239, 68, 68, 0.3)',\n borderRadius: 2,\n }}\n >\n Failed to save authentication. Please try again.\n </Alert>\n )}\n\n {/* Save button for non-OAuth2 apps */}\n {!isOAuth2 && (\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', pt: 1.5 }}>\n <Button\n variant=\"outlined\"\n size=\"medium\"\n onClick={(e) => {\n e.stopPropagation();\n handleSave();\n }}\n disabled={saving || !isFormValid()}\n sx={{\n borderColor: isFormValid() ? 'hsl(var(--primary) / 0.5)' : 'hsl(var(--border))',\n color: isFormValid() ? 'hsl(var(--primary))' : 'hsl(var(--muted-foreground))',\n fontWeight: 600,\n textTransform: 'none',\n fontSize: '0.9rem',\n px: 3,\n py: 1,\n borderRadius: 2,\n transition: 'all 0.2s ease',\n '&:hover': {\n borderColor: 'hsl(var(--primary))',\n backgroundColor: 'hsl(var(--primary) / 0.08)',\n },\n '&.Mui-disabled': {\n borderColor: 'hsl(var(--border))',\n color: 'hsl(var(--muted-foreground))',\n },\n }}\n >\n {saving ? 'Saving...' : 'Save Authentication'}\n </Button>\n </Box>\n )}\n\n {/* Save & Authenticate button for OAuth2 apps with manual credentials */}\n {isOAuth2 && (() => {\n const hasClientId = !!localCredentials['client_id']?.trim();\n const hasClientSecret = !!localCredentials['client_secret']?.trim();\n const hasScopes = selectedScopes.length > 0;\n const hasAuthUrl = !!auth?.authorization_url;\n const allFilled = hasClientId && hasClientSecret && (!auth?.scope?.length || hasScopes);\n\n // Build the direct OAuth2 authorization URL with state\n const buildOAuth2Url = (): string | null => {\n if (!localCredentials['client_id']?.trim()) return null;\n \n // Resolve authorization URL from multiple possible fields,\n // or derive from token_uri (common pattern: /token → /authorize)\n const authorizationUrl = auth?.authorization_url \n || auth?.auth_uri \n || auth?.authorize_url\n || (auth?.token_uri ? auth.token_uri.replace(/\\/token\\b.*$/, '/authorize') : null);\n \n if (!authorizationUrl) return null;\n \n const redirectUri = auth?.redirect_uri || 'https://shuffler.io/set_authentication';\n const scopes = selectedScopes.join(' ');\n const clientId = localCredentials['client_id'].trim();\n const clientSecret = localCredentials['client_secret']?.trim() || '';\n\n // Build state parameter matching Shuffle's expected format\n const stateParams = new URLSearchParams({\n workflow_id: '',\n reference_action_id: app.objectID,\n app_name: app.name,\n app_id: app.objectID,\n app_version: app.app_version || '1.0.0',\n authentication_url: auth?.token_uri || '',\n scope: scopes,\n client_id: clientId,\n client_secret: clientSecret,\n org_id: 'undefined',\n oauth_url: auth?.token_uri?.replace(/\\/token.*$/, '') || '',\n refresh_uri: auth?.refresh_uri || auth?.token_uri || '',\n });\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n prompt: 'login',\n scope: scopes,\n state: stateParams.toString(),\n access_type: 'offline',\n });\n\n console.log('[OAuth2] Built direct auth URL:', `${authorizationUrl}?${params.toString()}`);\n return `${authorizationUrl}?${params.toString()}`;\n };\n\n return (\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', pt: 1.5 }}>\n <Button\n variant=\"outlined\"\n size=\"medium\"\n startIcon={\n app.image_url ? (\n <Box\n component=\"img\"\n src={app.image_url}\n alt={app.name}\n sx={{ width: 20, height: 20, borderRadius: 0.5, objectFit: 'contain' }}\n />\n ) : (\n <LockIcon sx={{ fontSize: 18 }} />\n )\n }\n onClick={(e) => {\n e.stopPropagation();\n // Open OAuth2 popup directly — no save step needed\n // The OAuth redirect callback handles credential storage\n const directUrl = buildOAuth2Url();\n const popupUrl = directUrl || `https://shuffler.io/appauth?app_id=${app.objectID}&source=shuffle`;\n const popup = window.open(popupUrl, '_blank', 'width=600,height=700');\n if (popup && onRefreshAuth) {\n const authPollTimer = setInterval(() => {\n onRefreshAuth();\n }, 3000);\n const closePollTimer = setInterval(() => {\n if (popup.closed) {\n clearInterval(closePollTimer);\n clearInterval(authPollTimer);\n onRefreshAuth();\n }\n }, 500);\n }\n }}\n disabled={!allFilled}\n sx={{\n borderColor: allFilled ? 'hsl(var(--primary) / 0.5)' : 'hsl(var(--border))',\n color: allFilled ? 'hsl(var(--primary))' : 'hsl(var(--muted-foreground))',\n fontWeight: 600,\n textTransform: 'none',\n fontSize: '0.9rem',\n px: 3,\n py: 1,\n borderRadius: 2,\n transition: 'all 0.2s ease',\n '&:hover': {\n borderColor: 'hsl(var(--primary))',\n backgroundColor: 'hsl(var(--primary) / 0.08)',\n },\n '&.Mui-disabled': {\n borderColor: 'hsl(var(--border))',\n color: 'hsl(var(--muted-foreground))',\n },\n }}\n >\n Authenticate\n </Button>\n </Box>\n );\n })()}\n </Box>\n )}\n </Box>\n )}\n </Box>\n </Collapse>\n </Card>\n\n {/* Documentation Modal */}\n <Dialog\n open={docsOpen}\n onClose={() => setDocsOpen(false)}\n maxWidth=\"md\"\n fullWidth\n slotProps={{\n paper: {\n sx: {\n backgroundColor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 3,\n maxHeight: '80vh',\n },\n },\n }}\n >\n <DialogTitle\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n borderBottom: '1px solid hsl(var(--border))',\n color: 'hsl(var(--foreground))',\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n {app.image_url && (\n <Box\n component=\"img\"\n src={app.image_url}\n alt={app.name}\n sx={{ width: 32, height: 32, borderRadius: 1, objectFit: 'contain' }}\n />\n )}\n <Typography variant=\"h6\" sx={{ fontWeight: 600 }}>\n {app.name.replace(/_/g, ' ')} Documentation\n </Typography>\n </Box>\n <IconButton onClick={() => setDocsOpen(false)} sx={{ color: 'hsl(var(--muted-foreground))' }}>\n <CloseIcon />\n </IconButton>\n </DialogTitle>\n <DialogContent sx={{ pt: 3 }}>\n {docsLoading ? (\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', py: 6 }}>\n <CircularProgress size={32} sx={{ color: 'hsl(var(--primary))' }} />\n <Typography sx={{ ml: 2, color: 'hsl(var(--muted-foreground))' }}>\n Loading documentation...\n </Typography>\n </Box>\n ) : (\n <Box\n sx={{\n color: 'hsl(var(--foreground))',\n '& h1, & h2, & h3, & h4': { color: 'hsl(var(--foreground))', mt: 3, mb: 2 },\n '& p': { mb: 2, lineHeight: 1.7 },\n '& code': {\n backgroundColor: 'hsl(var(--muted))',\n px: 1,\n py: 0.5,\n borderRadius: 1,\n fontSize: '0.875rem',\n },\n '& pre': {\n backgroundColor: 'hsl(var(--background))',\n p: 2,\n borderRadius: 2,\n overflow: 'auto',\n },\n '& a': { color: 'hsl(var(--primary))' },\n '& ul, & ol': { pl: 3, mb: 2 },\n '& li': { mb: 1 },\n }}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{docsContent}</ReactMarkdown>\n </Box>\n )}\n </DialogContent>\n </Dialog>\n </motion.div>\n );\n};\n\nexport const AppAuthConfig = ({\n apps,\n authStates,\n authenticatedApps = [],\n onAuthChange,\n onTestConnection,\n onSaveAuth,\n onSelectAuth,\n onRefreshAuth,\n}: AppAuthConfigProps) => {\n // Helper to find ALL API auth entries for an app\n const getApiAuthEntries = (app: AlgoliaSearchApp): ApiAuthEntry[] => {\n const normalize = (n: string) => n.toLowerCase().replace(/[\\s_\\-]+/g, '_');\n return authenticatedApps\n .filter(auth => normalize(auth.app?.name || '') === normalize(app.name))\n .map(auth => ({\n ...auth,\n app: {\n ...auth.app,\n large_image: auth.app?.large_image || app.image_url,\n },\n }));\n };\n\n // Helper to check if app is configured (has any auth entry)\n const isAppConfigured = (app: AlgoliaSearchApp): boolean => {\n const entries = getApiAuthEntries(app);\n return entries.some(e => e.active === true);\n };\n\n // Helper to check if app is validated (data is already pre-processed to invalidate old entries)\n const isAppValidated = (app: AlgoliaSearchApp): boolean => {\n const entries = getApiAuthEntries(app);\n return entries.some(e => e.validation?.valid === true);\n };\n\n // Keep initial sort order stable - only sort once when authenticatedApps is loaded\n const initialSortRef = useRef<AlgoliaSearchApp[] | null>(null);\n const authAppsLoadedRef = useRef<boolean>(false);\n \n // Reset sort ref when authenticatedApps first loads with data\n if (!authAppsLoadedRef.current && authenticatedApps.length > 0) {\n authAppsLoadedRef.current = true;\n initialSortRef.current = null; // Force re-sort\n }\n \n if (initialSortRef.current === null && apps.length > 0 && authenticatedApps.length > 0) {\n // Sort priority: \n // 1. Category-matched apps (email, siem, edr, cases) first\n // 2. Within each group: Not Configured > Not Tested > Tested\n const getPriority = (app: AlgoliaSearchApp): number => {\n const isSourceCategory = getIngestionCategory(app.name, app.categories) !== null;\n const configured = isAppConfigured(app);\n const validated = isAppValidated(app);\n \n // Category apps get priority 0-2, non-category apps get 3-5\n const base = isSourceCategory ? 0 : 3;\n if (!configured) return base; // Not Configured - top of group\n if (!validated) return base + 1; // Configured but Not Tested - middle\n return base + 2; // Tested - bottom of group\n };\n \n initialSortRef.current = [...apps].sort((a, b) => {\n return getPriority(a) - getPriority(b);\n });\n }\n\n // Use the stable initial sort, or fall back to apps if not yet initialized\n const sortedApps = initialSortRef.current || apps;\n\n // Find first non-validated app for auto-expand (prefer not configured, then not tested)\n const firstNotConfigured = sortedApps.find(app => !isAppConfigured(app));\n const firstNotValidated = sortedApps.find(app => !isAppValidated(app));\n const defaultExpanded = firstNotConfigured?.objectID || firstNotValidated?.objectID || sortedApps[0]?.objectID || false;\n\n const [expanded, setExpanded] = useState<string | false>(defaultExpanded);\n\n if (apps.length === 0) {\n return (\n <Alert\n severity=\"info\"\n sx={{\n backgroundColor: 'rgba(255, 102, 0, 0.1)',\n color: 'hsl(var(--primary))',\n border: '1px solid rgba(255, 102, 0, 0.3)',\n borderRadius: 2,\n }}\n >\n No integrations selected. Go back and select at least one integration.\n </Alert>\n );\n }\n\n // Count validated vs total\n const validatedCount = sortedApps.filter(app => isAppValidated(app)).length;\n const totalCount = sortedApps.length;\n\n return (\n <Box sx={{ width: '100%', maxWidth: '100%', overflow: 'hidden' }}>\n <Typography\n variant=\"h5\"\n sx={{\n color: 'hsl(var(--foreground))',\n fontWeight: 700,\n mb: 1,\n fontSize: { xs: '1.25rem', sm: '1.5rem' },\n }}\n >\n Configure Authentication\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{ mb: 2, color: 'hsl(var(--muted-foreground))', fontSize: { xs: '0.875rem', sm: '1rem' } }}\n >\n Set up credentials for each integration. Apps with orange borders need configuration.\n </Typography>\n <Chip\n label={`${validatedCount}/${totalCount} validated`}\n size=\"small\"\n sx={{\n mb: 3,\n background: validatedCount === totalCount \n ? 'rgba(34, 197, 94, 0.15)' \n : 'rgba(255, 152, 0, 0.15)',\n color: validatedCount === totalCount ? '#22c55e' : '#ff9800',\n fontWeight: 600,\n }}\n />\n\n <motion.div variants={containerVariants} initial=\"hidden\" animate=\"visible\">\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, width: '100%', maxWidth: '100%' }}>\n {sortedApps.map((app) => {\n const authState = authStates[app.objectID] || { systemId: app.objectID, status: 'pending' as const, credentials: {} };\n const isExpanded = expanded === app.objectID;\n const apiAuthEntries = getApiAuthEntries(app);\n\n return (\n <AppAuthCard\n key={app.objectID}\n app={app}\n authState={authState}\n isExpanded={isExpanded}\n onToggle={() => setExpanded(isExpanded ? false : app.objectID)}\n onAuthChange={onAuthChange}\n onTestConnection={onTestConnection}\n onSaveAuth={onSaveAuth}\n apiAuthEntries={apiAuthEntries}\n onSelectAuth={onSelectAuth}\n onRefreshAuth={onRefreshAuth}\n />\n );\n })}\n </Box>\n </motion.div>\n </Box>\n );\n};\n","/**\n * Tiny toast facade — library version. The host app can replace this by\n * setting a custom impl via setToastImpl(). Falls back to console.warn.\n */\n\ntype ToastArg = { title?: string; description?: string; variant?: 'default' | 'destructive' };\ntype ToastFn = (arg: ToastArg) => void;\n\nlet _impl: ToastFn = ({ title, description, variant }) => {\n const msg = [title, description].filter(Boolean).join(' — ');\n if (variant === 'destructive') console.error('[toast]', msg);\n else console.log('[toast]', msg);\n};\n\nexport function setToastImpl(fn: ToastFn) {\n _impl = fn;\n}\n\nexport const toast: ToastFn = (arg) => _impl(arg);\n","/**\n * TryMcpSection — Standalone \"Try MCP\" block.\n *\n * Wraps the heading + AppMcpChat. Pass in the resolved app props.\n */\n\nimport { Box, Typography } from '@mui/material';\nimport { motion } from 'framer-motion';\nimport AppMcpChat from '@/Shuffle-MCPs/AppMcpChat';\n\nexport interface TryMcpSectionProps {\n appName: string;\n /** Image URL used as the chat avatar. */\n appIcon?: string;\n /** Resolved app id (Algolia objectID or Shuffle id). */\n appId: string;\n /** App categories — used to pick suggested actions. */\n categories?: string[];\n}\n\nexport default function TryMcpSection({ appName, appIcon, appId, categories }: TryMcpSectionProps) {\n return (\n <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.15 }}>\n <Box sx={{ mb: 3 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 600, fontSize: '0.95rem', mb: 1.5 }}>\n Try MCP\n </Typography>\n <AppMcpChat\n appName={appName}\n appIcon={appIcon}\n appId={appId}\n categories={categories}\n />\n </Box>\n </motion.div>\n );\n}\n","import { useState, useRef, useMemo } from 'react';\nimport {\n Box,\n Typography,\n Avatar,\n CircularProgress,\n Chip,\n InputBase,\n} from '@mui/material';\nimport AgentIcon from '@/Shuffle-MCPs/AgentIcon';\nimport PlayArrowRoundedIcon from '@mui/icons-material/PlayArrowRounded';\nimport RestartAltIcon from '@mui/icons-material/RestartAlt';\nimport CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { API_CONFIG, getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\nimport {\n THREAT_INTEL_PATTERNS,\n EMAIL_APP_PATTERNS,\n EDR_PATTERNS,\n SIEM_PATTERNS,\n CASES_PATTERNS,\n COMMUNICATION_PATTERNS_NAMES,\n} from '@/Shuffle-MCPs/ingestionDetection';\n\ninterface AppMcpChatProps {\n appName: string;\n appIcon?: string;\n appId?: string;\n categories?: string[];\n}\n\ntype RunState = 'idle' | 'running' | 'done';\n\n/** Category-based suggestion prompts — natural, actionable questions.\n * Keys are lowercase fragments that we match against app category strings. */\nconst CATEGORY_SUGGESTIONS: Record<string, string[]> = {\n 'threat': [\n 'Is 1.2.3.4 a known bad actor?',\n 'Check if this domain is malicious',\n 'Look up threat indicators for a hash',\n ],\n 'siem': [\n 'Show me the latest critical alerts',\n 'Any unusual login attempts today?',\n 'Summarize recent security events',\n ],\n 'email': [\n 'Did I get a message from my team yesterday?',\n 'Find emails with attachments from last week',\n 'Check for any phishing reports',\n ],\n 'communication': [\n 'Did I get a message from my team yesterday?',\n 'Send a status update to the channel',\n 'Check for unread notifications',\n ],\n 'edr': [\n 'Is this endpoint compromised?',\n 'Show recent detections on workstations',\n 'Isolate a suspicious host',\n ],\n 'endpoint': [\n 'Is this endpoint compromised?',\n 'Show recent detections on workstations',\n 'Isolate a suspicious host',\n ],\n 'cloud': [\n 'List my running instances',\n 'Any public S3 buckets detected?',\n 'Check IAM policy changes today',\n ],\n 'ticket': [\n 'What tickets are assigned to me?',\n 'Create a new incident ticket',\n 'Show open high-priority issues',\n ],\n 'itsm': [\n 'What tickets are assigned to me?',\n 'Create a new incident ticket',\n 'Show open high-priority issues',\n ],\n 'case': [\n 'What cases are assigned to me?',\n 'Create a new incident case',\n 'Show open high-priority cases',\n ],\n 'vulnerab': [\n 'Any new critical CVEs this week?',\n 'Check vulnerability status for this asset',\n 'Show unpatched systems',\n ],\n 'network': [\n 'Any unusual outbound connections?',\n 'Check firewall rule changes',\n 'Show top talkers in the last hour',\n ],\n 'identity': [\n 'Show recent failed login attempts',\n 'Is this user account locked out?',\n 'List users with admin privileges',\n ],\n 'intel': [\n 'Is 1.2.3.4 a known bad actor?',\n 'Check if this domain is malicious',\n 'Look up threat indicators for a hash',\n ],\n};\n\nconst DEFAULT_SUGGESTIONS = [\n 'What can you do?',\n 'Show me recent activity',\n 'Run a quick check',\n];\n\n/** Infer category keys from the app name using known patterns */\nfunction inferCategoryKeysFromName(appName: string): string[] {\n const name = appName.toLowerCase();\n const keys: string[] = [];\n if (THREAT_INTEL_PATTERNS.some(p => name.includes(p))) keys.push('threat', 'intel');\n if (EMAIL_APP_PATTERNS.some(p => name.includes(p))) keys.push('email');\n if (EDR_PATTERNS.some(p => name.includes(p))) keys.push('edr', 'endpoint');\n if (SIEM_PATTERNS.some(p => name.includes(p))) keys.push('siem');\n if (CASES_PATTERNS.some(p => name.includes(p))) keys.push('ticket', 'case');\n if (COMMUNICATION_PATTERNS_NAMES.some(p => name.includes(p))) keys.push('communication');\n return keys;\n}\n\nfunction getSuggestions(appName: string, categories?: string[]): string[] {\n const matched: string[] = [];\n\n // 1. Match from explicit categories\n if (categories && categories.length > 0) {\n for (const cat of categories) {\n const normalized = cat.toLowerCase();\n for (const [key, prompts] of Object.entries(CATEGORY_SUGGESTIONS)) {\n if (normalized.includes(key) || key.includes(normalized)) {\n matched.push(...prompts);\n }\n }\n }\n }\n\n // 2. Fallback: infer from the app name itself\n if (matched.length === 0) {\n const inferred = inferCategoryKeysFromName(appName);\n for (const inferredKey of inferred) {\n const prompts = CATEGORY_SUGGESTIONS[inferredKey];\n if (prompts) matched.push(...prompts);\n }\n }\n\n if (matched.length === 0) return DEFAULT_SUGGESTIONS;\n\n const unique = [...new Set(matched)];\n return unique.slice(0, 4);\n}\n\n/** Pick a short display label from categories, or infer from app name */\nfunction getPrimaryCategory(appName: string, categories?: string[]): string | null {\n if (categories && categories.length > 0) {\n const skip = ['other', 'general', 'integration'];\n const filtered = categories.filter(c => !skip.includes(c.toLowerCase()));\n if (filtered.length > 0) return filtered[0];\n return categories[0];\n }\n // Infer from name\n const name = appName.toLowerCase();\n if (THREAT_INTEL_PATTERNS.some(p => name.includes(p))) return 'Threat Intel';\n if (EMAIL_APP_PATTERNS.some(p => name.includes(p))) return 'Email';\n if (EDR_PATTERNS.some(p => name.includes(p))) return 'EDR';\n if (SIEM_PATTERNS.some(p => name.includes(p))) return 'SIEM';\n if (CASES_PATTERNS.some(p => name.includes(p))) return 'Ticketing';\n if (COMMUNICATION_PATTERNS_NAMES.some(p => name.includes(p))) return 'Communication';\n return null;\n}\n\nconst AppMcpChat = ({ appName, appIcon, appId, categories }: AppMcpChatProps) => {\n const [input, setInput] = useState('');\n const [runState, setRunState] = useState<RunState>('idle');\n const [query, setQuery] = useState('');\n const [result, setResult] = useState('');\n const [isError, setIsError] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const suggestions = useMemo(() => getSuggestions(appName, categories), [appName, categories]);\n const primaryCategory = useMemo(() => getPrimaryCategory(appName, categories), [appName, categories]);\n const runAction = async () => {\n const trimmed = input.trim();\n if (!trimmed || runState === 'running') return;\n\n setQuery(trimmed);\n setInput('');\n setRunState('running');\n setResult('');\n setIsError(false);\n\n try {\n const response = await fetch(\n getApiUrl(`/api/v1/apps/${encodeURIComponent(appName)}/mcp`),\n {\n method: 'POST',\n credentials: 'include',\n headers: {\n ...getAuthHeader(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: crypto.randomUUID(),\n method: 'tools/call',\n params: {\n tool_name: appName,\n tool_id: appId || appName,\n input: { text: trimmed },\n },\n }),\n }\n );\n\n // Read raw text first to handle non-JSON responses safely\n const rawText = await response.text();\n const contentType = response.headers.get('content-type');\n\n if (!response.ok) {\n setIsError(true);\n setResult(`Error ${response.status}: ${rawText || response.statusText}`);\n } else if (!contentType?.includes('application/json')) {\n // Got HTML or other non-JSON back\n if (rawText.trim().startsWith('<!') || rawText.includes('<html')) {\n setIsError(true);\n setResult(`Received an unexpected HTML response (status ${response.status}). This may indicate an auth redirect or server issue.`);\n } else {\n setResult(rawText);\n }\n } else {\n const data = JSON.parse(rawText);\n let content = '';\n\n if (typeof data === 'string') {\n content = data;\n } else if (data?.result) {\n // Extract message if result is an object with a message field\n if (typeof data.result === 'object' && data.result !== null) {\n if (data.result.message) {\n content = data.result.message;\n }\n // Append remaining fields as context if there's more than just message\n const rest = { ...data.result };\n delete rest.message;\n if (Object.keys(rest).length > 0) {\n const extra = JSON.stringify(rest, null, 2);\n content = content\n ? `${content}\\n\\n\\`\\`\\`json\\n${extra}\\n\\`\\`\\``\n : `\\`\\`\\`json\\n${extra}\\n\\`\\`\\``;\n }\n } else {\n content = String(data.result);\n }\n } else if (data?.response) {\n content = typeof data.response === 'string' ? data.response : JSON.stringify(data.response, null, 2);\n } else if (data?.message) {\n content = data.message;\n } else {\n content = `\\`\\`\\`json\\n${JSON.stringify(data, null, 2)}\\n\\`\\`\\``;\n }\n\n if (content) {\n setResult(content);\n } else {\n setResult('No output returned.');\n }\n }\n } catch (err) {\n setIsError(true);\n setResult(`Could not connect. ${err instanceof Error ? err.message : 'Unknown error'}`);\n } finally {\n setRunState('done');\n }\n };\n\n const reset = () => {\n setRunState('idle');\n setQuery('');\n setResult('');\n setIsError(false);\n setInput('');\n setTimeout(() => inputRef.current?.focus(), 50);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n runAction();\n }\n };\n\n const displayName = appName.replace(/_/g, ' ');\n\n return (\n <Box\n sx={{\n borderRadius: 3,\n border: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--background))',\n overflow: 'hidden',\n }}\n >\n <AnimatePresence mode=\"wait\">\n {/* ── IDLE ── */}\n {runState === 'idle' && (\n <motion.div\n key=\"idle\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n >\n <Box sx={{ p: 3, display: 'flex', flexDirection: 'column', gap: 2.5 }}>\n {/* Label */}\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Box\n sx={{\n width: 28,\n height: 28,\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'hsl(var(--primary) / 0.1)',\n border: '1px solid hsl(var(--primary) / 0.2)',\n flexShrink: 0,\n }}\n >\n {appIcon ? (\n <Avatar\n src={appIcon}\n sx={{ width: 18, height: 18, '& img': { objectFit: 'contain' } }}\n />\n ) : (\n <AgentIcon size={16} />\n )}\n </Box>\n <Typography sx={{ fontSize: '0.8rem', fontWeight: 600, color: 'hsl(var(--foreground))' }}>\n Try it out\n </Typography>\n {primaryCategory && (\n <Chip\n label={primaryCategory}\n size=\"small\"\n sx={{\n height: 20,\n fontSize: '0.6rem',\n fontWeight: 600,\n backgroundColor: 'hsl(var(--muted))',\n color: 'hsl(var(--muted-foreground))',\n textTransform: 'capitalize',\n }}\n />\n )}\n <Chip\n label=\"MCP\"\n size=\"small\"\n sx={{\n height: 20,\n fontSize: '0.6rem',\n fontWeight: 700,\n backgroundColor: 'hsl(var(--primary) / 0.12)',\n color: 'hsl(var(--primary))',\n letterSpacing: '0.06em',\n ml: 'auto',\n }}\n />\n </Box>\n\n {/* Command input */}\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n borderRadius: 2,\n border: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--card))',\n px: 1.5,\n py: 0.75,\n transition: 'border-color 0.15s ease, box-shadow 0.15s ease',\n '&:focus-within': {\n borderColor: 'hsl(var(--primary) / 0.5)',\n boxShadow: '0 0 0 3px hsl(var(--primary) / 0.08)',\n },\n }}\n >\n <Typography sx={{ fontSize: '0.85rem', color: 'hsl(var(--primary))', fontWeight: 600, userSelect: 'none', fontFamily: \"'JetBrains Mono', monospace\" }}>\n ›\n </Typography>\n <InputBase\n inputRef={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={`Ask ${displayName} something…`}\n fullWidth\n sx={{\n fontSize: '0.82rem',\n color: 'hsl(var(--foreground))',\n '& input::placeholder': {\n color: 'hsl(var(--muted-foreground))',\n opacity: 0.7,\n },\n }}\n />\n <Box\n component=\"button\"\n onClick={runAction}\n disabled={!input.trim()}\n sx={{\n all: 'unset',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 30,\n height: 30,\n borderRadius: '8px',\n flexShrink: 0,\n cursor: input.trim() ? 'pointer' : 'default',\n backgroundColor: input.trim() ? 'hsl(var(--primary))' : 'hsl(var(--muted))',\n color: input.trim() ? 'hsl(var(--primary-foreground))' : 'hsl(var(--muted-foreground))',\n transition: 'all 0.15s ease',\n '&:hover': input.trim() ? {\n filter: 'brightness(1.1)',\n } : {},\n }}\n >\n <PlayArrowRoundedIcon sx={{ fontSize: 18 }} />\n </Box>\n </Box>\n\n {/* Quick actions */}\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.75 }}>\n {suggestions.map((s) => (\n <Chip\n key={s}\n label={s}\n size=\"small\"\n onClick={() => {\n setInput(s);\n inputRef.current?.focus();\n }}\n sx={{\n height: 26,\n fontSize: '0.7rem',\n fontWeight: 500,\n cursor: 'pointer',\n backgroundColor: 'transparent',\n color: 'hsl(var(--muted-foreground))',\n border: '1px dashed hsl(var(--border))',\n transition: 'all 0.15s ease',\n '&:hover': {\n backgroundColor: 'hsl(var(--muted))',\n color: 'hsl(var(--foreground))',\n borderStyle: 'solid',\n borderColor: 'hsl(var(--primary) / 0.3)',\n },\n }}\n />\n ))}\n </Box>\n </Box>\n </motion.div>\n )}\n\n {/* ── RUNNING ── */}\n {runState === 'running' && (\n <motion.div\n key=\"running\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n >\n <Box sx={{ p: 3, display: 'flex', alignItems: 'center', gap: 2 }}>\n <CircularProgress size={20} thickness={5} sx={{ color: 'hsl(var(--primary))' }} />\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography sx={{ fontSize: '0.78rem', fontWeight: 600, color: 'hsl(var(--foreground))' }}>\n Executing…\n </Typography>\n <Typography\n sx={{\n fontSize: '0.72rem',\n color: 'hsl(var(--muted-foreground))',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontFamily: \"'JetBrains Mono', monospace\",\n }}\n >\n › {query}\n </Typography>\n </Box>\n </Box>\n </motion.div>\n )}\n\n {/* ── DONE ── */}\n {runState === 'done' && (\n <motion.div\n key=\"done\"\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n <Box sx={{ p: 3, display: 'flex', flexDirection: 'column', gap: 2 }}>\n {/* Status bar */}\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n {isError ? (\n <ErrorOutlineIcon sx={{ fontSize: 18, color: 'hsl(0 70% 55%)' }} />\n ) : (\n <CheckCircleOutlineIcon sx={{ fontSize: 18, color: 'hsl(145 60% 45%)' }} />\n )}\n <Typography sx={{ fontSize: '0.78rem', fontWeight: 600, color: 'hsl(var(--foreground))' }}>\n {isError ? 'Failed' : 'Completed'}\n </Typography>\n </Box>\n <Chip\n icon={<RestartAltIcon sx={{ fontSize: 14 }} />}\n label=\"Run again\"\n size=\"small\"\n onClick={reset}\n sx={{\n height: 26,\n fontSize: '0.7rem',\n fontWeight: 500,\n cursor: 'pointer',\n backgroundColor: 'transparent',\n color: 'hsl(var(--muted-foreground))',\n border: '1px solid hsl(var(--border))',\n transition: 'all 0.15s ease',\n '&:hover': {\n backgroundColor: 'hsl(var(--muted))',\n color: 'hsl(var(--foreground))',\n },\n }}\n />\n </Box>\n\n {/* Query echo */}\n <Typography\n sx={{\n fontSize: '0.72rem',\n color: 'hsl(var(--muted-foreground))',\n fontFamily: \"'JetBrains Mono', monospace\",\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n › {query}\n </Typography>\n\n {/* Output */}\n <Box\n sx={{\n p: 2,\n borderRadius: 2,\n backgroundColor: 'hsl(var(--card))',\n border: '1px solid',\n borderColor: isError ? 'hsl(0 60% 50% / 0.25)' : 'hsl(var(--border))',\n maxHeight: 340,\n overflowY: 'auto',\n '&::-webkit-scrollbar': { width: 4 },\n '&::-webkit-scrollbar-track': { background: 'transparent' },\n '&::-webkit-scrollbar-thumb': {\n background: 'hsl(var(--border))',\n borderRadius: 2,\n },\n '& p': {\n fontSize: '0.8rem',\n lineHeight: 1.65,\n color: 'hsl(var(--foreground))',\n m: 0,\n '&:not(:last-child)': { mb: 1 },\n },\n '& pre': {\n backgroundColor: 'hsl(var(--background))',\n border: '1px solid hsl(var(--border))',\n borderRadius: 1,\n p: 1.5,\n overflow: 'auto',\n fontSize: '0.72rem',\n fontFamily: \"'JetBrains Mono', monospace\",\n my: 1,\n },\n '& code': {\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.72rem',\n backgroundColor: 'hsl(var(--muted))',\n px: 0.5,\n borderRadius: 0.5,\n },\n '& pre code': { backgroundColor: 'transparent', p: 0 },\n '& ul, & ol': {\n pl: 2,\n fontSize: '0.8rem',\n color: 'hsl(var(--foreground))',\n },\n '& a': {\n color: 'hsl(var(--primary))',\n textDecoration: 'underline',\n },\n }}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]}>\n {result}\n </ReactMarkdown>\n </Box>\n </Box>\n </motion.div>\n )}\n </AnimatePresence>\n </Box>\n );\n};\n\nexport default AppMcpChat;\n","import singulAgentIcon from '@/assets/singul-agent-icon.png';\n\ninterface AgentIconProps {\n size?: number;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Renders the Singul agent icon — use this everywhere instead of 🤖.\n */\nconst AgentIcon = ({ size = 16, className, style }: AgentIconProps) => (\n <img\n src={singulAgentIcon}\n alt=\"AI Agent\"\n width={size}\n height={size}\n className={className}\n style={{ borderRadius: '3px', objectFit: 'contain', ...style }}\n />\n);\n\nexport default AgentIcon;\n","/**\n * SingulActionsPreview — Standalone \"Try individual actions\" block.\n *\n * Renders the action picker (grouped by category), curl/python toggle,\n * editable snippet, Play button (calls Shuffle Tools `execute_python` or\n * the http app `curl` action) and a response area that streams in.\n *\n * Self-contained — pass in the app name + categories. Optionally pass\n * `activeOrgId` so multi-org curl previews include the right Org-Id header.\n */\n\nimport { useState, useEffect, useMemo, useCallback, useRef } from 'react';\nimport { toast } from 'sonner';\nimport {\n Box,\n Typography,\n Chip,\n Button,\n Autocomplete,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n} from '@mui/material';\nimport PlayArrowIcon from '@mui/icons-material/PlayArrow';\nimport { API_CONFIG, getApiUrl, getAuthHeader, getTrackedOrgId } from '@/Shuffle-MCPs/api';\n\ninterface SingulAction {\n name: string;\n label: string;\n category: string;\n fields: { name: string; value: string }[];\n}\n\n/** Default starter fields per canonical action (lowercased snake_case key). */\nconst ACTION_DEFAULT_FIELDS: Record<string, { name: string; value: string }[]> = {\n list_messages: [{ name: 'channel', value: '#general' }, { name: 'limit', value: '10' }],\n send_message: [{ name: 'channel', value: '#general' }, { name: 'message', value: 'Hello from Shuffle' }],\n get_message: [{ name: 'message_id', value: '' }],\n search_messages: [{ name: 'query', value: 'incident' }],\n list_attachments: [{ name: 'message_id', value: '' }],\n get_attachment: [{ name: 'attachment_id', value: '' }],\n get_contact: [{ name: 'email', value: 'user@example.com' }],\n\n search: [{ name: 'query', value: 'event.type:login' }, { name: 'time_range', value: '24h' }],\n list_alerts: [{ name: 'severity', value: 'high' }],\n close_alert: [{ name: 'alert_id', value: '' }],\n get_alert: [{ name: 'alert_id', value: '' }],\n create_detection: [{ name: 'name', value: 'My detection' }, { name: 'query', value: 'event.type:login AND result:failure' }],\n add_to_lookup_list: [{ name: 'list_name', value: 'blocked_ips' }, { name: 'value', value: '1.2.3.4' }],\n isolate_endpoint: [{ name: 'host_id', value: '' }],\n\n block_hash: [{ name: 'hash', value: 'd41d8cd98f00b204e9800998ecf8427e' }],\n search_hosts: [{ name: 'query', value: 'hostname:laptop-*' }],\n isolate_host: [{ name: 'host_id', value: '' }],\n unisolate_host: [{ name: 'host_id', value: '' }],\n trigger_host_scan: [{ name: 'host_id', value: '' }],\n\n list_tickets: [{ name: 'status', value: 'open' }],\n get_ticket: [{ name: 'ticket_id', value: '' }],\n create_ticket: [{ name: 'title', value: 'New incident' }, { name: 'description', value: '' }, { name: 'priority', value: 'medium' }],\n close_ticket: [{ name: 'ticket_id', value: '' }],\n add_comment: [{ name: 'ticket_id', value: '' }, { name: 'comment', value: 'Investigation update' }],\n update_ticket: [{ name: 'ticket_id', value: '' }, { name: 'status', value: 'in_progress' }],\n search_tickets: [{ name: 'query', value: 'status:open' }],\n\n list_assets: [{ name: 'limit', value: '50' }],\n get_asset: [{ name: 'asset_id', value: '' }],\n search_assets: [{ name: 'query', value: 'os:windows' }],\n search_users: [{ name: 'query', value: 'department:finance' }],\n search_endpoints: [{ name: 'query', value: 'os:windows' }],\n search_vulnerabilities: [{ name: 'severity', value: 'critical' }],\n\n get_ioc: [{ name: 'value', value: '1.2.3.4' }],\n search_ioc: [{ name: 'query', value: 'malicious.com' }],\n create_ioc: [{ name: 'type', value: 'ipv4' }, { name: 'value', value: '1.2.3.4' }],\n update_ioc: [{ name: 'ioc_id', value: '' }, { name: 'value', value: '1.2.3.4' }],\n delete_ioc: [{ name: 'ioc_id', value: '' }],\n\n reset_password: [{ name: 'user_id', value: '' }],\n enable_user: [{ name: 'user_id', value: '' }],\n disable_user: [{ name: 'user_id', value: '' }],\n get_identity: [{ name: 'user_id', value: '' }],\n search_identity: [{ name: 'query', value: 'department:finance' }],\n get_kms_key: [{ name: 'key_id', value: '' }],\n\n get_rules: [],\n allow_ip: [{ name: 'ip', value: '1.2.3.4' }],\n block_ip: [{ name: 'ip', value: '1.2.3.4' }],\n\n answer_question: [{ name: 'question', value: 'What is this alert about?' }],\n run_action: [{ name: 'app', value: 'jira' }, { name: 'action', value: 'create_ticket' }],\n run_llm: [{ name: 'prompt', value: 'Summarize this incident' }, { name: 'model', value: 'gpt-4o-mini' }],\n\n update_info: [{ name: 'key', value: '' }, { name: 'value', value: '' }],\n get_info: [{ name: 'key', value: '' }],\n get_status: [],\n get_version: [],\n get_health: [],\n get_config: [{ name: 'key', value: '' }],\n get_configs: [],\n get_configs_by_type: [{ name: 'type', value: '' }],\n get_configs_by_name: [{ name: 'name', value: '' }],\n run_script: [{ name: 'script', value: 'whoami' }],\n};\n\n/** Default categories + their action labels (canonical order). */\nconst ACTION_CATEGORIES: { name: string; action_labels: string[] }[] = [\n { name: 'Communication', action_labels: ['List Messages', 'Send Message', 'Get Message', 'Search messages', 'List Attachments', 'Get Attachment', 'Get Contact'] },\n { name: 'SIEM', action_labels: ['Search', 'List Alerts', 'Close Alert', 'Get Alert', 'Create detection', 'Add to lookup list', 'Isolate endpoint'] },\n { name: 'Eradication', action_labels: ['List Alerts', 'Close Alert', 'Get Alert', 'Create detection', 'Block hash', 'Search Hosts', 'Isolate host', 'Unisolate host', 'Trigger host scan'] },\n { name: 'Cases', action_labels: ['List tickets', 'Get ticket', 'Create ticket', 'Close ticket', 'Add comment', 'Update ticket', 'Search tickets'] },\n { name: 'Assets', action_labels: ['List Assets', 'Get Asset', 'Search Assets', 'Search Users', 'Search endpoints', 'Search vulnerabilities'] },\n { name: 'Intel', action_labels: ['Get IOC', 'Search IOC', 'Create IOC', 'Update IOC', 'Delete IOC'] },\n { name: 'IAM', action_labels: ['Reset Password', 'Enable user', 'Disable user', 'Get Identity', 'Get Asset', 'Search Identity', 'Get KMS Key'] },\n { name: 'Network', action_labels: ['Get Rules', 'Allow IP', 'Block IP'] },\n { name: 'AI', action_labels: ['Answer Question', 'Run Action', 'Run LLM'] },\n { name: 'Internal', action_labels: ['Answer Question', 'Run Action', 'Run LLM'] },\n { name: 'Other', action_labels: ['Update Info', 'Get Info', 'Get Status', 'Get Version', 'Get Health', 'Get Config', 'Get Configs', 'Get Configs by type', 'Get Configs by name', 'Run script'] },\n];\n\nconst labelToName = (label: string) =>\n label.trim().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');\n\n/** Flat list of ALL actions across every category, preserving order. */\nconst ALL_ACTIONS: SingulAction[] = ACTION_CATEGORIES.flatMap((cat) =>\n cat.action_labels.map((label) => {\n const name = labelToName(label);\n return {\n name,\n label,\n category: cat.name,\n fields: ACTION_DEFAULT_FIELDS[name] ?? [],\n };\n }),\n);\n\n/** Pick the best matching default category for an app, given its raw categories. */\nfunction pickDefaultCategory(categories?: string[]): string {\n if (!categories || categories.length === 0) return 'Other';\n const known = ACTION_CATEGORIES.map((c) => c.name.toLowerCase());\n for (const cat of categories) {\n const n = cat.toLowerCase();\n const direct = known.find((k) => k === n);\n if (direct) return ACTION_CATEGORIES.find((c) => c.name.toLowerCase() === direct)!.name;\n const partial = known.find((k) => n.includes(k) || k.includes(n));\n if (partial) return ACTION_CATEGORIES.find((c) => c.name.toLowerCase() === partial)!.name;\n }\n return 'Other';\n}\n\nfunction buildSingulCurl(\n appName: string,\n action: SingulAction | null,\n opts?: { apiKey?: string | null; orgId?: string | null },\n): string {\n const act = action?.name || '{action}';\n const body = {\n app: appName || '<appname>',\n fields: action?.fields.length ? action.fields : [{ name: 'field1', value: 'value1' }],\n };\n const token = opts?.apiKey || 'YOUR_TOKEN';\n const orgLine = opts?.orgId ? `\\n -H \"Org-Id: ${opts.orgId}\" \\\\` : '';\n return `curl -X POST https://singul.io/api/${act} \\\\\n -H \"Authorization: Bearer ${token}\" \\\\${orgLine}\n -d '${JSON.stringify(body, null, 2)}'`;\n}\n\nfunction buildSingulPython(\n appName: string,\n action: SingulAction | null,\n): string {\n const act = action?.name || 'send_message';\n const app = appName || '<appname>';\n const fields = action?.fields.length ? action.fields : [];\n const fieldsStr = JSON.stringify(fields);\n return `import shufflepy\n\nresponse = shufflepy.run(\"${app}\", action=\"${act}\", fields=${fieldsStr})\n\nprint(response)`;\n}\n\ntype SnippetLang = 'curl' | 'python';\n\n/** HTML-escape user content before injecting into a highlighted <pre>. */\nconst escapeHtml = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\n/** Single-pass tokenizer-based highlighter. We MUST NOT run successive regex\n * passes over already-highlighted HTML, because the inline `style=\"color:hsl(...)\"`\n * attributes contain words/numbers that later passes would happily re-match\n * (e.g. `hsl` matches `\\w+(?=\\()`, digits inside `280` match `\\d+`). */\nfunction highlightSnippet(code: string, lang: SnippetLang): string {\n const COL = {\n string: 'hsl(140 60% 65%)',\n keyword: 'hsl(280 70% 75%)',\n func: 'hsl(45 90% 65%)',\n number: 'hsl(20 90% 65%)',\n flag: 'hsl(200 80% 70%)',\n builtin: 'hsl(0 70% 70%)',\n comment: 'hsl(var(--muted-foreground))',\n };\n const PY_KEYWORDS = new Set([\n 'import', 'from', 'as', 'def', 'return', 'if', 'else', 'elif', 'for',\n 'while', 'in', 'None', 'True', 'False', 'print', 'class', 'with', 'try', 'except',\n ]);\n const wrap = (color: string, text: string) =>\n `<span style=\"color:${color}\">${escapeHtml(text)}</span>`;\n\n const out: string[] = [];\n let i = 0;\n const n = code.length;\n while (i < n) {\n const ch = code[i];\n // Strings\n if (ch === '\"' || ch === \"'\") {\n const quote = ch;\n let j = i + 1;\n while (j < n && code[j] !== quote) {\n if (code[j] === '\\\\' && j + 1 < n) j += 2;\n else j++;\n }\n j = Math.min(j + 1, n);\n out.push(wrap(COL.string, code.slice(i, j)));\n i = j;\n continue;\n }\n // Python comments\n if (lang === 'python' && ch === '#') {\n let j = i;\n while (j < n && code[j] !== '\\n') j++;\n out.push(wrap(COL.comment, code.slice(i, j)));\n i = j;\n continue;\n }\n // Curl flags ( -X / --header ), only at start of token\n if (lang === 'curl' && ch === '-' && (i === 0 || /\\s/.test(code[i - 1]))) {\n let j = i + 1;\n if (code[j] === '-') j++;\n while (j < n && /[\\w-]/.test(code[j])) j++;\n out.push(wrap(COL.flag, code.slice(i, j)));\n i = j;\n continue;\n }\n // Numbers\n if (/\\d/.test(ch)) {\n let j = i;\n while (j < n && /[\\d.]/.test(code[j])) j++;\n out.push(wrap(COL.number, code.slice(i, j)));\n i = j;\n continue;\n }\n // Identifiers / keywords / function calls\n if (/[A-Za-z_]/.test(ch)) {\n let j = i;\n while (j < n && /[\\w]/.test(code[j])) j++;\n const word = code.slice(i, j);\n if (lang === 'python' && PY_KEYWORDS.has(word)) {\n out.push(wrap(COL.keyword, word));\n } else if (lang === 'curl' && word === 'curl') {\n out.push(wrap(COL.builtin, word));\n } else if (code[j] === '(') {\n out.push(wrap(COL.func, word));\n } else {\n out.push(escapeHtml(word));\n }\n i = j;\n continue;\n }\n // Plain char (operators, whitespace, punctuation)\n out.push(escapeHtml(ch));\n i++;\n }\n return out.join('');\n}\n\n\n\nconst SingulActionsPreview = ({\n appName,\n categories,\n activeOrgId,\n}: {\n appName: string;\n categories?: string[];\n activeOrgId?: string | null;\n}) => {\n const defaultCategory = useMemo(() => pickDefaultCategory(categories), [categories]);\n const actions = ALL_ACTIONS;\n // Sort so that the app's default category appears first, rest follow original order.\n const sortedActions = useMemo(() => {\n const inCat = actions.filter((a) => a.category === defaultCategory);\n const rest = actions.filter((a) => a.category !== defaultCategory);\n return [...inCat, ...rest];\n }, [actions, defaultCategory]);\n const isDisabled = false;\n const [selected, setSelected] = useState<SingulAction | null>(null);\n const [lang, setLang] = useState<SnippetLang>('curl');\n const [snippet, setSnippet] = useState<string>('');\n\n const curlOpts = useMemo(() => {\n const apiKey = API_CONFIG.apiKey;\n const trackedOrg = getTrackedOrgId();\n const orgId = trackedOrg && activeOrgId && trackedOrg !== activeOrgId ? trackedOrg : null;\n return { apiKey, orgId };\n }, [activeOrgId]);\n\n const buildSnippet = useCallback(\n (action: SingulAction | null, l: SnippetLang) =>\n l === 'python' ? buildSingulPython(appName, action) : buildSingulCurl(appName, action, curlOpts),\n [appName, curlOpts],\n );\n\n useEffect(() => {\n const initial = sortedActions[0] || null;\n setSelected(initial);\n setSnippet(buildSnippet(initial, lang));\n }, [appName, sortedActions, curlOpts, lang, buildSnippet]);\n\n const handleSelect = (action: SingulAction | null) => {\n setSelected(action);\n setSnippet(buildSnippet(action, lang));\n };\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(snippet);\n toast.success('Copied snippet');\n } catch {\n toast.error('Copy failed');\n }\n };\n\n const [playLoading, setPlayLoading] = useState(false);\n const [playResult, setPlayResult] = useState<string | null>(null);\n const responseRef = useRef<HTMLDivElement | null>(null);\n\n const scrollToResponse = () => {\n requestAnimationFrame(() => {\n responseRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n });\n };\n\n const handlePlay = async () => {\n if (!snippet || playLoading) return;\n setPlayLoading(true);\n setPlayResult('');\n scrollToResponse();\n try {\n const body = lang === 'python'\n ? {\n name: 'execute_python',\n app_id: '3e2bdf9d5069fe3f4746c29d68785a6a',\n environment: 'Cloud',\n parameters: [{ name: 'code', value: snippet, schema: { type: 'string' } }],\n app_name: 'Shuffle Tools',\n app_version: '1.2.0',\n }\n : {\n name: 'curl',\n app_id: 'ebfe7d5c80000676588f86731db0a555',\n environment: 'Cloud',\n parameters: [{ name: 'statement', value: snippet, schema: { type: 'string' } }],\n app_name: 'http',\n app_version: '1.4.0',\n };\n const path = lang === 'python' ? '/api/v1/apps/3e2bdf9d5069fe3f4746c29d68785a6a/run' : '/api/v1/apps/http/run';\n const res = await fetch(getApiUrl(path), {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', ...getAuthHeader() },\n body: JSON.stringify(body),\n });\n const data = await res.json();\n let output = data?.result;\n if (typeof output === 'string') {\n try { output = JSON.stringify(JSON.parse(output), null, 2); } catch {}\n } else if (output != null) {\n output = JSON.stringify(output, null, 2);\n } else {\n output = JSON.stringify(data, null, 2);\n }\n setPlayResult(output);\n const parsed = (() => { try { return JSON.parse(data?.result || '{}'); } catch { return null; } })();\n if (parsed?.success === false) {\n toast.error(parsed.reason || 'Run failed');\n } else {\n toast.success(`Ran ${selected?.name || lang}`);\n }\n } catch (err: any) {\n const msg = err?.message || 'Run failed';\n setPlayResult(msg);\n toast.error(msg);\n } finally {\n setPlayLoading(false);\n scrollToResponse();\n }\n };\n\n const lineCount = useMemo(() => Math.max(snippet.split('\\n').length, 1), [snippet]);\n\n return (\n <Box sx={{ mb: 3, opacity: isDisabled ? 0.55 : 1 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1.5 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 600, fontSize: '0.95rem' }}>\n Try individual actions\n </Typography>\n <Chip\n label=\"Preview\"\n size=\"small\"\n sx={{ height: 18, fontSize: '0.6rem', fontWeight: 500, backgroundColor: 'hsl(var(--muted))', color: 'hsl(var(--muted-foreground))' }}\n />\n </Box>\n\n <Box\n sx={{\n position: 'relative',\n p: 2,\n borderRadius: 2,\n border: '1px solid hsl(var(--border))',\n background: 'linear-gradient(180deg, hsl(var(--muted) / 0.35) 0%, hsl(var(--background) / 0.6) 100%)',\n pointerEvents: isDisabled ? 'none' : 'auto',\n overflow: 'hidden',\n '&::before': {\n content: '\"\"',\n position: 'absolute',\n inset: -1,\n borderRadius: 2,\n padding: '1px',\n background: 'linear-gradient(135deg, hsl(var(--primary) / 0.35), transparent 40%, hsl(var(--primary) / 0.15))',\n WebkitMask: 'linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)',\n WebkitMaskComposite: 'xor',\n maskComposite: 'exclude',\n pointerEvents: 'none',\n },\n }}\n >\n {isDisabled ? (\n <Typography sx={{ fontSize: '0.75rem', color: 'hsl(var(--muted-foreground))', fontStyle: 'italic', textAlign: 'center', py: 1 }}>\n No category detected for this app\n </Typography>\n ) : (\n <>\n <Box sx={{ display: 'flex', gap: 1, mb: 1.5, alignItems: 'center' }}>\n <Autocomplete\n size=\"small\"\n disableClearable\n options={sortedActions}\n value={selected ?? sortedActions[0]}\n onChange={(_, v) => v && handleSelect(v as SingulAction)}\n groupBy={(o: SingulAction) => o.category}\n getOptionLabel={(o: SingulAction | null) => o?.label ?? ''}\n isOptionEqualToValue={(a, b) => a?.name === b?.name && a?.category === b?.category}\n renderOption={(props, option) => (\n <li {...props} key={`${option.category}-${option.name}`}>\n <Box sx={{ display: 'flex', flexDirection: 'column' }}>\n <Typography sx={{ fontSize: '0.78rem', color: 'hsl(var(--foreground))' }}>{option.label}</Typography>\n <Typography sx={{ fontFamily: \"'JetBrains Mono', monospace\", fontSize: '0.65rem', color: 'hsl(var(--muted-foreground))' }}>\n {option.name}\n </Typography>\n </Box>\n </li>\n )}\n sx={{\n flex: 1,\n '& .MuiOutlinedInput-root': {\n backgroundColor: 'hsl(var(--card))',\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.75rem',\n color: 'hsl(var(--foreground))',\n '& fieldset': { borderColor: 'hsl(var(--border))' },\n '&:hover fieldset': { borderColor: 'hsl(var(--primary))' },\n '&.Mui-focused fieldset': { borderColor: 'hsl(var(--primary))' },\n },\n }}\n slotProps={{\n paper: {\n sx: {\n backgroundColor: 'hsl(var(--card))',\n color: 'hsl(var(--foreground))',\n border: '1px solid hsl(var(--border))',\n '& .MuiAutocomplete-groupLabel': {\n backgroundColor: 'hsl(var(--muted) / 0.6)',\n color: 'hsl(var(--muted-foreground))',\n fontSize: '0.65rem',\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: 0.6,\n lineHeight: '24px',\n },\n },\n },\n }}\n renderInput={(params) => (\n <TextField {...params} placeholder=\"Select action\" />\n )}\n />\n <ToggleButtonGroup\n size=\"small\"\n exclusive\n value={lang}\n onChange={(_, v) => v && setLang(v)}\n sx={{\n '& .MuiToggleButton-root': {\n height: 36,\n px: 1.5,\n fontSize: '0.7rem',\n textTransform: 'none',\n fontFamily: \"'JetBrains Mono', monospace\",\n color: 'hsl(var(--muted-foreground))',\n border: '1px solid hsl(var(--border))',\n '&.Mui-selected': {\n backgroundColor: 'hsl(var(--primary) / 0.15)',\n color: 'hsl(var(--primary))',\n borderColor: 'hsl(var(--primary))',\n '&:hover': { backgroundColor: 'hsl(var(--primary) / 0.2)' },\n },\n },\n }}\n >\n <ToggleButton value=\"curl\">curl</ToggleButton>\n <ToggleButton value=\"python\">python</ToggleButton>\n </ToggleButtonGroup>\n </Box>\n\n {/* Code card */}\n <Box\n sx={{\n position: 'relative',\n borderRadius: 1.5,\n border: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--background))',\n overflow: 'hidden',\n boxShadow: '0 8px 24px -12px hsl(var(--primary) / 0.25)',\n }}\n >\n {/* Header bar */}\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n px: 1.25,\n py: 0.75,\n borderBottom: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--muted) / 0.4)',\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ display: 'flex', gap: 0.4 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', backgroundColor: 'hsl(0 70% 60% / 0.6)' }} />\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', backgroundColor: 'hsl(40 80% 60% / 0.6)' }} />\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', backgroundColor: 'hsl(140 60% 55% / 0.6)' }} />\n </Box>\n <Typography\n sx={{\n ml: 1,\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.65rem',\n color: 'hsl(var(--muted-foreground))',\n letterSpacing: 0.4,\n }}\n >\n {lang === 'python' ? 'singul.py' : 'request.sh'}\n {selected ? ` · ${selected.name}` : ''}\n </Typography>\n </Box>\n <Box sx={{ display: 'flex', gap: 0.75 }}>\n <Button\n size=\"small\"\n onClick={handleCopy}\n sx={{\n height: 26,\n minWidth: 0,\n px: 1.25,\n fontSize: '0.65rem',\n textTransform: 'none',\n color: 'hsl(var(--muted-foreground))',\n backgroundColor: 'hsl(var(--card))',\n border: '1px solid hsl(var(--border))',\n '&:hover': { backgroundColor: 'hsl(var(--muted))', color: 'hsl(var(--foreground))' },\n }}\n >\n Copy\n </Button>\n <Button\n size=\"small\"\n onClick={handlePlay}\n disabled={playLoading}\n startIcon={!playLoading && <PlayArrowIcon sx={{ fontSize: 14 }} />}\n sx={{\n height: 26,\n minWidth: 0,\n px: 1.5,\n fontSize: '0.65rem',\n fontWeight: 600,\n textTransform: 'none',\n color: 'hsl(var(--primary-foreground))',\n backgroundColor: 'hsl(var(--primary))',\n border: '1px solid hsl(var(--primary))',\n boxShadow: '0 0 12px -2px hsl(var(--primary) / 0.6)',\n '& .MuiButton-startIcon': { mr: 0.5 },\n '&:hover': { backgroundColor: 'hsl(var(--primary) / 0.9)', boxShadow: '0 0 16px -2px hsl(var(--primary) / 0.7)' },\n '&.Mui-disabled': { color: 'hsl(var(--primary-foreground) / 0.7)', backgroundColor: 'hsl(var(--primary) / 0.45)', boxShadow: 'none', borderColor: 'hsl(var(--primary) / 0.45)' },\n }}\n >\n {playLoading ? 'Running…' : 'Play'}\n </Button>\n </Box>\n </Box>\n\n {/* Editor area with line numbers */}\n <Box sx={{ display: 'flex', minHeight: 270 }}>\n <Box\n aria-hidden\n sx={{\n userSelect: 'none',\n py: 1.5,\n pl: 1.25,\n pr: 1,\n textAlign: 'right',\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.72rem',\n lineHeight: 1.5,\n color: 'hsl(var(--muted-foreground) / 0.6)',\n borderRight: '1px solid hsl(var(--border))',\n backgroundColor: 'hsl(var(--muted) / 0.25)',\n minWidth: 36,\n }}\n >\n {Array.from({ length: lineCount }, (_, i) => (\n <div key={i}>{i + 1}</div>\n ))}\n </Box>\n <Box sx={{ flex: 1, position: 'relative', minHeight: 270 }}>\n <Box\n aria-hidden\n sx={{\n position: 'absolute',\n inset: 0,\n m: 0,\n p: 1.5,\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.72rem',\n lineHeight: 1.5,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n pointerEvents: 'none',\n overflow: 'hidden',\n }}\n dangerouslySetInnerHTML={{ __html: highlightSnippet(snippet, lang) + '\\n' }}\n />\n <Box\n component=\"textarea\"\n value={snippet}\n onChange={(e: any) => setSnippet(e.target.value)}\n spellCheck={false}\n sx={{\n position: 'relative',\n width: '100%',\n height: '100%',\n minHeight: 270,\n resize: 'vertical',\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.72rem',\n lineHeight: 1.5,\n color: 'transparent',\n WebkitTextFillColor: 'transparent',\n backgroundColor: 'transparent',\n border: 'none',\n p: 1.5,\n m: 0,\n outline: 'none',\n caretColor: 'hsl(var(--primary))',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n overflow: 'auto',\n '&::selection': { color: 'inherit', backgroundColor: 'hsl(var(--primary) / 0.3)' },\n }}\n />\n </Box>\n </Box>\n </Box>\n </>\n )}\n\n {(playLoading || playResult !== null) && (\n <Box ref={responseRef} sx={{ mt: 1.5 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mb: 0.5 }}>\n <Box sx={{ width: 6, height: 6, borderRadius: '50%', backgroundColor: 'hsl(140 60% 55%)' }} />\n <Typography sx={{ fontFamily: \"'JetBrains Mono', monospace\", fontSize: '0.65rem', color: 'hsl(var(--muted-foreground))', letterSpacing: 0.4 }}>\n response\n </Typography>\n </Box>\n <Box\n component=\"pre\"\n sx={{\n p: 1.5,\n maxHeight: 240,\n overflow: 'auto',\n fontFamily: \"'JetBrains Mono', monospace\",\n fontSize: '0.7rem',\n lineHeight: 1.5,\n color: 'hsl(var(--foreground))',\n backgroundColor: 'hsl(var(--background))',\n border: '1px solid hsl(var(--border))',\n borderRadius: 1.5,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n m: 0,\n }}\n >\n {playLoading && !playResult ? 'Running…' : playResult}\n </Box>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n\nexport default SingulActionsPreview;\n","/**\n * AppSearchDrawer — Reusable drawer for searching apps.\n * Selecting an app opens the AppDetailDrawer for full configuration.\n */\n\nimport { useState } from 'react';\nimport { Box, Typography, IconButton, Drawer, Avatar, Tooltip } from '@mui/material';\nimport CloseIcon from '@mui/icons-material/Close';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { ShuffleMCP, AppDetailDrawer } from '@/Shuffle-MCPs';\nimport type { AppSelectedEvent } from '@/Shuffle-MCPs';\nimport { API_CONFIG } from '@/Shuffle-MCPs/api';\nimport { ShufflePipelinesBanner } from '@/Shuffle-MCPs/ShufflePipelinesBanner';\nimport { IntegrationStatus } from '@/Shuffle-MCPs/IntegrationStatus';\n\n// Singul styles — compact dark theme\nconst singulStyles = {\n container: { width: '100%' },\n inputWrapper: {\n backgroundColor: 'hsl(var(--background-elevated))',\n borderRadius: '12px',\n border: '1px solid hsl(var(--border))',\n },\n input: {\n backgroundColor: 'transparent',\n color: 'hsl(var(--foreground))',\n border: 'none',\n borderRadius: '12px',\n padding: '12px 16px',\n fontSize: '14px',\n },\n searchIcon: { color: 'hsl(var(--muted-foreground))' },\n spinner: {\n borderColor: 'hsl(var(--border))',\n borderTopColor: 'hsl(var(--primary))',\n },\n resultsContainer: { marginTop: '12px', gap: '10px' },\n dropdownItem: {\n backgroundColor: 'hsl(var(--input))',\n border: '1px solid hsl(var(--border))',\n borderRadius: '12px',\n padding: '14px',\n color: 'hsl(var(--foreground))',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n },\n dropdownItemHover: {\n borderColor: 'hsl(var(--primary) / 0.5)',\n backgroundColor: 'hsl(var(--accent) / 0.08)',\n },\n selectedItem: {\n backgroundColor: 'hsl(var(--primary) / 0.1)',\n borderColor: 'hsl(var(--primary))',\n },\n appIcon: {\n width: '36px',\n height: '36px',\n borderRadius: '8px',\n backgroundColor: 'hsl(var(--muted))',\n objectFit: 'contain' as const,\n padding: '4px',\n },\n appName: { fontSize: '13px', fontWeight: 600, color: 'hsl(var(--foreground))' },\n appDescription: {\n fontSize: '11px',\n color: 'hsl(var(--muted-foreground))',\n lineHeight: 1.4,\n },\n appCategory: {\n marginTop: '6px',\n padding: '2px 8px',\n backgroundColor: 'hsl(var(--muted))',\n color: 'hsl(var(--muted-foreground))',\n fontSize: '10px',\n fontWeight: 600,\n textTransform: 'uppercase' as const,\n borderRadius: '4px',\n display: 'inline-block',\n width: 'fit-content',\n },\n checkbox: { border: '2px solid hsl(var(--border))' },\n checkboxChecked: { backgroundColor: 'hsl(var(--primary))', borderColor: 'hsl(var(--primary))' },\n emptyState: {\n padding: '24px',\n color: 'hsl(var(--muted-foreground))',\n textAlign: 'center' as const,\n fontSize: '13px',\n backgroundColor: 'hsl(var(--muted))',\n borderRadius: '12px',\n border: '1px solid hsl(var(--border))',\n gridColumn: '1 / -1',\n },\n};\n\ninterface ConnectionPathApp {\n name: string;\n icon: string;\n hasValidAuth?: boolean;\n isActiveOnly?: boolean;\n}\n\ninterface AppSearchDrawerProps {\n open: boolean;\n onClose: () => void;\n initialQuery?: string;\n title?: string;\n subtitle?: string;\n anchor?: 'left' | 'right';\n width?: number;\n /** Show the Shuffle Pipelines banner above search results */\n showPipelinesBanner?: boolean;\n /** If provided, selecting an app calls this instead of opening AppDetailDrawer */\n onQuickSelect?: (app: { name: string; icon: string; categories: string[]; id: string | null }) => void;\n /** If provided, called before default behavior. Return true to prevent opening detail drawer. */\n onSelectOverride?: (app: { name: string; icon: string; categories: string[] }) => boolean;\n /** Called when the detail drawer closes, with the app name that was being configured */\n onDetailClose?: (appName: string) => void;\n /** When set, replaces Activate with \"+ Add\" in the detail drawer */\n onAddToCanvas?: (appInfo: { name: string; icon: string; algoliaId: string | null }) => void;\n /** When set, apps matching this category are sorted to the top in user's apps */\n priorityCategory?: string;\n /** Apps currently in the connection path diagram — shown first in the drawer */\n connectionPathApps?: ConnectionPathApp[];\n /** Apps to pin at the top of the ShuffleMCP search results (deduped by name). */\n pinnedApps?: Array<{ name: string; image_url: string; categories?: string[]; objectID?: string }>;\n}\n\nexport default function AppSearchDrawer({\n open,\n onClose,\n initialQuery = '',\n title = 'Add Integration',\n subtitle = 'Search and configure a tool',\n anchor = 'right',\n width = 560,\n showPipelinesBanner = false,\n onQuickSelect,\n onSelectOverride,\n onDetailClose,\n onAddToCanvas,\n priorityCategory,\n connectionPathApps,\n pinnedApps,\n}: AppSearchDrawerProps) {\n const [detailAppName, setDetailAppName] = useState<string | null>(null);\n\n const handleClose = () => {\n setDetailAppName(null);\n onClose();\n };\n\n const handleAppSelected = (detail: AppSelectedEvent) => {\n const appInfo = {\n name: detail.app.name,\n icon: detail.app.image_url || '',\n categories: detail.app.categories || [],\n id: (detail.app as any).objectID || null,\n };\n if (onQuickSelect) {\n onQuickSelect(appInfo);\n onClose();\n return;\n }\n if (onSelectOverride?.(appInfo)) {\n return;\n }\n setDetailAppName(detail.app.name);\n };\n\n return (\n <>\n <Drawer\n anchor={anchor}\n open={open && detailAppName === null}\n onClose={handleClose}\n sx={{\n zIndex: 9999,\n '& .MuiDrawer-paper': {\n width,\n maxWidth: '100vw',\n background: 'linear-gradient(180deg, hsl(var(--card)) 0%, hsl(var(--background)) 100%)',\n borderLeft: anchor === 'right' ? '1px solid hsl(var(--border))' : 'none',\n borderRight: anchor === 'left' ? '1px solid hsl(var(--border))' : 'none',\n },\n }}\n >\n {/* Header */}\n <Box\n sx={{\n px: 3,\n py: 2,\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n borderBottom: '1px solid hsl(var(--border))',\n flexShrink: 0,\n }}\n >\n <Box sx={{ flex: 1 }}>\n <Typography sx={{ color: 'hsl(var(--foreground))', fontWeight: 700, fontSize: '1rem', lineHeight: 1.2 }}>\n {title}\n </Typography>\n <Typography sx={{ color: 'hsl(var(--muted-foreground))', fontSize: '0.75rem' }}>\n {subtitle}\n </Typography>\n </Box>\n <IconButton\n size=\"small\"\n onClick={handleClose}\n sx={{ color: 'hsl(var(--muted-foreground))', '&:hover': { color: 'hsl(var(--foreground))' } }}\n >\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n </Box>\n\n {/* Search body */}\n <Box sx={{ flex: 1, overflowY: 'auto', p: 3, minHeight: '92vh' }}>\n {showPipelinesBanner && <ShufflePipelinesBanner />}\n\n {/* Your Apps — reuse IntegrationStatus */}\n {API_CONFIG.apiKey && (\n <Box sx={{ mb: 2.5 }}>\n <IntegrationStatus collapsed={false} showAll hideAddButton priorityCategory={priorityCategory} />\n </Box>\n )}\n\n {/* Connection path apps — shown first */}\n {connectionPathApps && connectionPathApps.length > 0 && (\n <Box sx={{ mb: 2.5 }}>\n <Typography sx={{ color: 'hsl(var(--muted-foreground))', fontSize: '0.7rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', mb: 1 }}>\n In this usecase\n </Typography>\n <Box sx={{ display: 'flex', gap: 1.5, flexWrap: 'wrap' }}>\n {connectionPathApps.map((app) => (\n <Tooltip key={app.name} title={app.name.replace(/_/g, ' ')} arrow placement=\"bottom\">\n <Box\n onClick={() => handleAppSelected({ app: { name: app.name, image_url: app.icon, categories: [] } } as any)}\n sx={{\n position: 'relative',\n cursor: 'pointer',\n transition: 'transform 0.15s ease',\n '&:hover': { transform: 'scale(1.1)' },\n }}\n >\n <Avatar\n src={app.icon}\n alt={app.name}\n sx={{ width: 32, height: 32, borderRadius: '8px', backgroundColor: 'hsl(var(--muted))' }}\n variant=\"rounded\"\n />\n <Box\n sx={{\n position: 'absolute',\n bottom: -2,\n right: -2,\n width: 9,\n height: 9,\n borderRadius: '50%',\n backgroundColor: app.hasValidAuth ? 'hsl(var(--severity-low))' : app.isActiveOnly ? 'hsl(var(--destructive))' : 'hsl(var(--severity-medium))',\n border: '1.5px solid hsl(var(--card))',\n }}\n />\n </Box>\n </Tooltip>\n ))}\n </Box>\n </Box>\n )}\n\n <AnimatePresence mode=\"wait\">\n <motion.div\n key=\"search\"\n initial={{ opacity: 0, x: -20 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -20 }}\n transition={{ duration: 0.2 }}\n >\n <ShuffleMCP\n apiKey={API_CONFIG.apiKey || undefined}\n apiBaseUrl={API_CONFIG.baseUrl}\n placeholder={initialQuery ? `Search ${initialQuery} integrations...` : 'Search integrations...'}\n layout=\"grid\"\n gridColumns={2}\n inline={true}\n initialFilterQuery={initialQuery}\n hitsPerPage={12}\n showDescription={false}\n showCategories={true}\n showCheckbox={false}\n multiSelect={false}\n preventDefault={true}\n onAppSelected={handleAppSelected}\n pinnedApps={pinnedApps?.map(p => ({\n name: p.name,\n image_url: p.image_url,\n categories: p.categories || [],\n objectID: p.objectID || `pinned-${p.name}`,\n description: '',\n creator: '',\n app_version: '1.0.0',\n time_edited: 0,\n generated: false,\n invalid: false,\n priority: 0,\n actions: 0,\n tags: [],\n accessible_by: [],\n action_labels: [],\n triggers: [],\n verified: true,\n }))}\n customStyles={singulStyles}\n />\n </motion.div>\n </AnimatePresence>\n </Box>\n </Drawer>\n\n {/* App detail drawer — opens when an app is selected from search */}\n <AppDetailDrawer\n open={open && detailAppName !== null}\n onClose={() => {\n const name = detailAppName;\n setDetailAppName(null);\n if (name) onDetailClose?.(name);\n }}\n appName={detailAppName}\n anchor={anchor}\n width={width}\n onRefresh={onClose}\n onAddToCanvas={onAddToCanvas}\n />\n </>\n );\n}\n","import { Box, Typography, Chip } from '@mui/material';\nimport shuffleIcon from '@/assets/shuffle-icon.png';\n\nexport function ShufflePipelinesBanner() {\n return (\n <Box\n component=\"a\"\n href=\"/detection\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n p: 2,\n mb: 2,\n borderRadius: 2.5,\n background: 'linear-gradient(135deg, hsla(25, 100%, 50%, 0.08) 0%, hsla(25, 100%, 50%, 0.03) 100%)',\n border: '1px solid hsla(25, 100%, 50%, 0.2)',\n textDecoration: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n '&:hover': {\n border: '1px solid hsla(25, 100%, 50%, 0.4)',\n background: 'linear-gradient(135deg, hsla(25, 100%, 50%, 0.12) 0%, hsla(25, 100%, 50%, 0.05) 100%)',\n },\n }}\n >\n <Box\n component=\"img\"\n src={shuffleIcon}\n alt=\"Shuffle\"\n sx={{ width: 36, height: 36, borderRadius: '10px', flexShrink: 0 }}\n />\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Typography sx={{ fontWeight: 700, fontSize: '0.85rem', color: 'hsl(var(--foreground))', lineHeight: 1.3 }}>\n Shuffle Pipelines\n </Typography>\n <Typography sx={{ fontSize: '0.72rem', color: 'hsl(var(--muted-foreground))', lineHeight: 1.4 }}>\n Do not have a SIEM? Shuffle can ingest, parse, and correlate your logs and events directly — no external SIEM required.\n </Typography>\n </Box>\n <Chip\n label=\"Built-in\"\n size=\"small\"\n sx={{\n height: 22,\n fontSize: '0.65rem',\n fontWeight: 700,\n backgroundColor: 'hsl(var(--primary) / 0.15)',\n color: 'hsl(var(--primary))',\n border: '1px solid hsl(var(--primary) / 0.3)',\n flexShrink: 0,\n }}\n />\n </Box>\n );\n}\n\nexport default ShufflePipelinesBanner;\n","/**\n * useAppLookup — Resolve an app's display name, image, categories,\n * canonical Algolia objectID and matching auth entries from just\n * an app name (or id).\n *\n * Used by the standalone section components (Authentication, Try MCP,\n * Try individual actions) so consumers only need to pass `appName`.\n *\n * Resolution order:\n * 1. Algolia `appsearch` index (best-effort, may 429)\n * 2. /api/v1/apps fallback (private + activated apps)\n * 3. /api/v1/apps/:id/config to enrich with auth schema\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { API_CONFIG, getApiUrl, getAuthHeader } from '@/Shuffle-MCPs/api';\nimport { useAppAuth } from '@/Shuffle-MCPs/useAppAuth';\nimport type { AlgoliaSearchApp } from './shuffle-mcp.helpers';\n\nexport interface AppLookupResult {\n loading: boolean;\n displayName: string;\n image: string;\n categories: string[];\n /** Canonical Algolia objectID (or Shuffle private app id). */\n algoliaId: string | null;\n /** Synthesized AlgoliaSearchApp suitable for AppAuthCard. */\n algoliaApp: AlgoliaSearchApp | null;\n /** Auth entries matching this app name. */\n matchingEntries: any[];\n hasValidAuth: boolean;\n hasAnyAuth: boolean;\n authCount: number;\n authState: any;\n // Pass-through helpers from useAppAuth (so consumers do not need a second hook):\n handleAuthChange: any;\n handleTestConnection: (appId: string, authId?: string) => any;\n handleSaveAuth: (appId: string, credentials: Record<string, string>) => Promise<boolean>;\n refreshAuth: () => void;\n}\n\nconst norm = (s: string) => s.toLowerCase().replace(/[\\s_\\-]+/g, '_');\n\nexport function useAppLookup(appName: string | null): AppLookupResult {\n const [loading, setLoading] = useState(false);\n const [info, setInfo] = useState<{\n name: string;\n description: string;\n image: string;\n categories: string[];\n } | null>(null);\n const [algoliaId, setAlgoliaId] = useState<string | null>(null);\n\n const {\n authStates,\n authenticatedApps,\n handleAuthChange,\n handleTestConnection,\n handleSaveAuth,\n refreshAuth,\n } = useAppAuth();\n\n useEffect(() => {\n if (!appName) {\n setInfo(null);\n setAlgoliaId(null);\n return;\n }\n setLoading(true);\n setInfo(null);\n setAlgoliaId(null);\n refreshAuth();\n\n const normalizedName = norm(appName);\n const searchName = appName.replace(/_/g, ' ');\n\n (async () => {\n let id: string | null = null;\n try {\n const { algoliasearch } = await import('algoliasearch');\n const client = algoliasearch('JNSS5CFDZZ', '33e4e3564f4f060e96e0531957bed552');\n const res = await client.search({\n requests: [{ indexName: 'appsearch', query: searchName, hitsPerPage: 10 }],\n });\n const hits = (res as any)?.results?.[0]?.hits || [];\n const match = hits.find((h: any) => h.name && norm(h.name) === normalizedName) || hits[0];\n if (match) {\n id = match.objectID;\n setAlgoliaId(id);\n setInfo({\n name: match.name || searchName,\n description: match.description || '',\n image: match.image_url || '',\n categories: match.categories || [],\n });\n }\n } catch {}\n\n let appsList: any[] | null = null;\n if (API_CONFIG.apiKey) {\n try {\n const res = await fetch(getApiUrl('/api/v1/apps'), {\n credentials: 'include',\n headers: { ...getAuthHeader() },\n });\n if (res.ok) {\n const apps = await res.json();\n if (Array.isArray(apps)) appsList = apps;\n }\n } catch {}\n }\n\n if (!id && appsList) {\n const localMatch = appsList.find((a: any) => norm(a.name || '') === normalizedName);\n if (localMatch?.id) {\n id = localMatch.id;\n setAlgoliaId(localMatch.id);\n setInfo((prev) => prev ?? {\n name: localMatch.name || searchName,\n description: localMatch.description || '',\n image: localMatch.large_image || '',\n categories: localMatch.categories || [],\n });\n }\n }\n\n if (API_CONFIG.apiKey && id) {\n try {\n const response = await fetch(\n getApiUrl(`/api/v1/apps/${encodeURIComponent(id)}/config`),\n { credentials: 'include', headers: { ...getAuthHeader() } },\n );\n if (response.ok) {\n const data = await response.json();\n if (data?.name) {\n setInfo((prev) => ({\n name: data.name || prev?.name || searchName,\n description: data.description || prev?.description || '',\n image: data.large_image || prev?.image || '',\n categories: data.categories || prev?.categories || [],\n }));\n }\n }\n } catch {}\n }\n\n setInfo((prev) => prev ?? { name: searchName, description: '', image: '', categories: [] });\n setLoading(false);\n })();\n }, [appName]);\n\n const matchingEntries = useMemo(() => {\n if (!appName) return [];\n return authenticatedApps.filter(\n (auth) => auth.app?.name && norm(auth.app.name) === norm(appName),\n );\n }, [appName, authenticatedApps]);\n\n const image = useMemo(() => {\n if (info?.image) return info.image;\n for (const entry of matchingEntries) {\n const img = (entry as any).app?.large_image || (entry as any).large_image;\n if (img) return img;\n }\n return '';\n }, [info, matchingEntries]);\n\n const algoliaApp: AlgoliaSearchApp | null = useMemo(() => {\n if (!appName) return null;\n return {\n objectID: algoliaId || appName,\n name: appName,\n image_url: image,\n description: info?.description || '',\n categories: info?.categories || [],\n } as AlgoliaSearchApp;\n }, [appName, info, image, algoliaId]);\n\n const displayName = (info?.name || appName || '').replace(/_/g, ' ');\n const authState = authStates[appName || ''] || { systemId: appName || '', status: 'pending' as const, credentials: {} };\n\n return {\n loading,\n displayName,\n image,\n categories: info?.categories || [],\n algoliaId,\n algoliaApp,\n matchingEntries,\n hasValidAuth: matchingEntries.some((e) => e.validation?.valid === true),\n hasAnyAuth: matchingEntries.length > 0,\n authCount: matchingEntries.length,\n authState,\n handleAuthChange,\n handleTestConnection,\n handleSaveAuth,\n refreshAuth,\n };\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useCallback","useMemo","useState","useEffect","useMemo","useRef","toast","Box","Typography","IconButton","CloseIcon","ReactMarkdown","remarkGfm","motion","useState","useCallback","useEffect","useState","useCallback","norm","algoliasearch","url","jsx","useState","useCallback","useState","fetchAuthenticatedApps","useCallback","useEffect","Box","Typography","Avatar","jsx","jsxs","Box","Typography","motion","useState","useEffect","Box","Typography","Button","CircularProgress","Chip","IconButton","Tooltip","motion","CheckCircleIcon","Fragment","jsx","jsxs","useState","useEffect","auth","error","jsxs","Box","Fragment","jsx","Button","Typography","motion","Chip","Tooltip","IconButton","CheckCircleIcon","CircularProgress","jsx","jsxs","motion","Box","Typography","Box","Typography","motion","useState","useRef","Box","Typography","Avatar","CircularProgress","Chip","jsx","ErrorOutlineIcon","motion","ReactMarkdown","remarkGfm","jsx","jsxs","useState","useRef","Box","motion","Avatar","Typography","Chip","CircularProgress","ErrorOutlineIcon","ReactMarkdown","remarkGfm","jsx","jsxs","motion","Box","Typography","useState","useEffect","useMemo","useCallback","useRef","toast","Box","Typography","Chip","Button","TextField","Fragment","jsx","jsxs","useMemo","useState","useCallback","useEffect","toast","useRef","Box","Typography","Chip","TextField","Button","Fragment","jsx","jsxs","useState","useRef","useEffect","algoliasearch","useMemo","toast","jsxs","Box","jsx","Typography","IconButton","CloseIcon","Fragment","motion","Fragment","jsx","jsxs","useState","useRef","fetchAuthenticatedApps","useCallback","useEffect","useMemo","norm","useState","Box","Typography","IconButton","Drawer","Avatar","Tooltip","CloseIcon","motion","AnimatePresence","Box","Typography","Chip","jsx","jsxs","Box","Typography","Chip","Fragment","jsx","jsxs","useState","Drawer","Box","Typography","IconButton","CloseIcon","Tooltip","Avatar","AnimatePresence","motion","useEffect","useMemo","useState","useState","useEffect","algoliasearch","useMemo"]}
|