* Integration/trigger block row. The checkbox drives whole-block access * (`allowedIntegrations`); when allowed and the block exposes more than one * tool, the row expands to a per-tool deny-list grid (`deniedTools`), mirroring * the provider → models pattern.
({
block,
isBlockAllowed,
onToggleBlock,
deniedCount,
...controls
}: BlockToolRowProps)
| 475 | * the provider → models pattern. |
| 476 | */ |
| 477 | function BlockToolRow({ |
| 478 | block, |
| 479 | isBlockAllowed, |
| 480 | onToggleBlock, |
| 481 | deniedCount, |
| 482 | ...controls |
| 483 | }: BlockToolRowProps) { |
| 484 | const [expanded, setExpanded] = useState(false) |
| 485 | const BlockIcon = block.icon |
| 486 | const checkboxId = `block-${block.type}` |
| 487 | |
| 488 | const toolItems = useMemo<DenylistGridItem[]>( |
| 489 | () => (block.tools?.access ?? []).map((id) => ({ id, label: getTool(id)?.name ?? id })), |
| 490 | [block.tools?.access] |
| 491 | ) |
| 492 | const isExpandable = toolItems.length > 1 |
| 493 | |
| 494 | return ( |
| 495 | <div> |
| 496 | <div className='flex items-center gap-2 rounded-md px-2 py-[5px] transition-colors hover-hover:bg-[var(--surface-active)]'> |
| 497 | <Checkbox |
| 498 | id={checkboxId} |
| 499 | checked={isBlockAllowed} |
| 500 | onCheckedChange={() => onToggleBlock()} |
| 501 | /> |
| 502 | <div |
| 503 | className='relative flex size-[16px] flex-shrink-0 items-center justify-center overflow-hidden rounded-sm' |
| 504 | style={{ background: block.bgColor }} |
| 505 | > |
| 506 | {BlockIcon && <BlockIcon className='!h-[10px] !w-[10px] text-white' />} |
| 507 | </div> |
| 508 | <button |
| 509 | type='button' |
| 510 | onClick={() => isBlockAllowed && isExpandable && setExpanded((prev) => !prev)} |
| 511 | disabled={!isBlockAllowed || !isExpandable} |
| 512 | className={cn( |
| 513 | 'flex flex-1 items-center gap-2 text-left', |
| 514 | isBlockAllowed && isExpandable ? 'cursor-pointer' : 'cursor-default', |
| 515 | !isBlockAllowed && 'opacity-60' |
| 516 | )} |
| 517 | > |
| 518 | <span className='truncate font-medium text-sm'>{block.name}</span> |
| 519 | {isBlockAllowed && deniedCount > 0 && ( |
| 520 | <ChipTag variant='gray' className='flex-shrink-0'> |
| 521 | {deniedCount} blocked |
| 522 | </ChipTag> |
| 523 | )} |
| 524 | {isBlockAllowed && isExpandable && ( |
| 525 | <ChevronDown |
| 526 | className={cn( |
| 527 | 'ml-auto size-[14px] flex-shrink-0 text-[var(--text-icon)] transition-transform', |
| 528 | expanded && 'rotate-180' |
| 529 | )} |
| 530 | /> |
| 531 | )} |
| 532 | </button> |
| 533 | </div> |
| 534 | {expanded && isBlockAllowed && isExpandable && ( |