Added checkbox list subblock; added checkbox list to Jina; reorganized block configs to have API subblock last

This commit is contained in:
Emir Karabeg
2025-02-04 12:34:44 -08:00
parent 58fc54f8e8
commit d419e9879a
10 changed files with 196 additions and 54 deletions

View File

@@ -0,0 +1,81 @@
import { Label } from '@/components/ui/label'
import { Checkbox } from '@/components/ui/checkbox'
import { useSubBlockValue } from '../hooks/use-sub-block-value'
import { cn } from '@/lib/utils'
import { useEffect } from 'react'
interface CheckboxListProps {
blockId: string
subBlockId: string
title: string
options: { label: string; id: string }[]
layout?: 'full' | 'half'
}
export function CheckboxList({
blockId,
subBlockId,
title,
options,
layout,
}: CheckboxListProps) {
const [value, setValue] = useSubBlockValue(blockId, subBlockId)
// Initialize values with all options set to false by default
const values = (() => {
const defaultValues = options.reduce(
(acc, option) => ({
...acc,
[option.id]: false,
}),
{}
)
return {
...defaultValues,
...(typeof value === 'object' && value !== null ? value : {}),
}
})() as Record<string, boolean>
// Move initialization to useEffect
useEffect(() => {
if (value === null) {
setValue(values)
}
}, [value, setValue, values])
const handleCheckedChange = (id: string, checked: boolean) => {
setValue({
...values,
[id]: checked,
})
}
return (
<div
className={cn(
'grid gap-4',
layout === 'half' ? 'grid-cols-2' : 'grid-cols-1',
'pt-1'
)}
>
{options.map((option) => (
<div key={option.id} className="flex items-center space-x-2">
<Checkbox
id={`${blockId}-${subBlockId}-${option.id}`}
checked={Boolean(values[option.id])}
onCheckedChange={(checked) =>
handleCheckedChange(option.id, checked as boolean)
}
/>
<Label
htmlFor={`${blockId}-${subBlockId}-${option.id}`}
className="text-sm font-normal leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer"
>
{option.label}
</Label>
</div>
))}
</div>
)
}

View File

@@ -8,6 +8,7 @@ import { Table } from './components/table'
import { Code } from './components/code'
import { Switch } from './components/switch'
import { ToolInput } from './components/tool-input'
import { CheckboxList } from './components/checkbox-list'
interface SubBlockProps {
blockId: string
@@ -53,7 +54,7 @@ export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
<Dropdown
blockId={blockId}
subBlockId={config.id}
options={config.options ?? []}
options={config.options as string[]}
/>
</div>
)
@@ -95,6 +96,16 @@ export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
)
case 'tool-input':
return <ToolInput blockId={blockId} subBlockId={config.id} />
case 'checkbox-list':
return (
<CheckboxList
blockId={blockId}
subBlockId={config.id}
title={config.title}
options={config.options as { label: string; id: string }[]}
layout={config.layout}
/>
)
default:
return null
}

View File

@@ -49,6 +49,13 @@ export const CrewAIVisionBlock: BlockConfig<VisionResponse> = {
'claude-3-sonnet-20240229'
]
},
{
id: 'prompt',
title: 'Prompt',
type: 'long-input',
layout: 'full',
placeholder: 'Enter prompt for image analysis (optional)'
},
{
id: 'apiKey',
title: 'API Key',
@@ -56,14 +63,7 @@ export const CrewAIVisionBlock: BlockConfig<VisionResponse> = {
layout: 'full',
placeholder: 'Enter your API key',
password: true
},
{
id: 'prompt',
title: 'Custom Prompt',
type: 'long-input',
layout: 'full',
placeholder: 'Enter custom prompt for image analysis (optional)'
}
},
]
}
}

View File

@@ -30,6 +30,19 @@ export const FirecrawlScrapeBlock: BlockConfig<ScrapeResponse> = {
}
},
subBlocks: [
{
id: 'url',
title: 'Website URL',
type: 'short-input',
layout: 'full',
placeholder: 'Enter the webpage URL to scrape'
},
{
id: 'onlyMainContent',
title: 'Only Main Content',
type: 'switch',
layout: 'half'
},
{
id: 'apiKey',
title: 'API Key',
@@ -38,19 +51,6 @@ export const FirecrawlScrapeBlock: BlockConfig<ScrapeResponse> = {
placeholder: 'Enter your Firecrawl API key',
password: true
},
{
id: 'url',
title: 'Website URL',
type: 'short-input',
layout: 'full',
placeholder: 'Enter the webpage URL to scrape'
},
{
id: 'onlyMainContent',
title: 'Only Main Content',
type: 'switch',
layout: 'half'
}
]
}
}

View File

@@ -38,28 +38,16 @@ export const JinaBlock: BlockConfig<ReadUrlResponse> = {
placeholder: 'Enter URL to read',
},
{
id: 'useReaderLMv2',
title: 'Use ReaderLM v2',
type: 'switch',
layout: 'half',
},
{
id: 'removeImages',
title: 'Remove Images',
type: 'switch',
layout: 'half',
},
{
id: 'gatherLinks',
title: 'Gather Links',
type: 'switch',
layout: 'half',
},
{
id: 'jsonResponse',
title: 'JSON Response',
type: 'switch',
id: 'options',
title: 'Options',
type: 'checkbox-list',
layout: 'half',
options: [
{ label: 'Use ReaderLM v2', id: 'useReaderLMv2' },
{ label: 'Remove Images', id: 'removeImages' },
{ label: 'Gather Links', id: 'gatherLinks' },
{ label: 'JSON Response', id: 'jsonResponse' }
]
},
{
id: 'apiKey',

View File

@@ -29,15 +29,6 @@ export const SlackMessageBlock: BlockConfig<SlackMessageResponse> = {
}
},
subBlocks: [
{
id: 'apiKey',
title: 'OAuth Token',
type: 'short-input',
layout: 'full',
placeholder: 'Enter your Slack OAuth token',
password: true,
connectionDroppable: false
},
{
id: 'channel',
title: 'Channel',
@@ -51,6 +42,15 @@ export const SlackMessageBlock: BlockConfig<SlackMessageResponse> = {
type: 'long-input',
layout: 'full',
placeholder: 'Enter your alert message'
},
{
id: 'apiKey',
title: 'OAuth Token',
type: 'short-input',
layout: 'full',
placeholder: 'Enter your Slack OAuth token',
password: true,
connectionDroppable: false
}
]
}

View File

@@ -15,7 +15,7 @@ export type BlockOutput =
export type ParamType = 'string' | 'number' | 'boolean' | 'json'
export type SubBlockType = 'short-input' | 'long-input' | 'dropdown' | 'slider' | 'table' | 'code' | 'switch' | 'tool-input'
export type SubBlockType = 'short-input' | 'long-input' | 'dropdown' | 'slider' | 'table' | 'code' | 'switch' | 'tool-input' | 'checkbox-list'
export type SubBlockLayout = 'full' | 'half'
export interface ParamConfig {
@@ -28,7 +28,7 @@ export interface SubBlockConfig {
title: string
type: SubBlockType
layout?: SubBlockLayout
options?: string[]
options?: string[] | { label: string; id: string }[]
min?: number
max?: number
columns?: string[]

View File

@@ -0,0 +1,30 @@
"use client"
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"
import { cn } from "@/lib/utils"
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName
export { Checkbox }

31
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.5",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.5",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",
@@ -2050,6 +2051,36 @@
}
}
},
"node_modules/@radix-ui/react-checkbox": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.3.tgz",
"integrity": "sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-use-controllable-state": "1.1.0",
"@radix-ui/react-use-previous": "1.1.0",
"@radix-ui/react-use-size": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz",

View File

@@ -12,6 +12,7 @@
},
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.5",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.5",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",