diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 0de540e9e9f..dd5ab47b8cb 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -263,7 +263,6 @@ export const blockTypeToIconMap: Record = { extend_v2: ExtendIcon, fathom: FathomIcon, file: DocumentIcon, - file_v3: DocumentIcon, file_v4: DocumentIcon, findymail: FindymailIcon, firecrawl: FirecrawlIcon, diff --git a/apps/docs/content/docs/de/tools/file.mdx b/apps/docs/content/docs/de/tools/file.mdx index 2844895777e..54858d4b528 100644 --- a/apps/docs/content/docs/de/tools/file.mdx +++ b/apps/docs/content/docs/de/tools/file.mdx @@ -6,7 +6,7 @@ description: Mehrere Dateien lesen und parsen import { BlockInfoCard } from "@/components/ui/block-info-card" diff --git a/apps/docs/content/docs/en/tools/prospeo.mdx b/apps/docs/content/docs/en/tools/prospeo.mdx index 2072046a4a3..9e40823dfd9 100644 --- a/apps/docs/content/docs/en/tools/prospeo.mdx +++ b/apps/docs/content/docs/en/tools/prospeo.mdx @@ -229,9 +229,9 @@ Free endpoint to retrieve valid location or job title values for use in Search f | Parameter | Type | Description | | --------- | ---- | ----------- | -| `location_suggestions` | array | Location suggestions when using location_search \(null when searching job titles\) | +| `location_suggestions` | array | Location suggestions when using location_search \(empty when searching job titles\) | | ↳ `name` | string | Formatted location name to use in filters | | ↳ `type` | string | Location type \(COUNTRY, STATE, CITY, or ZONE\) | -| `job_title_suggestions` | array | Up to 25 job title suggestions ordered by popularity when using job_title_search \(null when searching locations\) | +| `job_title_suggestions` | array | Up to 25 job title suggestions ordered by popularity when using job_title_search \(empty when searching locations\) | diff --git a/apps/docs/content/docs/es/tools/file.mdx b/apps/docs/content/docs/es/tools/file.mdx index 852c5f6202e..f38e03ee15b 100644 --- a/apps/docs/content/docs/es/tools/file.mdx +++ b/apps/docs/content/docs/es/tools/file.mdx @@ -6,7 +6,7 @@ description: Leer y analizar múltiples archivos import { BlockInfoCard } from "@/components/ui/block-info-card" diff --git a/apps/docs/content/docs/fr/tools/file.mdx b/apps/docs/content/docs/fr/tools/file.mdx index b57c4e1a19a..32ac4fe9150 100644 --- a/apps/docs/content/docs/fr/tools/file.mdx +++ b/apps/docs/content/docs/fr/tools/file.mdx @@ -6,7 +6,7 @@ description: Lire et analyser plusieurs fichiers import { BlockInfoCard } from "@/components/ui/block-info-card" diff --git a/apps/docs/content/docs/ja/tools/file.mdx b/apps/docs/content/docs/ja/tools/file.mdx index 2dcf9d02580..a08d976cf77 100644 --- a/apps/docs/content/docs/ja/tools/file.mdx +++ b/apps/docs/content/docs/ja/tools/file.mdx @@ -6,7 +6,7 @@ description: 複数のファイルを読み込んで解析する import { BlockInfoCard } from "@/components/ui/block-info-card" diff --git a/apps/docs/content/docs/zh/tools/file.mdx b/apps/docs/content/docs/zh/tools/file.mdx index 2f923430ce4..a347387f19a 100644 --- a/apps/docs/content/docs/zh/tools/file.mdx +++ b/apps/docs/content/docs/zh/tools/file.mdx @@ -6,7 +6,7 @@ description: 读取并解析多个文件 import { BlockInfoCard } from "@/components/ui/block-info-card" diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css index 1608115e584..15fb1c30cf3 100644 --- a/apps/sim/app/_styles/globals.css +++ b/apps/sim/app/_styles/globals.css @@ -878,22 +878,22 @@ input[type="search"]::-ms-clear { @keyframes toast-enter { from { opacity: 0; - transform: translateY(8px) scale(0.97); + transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); } to { opacity: 1; - transform: translateY(0) scale(1); + transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); } } @keyframes toast-exit { from { opacity: 1; - transform: translateY(0) scale(1); + transform: translateX(var(--stack-offset, 0px)) translateY(0) scale(1); } to { opacity: 0; - transform: translateY(8px) scale(0.97); + transform: translateX(var(--stack-offset, 0px)) translateY(8px) scale(0.97); } } diff --git a/apps/sim/app/workspace/[workspaceId]/components/index.ts b/apps/sim/app/workspace/[workspaceId]/components/index.ts index 66ba3cfdecf..bc76e7d77ad 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/index.ts +++ b/apps/sim/app/workspace/[workspaceId]/components/index.ts @@ -25,4 +25,4 @@ export type { RowDragDropConfig, SelectableConfig, } from './resource/resource' -export { Resource, ResourceTable } from './resource/resource' +export { EMPTY_CELL_PLACEHOLDER, Resource, ResourceTable } from './resource/resource' diff --git a/apps/sim/app/workspace/[workspaceId]/components/resource/resource.tsx b/apps/sim/app/workspace/[workspaceId]/components/resource/resource.tsx index b0a149b5f1e..d2490ec46f6 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/resource/resource.tsx +++ b/apps/sim/app/workspace/[workspaceId]/components/resource/resource.tsx @@ -23,8 +23,6 @@ export interface ResourceColumn { id: string header: string widthMultiplier?: number - /** Fixed pixel width. When set, the column is excluded from proportional sizing. */ - widthPx?: number } export interface ResourceCell { @@ -94,7 +92,7 @@ interface ResourceProps { overlay?: ReactNode } -const EMPTY_CELL_PLACEHOLDER = '- - -' +export const EMPTY_CELL_PLACEHOLDER = '—' const SKELETON_ROW_COUNT = 5 /** @@ -214,7 +212,6 @@ export const ResourceTable = memo(function ResourceTable({ emptyMessage, overlay, }: ResourceTableProps) { - const headerRef = useRef(null) const loadMoreRef = useRef(null) const sortEnabled = defaultSort != null const [internalSort, setInternalSort] = useState<{ column: string; direction: 'asc' | 'desc' }>({ @@ -222,12 +219,6 @@ export const ResourceTable = memo(function ResourceTable({ direction: 'desc', }) - const handleBodyScroll = useCallback((e: React.UIEvent) => { - if (headerRef.current) { - headerRef.current.scrollLeft = e.currentTarget.scrollLeft - } - }, []) - const handleSort = useCallback((column: string, direction: 'asc' | 'desc') => { setInternalSort({ column, direction }) }, []) @@ -290,10 +281,10 @@ export const ResourceTable = memo(function ResourceTable({ return (
-
+
- + {hasCheckbox && ( -
@@ -341,14 +332,6 @@ export const ResourceTable = memo(function ResourceTable({ })}
-
-
- - {displayRows.map((row) => ( sum + (col.widthPx ?? 0), 0) - const flexibleWeights = columns.map((col, colIdx) => - col.widthPx ? 0 : (colIdx === 0 ? 2.5 : 1.0) * (col.widthMultiplier ?? 1) + const weights = columns.map( + (col, colIdx) => (colIdx === 0 ? 2.5 : 1.0) * (col.widthMultiplier ?? 1) ) - const flexibleTotal = flexibleWeights.reduce((s, w) => s + w, 0) - const reservedPx = fixedPxTotal + (hasCheckbox ? CHECKBOX_COLUMN_WIDTH_PX : 0) - + const total = weights.reduce((s, w) => s + w, 0) return ( {hasCheckbox && } - {columns.map((col, colIdx) => { - if (col.widthPx) { - return - } - const columnRatio = flexibleTotal > 0 ? flexibleWeights[colIdx] / flexibleTotal : 0 - const columnPercent = columnRatio * 100 - const reservedOffset = reservedPx * columnRatio - - return ( - 0 - ? `calc(${columnPercent}% - ${reservedOffset}px)` - : `${columnPercent}%`, - }} - /> - ) - })} + {columns.map((col, colIdx) => ( + + ))} ) }) @@ -697,55 +659,48 @@ const DataTableSkeleton = memo(function DataTableSkeleton({ hasCheckbox, }: DataTableSkeletonProps) { return ( - <> -
-
- - - +
+
+ + + + {hasCheckbox && ( + + )} + {columns.map((col) => ( + + ))} + + + + {Array.from({ length: rowCount }, (_, i) => ( + {hasCheckbox && ( - )} - {columns.map((col) => ( - + {columns.map((col, colIdx) => ( + ))} - -
+ + +
+ +
+
+ - + -
- -
-
+ + {colIdx === 0 && } + + +
-
-
- - - - {Array.from({ length: rowCount }, (_, i) => ( - - {hasCheckbox && ( - - )} - {columns.map((col, colIdx) => ( - - ))} - - ))} - -
- - - - {colIdx === 0 && } - - -
-
- + ))} + + +
) }) diff --git a/apps/sim/app/workspace/[workspaceId]/files/files.tsx b/apps/sim/app/workspace/[workspaceId]/files/files.tsx index 6cf3f4f7285..1e715a8a373 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/files.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/files.tsx @@ -56,6 +56,7 @@ import type { SortConfig, } from '@/app/workspace/[workspaceId]/components' import { + EMPTY_CELL_PLACEHOLDER, InlineRenameInput, ownerCell, Resource, @@ -112,12 +113,12 @@ const SUPPORTED_EXTENSIONS = [ const ACCEPT_ATTR = SUPPORTED_EXTENSIONS.map((ext) => `.${ext}`).join(',') const COLUMNS: ResourceColumn[] = [ - { id: 'name', header: 'Name' }, - { id: 'size', header: 'Size', widthPx: 110 }, - { id: 'type', header: 'Type', widthPx: 120 }, - { id: 'created', header: 'Created', widthPx: 150 }, - { id: 'owner', header: 'Owner', widthPx: 160 }, - { id: 'updated', header: 'Last Updated', widthPx: 150 }, + { id: 'name', header: 'Name', widthMultiplier: 1.15 }, + { id: 'size', header: 'Size', widthMultiplier: 0.85 }, + { id: 'type', header: 'Type', widthMultiplier: 1.0 }, + { id: 'created', header: 'Created' }, + { id: 'owner', header: 'Owner' }, + { id: 'updated', header: 'Last Updated' }, ] const MIME_TYPE_LABELS: Record = { @@ -301,6 +302,26 @@ export function Files() { const folderById = useMemo(() => new Map(folders.map((folder) => [folder.id, folder])), [folders]) const currentFolder = currentFolderId ? (folderById.get(currentFolderId) ?? null) : null + + const folderSizeMap = useMemo(() => { + const directSize = new Map() + for (const file of files) { + if (file.folderId) { + directSize.set(file.folderId, (directSize.get(file.folderId) ?? 0) + file.size) + } + } + const totalSize = new Map() + const getTotal = (folderId: string): number => { + if (totalSize.has(folderId)) return totalSize.get(folderId)! + const children = folders.filter((f) => f.parentId === folderId) + const size = + (directSize.get(folderId) ?? 0) + children.reduce((s, c) => s + getTotal(c.id), 0) + totalSize.set(folderId, size) + return size + } + for (const folder of folders) getTotal(folder.id) + return totalSize + }, [files, folders]) const currentFolderPath = currentFolder?.path ?? null const visibleFolders = useMemo(() => { @@ -406,7 +427,12 @@ export function Files() { icon: , label: folder.name, }, - size: { label: 'Folder' }, + size: { + label: + (folderSizeMap.get(folder.id) ?? 0) > 0 + ? formatFileSize(folderSizeMap.get(folder.id)!, { includeBytes: true }) + : EMPTY_CELL_PLACEHOLDER, + }, type: { icon: , label: 'Folder', @@ -417,7 +443,7 @@ export function Files() { }, sortValues: { name: folder.name, - size: -1, + size: folderSizeMap.get(folder.id) ?? -1, type: 'Folder', created: new Date(folder.createdAt).getTime(), updated: new Date(folder.updatedAt).getTime(), @@ -458,7 +484,7 @@ export function Files() { }) return [...folderRows, ...fileRows] - }, [visibleFolders, filteredFiles, members]) + }, [visibleFolders, filteredFiles, members, folderSizeMap]) const rows: ResourceRow[] = useMemo(() => { if (!listRename.editingId) return baseRows @@ -1644,9 +1670,7 @@ export function Files() { ? `No files match "${debouncedSearchTerm}"` : hasActiveFilters ? 'No files match the active filters' - : currentFolderId - ? 'This folder is empty' - : 'No files yet' + : undefined const filterContent = useMemo(() => { const typeDisplayLabel = diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx index 59dee5bbd92..d6aede43d85 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx @@ -30,7 +30,11 @@ import type { SelectableConfig, SortConfig, } from '@/app/workspace/[workspaceId]/components' -import { Resource, ResourceHeader } from '@/app/workspace/[workspaceId]/components' +import { + EMPTY_CELL_PLACEHOLDER, + Resource, + ResourceHeader, +} from '@/app/workspace/[workspaceId]/components' import { ChunkContextMenu, ChunkEditor, @@ -127,9 +131,9 @@ function truncateContent(content: string, maxLength = 150, searchQuery = ''): st const CHUNK_COLUMNS: ResourceColumn[] = [ { id: 'content', header: 'Content' }, - { id: 'index', header: 'Index', widthPx: 100 }, - { id: 'tokens', header: 'Tokens', widthPx: 100 }, - { id: 'status', header: 'Status', widthPx: 120 }, + { id: 'index', header: 'Index', widthMultiplier: 0.6 }, + { id: 'tokens', header: 'Tokens', widthMultiplier: 0.6 }, + { id: 'status', header: 'Status', widthMultiplier: 0.75 }, ] export function Document({ @@ -874,9 +878,9 @@ export function Document({
), }, - index: { label: '—' }, - tokens: { label: '—' }, - status: { label: '—' }, + index: { label: EMPTY_CELL_PLACEHOLDER }, + tokens: { label: EMPTY_CELL_PLACEHOLDER }, + status: { label: EMPTY_CELL_PLACEHOLDER }, }, }, ] diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx index 26489ab687d..65f71d7f516 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx @@ -85,13 +85,13 @@ const logger = createLogger('KnowledgeBase') const DOCUMENTS_PER_PAGE = 50 const DOCUMENT_COLUMNS: ResourceColumn[] = [ - { id: 'name', header: 'Name' }, - { id: 'size', header: 'Size', widthPx: 90 }, - { id: 'tokens', header: 'Tokens', widthPx: 90 }, - { id: 'chunks', header: 'Chunks', widthPx: 90 }, - { id: 'uploaded', header: 'Uploaded', widthPx: 140 }, - { id: 'status', header: 'Status', widthPx: 110 }, - { id: 'tags', header: 'Tags', widthPx: 160 }, + { id: 'name', header: 'Name', widthMultiplier: 0.8 }, + { id: 'size', header: 'Size', widthMultiplier: 0.75 }, + { id: 'tokens', header: 'Tokens', widthMultiplier: 0.75 }, + { id: 'chunks', header: 'Chunks', widthMultiplier: 0.75 }, + { id: 'uploaded', header: 'Uploaded' }, + { id: 'status', header: 'Status', widthMultiplier: 0.75 }, + { id: 'tags', header: 'Tags' }, ] interface KnowledgeBaseProps { diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx index 32e4d9e7451..d5a4bc18009 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx @@ -16,7 +16,12 @@ import type { SearchConfig, SortConfig, } from '@/app/workspace/[workspaceId]/components' -import { ownerCell, Resource, timeCell } from '@/app/workspace/[workspaceId]/components' +import { + EMPTY_CELL_PLACEHOLDER, + ownerCell, + Resource, + timeCell, +} from '@/app/workspace/[workspaceId]/components' import { BaseTagsModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/components' import { CreateBaseModal, @@ -43,19 +48,19 @@ interface KnowledgeBaseWithDocCount extends KnowledgeBaseData { const COLUMNS: ResourceColumn[] = [ { id: 'name', header: 'Name' }, - { id: 'documents', header: 'Documents', widthPx: 110 }, - { id: 'tokens', header: 'Tokens', widthPx: 90 }, - { id: 'connectors', header: 'Connectors', widthPx: 130 }, - { id: 'created', header: 'Created', widthPx: 140 }, - { id: 'owner', header: 'Owner', widthPx: 150 }, - { id: 'updated', header: 'Last Updated', widthPx: 140 }, + { id: 'documents', header: 'Documents', widthMultiplier: 0.6 }, + { id: 'tokens', header: 'Tokens', widthMultiplier: 0.6 }, + { id: 'connectors', header: 'Connectors', widthMultiplier: 0.7 }, + { id: 'created', header: 'Created' }, + { id: 'owner', header: 'Owner' }, + { id: 'updated', header: 'Last Updated' }, ] const DATABASE_ICON = function connectorCell(connectorTypes?: string[]): ResourceCell { if (!connectorTypes || connectorTypes.length === 0) { - return { label: '—' } + return { label: EMPTY_CELL_PLACEHOLDER } } const entries = connectorTypes @@ -64,7 +69,7 @@ function connectorCell(connectorTypes?: string[]): ResourceCell { Boolean(e.def?.icon) ) - if (entries.length === 0) return { label: '—' } + if (entries.length === 0) return { label: EMPTY_CELL_PLACEHOLDER } return { content: ( diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index 20413838aec..7ddf9eec8f2 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -106,11 +106,11 @@ const REFRESH_SPINNER_DURATION_MS = 1000 as const const LOG_COLUMNS: ResourceColumn[] = [ { id: 'workflow', header: 'Workflow' }, - { id: 'date', header: 'Date', widthPx: 160 }, - { id: 'status', header: 'Status', widthPx: 120 }, - { id: 'cost', header: 'Cost', widthPx: 100 }, - { id: 'trigger', header: 'Trigger', widthPx: 140 }, - { id: 'duration', header: 'Duration', widthPx: 110 }, + { id: 'date', header: 'Date' }, + { id: 'status', header: 'Status' }, + { id: 'cost', header: 'Cost' }, + { id: 'trigger', header: 'Trigger' }, + { id: 'duration', header: 'Duration' }, ] interface LogSelectionState { diff --git a/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/scheduled-tasks.tsx b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/scheduled-tasks.tsx index 06182ff41d5..f74b92e3152 100644 --- a/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/scheduled-tasks.tsx +++ b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/scheduled-tasks.tsx @@ -22,7 +22,11 @@ import type { ResourceRow, SortConfig, } from '@/app/workspace/[workspaceId]/components' -import { Resource, timeCell } from '@/app/workspace/[workspaceId]/components' +import { + EMPTY_CELL_PLACEHOLDER, + Resource, + timeCell, +} from '@/app/workspace/[workspaceId]/components' import { ScheduleModal } from '@/app/workspace/[workspaceId]/scheduled-tasks/components/create-schedule-modal' import { ScheduleContextMenu } from '@/app/workspace/[workspaceId]/scheduled-tasks/components/schedule-context-menu' import { ScheduleListContextMenu } from '@/app/workspace/[workspaceId]/scheduled-tasks/components/schedule-list-context-menu' @@ -44,14 +48,14 @@ function getScheduleDescription(s: WorkspaceScheduleData) { const timing = parseCronToHumanReadable(s.cronExpression, s.timezone) return `Recurring, ${timing.charAt(0).toLowerCase()}${timing.slice(1)}` } - return '- - -' + return EMPTY_CELL_PLACEHOLDER } const COLUMNS: ResourceColumn[] = [ { id: 'task', header: 'Task' }, - { id: 'schedule', header: 'Schedule', widthMultiplier: 1.5 }, - { id: 'nextRun', header: 'Next Run', widthPx: 160 }, - { id: 'lastRun', header: 'Last Run', widthPx: 160 }, + { id: 'schedule', header: 'Schedule' }, + { id: 'nextRun', header: 'Next Run' }, + { id: 'lastRun', header: 'Last Run' }, ] export function ScheduledTasks() { diff --git a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx index 6bd2a04d796..5cf881a2f4b 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx @@ -49,11 +49,11 @@ const logger = createLogger('Tables') const COLUMNS: ResourceColumn[] = [ { id: 'name', header: 'Name' }, - { id: 'columns', header: 'Columns', widthPx: 110 }, - { id: 'rows', header: 'Rows', widthPx: 100 }, - { id: 'created', header: 'Created', widthPx: 150 }, - { id: 'owner', header: 'Owner', widthPx: 160 }, - { id: 'updated', header: 'Last Updated', widthPx: 150 }, + { id: 'columns', header: 'Columns' }, + { id: 'rows', header: 'Rows' }, + { id: 'created', header: 'Created' }, + { id: 'owner', header: 'Owner' }, + { id: 'updated', header: 'Last Updated' }, ] export function Tables() { diff --git a/apps/sim/blocks/blocks/findymail.ts b/apps/sim/blocks/blocks/findymail.ts index d5f11bc7431..4f8bea4911d 100644 --- a/apps/sim/blocks/blocks/findymail.ts +++ b/apps/sim/blocks/blocks/findymail.ts @@ -37,7 +37,7 @@ export const FindymailBlock: BlockConfig = { }, // Find Email From Name { - id: 'name', + id: 'fn_name', title: 'Full Name', type: 'short-input', required: true, @@ -45,7 +45,7 @@ export const FindymailBlock: BlockConfig = { condition: { field: 'operation', value: 'findymail_find_email_from_name' }, }, { - id: 'domain', + id: 'fn_domain', title: 'Company Domain or Name', type: 'short-input', required: true, @@ -54,7 +54,7 @@ export const FindymailBlock: BlockConfig = { }, // Find Email From LinkedIn { - id: 'linkedin_url', + id: 'fefl_linkedin_url', title: 'LinkedIn URL', type: 'short-input', required: true, @@ -63,7 +63,7 @@ export const FindymailBlock: BlockConfig = { }, // Find Emails By Domain { - id: 'domain', + id: 'fed_domain', title: 'Domain', type: 'short-input', required: true, @@ -77,10 +77,16 @@ export const FindymailBlock: BlockConfig = { required: true, placeholder: '["CEO", "Founder"]', condition: { field: 'operation', value: 'findymail_find_emails_by_domain' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON array of job roles/titles to target at the company (max 3). Return ONLY the JSON array - no explanations, no extra text.', + placeholder: 'e.g. CEO, Founder, CTO', + }, }, // Verify Email { - id: 'email', + id: 've_email', title: 'Email Address', type: 'short-input', required: true, @@ -89,7 +95,7 @@ export const FindymailBlock: BlockConfig = { }, // Reverse Email Lookup { - id: 'email', + id: 'rel_email', title: 'Email Address', type: 'short-input', required: true, @@ -99,27 +105,32 @@ export const FindymailBlock: BlockConfig = { { id: 'with_profile', title: 'Return Full Profile', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', condition: { field: 'operation', value: 'findymail_reverse_email_lookup' }, mode: 'advanced', }, // Get Company Info — provide at least one of LinkedIn URL, domain, or name { - id: 'linkedin_url', + id: 'gc_linkedin_url', title: 'Company LinkedIn URL', type: 'short-input', placeholder: 'LinkedIn URL (at least one of URL/domain/name required)', condition: { field: 'operation', value: 'findymail_get_company' }, }, { - id: 'domain', + id: 'gc_domain', title: 'Company Domain', type: 'short-input', placeholder: 'stripe.com (at least one of URL/domain/name required)', condition: { field: 'operation', value: 'findymail_get_company' }, }, { - id: 'name', + id: 'gc_name', title: 'Company Name', type: 'short-input', placeholder: 'Stripe (at least one of URL/domain/name required)', @@ -141,6 +152,12 @@ export const FindymailBlock: BlockConfig = { required: true, placeholder: '["Software Engineer", "CEO"]', condition: { field: 'operation', value: 'findymail_find_employees' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON array of job titles to search for at the company (max 10). Return ONLY the JSON array - no explanations, no extra text.', + placeholder: 'e.g. Software Engineer, CEO, Product Manager', + }, }, { id: 'count', @@ -152,7 +169,7 @@ export const FindymailBlock: BlockConfig = { }, // Find Phone { - id: 'linkedin_url', + id: 'fp_linkedin_url', title: 'LinkedIn URL', type: 'short-input', required: true, @@ -167,10 +184,16 @@ export const FindymailBlock: BlockConfig = { required: true, placeholder: 'React', condition: { field: 'operation', value: 'findymail_search_technologies' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a technology search term to look up in the Findymail technology catalog. Return ONLY the search term - no explanations, no extra text.', + placeholder: 'e.g. React, Stripe, Salesforce', + }, }, // Lookup Technologies By Domain { - id: 'domain', + id: 'lt_domain', title: 'Company Domain', type: 'short-input', required: true, @@ -184,6 +207,12 @@ export const FindymailBlock: BlockConfig = { placeholder: '["React", "TypeScript"]', condition: { field: 'operation', value: 'findymail_lookup_technologies' }, mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON array of technology names to filter by (case-insensitive). Return ONLY the JSON array - no explanations, no extra text.', + placeholder: 'e.g. React, TypeScript, Node.js', + }, }, // API Key { @@ -230,35 +259,58 @@ export const FindymailBlock: BlockConfig = { }, params: (params) => { const { operation: _operation, ...rest } = params + + // Map unique subBlock IDs back to tool param names + const idToParam: Record = { + fn_name: 'name', + fn_domain: 'domain', + fefl_linkedin_url: 'linkedin_url', + fed_domain: 'domain', + ve_email: 'email', + rel_email: 'email', + gc_linkedin_url: 'linkedin_url', + gc_domain: 'domain', + gc_name: 'name', + fp_linkedin_url: 'linkedin_url', + lt_domain: 'domain', + } + const result: Record = {} for (const [key, value] of Object.entries(rest)) { if (value === undefined || value === null || value === '') continue - if (key === 'count') { + const mappedKey = idToParam[key] ?? key + if (mappedKey === 'count') { const n = Number(value) - if (!Number.isNaN(n)) result[key] = n - } else if (key === 'roles' || key === 'job_titles' || key === 'technologies') { + if (!Number.isNaN(n)) result[mappedKey] = n + } else if (mappedKey === 'with_profile') { + result[mappedKey] = value === true || value === 'true' + } else if ( + mappedKey === 'roles' || + mappedKey === 'job_titles' || + mappedKey === 'technologies' + ) { if (Array.isArray(value)) { - result[key] = value + result[mappedKey] = value } else if (typeof value === 'string') { const trimmed = value.trim() if (trimmed.startsWith('[')) { try { const parsed = JSON.parse(trimmed) if (Array.isArray(parsed)) { - result[key] = parsed + result[mappedKey] = parsed continue } } catch { // fall through to comma-split } } - result[key] = trimmed + result[mappedKey] = trimmed .split(',') .map((s) => s.trim()) .filter(Boolean) } } else { - result[key] = value + result[mappedKey] = value } } return result @@ -268,23 +320,30 @@ export const FindymailBlock: BlockConfig = { inputs: { operation: { type: 'string', description: 'Operation to perform' }, apiKey: { type: 'string', description: 'Findymail API key' }, - email: { type: 'string', description: 'Email address' }, - name: { type: 'string', description: 'Full name or company name' }, - domain: { type: 'string', description: 'Company domain' }, - linkedin_url: { type: 'string', description: 'LinkedIn profile or company URL' }, + fn_name: { type: 'string', description: 'Full name (find email from name)' }, + fn_domain: { type: 'string', description: 'Company domain or name (find email from name)' }, + fefl_linkedin_url: { type: 'string', description: 'LinkedIn URL (find email from LinkedIn)' }, + fed_domain: { type: 'string', description: 'Company domain (find emails by domain)' }, roles: { type: 'array', description: 'Target roles (max 3)' }, + ve_email: { type: 'string', description: 'Email address to verify' }, + rel_email: { type: 'string', description: 'Email address for reverse lookup' }, with_profile: { type: 'boolean', description: 'Return full profile data on reverse lookup' }, + gc_linkedin_url: { type: 'string', description: 'Company LinkedIn URL (get company info)' }, + gc_domain: { type: 'string', description: 'Company domain (get company info)' }, + gc_name: { type: 'string', description: 'Company name (get company info)' }, website: { type: 'string', description: 'Company website for employee search' }, job_titles: { type: 'array', description: 'Target job titles (max 10)' }, count: { type: 'number', description: 'Number of contacts to return (max 5)' }, + fp_linkedin_url: { type: 'string', description: 'LinkedIn URL (find phone)' }, q: { type: 'string', description: 'Technology search query' }, + lt_domain: { type: 'string', description: 'Company domain (lookup technologies)' }, technologies: { type: 'array', description: 'Technology names to filter by' }, }, outputs: { // Verify Email verified: { type: 'boolean', description: 'Whether the email is deliverable' }, provider: { type: 'string', description: 'Email service provider' }, - // Find / Reverse / Company + // Find Email / LinkedIn contact: { type: 'json', description: 'Contact found (name, email, domain)', @@ -293,6 +352,7 @@ export const FindymailBlock: BlockConfig = { type: 'array', description: 'Contacts found at the domain (name, email, domain)', }, + // Reverse Email Lookup linkedin_url: { type: 'string', description: 'LinkedIn URL' }, fullName: { type: 'string', description: 'Full name from LinkedIn profile' }, username: { type: 'string', description: 'LinkedIn username' }, @@ -302,10 +362,16 @@ export const FindymailBlock: BlockConfig = { city: { type: 'string', description: 'City' }, region: { type: 'string', description: 'Region/state' }, country: { type: 'string', description: 'Country' }, - companyLinkedinUrl: { type: 'string', description: 'Current company LinkedIn URL' }, + companyLinkedinUrl: { + type: 'string', + description: 'Current company LinkedIn URL', + }, companyName: { type: 'string', description: 'Current company name' }, companyWebsite: { type: 'string', description: 'Current company website' }, - isPremium: { type: 'boolean', description: 'Whether the profile has LinkedIn Premium' }, + isPremium: { + type: 'boolean', + description: 'Whether the profile has LinkedIn Premium', + }, isOpenProfile: { type: 'boolean', description: 'Whether the profile is open' }, skills: { type: 'array', description: 'Profile skills' }, jobs: { type: 'array', description: 'Job history entries' }, @@ -318,9 +384,12 @@ export const FindymailBlock: BlockConfig = { description: 'Certifications (name, issuingOrganization, issueDate, expirationDate)', }, // Get Company - name: { type: 'string', description: 'Company name (get-company)' }, + name: { type: 'string', description: 'Company name' }, domain: { type: 'string', description: 'Company domain' }, - company_size: { type: 'string', description: 'Headcount range (e.g., 1001-5000)' }, + company_size: { + type: 'string', + description: 'Headcount range (e.g., 1001-5000)', + }, industry: { type: 'string', description: 'Industry classification' }, description: { type: 'string', description: 'Company description' }, // Find Employees @@ -329,8 +398,14 @@ export const FindymailBlock: BlockConfig = { description: 'Employees found (name, linkedinUrl, companyWebsite, companyName, jobTitle)', }, // Find Phone - phone: { type: 'string', description: 'Phone number in E.164 format (US only)' }, - line_type: { type: 'string', description: 'Phone line type (Mobile, Landline)' }, + phone: { + type: 'string', + description: 'Phone number in E.164 format (US only)', + }, + line_type: { + type: 'string', + description: 'Phone line type (Mobile, Landline)', + }, // Technologies technologies: { type: 'array', @@ -338,8 +413,11 @@ export const FindymailBlock: BlockConfig = { }, // Get Credits credits: { type: 'number', description: 'Remaining finder credits' }, - verifier_credits: { type: 'number', description: 'Remaining verifier credits' }, - // Reverse / Verify shared + verifier_credits: { + type: 'number', + description: 'Remaining verifier credits', + }, + // Verify / Reverse shared email: { type: 'string', description: 'Email address' }, }, } diff --git a/apps/sim/blocks/blocks/prospeo.ts b/apps/sim/blocks/blocks/prospeo.ts index 823b1f04f24..2980efdb96a 100644 --- a/apps/sim/blocks/blocks/prospeo.ts +++ b/apps/sim/blocks/blocks/prospeo.ts @@ -70,21 +70,21 @@ export const ProspeoBlock: BlockConfig = { condition: { field: 'operation', value: 'prospeo_enrich_person' }, }, { - id: 'company_name', + id: 'ep_company_name', title: 'Company Name', type: 'short-input', placeholder: 'Intercom', condition: { field: 'operation', value: 'prospeo_enrich_person' }, }, { - id: 'company_website', + id: 'ep_company_website', title: 'Company Website', type: 'short-input', placeholder: 'intercom.com', condition: { field: 'operation', value: 'prospeo_enrich_person' }, }, { - id: 'company_linkedin_url', + id: 'ep_company_linkedin_url', title: 'Company LinkedIn URL', type: 'short-input', placeholder: 'https://www.linkedin.com/company/intercom', @@ -100,44 +100,56 @@ export const ProspeoBlock: BlockConfig = { mode: 'advanced', }, { - id: 'only_verified_email', + id: 'ep_only_verified_email', title: 'Only Verified Email', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_enrich_person' }, mode: 'advanced', }, { - id: 'enrich_mobile', + id: 'ep_enrich_mobile', title: 'Enrich Mobile', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_enrich_person' }, mode: 'advanced', }, { - id: 'only_verified_mobile', + id: 'ep_only_verified_mobile', title: 'Only Verified Mobile', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_enrich_person' }, mode: 'advanced', }, // Enrich Company { - id: 'company_website', + id: 'ec_company_website', title: 'Company Website', type: 'short-input', placeholder: 'intercom.com', condition: { field: 'operation', value: 'prospeo_enrich_company' }, }, { - id: 'company_linkedin_url', + id: 'ec_company_linkedin_url', title: 'Company LinkedIn URL', type: 'short-input', placeholder: 'https://www.linkedin.com/company/intercom', condition: { field: 'operation', value: 'prospeo_enrich_company' }, }, { - id: 'company_name', + id: 'ec_company_name', title: 'Company Name', type: 'short-input', placeholder: 'Intercom', @@ -155,7 +167,7 @@ export const ProspeoBlock: BlockConfig = { // Bulk Enrich Person { - id: 'data', + id: 'bep_data', title: 'Records', type: 'code', language: 'json', @@ -171,30 +183,42 @@ export const ProspeoBlock: BlockConfig = { }, }, { - id: 'only_verified_email', + id: 'bep_only_verified_email', title: 'Only Verified Email', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_bulk_enrich_person' }, mode: 'advanced', }, { - id: 'enrich_mobile', + id: 'bep_enrich_mobile', title: 'Enrich Mobile', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_bulk_enrich_person' }, mode: 'advanced', }, { - id: 'only_verified_mobile', + id: 'bep_only_verified_mobile', title: 'Only Verified Mobile', - type: 'switch', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], condition: { field: 'operation', value: 'prospeo_bulk_enrich_person' }, mode: 'advanced', }, // Bulk Enrich Company { - id: 'data', + id: 'bec_data', title: 'Records', type: 'code', language: 'json', @@ -212,7 +236,7 @@ export const ProspeoBlock: BlockConfig = { // Search Person { - id: 'filters', + id: 'sp_filters', title: 'Filters', type: 'code', language: 'json', @@ -228,7 +252,7 @@ export const ProspeoBlock: BlockConfig = { }, }, { - id: 'page', + id: 'sp_page', title: 'Page', type: 'short-input', placeholder: '1', @@ -238,7 +262,7 @@ export const ProspeoBlock: BlockConfig = { // Search Company { - id: 'filters', + id: 'sc_filters', title: 'Filters', type: 'code', language: 'json', @@ -254,7 +278,7 @@ export const ProspeoBlock: BlockConfig = { }, }, { - id: 'page', + id: 'sc_page', title: 'Page', type: 'short-input', placeholder: '1', @@ -323,23 +347,45 @@ export const ProspeoBlock: BlockConfig = { } }, params: (params) => { + const renames: Record = { + ep_company_name: 'company_name', + ep_company_website: 'company_website', + ep_company_linkedin_url: 'company_linkedin_url', + ep_only_verified_email: 'only_verified_email', + ep_enrich_mobile: 'enrich_mobile', + ep_only_verified_mobile: 'only_verified_mobile', + ec_company_website: 'company_website', + ec_company_linkedin_url: 'company_linkedin_url', + ec_company_name: 'company_name', + bep_data: 'data', + bep_only_verified_email: 'only_verified_email', + bep_enrich_mobile: 'enrich_mobile', + bep_only_verified_mobile: 'only_verified_mobile', + bec_data: 'data', + sp_filters: 'filters', + sp_page: 'page', + sc_filters: 'filters', + sc_page: 'page', + } const result: Record = {} for (const [key, value] of Object.entries(params)) { if (value === undefined || value === null || value === '') continue - if (key === 'page') { + if (key === 'operation') continue + const targetKey = renames[key] ?? key + if (targetKey === 'page') { const n = Number(value) - if (Number.isFinite(n)) result[key] = n + if (Number.isFinite(n)) result[targetKey] = n continue } if ( - key === 'only_verified_email' || - key === 'enrich_mobile' || - key === 'only_verified_mobile' + targetKey === 'only_verified_email' || + targetKey === 'enrich_mobile' || + targetKey === 'only_verified_mobile' ) { - result[key] = typeof value === 'string' ? value === 'true' : Boolean(value) + result[targetKey] = typeof value === 'string' ? value === 'true' : Boolean(value) continue } - result[key] = value + result[targetKey] = value } return result }, @@ -348,25 +394,55 @@ export const ProspeoBlock: BlockConfig = { inputs: { operation: { type: 'string', description: 'Operation to perform' }, apiKey: { type: 'string', description: 'Prospeo API key' }, - // Enrich Person / Company match keys + // Enrich Person match keys first_name: { type: 'string', description: 'First name' }, last_name: { type: 'string', description: 'Last name' }, full_name: { type: 'string', description: 'Full name' }, linkedin_url: { type: 'string', description: 'Person LinkedIn URL' }, email: { type: 'string', description: 'Work email' }, - company_name: { type: 'string', description: 'Company name' }, - company_website: { type: 'string', description: 'Company website' }, - company_linkedin_url: { type: 'string', description: 'Company LinkedIn URL' }, - company_id: { type: 'string', description: 'Prospeo company_id' }, + ep_company_name: { type: 'string', description: 'Company name (enrich person)' }, + ep_company_website: { type: 'string', description: 'Company website (enrich person)' }, + ep_company_linkedin_url: { + type: 'string', + description: 'Company LinkedIn URL (enrich person)', + }, person_id: { type: 'string', description: 'Prospeo person_id' }, - only_verified_email: { type: 'boolean', description: 'Only verified emails' }, - enrich_mobile: { type: 'boolean', description: 'Reveal mobile numbers' }, - only_verified_mobile: { type: 'boolean', description: 'Only records with a mobile' }, - // Bulk - data: { type: 'json', description: 'Array of records to enrich' }, - // Search - filters: { type: 'json', description: 'Search filters configuration' }, - page: { type: 'number', description: 'Page number (defaults to 1)' }, + ep_only_verified_email: { type: 'string', description: 'Only verified emails (enrich person)' }, + ep_enrich_mobile: { type: 'string', description: 'Reveal mobile numbers (enrich person)' }, + ep_only_verified_mobile: { + type: 'string', + description: 'Only records with a mobile (enrich person)', + }, + // Enrich Company match keys + ec_company_website: { type: 'string', description: 'Company website (enrich company)' }, + ec_company_linkedin_url: { + type: 'string', + description: 'Company LinkedIn URL (enrich company)', + }, + ec_company_name: { type: 'string', description: 'Company name (enrich company)' }, + company_id: { type: 'string', description: 'Prospeo company_id' }, + // Bulk Person + bep_data: { type: 'json', description: 'Array of person records to enrich (bulk)' }, + bep_only_verified_email: { + type: 'string', + description: 'Only verified emails (bulk enrich person)', + }, + bep_enrich_mobile: { + type: 'string', + description: 'Reveal mobile numbers (bulk enrich person)', + }, + bep_only_verified_mobile: { + type: 'string', + description: 'Only records with a mobile (bulk enrich person)', + }, + // Bulk Company + bec_data: { type: 'json', description: 'Array of company records to enrich (bulk)' }, + // Search Person + sp_filters: { type: 'json', description: 'Search person filters configuration' }, + sp_page: { type: 'string', description: 'Search person page number (defaults to 1)' }, + // Search Company + sc_filters: { type: 'json', description: 'Search company filters configuration' }, + sc_page: { type: 'string', description: 'Search company page number (defaults to 1)' }, // Suggestions location_search: { type: 'string', description: 'Location search query' }, job_title_search: { type: 'string', description: 'Job title search query' }, diff --git a/apps/sim/components/emcn/components/toast/toast.tsx b/apps/sim/components/emcn/components/toast/toast.tsx index 11364ff3a7f..f784c4b9cce 100644 --- a/apps/sim/components/emcn/components/toast/toast.tsx +++ b/apps/sim/components/emcn/components/toast/toast.tsx @@ -1,6 +1,7 @@ 'use client' import { + type CSSProperties, createContext, type ReactNode, useCallback, @@ -17,7 +18,8 @@ import { cn } from '@/lib/core/utils/cn' const AUTO_DISMISS_MS = 5000 const EXIT_ANIMATION_MS = 200 -const MAX_VISIBLE = 20 +const MAX_VISIBLE = 4 +const STACK_OFFSET_PX = 3 const RING_RADIUS = 5.5 const RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS @@ -127,7 +129,15 @@ function CountdownRing({ duration }: { duration: number }) { ) } -function ToastItem({ toast: t, onDismiss }: { toast: ToastData; onDismiss: (id: string) => void }) { +function ToastItem({ + toast: t, + stackOffset, + onDismiss, +}: { + toast: ToastData + stackOffset: number + onDismiss: (id: string) => void +}) { const [exiting, setExiting] = useState(false) const pausedRef = useRef(false) const timerRef = useRef>(undefined) @@ -168,8 +178,9 @@ function ToastItem({ toast: t, onDismiss }: { toast: ToastData; onDismiss: (id:
- {toasts.map((t) => ( - - ))} + {toasts.map((t, index) => { + const depth = toasts.length - index - 1 + + return ( + + ) + })}
, document.body )} diff --git a/apps/sim/tools/findymail/index.ts b/apps/sim/tools/findymail/index.ts index 759ee4c5f0e..ddf4b5db138 100644 --- a/apps/sim/tools/findymail/index.ts +++ b/apps/sim/tools/findymail/index.ts @@ -1,3 +1,5 @@ +export * from './types' + import { findEmailFromLinkedInTool } from '@/tools/findymail/find_email_from_linkedin' import { findEmailFromNameTool } from '@/tools/findymail/find_email_from_name' import { findEmailsByDomainTool } from '@/tools/findymail/find_emails_by_domain' diff --git a/apps/sim/tools/prospeo/bulk_enrich_person.ts b/apps/sim/tools/prospeo/bulk_enrich_person.ts index 272b15a72b4..b6d095e9526 100644 --- a/apps/sim/tools/prospeo/bulk_enrich_person.ts +++ b/apps/sim/tools/prospeo/bulk_enrich_person.ts @@ -32,19 +32,19 @@ export const bulkEnrichPersonTool: ToolConfig< only_verified_email: { type: 'boolean', required: false, - visibility: 'user-only', + visibility: 'user-or-llm', description: 'Only return records with a verified email', }, enrich_mobile: { type: 'boolean', required: false, - visibility: 'user-only', + visibility: 'user-or-llm', description: 'Reveal mobile numbers (10 credits per match; email included)', }, only_verified_mobile: { type: 'boolean', required: false, - visibility: 'user-only', + visibility: 'user-or-llm', description: 'Only return records that have a mobile (implies enrich_mobile)', }, }, diff --git a/apps/sim/tools/prospeo/enrich_person.ts b/apps/sim/tools/prospeo/enrich_person.ts index 2187383e059..44c72a26007 100644 --- a/apps/sim/tools/prospeo/enrich_person.ts +++ b/apps/sim/tools/prospeo/enrich_person.ts @@ -76,19 +76,19 @@ export const enrichPersonTool: ToolConfig { + if (!params.location_search && !params.job_title_search) { + throw new Error( + 'Provide exactly one of location_search or job_title_search (minimum 2 characters).' + ) + } + if (params.location_search && params.job_title_search) { + throw new Error( + 'location_search and job_title_search are mutually exclusive — provide only one.' + ) + } const body: Record = {} if (params.location_search) body.location_search = params.location_search if (params.job_title_search) body.job_title_search = params.job_title_search @@ -61,8 +71,8 @@ export const searchSuggestionsTool: ToolConfig< return { success: true, output: { - location_suggestions: data.location_suggestions ?? null, - job_title_suggestions: data.job_title_suggestions ?? null, + location_suggestions: data.location_suggestions ?? [], + job_title_suggestions: data.job_title_suggestions ?? [], }, } }, @@ -71,7 +81,7 @@ export const searchSuggestionsTool: ToolConfig< location_suggestions: { type: 'array', description: - 'Location suggestions when using location_search (null when searching job titles)', + 'Location suggestions when using location_search (empty when searching job titles)', optional: true, items: { type: 'object', @@ -87,7 +97,7 @@ export const searchSuggestionsTool: ToolConfig< job_title_suggestions: { type: 'array', description: - 'Up to 25 job title suggestions ordered by popularity when using job_title_search (null when searching locations)', + 'Up to 25 job title suggestions ordered by popularity when using job_title_search (empty when searching locations)', optional: true, items: { type: 'string' }, }, diff --git a/apps/sim/tools/prospeo/types.ts b/apps/sim/tools/prospeo/types.ts index 391006b4678..c44ec03f83c 100644 --- a/apps/sim/tools/prospeo/types.ts +++ b/apps/sim/tools/prospeo/types.ts @@ -5,7 +5,6 @@ export interface ProspeoBaseParams { } export interface ProspeoPersonData { - identifier?: string first_name?: string last_name?: string full_name?: string @@ -18,7 +17,6 @@ export interface ProspeoPersonData { } export interface ProspeoCompanyData { - identifier?: string company_name?: string company_website?: string company_linkedin_url?: string @@ -35,6 +33,7 @@ export interface ProspeoPaginationOutput { export const PROSPEO_PAGINATION_OUTPUT: OutputProperty = { type: 'object', description: 'Pagination details', + optional: true, properties: { current_page: { type: 'number', description: 'Current page number' }, per_page: { type: 'number', description: 'Results per page' }, @@ -84,7 +83,7 @@ export interface ProspeoEnrichCompanyResponse extends ToolResponse { /** Bulk Enrich Person */ export interface ProspeoBulkEnrichPersonParams extends ProspeoBaseParams { - data: ProspeoPersonData[] + data: Array only_verified_email?: boolean enrich_mobile?: boolean only_verified_mobile?: boolean @@ -105,7 +104,7 @@ export interface ProspeoBulkEnrichPersonResponse extends ToolResponse { /** Bulk Enrich Company */ export interface ProspeoBulkEnrichCompanyParams extends ProspeoBaseParams { - data: ProspeoCompanyData[] + data: Array } export interface ProspeoBulkEnrichCompanyResponse extends ToolResponse { @@ -161,8 +160,8 @@ export interface ProspeoSearchSuggestionsParams extends ProspeoBaseParams { export interface ProspeoSearchSuggestionsResponse extends ToolResponse { output: { - location_suggestions: Array<{ name: string; type: string }> | null - job_title_suggestions: string[] | null + location_suggestions: Array<{ name: string; type: string }> + job_title_suggestions: string[] } }