Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ export function ImportCsvDialog({
<div className='flex flex-col gap-4'>
<div className='flex items-center justify-between gap-3 rounded-sm border border-[var(--border)] p-2'>
<div className='flex min-w-0 flex-col'>
<span className='truncate text-caption text-[var(--text-primary)]'>
<span className='truncate text-[var(--text-primary)] text-caption'>
{parsed.file.name}
</span>
<span className='text-[var(--text-tertiary)] text-xs'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
import { Checkbox, Label } from '@/components/emcn'
import { Info } from 'lucide-react'
import { Checkbox, Label, Tooltip } from '@/components/emcn'
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value'

interface CheckboxListOption {
label: string
id: string
defaultChecked?: boolean
description?: string
}

interface CheckboxListProps {
blockId: string
subBlockId: string
title: string
options: { label: string; id: string }[]
options: CheckboxListOption[]
isPreview?: boolean
subBlockValues?: Record<string, any>
disabled?: boolean
}

interface CheckboxItemProps {
blockId: string
option: { label: string; id: string }
option: CheckboxListOption
isPreview: boolean
subBlockValues?: Record<string, any>
disabled: boolean
}

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

// Get preview value for this specific option
const previewValue = isPreview && subBlockValues ? subBlockValues[option.id]?.value : undefined

// Use preview value when in preview mode, otherwise use store value
const value = isPreview ? previewValue : storeValue
const rawValue = isPreview ? previewValue : storeValue
const effectiveValue = rawValue ?? option.defaultChecked ?? false

const handleChange = (checked: boolean) => {
// Only update store when not in preview mode or disabled
if (!isPreview && !disabled) {
setStoreValue(checked)
}
}

return (
<div className='flex items-center space-x-2'>
<div className='flex items-center gap-2'>
<Checkbox
id={`${blockId}-${option.id}`}
checked={Boolean(value)}
checked={Boolean(effectiveValue)}
onCheckedChange={handleChange}
disabled={isPreview || disabled}
/>
Expand All @@ -52,21 +60,29 @@ function CheckboxItem({ blockId, option, isPreview, subBlockValues, disabled }:
>
{option.label}
</Label>
{option.description && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Info className='h-[14px] w-[14px] cursor-default text-[var(--text-muted)]' />
</Tooltip.Trigger>
<Tooltip.Content side='top' align='start' className='max-w-xs'>
<p>{option.description}</p>
</Tooltip.Content>
</Tooltip.Root>
)}
</div>
)
}

export function CheckboxList({
blockId,
subBlockId,
title,
options,
isPreview = false,
subBlockValues,
disabled = false,
}: CheckboxListProps) {
return (
<div className='grid grid-cols-1 gap-4 pt-1'>
<div className='flex flex-col gap-y-2.5 pt-1'>
Comment thread
cursor[bot] marked this conversation as resolved.
{options.map((option) => (
<CheckboxItem
key={option.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { ComponentType } from 'react'
import { SlackSetupWizard } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/slack-setup-wizard/slack-setup-wizard'

/**
* Props every `type: 'modal'` sub-block component must accept. The sub-block
* dispatcher passes these through from the surrounding editor shell.
*/
export interface ModalSubBlockProps {
blockId: string
isPreview?: boolean
disabled?: boolean
}

/**
* Registry of available modal sub-block components keyed by the `modalId`
* string that trigger / block configs pass in their `SubBlockConfig`.
*
* @remarks
* Adding a new modal sub-block is two lines: import the component, then
* register it under a unique id. The id travels through config and
* persistence as a plain string, so nothing here leaks into serialization.
* Keep this file client-only — it imports React components and must not be
* pulled into trigger / block config modules.
*/
export const MODAL_REGISTRY: Readonly<Record<string, ComponentType<ModalSubBlockProps>>> = {
'slack-setup-wizard': SlackSetupWizard,
}

export type ModalId = keyof typeof MODAL_REGISTRY
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SlackSetupWizard } from './slack-setup-wizard'
Loading
Loading