mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 06:25:48 +08:00
Added starter block with options; added nesting ability for subblock config
This commit is contained in:
@@ -111,10 +111,18 @@ export function WorkflowBlock({ id, data, selected }: NodeProps<WorkflowBlockPro
|
||||
// If there's no condition, the block should be shown
|
||||
if (!block.condition) return true
|
||||
|
||||
// Get the value of the field this block depends on
|
||||
// Get the values of the fields this block depends on
|
||||
const fieldValue =
|
||||
useWorkflowStore.getState().blocks[blockId]?.subBlocks[block.condition.field]?.value
|
||||
return fieldValue === block.condition.value
|
||||
const andFieldValue = block.condition.and
|
||||
? useWorkflowStore.getState().blocks[blockId]?.subBlocks[block.condition.and.field]?.value
|
||||
: undefined
|
||||
|
||||
// Check both conditions if 'and' is present
|
||||
return (
|
||||
fieldValue === block.condition.value &&
|
||||
(!block.condition.and || andFieldValue === block.condition.and.value)
|
||||
)
|
||||
})
|
||||
|
||||
visibleSubBlocks.forEach((block) => {
|
||||
@@ -174,25 +182,27 @@ export function WorkflowBlock({ id, data, selected }: NodeProps<WorkflowBlockPro
|
||||
{selected && <ActionBar blockId={id} />}
|
||||
<ConnectionBlocks blockId={id} setIsConnecting={setIsConnecting} />
|
||||
|
||||
{/* Input Handle */}
|
||||
<Handle
|
||||
type="target"
|
||||
position={horizontalHandles ? Position.Left : Position.Top}
|
||||
id="target"
|
||||
className={cn(
|
||||
'!w-3.5 !h-3.5',
|
||||
'!bg-white !rounded-full !border !border-gray-200',
|
||||
'group-hover:!border-blue-500',
|
||||
'!cursor-crosshair',
|
||||
'transition-[border-color] duration-150',
|
||||
horizontalHandles ? '!left-[-7px]' : '!top-[-7px]'
|
||||
)}
|
||||
data-nodeid={id}
|
||||
data-handleid="target"
|
||||
isConnectableStart={false}
|
||||
isConnectableEnd={true}
|
||||
isValidConnection={(connection) => connection.source !== id}
|
||||
/>
|
||||
{/* Input Handle - Don't show for starter blocks */}
|
||||
{type !== 'starter' && (
|
||||
<Handle
|
||||
type="target"
|
||||
position={horizontalHandles ? Position.Left : Position.Top}
|
||||
id="target"
|
||||
className={cn(
|
||||
'!w-3.5 !h-3.5',
|
||||
'!bg-white !rounded-full !border !border-gray-200',
|
||||
'group-hover:!border-blue-500',
|
||||
'!cursor-crosshair',
|
||||
'transition-[border-color] duration-150',
|
||||
horizontalHandles ? '!left-[-7px]' : '!top-[-7px]'
|
||||
)}
|
||||
data-nodeid={id}
|
||||
data-handleid="target"
|
||||
isConnectableStart={false}
|
||||
isConnectableEnd={true}
|
||||
isValidConnection={(connection) => connection.source !== id}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Block Header */}
|
||||
<div className="flex items-center justify-between p-3 border-b workflow-drag-handle cursor-grab [&:active]:cursor-grabbing">
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { InputIcon } from '@/components/icons'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
export const InputBlock: BlockConfig = {
|
||||
type: 'input',
|
||||
toolbar: {
|
||||
title: 'Input',
|
||||
description: 'Add workflow input',
|
||||
bgColor: '#2FB3FF',
|
||||
icon: InputIcon,
|
||||
category: 'blocks',
|
||||
},
|
||||
tools: {
|
||||
access: [],
|
||||
},
|
||||
workflow: {
|
||||
inputs: {
|
||||
code: { type: 'string', required: true },
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
result: 'any',
|
||||
stdout: 'string',
|
||||
executionTime: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
subBlocks: [
|
||||
{
|
||||
title: 'Input',
|
||||
id: 'input',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
import { StartIcon } from '@/components/icons'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
export const StarterBlock: BlockConfig = {
|
||||
type: 'starter',
|
||||
toolbar: {
|
||||
title: 'Starter',
|
||||
description: 'Start workflow',
|
||||
bgColor: '#2FB3FF',
|
||||
icon: StartIcon,
|
||||
category: 'blocks',
|
||||
},
|
||||
tools: {
|
||||
access: [],
|
||||
},
|
||||
workflow: {
|
||||
inputs: {
|
||||
code: { type: 'string', required: true },
|
||||
executionMode: { type: 'string', required: true },
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
result: 'any',
|
||||
stdout: 'string',
|
||||
executionTime: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
subBlocks: [
|
||||
// Main trigger selector
|
||||
{
|
||||
id: 'startWorkflow',
|
||||
title: 'Start Workflow',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Run manually', id: 'manual' },
|
||||
{ label: 'On webhook call', id: 'webhook' },
|
||||
{ label: 'On schedule', id: 'schedule' },
|
||||
],
|
||||
value: () => 'manual',
|
||||
},
|
||||
// Webhook configuration
|
||||
{
|
||||
id: 'webhookPath',
|
||||
title: 'Webhook Path',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter webhook path (e.g., /my-webhook)',
|
||||
condition: { field: 'startWorkflow', value: 'webhook' },
|
||||
},
|
||||
{
|
||||
id: 'webhookSecret',
|
||||
title: 'Webhook Secret',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter a secret key for webhook security',
|
||||
password: true,
|
||||
condition: { field: 'startWorkflow', value: 'webhook' },
|
||||
},
|
||||
// Schedule configuration
|
||||
{
|
||||
id: 'scheduleType',
|
||||
title: 'Frequency',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Every X Minutes', id: 'minutes' },
|
||||
{ label: 'Hourly', id: 'hourly' },
|
||||
{ label: 'Daily', id: 'daily' },
|
||||
{ label: 'Weekly', id: 'weekly' },
|
||||
{ label: 'Monthly', id: 'monthly' },
|
||||
{ label: 'Custom Cron', id: 'custom' },
|
||||
],
|
||||
value: () => 'daily',
|
||||
condition: { field: 'startWorkflow', value: 'schedule' },
|
||||
},
|
||||
// Minutes schedule options
|
||||
{
|
||||
id: 'minutesInterval',
|
||||
title: 'Run Every',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '15 minutes',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'minutes',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'minutesStartingAt',
|
||||
title: 'Starting At',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '09:00',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'minutes',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Hourly schedule options
|
||||
{
|
||||
id: 'hourlyMinute',
|
||||
title: 'Start at Minute',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '00',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'hourly',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Daily schedule options
|
||||
{
|
||||
id: 'dailyTime',
|
||||
title: 'Time',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '09:00',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'daily',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Weekly schedule options
|
||||
{
|
||||
id: 'weeklyDay',
|
||||
title: 'Day of Week',
|
||||
type: 'dropdown',
|
||||
layout: 'half',
|
||||
options: [
|
||||
{ label: 'Monday', id: 'MON' },
|
||||
{ label: 'Tuesday', id: 'TUE' },
|
||||
{ label: 'Wednesday', id: 'WED' },
|
||||
{ label: 'Thursday', id: 'THU' },
|
||||
{ label: 'Friday', id: 'FRI' },
|
||||
{ label: 'Saturday', id: 'SAT' },
|
||||
{ label: 'Sunday', id: 'SUN' },
|
||||
],
|
||||
value: () => 'MON',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'weekly',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'weeklyDayTime',
|
||||
title: 'Time',
|
||||
type: 'short-input',
|
||||
layout: 'half',
|
||||
placeholder: '09:00',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'weekly',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Monthly schedule options
|
||||
{
|
||||
id: 'monthlyDay',
|
||||
title: 'Day of Month',
|
||||
type: 'short-input',
|
||||
layout: 'half',
|
||||
placeholder: '1',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'monthly',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monthlyTime',
|
||||
title: 'Time',
|
||||
type: 'short-input',
|
||||
layout: 'half',
|
||||
placeholder: '09:00',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'monthly',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Custom cron options
|
||||
{
|
||||
id: 'cronExpression',
|
||||
title: 'Cron Expression',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '*/15 * * * *',
|
||||
condition: {
|
||||
field: 'scheduleType',
|
||||
value: 'custom',
|
||||
and: {
|
||||
field: 'startWorkflow',
|
||||
value: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
// Timezone configuration (for all schedule types)
|
||||
{
|
||||
id: 'timezone',
|
||||
title: 'Timezone',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'UTC', id: 'UTC' },
|
||||
{ label: 'US Eastern (UTC-4)', id: 'America/New_York' },
|
||||
{ label: 'US Central (UTC-5)', id: 'America/Chicago' },
|
||||
{ label: 'US Mountain (UTC-6)', id: 'America/Denver' },
|
||||
{ label: 'US Pacific (UTC-7)', id: 'America/Los_Angeles' },
|
||||
{ label: 'London (UTC+1)', id: 'Europe/London' },
|
||||
{ label: 'Paris (UTC+2)', id: 'Europe/Paris' },
|
||||
{ label: 'Singapore (UTC+8)', id: 'Asia/Singapore' },
|
||||
{ label: 'Tokyo (UTC+9)', id: 'Asia/Tokyo' },
|
||||
{ label: 'Sydney (UTC+10)', id: 'Australia/Sydney' },
|
||||
],
|
||||
value: () => 'UTC',
|
||||
condition: { field: 'startWorkflow', value: 'schedule' },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { NotionBlock } from './blocks/notion'
|
||||
import { RouterBlock } from './blocks/router'
|
||||
import { SerperBlock } from './blocks/serper'
|
||||
import { SlackMessageBlock } from './blocks/slack'
|
||||
import { StarterBlock } from './blocks/starter'
|
||||
import { TavilyBlock } from './blocks/tavily'
|
||||
import { TranslateBlock } from './blocks/translate'
|
||||
import { XBlock } from './blocks/x'
|
||||
@@ -39,12 +40,14 @@ export {
|
||||
NotionBlock,
|
||||
GmailBlock,
|
||||
XBlock,
|
||||
StarterBlock,
|
||||
}
|
||||
|
||||
// Registry of all block configurations
|
||||
const blocks: Record<string, BlockConfig> = {
|
||||
agent: AgentBlock,
|
||||
api: ApiBlock,
|
||||
starter: StarterBlock,
|
||||
condition: ConditionBlock,
|
||||
function: FunctionBlock,
|
||||
router: RouterBlock,
|
||||
|
||||
@@ -81,6 +81,10 @@ export interface SubBlockConfig {
|
||||
condition?: {
|
||||
field: string
|
||||
value: string | number | boolean
|
||||
and?: {
|
||||
field: string
|
||||
value: string | number | boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1370,3 +1370,21 @@ export function InputIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function StartIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
width="26"
|
||||
height="16"
|
||||
viewBox="0 0 26 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.8 13C9.23 13 10.4542 12.4908 11.4725 11.4725C12.4908 10.4542 13 9.23 13 7.8C13 6.37 12.4908 5.14583 11.4725 4.1275C10.4542 3.10917 9.23 2.6 7.8 2.6C6.37 2.6 5.14583 3.10917 4.1275 4.1275C3.10917 5.14583 2.6 6.37 2.6 7.8C2.6 9.23 3.10917 10.4542 4.1275 11.4725C5.14583 12.4908 6.37 13 7.8 13ZM7.8 15.6C5.63333 15.6 3.79167 14.8417 2.275 13.325C0.758333 11.8083 0 9.96666 0 7.8C0 5.63333 0.758333 3.79167 2.275 2.275C3.79167 0.758333 5.63333 0 7.8 0C9.75 0 11.4456 0.6175 12.8869 1.8525C14.3282 3.0875 15.2 4.63667 15.5025 6.5H24.7C25.0683 6.5 25.3773 6.6248 25.6269 6.8744C25.8765 7.124 26.0009 7.43253 26 7.8C25.9991 8.16746 25.8743 8.47643 25.6256 8.7269C25.3769 8.97737 25.0683 9.10173 24.7 9.1H15.5025C15.1992 10.9633 14.3269 12.5125 12.8856 13.7475C11.4443 14.9825 9.74913 15.6 7.8 15.6Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user