From 4d03c8b6ac2d59226c08700b3e60e4a63a4fbd96 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 26 May 2025 09:42:32 -0700 Subject: [PATCH] feat(search): added search to variables & credentials, fixed missing docs --- .github/workflows/ci.yml | 2 +- apps/docs/content/docs/tools/dropdown.mdx | 21 +-- apps/docs/content/docs/tools/file.mdx | 102 +++++++++++++ apps/docs/content/docs/tools/meta.json | 2 + .../content/docs/tools/microsoft_teams.mdx | 6 +- .../docs/content/docs/tools/mistral_parse.mdx | 137 +++++++++++++++++ apps/docs/content/docs/tools/outlook.mdx | 144 +++++++++++++----- .../components/credentials/credentials.tsx | 46 +++++- .../components/environment/environment.tsx | 73 +++++++-- .../settings-navigation.tsx | 4 +- apps/sim/blocks/blocks/file.ts | 2 +- apps/sim/components/icons.tsx | 22 +-- scripts/generate-block-docs.ts | 39 ++++- 13 files changed, 507 insertions(+), 93 deletions(-) create mode 100644 apps/docs/content/docs/tools/file.mdx create mode 100644 apps/docs/content/docs/tools/mistral_parse.mdx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6dcb58b2..d8e3706e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Bun - uses: oven-sh/setup-bun@main + uses: oven-sh/setup-bun@v2 with: bun-version: latest diff --git a/apps/docs/content/docs/tools/dropdown.mdx b/apps/docs/content/docs/tools/dropdown.mdx index edcfc321a..ccf80b081 100644 --- a/apps/docs/content/docs/tools/dropdown.mdx +++ b/apps/docs/content/docs/tools/dropdown.mdx @@ -33,21 +33,6 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" `} /> -{/* MANUAL-CONTENT-START:intro */} -The File Parser tool provides a powerful way to extract and process content from various file formats, making it easy to incorporate document data into your agent workflows. This tool supports multiple file formats and can handle files up to 200MB in size. - -With the File Parser, you can: - -- **Process multiple file formats**: Extract text from PDFs, CSVs, Word documents (DOCX), text files, and more -- **Handle large files**: Process documents up to 200MB in size -- **Parse files from URLs**: Directly extract content from files hosted online by providing their URLs -- **Process multiple files at once**: Upload and parse several files in a single operation -- **Extract structured data**: Maintain formatting and structure from the original documents when possible - -The File Parser tool is particularly useful for scenarios where your agents need to work with document content, such as analyzing reports, extracting data from spreadsheets, or processing text from various document sources. It simplifies the process of making document content available to your agents, allowing them to work with information stored in files just as easily as with direct text input. -{/* MANUAL-CONTENT-END */} - - ## Usage Instructions Upload and extract contents from structured file formats including PDFs, CSV spreadsheets, and Word documents (DOCX). ${ @@ -79,7 +64,11 @@ This tool does not produce any outputs. ## Block Configuration -No configuration parameters required. +### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `inputMethod` | string | No | | diff --git a/apps/docs/content/docs/tools/file.mdx b/apps/docs/content/docs/tools/file.mdx new file mode 100644 index 000000000..c43e51e1e --- /dev/null +++ b/apps/docs/content/docs/tools/file.mdx @@ -0,0 +1,102 @@ +--- +title: File +description: Read and parse multiple files +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + + + `} +/> + +{/* MANUAL-CONTENT-START:intro */} +The File Parser tool provides a powerful way to extract and process content from various file formats, making it easy to incorporate document data into your agent workflows. This tool supports multiple file formats and can handle files up to 200MB in size. + +With the File Parser, you can: + +- **Process multiple file formats**: Extract text from PDFs, CSVs, Word documents (DOCX), text files, and more +- **Handle large files**: Process documents up to 200MB in size +- **Parse files from URLs**: Directly extract content from files hosted online by providing their URLs +- **Process multiple files at once**: Upload and parse several files in a single operation +- **Extract structured data**: Maintain formatting and structure from the original documents when possible + +The File Parser tool is particularly useful for scenarios where your agents need to work with document content, such as analyzing reports, extracting data from spreadsheets, or processing text from various document sources. It simplifies the process of making document content available to your agents, allowing them to work with information stored in files just as easily as with direct text input. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Upload and extract contents from structured file formats including PDFs, CSV spreadsheets, and Word documents (DOCX). ${ + shouldEnableURLInput + ? 'You can either provide a URL to a file or upload files directly. ' + : 'Upload files directly. ' + }Specialized parsers extract text and metadata from each format. You can upload multiple files at once and access them individually or as a combined document. + + + +## Tools + +### `file_parser` + +Parse one or more uploaded files or files from URLs (text, PDF, CSV, images, etc.) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `filePath` | string | Yes | Path to the file\(s\). Can be a single path, URL, or an array of paths. | +| `fileType` | string | No | Type of file to parse \(auto-detected if not specified\) | + +#### Output + +This tool does not produce any outputs. + + + +## Block Configuration + +### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `inputMethod` | string | No | | + + + +### Outputs + +| Output | Type | Description | +| ------ | ---- | ----------- | +| `response` | object | Output from response | +| ↳ `files` | json | files of the response | +| ↳ `combinedContent` | string | combinedContent of the response | + + +## Notes + +- Category: `tools` +- Type: `file` diff --git a/apps/docs/content/docs/tools/meta.json b/apps/docs/content/docs/tools/meta.json index f849bd071..30754e6d9 100644 --- a/apps/docs/content/docs/tools/meta.json +++ b/apps/docs/content/docs/tools/meta.json @@ -10,6 +10,7 @@ "dropdown", "elevenlabs", "exa", + "file", "firecrawl", "github", "gmail", @@ -25,6 +26,7 @@ "mem0", "memory", "microsoft_teams", + "mistral_parse", "notion", "openai", "outlook", diff --git a/apps/docs/content/docs/tools/microsoft_teams.mdx b/apps/docs/content/docs/tools/microsoft_teams.mdx index 1e5e76316..d3b868f26 100644 --- a/apps/docs/content/docs/tools/microsoft_teams.mdx +++ b/apps/docs/content/docs/tools/microsoft_teams.mdx @@ -61,9 +61,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" y2='394.2607' gradientTransform='matrix(1 0 0 -1 0 2075.3333)' > - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + `} +/> + +{/* MANUAL-CONTENT-START:intro */} +The Mistral Parse tool provides a powerful way to extract and process content from PDF documents using [Mistral's OCR API](https://mistral.ai/). This tool leverages advanced optical character recognition to accurately extract text and structure from PDF files, making it easy to incorporate document data into your agent workflows. + +With the Mistral Parse tool, you can: + +- **Extract text from PDFs**: Accurately convert PDF content to text, markdown, or JSON formats +- **Process PDFs from URLs**: Directly extract content from PDFs hosted online by providing their URLs +- **Maintain document structure**: Preserve formatting, tables, and layout from the original PDFs +- **Extract images**: Optionally include embedded images from the PDFs +- **Select specific pages**: Process only the pages you need from multi-page documents + +The Mistral Parse tool is particularly useful for scenarios where your agents need to work with PDF content, such as analyzing reports, extracting data from forms, or processing text from scanned documents. It simplifies the process of making PDF content available to your agents, allowing them to work with information stored in PDFs just as easily as with direct text input. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Extract text and structure from PDF documents using Mistral's OCR API.${ + shouldEnableFileUpload + ? ' Either enter a URL to a PDF document or upload a PDF file directly.' + : ' Enter a URL to a PDF document (.pdf extension required).' + } Configure processing options and get the content in your preferred format. For URLs, they must be publicly accessible and point to a valid PDF file. Note: Google Drive, Dropbox, and other cloud storage links are not supported; use a direct download URL from a web server instead. + + + +## Tools + +### `mistral_parser` + +Parse PDF documents using Mistral OCR API + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `filePath` | string | Yes | URL to a PDF document to be processed | +| `fileUpload` | object | No | File upload data from file-upload component | +| `resultType` | string | No | Type of parsed result \(markdown, text, or json\). Defaults to markdown. | +| `apiKey` | string | Yes | Mistral API key \(MISTRAL_API_KEY\) | +| `includeImageBase64` | boolean | No | Include base64-encoded images in the response | +| `pages` | array | No | Specific pages to process \(array of page numbers, starting from 0\) | +| `imageLimit` | number | No | Maximum number of images to extract from the PDF | +| `imageMinSize` | number | No | Minimum height and width of images to extract from the PDF | + +#### Output + +This tool does not produce any outputs. + + + +## Block Configuration + +### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `inputMethod` | string | No | | + + + +### Outputs + +| Output | Type | Description | +| ------ | ---- | ----------- | +| `response` | object | Output from response | +| ↳ `content` | string | content of the response | +| ↳ `metadata` | json | metadata of the response | + + +## Notes + +- Category: `tools` +- Type: `mistral_parse` diff --git a/apps/docs/content/docs/tools/outlook.mdx b/apps/docs/content/docs/tools/outlook.mdx index fa7415c8a..adb05fc75 100644 --- a/apps/docs/content/docs/tools/outlook.mdx +++ b/apps/docs/content/docs/tools/outlook.mdx @@ -11,43 +11,113 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" icon={true} iconSvg={` + + + + + + + + + - - - - - - - - - - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + `} /> @@ -67,9 +137,10 @@ With Microsoft Outlook, you can: In Sim Studio, the Microsoft Outlook integration enables your agents to interact directly with email and calendar data programmatically. This allows for powerful automation scenarios such as sending custom email updates, parsing incoming messages for workflow triggers, creating calendar events, and managing task reminders. By connecting Sim Studio with Microsoft Outlook, you enable intelligent agents to automate communications, streamline scheduling, and maintain visibility into organizational correspondence — all within your workflow ecosystem. {/* MANUAL-CONTENT-END */} + ## Usage Instructions -Integrate Outlook functionality to read, draft, and send email messages within your workflow. Automate email communications and process email content using OAuth authentication. +Integrate Outlook functionality to read, draft, andsend email messages within your workflow. Automate email communications and process email content using OAuth authentication. @@ -130,14 +201,13 @@ Read emails from Outlook | `accessToken` | string | Yes | OAuth access token for Outlook | | `folder` | string | No | Folder ID to read emails from \(default: Inbox\) | | `maxResults` | number | No | Maximum number of emails to retrieve \(default: 1, max: 10\) | -| `messageId` | string | No | Message ID to read | #### Output | Parameter | Type | | --------- | ---- | | `message` | string | -| `results` | json | +| `results` | string | diff --git a/apps/sim/app/w/components/sidebar/components/settings-modal/components/credentials/credentials.tsx b/apps/sim/app/w/components/sidebar/components/settings-modal/components/credentials/credentials.tsx index 24f0cd1f4..dab2d04b6 100644 --- a/apps/sim/app/w/components/sidebar/components/settings-modal/components/credentials/credentials.tsx +++ b/apps/sim/app/w/components/sidebar/components/settings-modal/components/credentials/credentials.tsx @@ -1,10 +1,11 @@ 'use client' import { useEffect, useRef, useState } from 'react' -import { Check, ChevronDown, ExternalLink, RefreshCw } from 'lucide-react' +import { Check, ChevronDown, ExternalLink, RefreshCw, Search } from 'lucide-react' import { useRouter, useSearchParams } from 'next/navigation' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' +import { Input } from '@/components/ui/input' import { Skeleton } from '@/components/ui/skeleton' import { client, useSession } from '@/lib/auth-client' import { createLogger } from '@/lib/logs/console-logger' @@ -32,6 +33,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) { const pendingServiceRef = useRef(null) const [services, setServices] = useState([]) + const [searchTerm, setSearchTerm] = useState('') const [isLoading, setIsLoading] = useState(true) const [isConnecting, setIsConnecting] = useState(null) const [pendingService, setPendingService] = useState(null) @@ -292,6 +294,24 @@ export function Credentials({ onOpenChange }: CredentialsProps) { {} as Record ) + // Filter services based on search term + const filteredGroupedServices = Object.entries(groupedServices).reduce( + (acc, [providerKey, providerServices]) => { + const filteredServices = providerServices.filter( + (service) => + service.name.toLowerCase().includes(searchTerm.toLowerCase()) || + service.description.toLowerCase().includes(searchTerm.toLowerCase()) + ) + + if (filteredServices.length > 0) { + acc[providerKey] = filteredServices + } + + return acc + }, + {} as Record + ) + const scrollToHighlightedService = () => { if (pendingServiceRef.current) { pendingServiceRef.current.scrollIntoView({ @@ -304,7 +324,20 @@ export function Credentials({ onOpenChange }: CredentialsProps) { return (
-

Credentials

+
+

Credentials

+ + {/* Search Input */} +
+ + setSearchTerm(e.target.value)} + className='h-9 pl-9 text-sm' + /> +
+

Connect your accounts to use tools that require authentication.

@@ -359,7 +392,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) { ) : (
{/* Group services by provider */} - {Object.entries(groupedServices).map(([providerKey, providerServices]) => ( + {Object.entries(filteredGroupedServices).map(([providerKey, providerServices]) => (

{OAUTH_PROVIDERS[providerKey]?.name || 'Other Services'} @@ -466,6 +499,13 @@ export function Credentials({ onOpenChange }: CredentialsProps) {

))} + + {/* Show message when search has no results */} + {searchTerm.trim() && Object.keys(filteredGroupedServices).length === 0 && ( +
+ No services found matching "{searchTerm}" +
+ )}
)}
diff --git a/apps/sim/app/w/components/sidebar/components/settings-modal/components/environment/environment.tsx b/apps/sim/app/w/components/sidebar/components/settings-modal/components/environment/environment.tsx index 004465c9e..872fd8fe8 100644 --- a/apps/sim/app/w/components/sidebar/components/settings-modal/components/environment/environment.tsx +++ b/apps/sim/app/w/components/sidebar/components/settings-modal/components/environment/environment.tsx @@ -1,6 +1,7 @@ 'use client' import { useEffect, useMemo, useRef, useState } from 'react' +import { Search } from 'lucide-react' import { AlertDialog, AlertDialogAction, @@ -30,19 +31,28 @@ interface EnvironmentVariablesProps { } export function EnvironmentVariables({ onOpenChange }: EnvironmentVariablesProps) { - // Store access const { variables } = useEnvironmentStore() - // State const [envVars, setEnvVars] = useState([]) + const [searchTerm, setSearchTerm] = useState('') const [focusedValueIndex, setFocusedValueIndex] = useState(null) const [showUnsavedChanges, setShowUnsavedChanges] = useState(false) - // Refs const scrollContainerRef = useRef(null) const pendingClose = useRef(false) const initialVarsRef = useRef([]) + // Filter environment variables based on search term + const filteredEnvVars = useMemo(() => { + if (!searchTerm.trim()) { + return envVars.map((envVar, index) => ({ envVar, originalIndex: index })) + } + + return envVars + .map((envVar, index) => ({ envVar, originalIndex: index })) + .filter(({ envVar }) => envVar.key.toLowerCase().includes(searchTerm.toLowerCase())) + }, [envVars, searchTerm]) + // Derived state const hasChanges = useMemo(() => { const initialVars = initialVarsRef.current.filter((v) => v.key || v.value) @@ -88,6 +98,8 @@ export function EnvironmentVariables({ onOpenChange }: EnvironmentVariablesProps const addEnvVar = () => { const newVar = { key: '', value: '', id: Date.now() } setEnvVars([...envVars, newVar]) + // Clear search to ensure the new variable is visible + setSearchTerm('') } const updateEnvVar = (index: number, field: 'key' | 'value', value: string) => { @@ -202,38 +214,43 @@ export function EnvironmentVariables({ onOpenChange }: EnvironmentVariablesProps } // UI rendering - const renderEnvVarRow = (envVar: UIEnvironmentVariable, index: number) => ( -
+ const renderEnvVarRow = (envVar: UIEnvironmentVariable, originalIndex: number) => ( +
updateEnvVar(index, 'key', e.target.value)} - onPaste={(e) => handlePaste(e, index)} + onChange={(e) => updateEnvVar(originalIndex, 'key', e.target.value)} + onPaste={(e) => handlePaste(e, originalIndex)} placeholder='API_KEY' autoComplete='off' autoCorrect='off' autoCapitalize='off' spellCheck='false' - name={`env-var-key-${envVar.id || index}-${Math.random()}`} + name={`env-var-key-${envVar.id || originalIndex}-${Math.random()}`} /> updateEnvVar(index, 'value', e.target.value)} - type={focusedValueIndex === index ? 'text' : 'password'} - onFocus={(e) => handleValueFocus(index, e)} + onChange={(e) => updateEnvVar(originalIndex, 'value', e.target.value)} + type={focusedValueIndex === originalIndex ? 'text' : 'password'} + onFocus={(e) => handleValueFocus(originalIndex, e)} onClick={handleValueClick} onBlur={() => setFocusedValueIndex(null)} - onPaste={(e) => handlePaste(e, index)} + onPaste={(e) => handlePaste(e, originalIndex)} placeholder='Enter value' className='allow-scroll' autoComplete='off' autoCorrect='off' autoCapitalize='off' spellCheck='false' - name={`env-var-value-${envVar.id || index}-${Math.random()}`} + name={`env-var-value-${envVar.id || originalIndex}-${Math.random()}`} /> -
@@ -243,7 +260,21 @@ export function EnvironmentVariables({ onOpenChange }: EnvironmentVariablesProps
{/* Fixed Header */}
-

Environment Variables

+
+

Environment Variables

+ + {/* Search Input */} +
+ + setSearchTerm(e.target.value)} + className='h-9 pl-9 text-sm' + /> +
+
+
@@ -256,7 +287,17 @@ export function EnvironmentVariables({ onOpenChange }: EnvironmentVariablesProps ref={scrollContainerRef} className='scrollbar-thin scrollbar-thumb-muted-foreground/20 hover:scrollbar-thumb-muted-foreground/25 scrollbar-track-transparent min-h-0 flex-1 overflow-y-auto px-6' > -
{envVars.map(renderEnvVarRow)}
+
+ {filteredEnvVars.map(({ envVar, originalIndex }) => + renderEnvVarRow(envVar, originalIndex) + )} + {/* Show message when search has no results but there are variables */} + {searchTerm.trim() && filteredEnvVars.length === 0 && envVars.length > 0 && ( +
+ No environment variables found matching "{searchTerm}" +
+ )} +
{/* Fixed Footer */} diff --git a/apps/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx b/apps/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx index d20d0481f..50441d472 100644 --- a/apps/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx +++ b/apps/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx @@ -1,8 +1,8 @@ import { CreditCard, - Key, KeyRound, KeySquare, + Lock, Settings, Shield, UserCircle, @@ -63,7 +63,7 @@ const allNavigationItems: NavigationItem[] = [ { id: 'credentials', label: 'Credentials', - icon: Key, + icon: Lock, }, { id: 'apikeys', diff --git a/apps/sim/blocks/blocks/file.ts b/apps/sim/blocks/blocks/file.ts index 72f903d02..97d10b8ac 100644 --- a/apps/sim/blocks/blocks/file.ts +++ b/apps/sim/blocks/blocks/file.ts @@ -37,7 +37,7 @@ export const FileBlock: BlockConfig = { ? 'You can either provide a URL to a file or upload files directly. ' : 'Upload files directly. ' }Specialized parsers extract text and metadata from each format. You can upload multiple files at once and access them individually or as a combined document.`, - docsLink: 'https://docs.simstudio.ai/tools/dropdown', + docsLink: 'https://docs.simstudio.ai/tools/file', category: 'tools', bgColor: '#40916C', icon: DocumentIcon, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 66f456898..d7e2f3f22 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -2541,9 +2541,9 @@ export function MicrosoftTeamsIcon(props: SVGProps) { y2='394.2607' gradientTransform='matrix(1 0 0 -1 0 2075.3333)' > - - - + + + ) { x='0px' y='0px' viewBox='0 0 1831.085 1703.335' - enable-background='new 0 0 1831.085 1703.335' + enableBackground='new 0 0 1831.085 1703.335' > ) { ) { /> ) { /> 0) { + if (afterExport[blockEnd] === '{') braceCount++ + else if (afterExport[blockEnd] === '}') braceCount-- + blockEnd++ + } + + // Extract the block content and look for type + const blockContent = afterExport.substring(blockStart, blockEnd) + const typeMatch = blockContent.match(/type\s*:\s*['"]([^'"]+)['"]/) + if (typeMatch) return typeMatch[1] + } + } // Convert CamelCase to snake_case as fallback return blockName