Skip to content

Commit 2ae1ad2

Browse files
feat(ui): Add slack manifest generator (#4237)
* feat(slack): add manifest copying * Try using wizard modal * clean up modal * feat(ui): Add wizard emcn component * Made modal subblock more generic * Fix test * Address greptile comments * fix handle copy behavior * Add secret input emcn type * Lint code
1 parent febc36f commit 2ae1ad2

File tree

12 files changed

+1101
-38
lines changed

12 files changed

+1101
-38
lines changed

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

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,56 @@
1-
import { Checkbox, Label } from '@/components/emcn'
1+
import { Info } from 'lucide-react'
2+
import { Checkbox, Label, Tooltip } from '@/components/emcn'
23
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value'
34

5+
interface CheckboxListOption {
6+
label: string
7+
id: string
8+
defaultChecked?: boolean
9+
description?: string
10+
}
11+
412
interface CheckboxListProps {
513
blockId: string
6-
subBlockId: string
7-
title: string
8-
options: { label: string; id: string }[]
14+
options: CheckboxListOption[]
915
isPreview?: boolean
1016
subBlockValues?: Record<string, any>
1117
disabled?: boolean
1218
}
1319

1420
interface CheckboxItemProps {
1521
blockId: string
16-
option: { label: string; id: string }
22+
option: CheckboxListOption
1723
isPreview: boolean
1824
subBlockValues?: Record<string, any>
1925
disabled: boolean
2026
}
2127

2228
/**
23-
* Individual checkbox item component that calls useSubBlockValue hook at top level
29+
* Individual checkbox item component that calls useSubBlockValue hook at top level.
30+
*
31+
* @remarks
32+
* A `null` store value means the user has never toggled the checkbox, in which
33+
* case we fall back to `option.defaultChecked` for the displayed state. Any
34+
* explicit boolean (including `false`) takes precedence over the default.
2435
*/
2536
function CheckboxItem({ blockId, option, isPreview, subBlockValues, disabled }: CheckboxItemProps) {
26-
const [storeValue, setStoreValue] = useSubBlockValue(blockId, option.id)
37+
const [storeValue, setStoreValue] = useSubBlockValue<boolean>(blockId, option.id)
2738

28-
// Get preview value for this specific option
2939
const previewValue = isPreview && subBlockValues ? subBlockValues[option.id]?.value : undefined
30-
31-
// Use preview value when in preview mode, otherwise use store value
32-
const value = isPreview ? previewValue : storeValue
40+
const rawValue = isPreview ? previewValue : storeValue
41+
const effectiveValue = rawValue ?? option.defaultChecked ?? false
3342

3443
const handleChange = (checked: boolean) => {
35-
// Only update store when not in preview mode or disabled
3644
if (!isPreview && !disabled) {
3745
setStoreValue(checked)
3846
}
3947
}
4048

4149
return (
42-
<div className='flex items-center space-x-2'>
50+
<div className='flex items-center gap-2'>
4351
<Checkbox
4452
id={`${blockId}-${option.id}`}
45-
checked={Boolean(value)}
53+
checked={Boolean(effectiveValue)}
4654
onCheckedChange={handleChange}
4755
disabled={isPreview || disabled}
4856
/>
@@ -52,21 +60,29 @@ function CheckboxItem({ blockId, option, isPreview, subBlockValues, disabled }:
5260
>
5361
{option.label}
5462
</Label>
63+
{option.description && (
64+
<Tooltip.Root>
65+
<Tooltip.Trigger asChild>
66+
<Info className='h-[14px] w-[14px] cursor-default text-[var(--text-muted)]' />
67+
</Tooltip.Trigger>
68+
<Tooltip.Content side='top' align='start' className='max-w-xs'>
69+
<p>{option.description}</p>
70+
</Tooltip.Content>
71+
</Tooltip.Root>
72+
)}
5573
</div>
5674
)
5775
}
5876

5977
export function CheckboxList({
6078
blockId,
61-
subBlockId,
62-
title,
6379
options,
6480
isPreview = false,
6581
subBlockValues,
6682
disabled = false,
6783
}: CheckboxListProps) {
6884
return (
69-
<div className='grid grid-cols-1 gap-4 pt-1'>
85+
<div className='flex flex-col gap-y-2.5 pt-1'>
7086
{options.map((option) => (
7187
<CheckboxItem
7288
key={option.id}
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { SlackSetupWizard } from './slack-setup-wizard'

0 commit comments

Comments
 (0)