feat(sidebar): context menu for nav items in sidebar, toolbar blocks, added missing docs for various blocks and triggers (#2754)

* feat(sidebar): context menu for nav items in sidebar

* added toolbar context menu, fixed incorrect access pattern in old context menus and added docs for missing blocks

* fixed links
This commit is contained in:
Waleed
2026-01-09 17:50:10 -08:00
committed by GitHub
parent 38e827b61a
commit 1dbd16115f
33 changed files with 388 additions and 25 deletions

View File

@@ -95,7 +95,12 @@ export function ChunkContextMenu({
}
return (
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
>
<PopoverAnchor
style={{
position: 'fixed',

View File

@@ -100,7 +100,12 @@ export function DocumentContextMenu({
}
return (
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
>
<PopoverAnchor
style={{
position: 'fixed',

View File

@@ -99,7 +99,12 @@ export function KnowledgeBaseContextMenu({
disableDelete = false,
}: KnowledgeBaseContextMenuProps) {
return (
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
>
<PopoverAnchor
style={{
position: 'fixed',

View File

@@ -43,7 +43,12 @@ export function KnowledgeListContextMenu({
disableAdd = false,
}: KnowledgeListContextMenuProps) {
return (
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
>
<PopoverAnchor
style={{
position: 'fixed',

View File

@@ -44,7 +44,7 @@ export function SnapshotContextMenu({
return createPortal(
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -47,7 +47,12 @@ export function LogRowContextMenu({
const hasWorkflow = Boolean(log?.workflow?.id || log?.workflowId)
return (
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
>
<PopoverAnchor
style={{
position: 'fixed',

View File

@@ -56,7 +56,7 @@ export function BlockContextMenu({
return (
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -38,7 +38,7 @@ export function PaneContextMenu({
return (
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -673,7 +673,7 @@ function WorkflowInputMapperSyncWrapper({
if (!workflowId) {
return (
<div className='rounded-md border border-gray-600/50 bg-gray-900/20 p-4 text-center text-gray-400 text-sm'>
<div className='rounded-md border border-[var(--border-1)] border-dashed bg-[var(--surface-3)] p-4 text-center text-[var(--text-muted)] text-sm'>
Select a workflow to configure its inputs
</div>
)
@@ -681,15 +681,15 @@ function WorkflowInputMapperSyncWrapper({
if (isLoading) {
return (
<div className='flex items-center justify-center rounded-md border border-gray-600/50 bg-gray-900/20 p-8'>
<Loader2 className='h-5 w-5 animate-spin text-gray-400' />
<div className='flex items-center justify-center rounded-md border border-[var(--border-1)] border-dashed bg-[var(--surface-3)] p-8'>
<Loader2 className='h-5 w-5 animate-spin text-[var(--text-muted)]' />
</div>
)
}
if (inputFields.length === 0) {
return (
<div className='rounded-md border border-gray-600/50 bg-gray-900/20 p-4 text-center text-gray-400 text-sm'>
<div className='rounded-md border border-[var(--border-1)] border-dashed bg-[var(--surface-3)] p-4 text-center text-[var(--text-muted)] text-sm'>
This workflow has no custom input fields
</div>
)

View File

@@ -1,7 +1,7 @@
'use client'
import { useCallback, useEffect, useRef, useState } from 'react'
import { BookOpen, Check, ChevronUp, Pencil, RepeatIcon, Settings, SplitIcon } from 'lucide-react'
import { BookOpen, Check, ChevronUp, Pencil, Settings } from 'lucide-react'
import { Button, Tooltip } from '@/components/emcn'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import {
@@ -15,6 +15,8 @@ import {
useEditorBlockProperties,
useEditorSubblockLayout,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks'
import { LoopTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/loop/loop-config'
import { ParallelTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/parallel/parallel-config'
import { getSubBlockStableKey } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/utils'
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import { getBlock } from '@/blocks/registry'
@@ -58,9 +60,8 @@ export function Editor() {
const isSubflow =
currentBlock && (currentBlock.type === 'loop' || currentBlock.type === 'parallel')
// Get subflow display properties
const subflowIcon = isSubflow && currentBlock.type === 'loop' ? RepeatIcon : SplitIcon
const subflowBgColor = isSubflow && currentBlock.type === 'loop' ? '#2FB3FF' : '#FEE12B'
// Get subflow display properties from configs
const subflowConfig = isSubflow ? (currentBlock.type === 'loop' ? LoopTool : ParallelTool) : null
// Refs for resize functionality
const subBlocksRef = useRef<HTMLDivElement>(null)
@@ -176,8 +177,9 @@ export function Editor() {
* Handles opening documentation link in a new secure tab.
*/
const handleOpenDocs = () => {
if (blockConfig?.docsLink) {
window.open(blockConfig.docsLink, '_blank', 'noopener,noreferrer')
const docsLink = isSubflow ? subflowConfig?.docsLink : blockConfig?.docsLink
if (docsLink) {
window.open(docsLink, '_blank', 'noopener,noreferrer')
}
}
@@ -195,10 +197,10 @@ export function Editor() {
{(blockConfig || isSubflow) && currentBlock?.type !== 'note' && (
<div
className='flex h-[18px] w-[18px] items-center justify-center rounded-[4px]'
style={{ background: isSubflow ? subflowBgColor : blockConfig?.bgColor }}
style={{ background: isSubflow ? subflowConfig?.bgColor : blockConfig?.bgColor }}
>
<IconComponent
icon={isSubflow ? subflowIcon : blockConfig?.icon}
icon={isSubflow ? subflowConfig?.icon : blockConfig?.icon}
className='h-[12px] w-[12px] text-[var(--white)]'
/>
</div>
@@ -295,7 +297,7 @@ export function Editor() {
</Tooltip.Content>
</Tooltip.Root>
)}
{currentBlock && !isSubflow && blockConfig?.docsLink && (
{currentBlock && (isSubflow ? subflowConfig?.docsLink : blockConfig?.docsLink) && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button

View File

@@ -1 +1,2 @@
export { createDragPreview, type DragItemInfo } from './drag-preview'
export { ToolbarItemContextMenu } from './toolbar-item-context-menu'

View File

@@ -0,0 +1 @@
export { ToolbarItemContextMenu } from './toolbar-item-context-menu'

View File

@@ -0,0 +1,88 @@
'use client'
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
interface ToolbarItemContextMenuProps {
/**
* Whether the context menu is open
*/
isOpen: boolean
/**
* Position of the context menu
*/
position: { x: number; y: number }
/**
* Ref for the menu element
*/
menuRef: React.RefObject<HTMLDivElement | null>
/**
* Callback when menu should close
*/
onClose: () => void
/**
* Callback when add to canvas is clicked
*/
onAddToCanvas: () => void
/**
* Callback when view documentation is clicked
*/
onViewDocumentation?: () => void
/**
* Whether the view documentation option should be shown
*/
showViewDocumentation?: boolean
}
/**
* Context menu component for toolbar items (triggers and blocks).
* Displays options to add to canvas and view documentation.
*/
export function ToolbarItemContextMenu({
isOpen,
position,
menuRef,
onClose,
onAddToCanvas,
onViewDocumentation,
showViewDocumentation = false,
}: ToolbarItemContextMenuProps) {
return (
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'
>
<PopoverAnchor
style={{
position: 'fixed',
left: `${position.x}px`,
top: `${position.y}px`,
width: '1px',
height: '1px',
}}
/>
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
<PopoverItem
onClick={() => {
onAddToCanvas()
onClose()
}}
>
Add to canvas
</PopoverItem>
{showViewDocumentation && onViewDocumentation && (
<PopoverItem
onClick={() => {
onViewDocumentation()
onClose()
}}
>
View documentation
</PopoverItem>
)}
</PopoverContent>
</Popover>
)
}

View File

@@ -17,6 +17,7 @@ import {
getTriggersForSidebar,
hasTriggerCapability,
} from '@/lib/workflows/triggers/trigger-utils'
import { ToolbarItemContextMenu } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/components'
import {
calculateTriggerHeights,
useToolbarItemInteractions,
@@ -34,6 +35,7 @@ interface BlockItem {
config?: BlockConfig
icon?: any
bgColor?: string
docsLink?: string
}
/**
@@ -98,6 +100,7 @@ function getBlocks() {
type: LoopTool.type,
icon: LoopTool.icon,
bgColor: LoopTool.bgColor,
docsLink: LoopTool.docsLink,
isSpecial: true,
})
@@ -106,6 +109,7 @@ function getBlocks() {
type: ParallelTool.type,
icon: ParallelTool.icon,
bgColor: ParallelTool.bgColor,
docsLink: ParallelTool.docsLink,
isSpecial: true,
})
@@ -178,6 +182,16 @@ export const Toolbar = forwardRef<ToolbarRef, ToolbarProps>(function Toolbar(
// Toggle animation state
const [isToggling, setIsToggling] = useState(false)
// Context menu state
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false)
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 })
const contextMenuRef = useRef<HTMLDivElement>(null)
const [activeItemInfo, setActiveItemInfo] = useState<{
type: string
isTrigger: boolean
docsLink?: string
} | null>(null)
// Toolbar store
const { toolbarTriggersHeight, setToolbarTriggersHeight, preSearchHeight, setPreSearchHeight } =
useToolbarStore()
@@ -338,6 +352,68 @@ export const Toolbar = forwardRef<ToolbarRef, ToolbarProps>(function Toolbar(
setIsToggling(false)
}, [])
/**
* Handle context menu for toolbar items
*/
const handleItemContextMenu = useCallback(
(e: React.MouseEvent, type: string, isTrigger: boolean, docsLink?: string) => {
e.preventDefault()
e.stopPropagation()
setContextMenuPosition({ x: e.clientX, y: e.clientY })
setActiveItemInfo({ type, isTrigger, docsLink })
setIsContextMenuOpen(true)
},
[]
)
/**
* Close context menu and clear active item state
*/
const closeContextMenu = useCallback(() => {
setIsContextMenuOpen(false)
setActiveItemInfo(null)
}, [])
/**
* Handle add to canvas from context menu
*/
const handleContextMenuAddToCanvas = useCallback(() => {
if (activeItemInfo) {
handleItemClick(activeItemInfo.type, activeItemInfo.isTrigger)
}
}, [activeItemInfo, handleItemClick])
/**
* Handle view documentation from context menu
*/
const handleViewDocumentation = useCallback(() => {
if (activeItemInfo?.docsLink) {
window.open(activeItemInfo.docsLink, '_blank', 'noopener,noreferrer')
}
}, [activeItemInfo])
/**
* Handle clicks outside the context menu to close it
*/
useEffect(() => {
if (!isContextMenuOpen) return
const handleClickOutside = (e: MouseEvent) => {
if (contextMenuRef.current && !contextMenuRef.current.contains(e.target as Node)) {
closeContextMenu()
}
}
const timeoutId = setTimeout(() => {
document.addEventListener('click', handleClickOutside)
}, 0)
return () => {
clearTimeout(timeoutId)
document.removeEventListener('click', handleClickOutside)
}
}, [isContextMenuOpen, closeContextMenu])
/**
* Handle keyboard navigation with ArrowUp / ArrowDown when the toolbar tab
* is active and search is open (e.g. after Mod+F). Navigation order:
@@ -553,6 +629,9 @@ export const Toolbar = forwardRef<ToolbarRef, ToolbarProps>(function Toolbar(
})
}}
onClick={() => handleItemClick(trigger.type, isTriggerCapable)}
onContextMenu={(e) =>
handleItemContextMenu(e, trigger.type, isTriggerCapable, trigger.docsLink)
}
className={clsx(
'group flex h-[28px] items-center gap-[8px] rounded-[8px] px-[6px] text-[14px]',
'cursor-pointer hover:bg-[var(--surface-6)] active:cursor-grabbing dark:hover:bg-[var(--surface-5)]',
@@ -642,6 +721,14 @@ export const Toolbar = forwardRef<ToolbarRef, ToolbarProps>(function Toolbar(
document.body.classList.remove('sim-drag-subflow')
}}
onClick={() => handleItemClick(block.type, false)}
onContextMenu={(e) =>
handleItemContextMenu(
e,
block.type,
false,
block.docsLink ?? block.config?.docsLink
)
}
className={clsx(
'group flex h-[28px] items-center gap-[8px] rounded-[8px] px-[6px] text-[14px]',
'cursor-pointer hover:bg-[var(--surface-6)] active:cursor-grabbing dark:hover:bg-[var(--surface-5)]',
@@ -685,6 +772,17 @@ export const Toolbar = forwardRef<ToolbarRef, ToolbarProps>(function Toolbar(
</div>
</div>
</div>
{/* Toolbar Item Context Menu */}
<ToolbarItemContextMenu
isOpen={isContextMenuOpen}
position={contextMenuPosition}
menuRef={contextMenuRef}
onClose={closeContextMenu}
onAddToCanvas={handleContextMenuAddToCanvas}
onViewDocumentation={handleViewDocumentation}
showViewDocumentation={Boolean(activeItemInfo?.docsLink)}
/>
</div>
)
})

View File

@@ -9,4 +9,5 @@ export const LoopTool = {
name: 'Loop',
icon: RepeatIcon,
bgColor: '#2FB3FF',
docsLink: 'https://docs.sim.ai/blocks/loop',
} as const

View File

@@ -9,4 +9,5 @@ export const ParallelTool = {
name: 'Parallel',
icon: SplitIcon,
bgColor: '#FEE12B',
docsLink: 'https://docs.sim.ai/blocks/parallel',
} as const

View File

@@ -66,7 +66,7 @@ export function LogRowContextMenu({
return (
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -52,7 +52,7 @@ export function OutputContextMenu({
return (
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -1,4 +1,5 @@
export { HelpModal } from './help-modal/help-modal'
export { NavItemContextMenu } from './nav-item-context-menu'
export { SearchModal } from './search-modal/search-modal'
export { SettingsModal } from './settings-modal/settings-modal'
export { UsageIndicator } from './usage-indicator/usage-indicator'

View File

@@ -0,0 +1 @@
export { NavItemContextMenu } from './nav-item-context-menu'

View File

@@ -0,0 +1,81 @@
'use client'
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
interface NavItemContextMenuProps {
/**
* Whether the context menu is open
*/
isOpen: boolean
/**
* Position of the context menu
*/
position: { x: number; y: number }
/**
* Ref for the menu element
*/
menuRef: React.RefObject<HTMLDivElement | null>
/**
* Callback when menu should close
*/
onClose: () => void
/**
* Callback when open in new tab is clicked
*/
onOpenInNewTab: () => void
/**
* Callback when copy link is clicked
*/
onCopyLink: () => void
}
/**
* Context menu component for sidebar navigation items.
* Displays navigation-appropriate options (open in new tab, copy link) in a popover at the right-click position.
*/
export function NavItemContextMenu({
isOpen,
position,
menuRef,
onClose,
onOpenInNewTab,
onCopyLink,
}: NavItemContextMenuProps) {
return (
<Popover
open={isOpen}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'
>
<PopoverAnchor
style={{
position: 'fixed',
left: `${position.x}px`,
top: `${position.y}px`,
width: '1px',
height: '1px',
}}
/>
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
<PopoverItem
onClick={() => {
onOpenInNewTab()
onClose()
}}
>
Open in new tab
</PopoverItem>
<PopoverItem
onClick={() => {
onCopyLink()
onClose()
}}
>
Copy link
</PopoverItem>
</PopoverContent>
</Popover>
)
}

View File

@@ -150,7 +150,7 @@ export function ContextMenu({
return (
<Popover
open={isOpen}
onOpenChange={onClose}
onOpenChange={(open) => !open && onClose()}
variant='secondary'
size='sm'
colorScheme='inverted'

View File

@@ -13,6 +13,7 @@ import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/provide
import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils'
import {
HelpModal,
NavItemContextMenu,
SearchModal,
SettingsModal,
UsageIndicator,
@@ -20,6 +21,7 @@ import {
WorkspaceHeader,
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components'
import {
useContextMenu,
useFolderOperations,
useSidebarResize,
useWorkflowOperations,
@@ -168,6 +170,46 @@ export function Sidebar() {
workspaceId,
})
/** Context menu state for navigation items */
const [activeNavItemHref, setActiveNavItemHref] = useState<string | null>(null)
const {
isOpen: isNavContextMenuOpen,
position: navContextMenuPosition,
menuRef: navMenuRef,
handleContextMenu: handleNavContextMenuBase,
closeMenu: closeNavContextMenu,
} = useContextMenu()
const handleNavItemContextMenu = useCallback(
(e: React.MouseEvent, href: string) => {
setActiveNavItemHref(href)
handleNavContextMenuBase(e)
},
[handleNavContextMenuBase]
)
const handleNavContextMenuClose = useCallback(() => {
closeNavContextMenu()
setActiveNavItemHref(null)
}, [closeNavContextMenu])
const handleNavOpenInNewTab = useCallback(() => {
if (activeNavItemHref) {
window.open(activeNavItemHref, '_blank', 'noopener,noreferrer')
}
}, [activeNavItemHref])
const handleNavCopyLink = useCallback(async () => {
if (activeNavItemHref) {
const fullUrl = `${window.location.origin}${activeNavItemHref}`
try {
await navigator.clipboard.writeText(fullUrl)
} catch (error) {
logger.error('Failed to copy link to clipboard', { error })
}
}
}, [activeNavItemHref])
const { handleDuplicateWorkspace: duplicateWorkspace } = useDuplicateWorkspace({
getWorkspaceId: () => workspaceId,
})
@@ -629,12 +671,23 @@ export function Sidebar() {
href={item.href!}
data-item-id={item.id}
className={`${baseClasses} ${activeClasses}`}
onContextMenu={(e) => handleNavItemContextMenu(e, item.href!)}
>
{content}
</Link>
)
})}
</div>
{/* Nav Item Context Menu */}
<NavItemContextMenu
isOpen={isNavContextMenuOpen}
position={navContextMenuPosition}
menuRef={navMenuRef}
onClose={handleNavContextMenuClose}
onOpenInNewTab={handleNavOpenInNewTab}
onCopyLink={handleNavCopyLink}
/>
</div>
</aside>

View File

@@ -13,6 +13,7 @@ export const DiscordBlock: BlockConfig<DiscordResponse> = {
category: 'tools',
bgColor: '#5865F2',
icon: DiscordIcon,
docsLink: 'https://docs.sim.ai/tools/discord',
subBlocks: [
{
id: 'operation',

View File

@@ -12,7 +12,7 @@ export const FirefliesBlock: BlockConfig<FirefliesResponse> = {
triggerAllowed: true,
longDescription:
'Integrate Fireflies.ai into the workflow. Manage meeting transcripts, add bot to live meetings, create soundbites, and more. Can also trigger workflows when transcriptions complete.',
docsLink: 'https://docs.fireflies.ai',
docsLink: 'https://docs.sim.ai/tools/fireflies',
category: 'tools',
icon: FirefliesIcon,
bgColor: '#100730',

View File

@@ -13,6 +13,7 @@ export const GenericWebhookBlock: BlockConfig = {
category: 'triggers',
icon: WebhookIcon,
bgColor: '#10B981', // Green color for triggers
docsLink: 'https://docs.sim.ai/triggers/webhook',
triggerAllowed: true,
bestPractices: `
- You can test the webhook by sending a request to the webhook URL. E.g. depending on authorization: curl -X POST http://localhost:3000/api/webhooks/trigger/d8abcf0d-1ee5-4b77-bb07-b1e8142ea4e9 -H "Content-Type: application/json" -H "X-Sim-Secret: 1234" -d '{"message": "Test webhook trigger", "data": {"key": "v"}}'

View File

@@ -13,6 +13,7 @@ export const GrainBlock: BlockConfig = {
longDescription:
'Integrate Grain into your workflow. Access meeting recordings, transcripts, highlights, and AI-generated summaries. Can also trigger workflows based on Grain webhook events.',
category: 'tools',
docsLink: 'https://docs.sim.ai/tools/grain',
icon: GrainIcon,
bgColor: '#F6FAF9',
subBlocks: [

View File

@@ -12,6 +12,7 @@ export const ImapBlock: BlockConfig = {
bgColor: '#6366F1',
icon: MailServerIcon,
triggerAllowed: true,
docsLink: 'https://docs.sim.ai/tools/imap',
hideFromToolbar: false,
subBlocks: [...getTrigger('imap_poller').subBlocks],
tools: {

View File

@@ -164,6 +164,7 @@ export const RouterBlock: BlockConfig<RouterResponse> = {
name: 'Router (Legacy)',
description: 'Route workflow',
authMode: AuthMode.ApiKey,
docsLink: 'https://docs.sim.ai/blocks/router',
longDescription:
'This is a core workflow block. Intelligently direct workflow execution to different paths based on input analysis. Use natural language to instruct the router to route to certain blocks based on the input.',
bestPractices: `
@@ -283,6 +284,7 @@ export const RouterV2Block: BlockConfig<RouterV2Response> = {
name: 'Router',
description: 'Route workflow based on context',
authMode: AuthMode.ApiKey,
docsLink: 'https://docs.sim.ai/blocks/router',
longDescription:
'Intelligently route workflow execution to different paths based on context analysis. Define multiple routes with descriptions, and an LLM will determine which route to take based on the provided context.',
bestPractices: `

View File

@@ -12,6 +12,7 @@ export const RssBlock: BlockConfig = {
bgColor: '#F97316',
icon: RssIcon,
triggerAllowed: true,
docsLink: 'https://docs.sim.ai/triggers/rss',
subBlocks: [...getTrigger('rss_poller').subBlocks],

View File

@@ -15,6 +15,7 @@ export const StartTriggerBlock: BlockConfig = {
`,
category: 'triggers',
bgColor: '#34B5FF',
docsLink: 'https://docs.sim.ai/triggers/start',
icon: StartIcon,
hideFromToolbar: false,
subBlocks: [

View File

@@ -10,6 +10,7 @@ export const TwilioSMSBlock: BlockConfig<TwilioSMSBlockOutput> = {
authMode: AuthMode.ApiKey,
longDescription: 'Integrate Twilio into the workflow. Can send SMS messages.',
category: 'tools',
docsLink: 'https://docs.sim.ai/tools/twilio',
bgColor: '#F22F46', // Twilio brand color
icon: TwilioIcon,
subBlocks: [

View File

@@ -12,6 +12,7 @@ export const TwilioVoiceBlock: BlockConfig<ToolResponse> = {
longDescription:
'Integrate Twilio Voice into the workflow. Make outbound calls and retrieve call recordings.',
category: 'tools',
docsLink: 'https://docs.sim.ai/tools/twilio_voice',
bgColor: '#F22F46', // Twilio brand color
icon: TwilioIcon,
triggerAllowed: true,