From 9a4a8d20b6d1237f6938f73fd2ae04a99b0a5daa Mon Sep 17 00:00:00 2001 From: centdix Date: Fri, 27 Mar 2026 12:28:59 +0100 Subject: [PATCH] feat: support multiple folder selection in MCP scope selector Co-Authored-By: Claude Opus 4.6 (1M context) --- .../components/mcp/McpScopeSelector.svelte | 84 +++++++++++++++---- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/frontend/src/lib/components/mcp/McpScopeSelector.svelte b/frontend/src/lib/components/mcp/McpScopeSelector.svelte index 9fe525dd5c..44bc85cf3b 100644 --- a/frontend/src/lib/components/mcp/McpScopeSelector.svelte +++ b/frontend/src/lib/components/mcp/McpScopeSelector.svelte @@ -5,9 +5,9 @@ import Popover from '$lib/components/Popover.svelte' import MultiSelect from '$lib/components/select/MultiSelect.svelte' import { safeSelectItems } from '$lib/components/select/utils.svelte' - import FolderPicker from '$lib/components/FolderPicker.svelte' import TextInput from '$lib/components/text_input/TextInput.svelte' - import { FlowService, IntegrationService, ScriptService } from '$lib/gen' + import { FlowService, FolderService, IntegrationService, ScriptService } from '$lib/gen' + import { workspaceStore } from '$lib/stores' import { mcpEndpointTools } from '$lib/mcpEndpointTools' import InfoIcon from 'lucide-svelte/icons/info' import { SvelteMap } from 'svelte/reactivity' @@ -20,7 +20,9 @@ let { workspaceId, scope = $bindable() }: Props = $props() let selectedMode = $state<'favorites' | 'all' | 'folder' | 'custom'>('favorites') - let selectedFolder = $state('') + let selectedFolders = $state([]) + let allFolders = $state([]) + let loadingFolders = $state(false) let selectedScripts = $state([]) let selectedFlows = $state([]) let selectedEndpoints = $state([]) @@ -70,8 +72,10 @@ scopeParts.push(`mcp:endpoints:${selectedEndpoints.join(',')}`) } } else if (selectedMode === 'folder') { - const folderPath = `f/${selectedFolder}/*` - scopeParts = [`mcp:scripts:${folderPath}`, `mcp:flows:${folderPath}`, `mcp:endpoints:*`] + const folderPaths = selectedFolders.map((f) => `f/${f}/*`).join(',') + if (folderPaths.length > 0) { + scopeParts = [`mcp:scripts:${folderPaths}`, `mcp:flows:${folderPaths}`, `mcp:endpoints:*`] + } } else { scopeParts = [`mcp:${selectedMode}`] } @@ -91,13 +95,32 @@ } }) - // Clear folder when not in folder mode + // Clear folders when not in folder mode, load folder names when entering folder mode $effect(() => { - if (selectedMode !== 'folder') { - selectedFolder = '' + if (selectedMode === 'folder') { + loadFolderNames() + } else { + selectedFolders = [] } }) + async function loadFolderNames() { + if (allFolders.length > 0) return + try { + loadingFolders = true + const excludedFolders = ['app_groups', 'app_custom', 'app_themes'] + allFolders = ( + await FolderService.listFolderNames({ + workspace: $workspaceStore! + }) + ).filter((x) => !excludedFolders.includes(x)) + } catch { + allFolders = [] + } finally { + loadingFolders = false + } + } + // Load hub apps on mount async function getAllApps() { if (allApps.length > 0) return @@ -192,11 +215,32 @@ // Load runnables based on mode $effect(() => { if (workspaceId) { - const folderParam = selectedFolder.length > 0 ? selectedFolder : undefined - getScriptsAndFlows(selectedMode === 'favorites', workspaceId, folderParam) + if (selectedMode === 'folder' && selectedFolders.length > 0) { + loadRunnablesForFolders(workspaceId, selectedFolders) + } else { + getScriptsAndFlows(selectedMode === 'favorites', workspaceId, undefined) + } } }) + async function loadRunnablesForFolders(workspace: string, folders: string[]) { + try { + loadingRunnables = true + const results = await Promise.all( + folders.map(async (folder) => { + const [scripts, flows] = await Promise.all([ + getScripts(false, workspace, folder), + getFlows(false, workspace, folder) + ]) + return [...scripts, ...flows] + }) + ) + includedRunnables = [...new Set(results.flat())] + } finally { + loadingRunnables = false + } + } + // Load all scripts/flows for custom mode $effect(() => { if (selectedMode === 'custom' && workspaceId) { @@ -209,7 +253,7 @@ ? 'Create your first scripts or flows to make them available via MCP.' : selectedMode === 'favorites' ? `You do not have any favorite scripts or flows. You can favorite some scripts and flows to include them, or change the scope to "All scripts/flows" to include all your scripts and flows.` - : `You do not have any scripts or flows in the selected folder.` + : `You do not have any scripts or flows in the selected folder(s).` ) function selectAllScripts() { @@ -252,8 +296,8 @@ - Select Folder - + Select Folders + {#if loadingFolders} +
Loading folders...
+ {:else} + + {/if} {/if} @@ -389,7 +441,7 @@ {/if} - {:else if selectedMode !== 'folder' || selectedFolder.length > 0} + {:else if selectedMode !== 'folder' || selectedFolders.length > 0} {#if loadingRunnables}