Skip to content

Commit 975f857

Browse files
Made modal subblock more generic
1 parent 4d9496d commit 975f857

7 files changed

Lines changed: 104 additions & 60 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export { ScheduleInfo } from './schedule-info/schedule-info'
2222
export { SelectorInput, type SelectorOverrides } from './selector-input/selector-input'
2323
export { ShortInput } from './short-input/short-input'
2424
export { SkillInput } from './skill-input/skill-input'
25-
export { SlackSetupWizard } from './slack-setup-wizard/slack-setup-wizard'
2625
export { SliderInput } from './slider-input/slider-input'
2726
export { SortBuilder } from './sort-builder/sort-builder'
2827
export { InputFormat } from './starter/input-format'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { ComponentType } from 'react'
2+
import { SlackSetupWizard } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/slack-setup-wizard/slack-setup-wizard'
3+
4+
/**
5+
* Props every `type: 'modal'` sub-block component must accept. The sub-block
6+
* dispatcher passes these through from the surrounding editor shell.
7+
*/
8+
export interface ModalSubBlockProps {
9+
blockId: string
10+
isPreview?: boolean
11+
disabled?: boolean
12+
}
13+
14+
/**
15+
* Registry of available modal sub-block components keyed by the `modalId`
16+
* string that trigger / block configs pass in their `SubBlockConfig`.
17+
*
18+
* @remarks
19+
* Adding a new modal sub-block is two lines: import the component, then
20+
* register it under a unique id. The id travels through config and
21+
* persistence as a plain string, so nothing here leaks into serialization.
22+
* Keep this file client-only — it imports React components and must not be
23+
* pulled into trigger / block config modules.
24+
*/
25+
export const MODAL_REGISTRY: Readonly<Record<string, ComponentType<ModalSubBlockProps>>> = {
26+
'slack-setup-wizard': SlackSetupWizard,
27+
}
28+
29+
export type ModalId = keyof typeof MODAL_REGISTRY

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/slack-setup-wizard/slack-setup-wizard.tsx

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -339,23 +339,14 @@ function StepSecret({ blockId, value, onChange, disabled }: StepSecretProps) {
339339
</SubStep>
340340
<SubStep n={3}>Paste it into the field below.</SubStep>
341341
</SubStepList>
342-
<div className='space-y-1.5'>
343-
<Label
344-
htmlFor={`${blockId}-wizard-signing-secret`}
345-
className='font-medium text-[var(--text-secondary)] text-xs'
346-
>
347-
Signing Secret
348-
</Label>
349-
<Input
350-
id={`${blockId}-wizard-signing-secret`}
351-
type='password'
352-
value={value}
353-
onChange={(e) => onChange(e.target.value)}
354-
disabled={disabled}
355-
placeholder='Paste your signing secret'
356-
className='h-9 text-sm'
357-
/>
358-
</div>
342+
<SecretInput
343+
id={`${blockId}-wizard-signing-secret`}
344+
label='Signing Secret'
345+
value={value}
346+
onChange={onChange}
347+
disabled={disabled}
348+
placeholder='Paste your signing secret'
349+
/>
359350
</div>
360351
)
361352
}
@@ -380,23 +371,53 @@ function StepToken({ blockId, value, onChange, disabled }: StepTokenProps) {
380371
</SubStep>
381372
<SubStep n={3}>Paste it into the field below.</SubStep>
382373
</SubStepList>
383-
<div className='space-y-1.5'>
384-
<Label
385-
htmlFor={`${blockId}-wizard-bot-token`}
386-
className='font-medium text-[var(--text-secondary)] text-xs'
387-
>
388-
Bot Token
389-
</Label>
390-
<Input
391-
id={`${blockId}-wizard-bot-token`}
392-
type='password'
393-
value={value}
394-
onChange={(e) => onChange(e.target.value)}
395-
disabled={disabled}
396-
placeholder='xoxb-...'
397-
className='h-9 text-sm'
398-
/>
399-
</div>
374+
<SecretInput
375+
id={`${blockId}-wizard-bot-token`}
376+
label='Bot Token'
377+
value={value}
378+
onChange={onChange}
379+
disabled={disabled}
380+
placeholder='xoxb-...'
381+
/>
382+
</div>
383+
)
384+
}
385+
386+
interface SecretInputProps {
387+
id: string
388+
label: string
389+
value: string
390+
onChange: (next: string) => void
391+
disabled: boolean
392+
placeholder?: string
393+
}
394+
395+
/**
396+
* Password-style input that masks its value with bullets only while the
397+
* field is unfocused. Typing, pasting, and selection all see the real text
398+
* so users can verify what they just pasted before clicking Next.
399+
*/
400+
function SecretInput({ id, label, value, onChange, disabled, placeholder }: SecretInputProps) {
401+
const [isFocused, setIsFocused] = useState<boolean>(false)
402+
const displayValue = isFocused ? value : '•'.repeat(value.length)
403+
404+
return (
405+
<div className='space-y-1.5'>
406+
<Label htmlFor={id} className='font-medium text-[var(--text-secondary)] text-xs'>
407+
{label}
408+
</Label>
409+
<Input
410+
id={id}
411+
type='text'
412+
value={displayValue}
413+
onChange={(e) => onChange(e.target.value)}
414+
onFocus={() => setIsFocused(true)}
415+
onBlur={() => setIsFocused(false)}
416+
disabled={disabled}
417+
placeholder={placeholder}
418+
autoComplete='off'
419+
className='h-9 text-sm'
420+
/>
400421
</div>
401422
)
402423
}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import {
3939
type SelectorOverrides,
4040
ShortInput,
4141
SkillInput,
42-
SlackSetupWizard,
4342
SliderInput,
4443
SortBuilder,
4544
Switch,
@@ -51,6 +50,7 @@ import {
5150
VariablesInput,
5251
WorkflowSelectorInput,
5352
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components'
53+
import { MODAL_REGISTRY } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/modal-registry'
5454
import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate'
5555
import type { SubBlockConfig } from '@/blocks/types'
5656
import { useWebhookManagement } from '@/hooks/use-webhook-management'
@@ -1137,8 +1137,17 @@ function SubBlockComponent({
11371137
}
11381138
/>
11391139
)
1140-
case 'slack-setup-wizard':
1141-
return <SlackSetupWizard blockId={blockId} isPreview={isPreview} disabled={isDisabled} />
1140+
case 'modal': {
1141+
const ModalComponent = config.modalId ? MODAL_REGISTRY[config.modalId] : undefined
1142+
if (!ModalComponent) {
1143+
return (
1144+
<div className='text-[var(--text-error)] text-sm'>
1145+
Unknown modal: {String(config.modalId)}
1146+
</div>
1147+
)
1148+
}
1149+
return <ModalComponent blockId={blockId} isPreview={isPreview} disabled={isDisabled} />
1150+
}
11421151
case 'messages-input':
11431152
return (
11441153
<MessagesInput

apps/sim/blocks/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export type SubBlockType =
162162
| 'text' // Read-only text display
163163
| 'router-input' // Router route definitions with descriptions
164164
| 'table-selector' // Table selector with link to view table
165-
| 'slack-setup-wizard' // Slack app setup wizard (manifest + credentials) in a modal
165+
| 'modal' // Launches a modal component resolved via the client-side modal registry
166166

167167
/**
168168
* Selector types that require display name hydration
@@ -330,6 +330,7 @@ export interface SubBlockConfig {
330330
hideWhenEnvSet?: string // Hide this subblock when the named NEXT_PUBLIC_ env var is truthy
331331
description?: string
332332
tooltip?: string // Tooltip text displayed via info icon next to the title
333+
modalId?: string // Registry key when type is 'modal'; see sub-block/components/modal-registry.ts
333334
value?: (params: Record<string, any>) => string
334335
grouped?: boolean
335336
scrollable?: boolean

apps/sim/triggers/slack/capabilities.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,10 @@ export const SLACK_CAPABILITIES: readonly SlackCapability[] = [
6868
events: ['message.groups'],
6969
},
7070
{
71-
id: 'trigger_public_channel_reaction',
72-
label: 'Public channel reaction',
73-
description: 'Trigger when emoji reactions are added or removed in public channels.',
74-
defaultChecked: true,
75-
group: 'trigger',
76-
scopes: ['reactions:read'],
77-
events: ['reaction_added', 'reaction_removed'],
78-
},
79-
{
80-
id: 'trigger_any_reaction',
81-
label: 'Reaction (any channel)',
82-
description: 'Trigger on any emoji reaction your bot can see — public or private.',
71+
id: 'trigger_reaction',
72+
label: 'Reaction',
73+
description:
74+
'Trigger when an emoji reaction is added or removed anywhere the bot can see — public, private, or DM. Slack does not allow restricting the reactions scope by channel type.',
8375
defaultChecked: true,
8476
group: 'trigger',
8577
scopes: ['reactions:read'],
@@ -123,14 +115,6 @@ export const SLACK_CAPABILITIES: readonly SlackCapability[] = [
123115
},
124116
] as const
125117

126-
export const SLACK_TRIGGER_OPTIONS = SLACK_CAPABILITIES.filter((c) => c.group === 'trigger').map(
127-
({ id, label, description, defaultChecked }) => ({ id, label, description, defaultChecked })
128-
)
129-
130-
export const SLACK_ACTION_OPTIONS = SLACK_CAPABILITIES.filter((c) => c.group === 'action').map(
131-
({ id, label, description, defaultChecked }) => ({ id, label, description, defaultChecked })
132-
)
133-
134118
const WEBHOOK_URL_PLACEHOLDER = '<deploy workflow to generate webhook URL>'
135119

136120
export interface BuildManifestOptions {

apps/sim/triggers/slack/webhook.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export const slackWebhookTrigger: TriggerConfig = {
5454
{
5555
id: 'setupWizard',
5656
title: 'Slack app setup',
57-
type: 'slack-setup-wizard',
57+
type: 'modal',
58+
modalId: 'slack-setup-wizard',
5859
description: 'Walk through manifest creation, app install, and pasting credentials.',
5960
hideFromPreview: true,
6061
mode: 'trigger',

0 commit comments

Comments
 (0)