mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
Added checkbox list subblock; added checkbox list to Jina; reorganized block configs to have API subblock last
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)'
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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[]
|
||||
|
||||
30
components/ui/checkbox.tsx
Normal file
30
components/ui/checkbox.tsx
Normal 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
31
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user