Files
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

205 lines
5.8 KiB
TypeScript

import { RepeatIcon, SplitIcon } from 'lucide-react'
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { getToolOperationsIndex } from '@/lib/search/tool-operations'
import { getTriggersForSidebar } from '@/lib/workflows/triggers/trigger-utils'
import { getAllBlocks } from '@/blocks'
import type { BlockConfig, SubBlockConfig } from '@/blocks/types'
import type {
SearchBlockItem,
SearchData,
SearchDocItem,
SearchModalState,
SearchToolOperationItem,
} from './types'
const initialData: SearchData = {
blocks: [],
tools: [],
triggers: [],
toolOperations: [],
docs: [],
isInitialized: false,
}
type CommandSearchableOption = {
label: string
id: string
hidden?: boolean
}
function getCommandSearchableOptions(subBlock: SubBlockConfig): CommandSearchableOption[] {
if (!subBlock.options) return []
try {
const options = typeof subBlock.options === 'function' ? subBlock.options() : subBlock.options
return Array.isArray(options) ? options : []
} catch {
return []
}
}
export function buildCommandSearchableOptionSearchValue(block: BlockConfig): string {
const terms = new Set<string>()
for (const subBlock of block.subBlocks) {
if (
(subBlock.type !== 'dropdown' && subBlock.type !== 'combobox') ||
!subBlock.commandSearchable
) {
continue
}
for (const option of getCommandSearchableOptions(subBlock)) {
if (option.hidden) continue
const subBlockTitle = subBlock.title ?? subBlock.id
terms.add(subBlockTitle)
terms.add(option.label)
terms.add(option.id)
}
}
return Array.from(terms).join(' ')
}
export const useSearchModalStore = create<SearchModalState>()(
devtools(
(set, _) => ({
isOpen: false,
sections: null,
pendingConnect: null,
data: initialData,
setOpen: (open: boolean) => {
set({ isOpen: open, sections: null, pendingConnect: null })
},
open: (options) => {
set({
isOpen: true,
sections: options?.sections ?? null,
pendingConnect: options?.pendingConnect ?? null,
})
},
close: () => {
set({ isOpen: false, sections: null, pendingConnect: null })
},
initializeData: (filterBlocks) => {
const allBlocks = getAllBlocks()
const filteredAllBlocks = filterBlocks(allBlocks) as typeof allBlocks
const regularBlocks: SearchBlockItem[] = []
const tools: SearchBlockItem[] = []
const docs: SearchDocItem[] = []
for (const block of filteredAllBlocks) {
if (block.hideFromToolbar) continue
const searchItem: SearchBlockItem = {
id: block.type,
name: block.name,
icon: block.icon,
bgColor: block.bgColor || '#6B7280',
type: block.type,
searchValue: `${block.name} ${block.type} ${buildCommandSearchableOptionSearchValue(block)}`,
}
if (block.category === 'blocks' && block.type !== 'starter') {
regularBlocks.push(searchItem)
} else if (block.category === 'tools') {
tools.push(searchItem)
}
if (block.docsLink) {
docs.push({
id: `docs-${block.type}`,
name: block.name,
icon: block.icon,
href: block.docsLink,
})
}
}
const specialBlocks: SearchBlockItem[] = [
{
id: 'loop',
name: 'Loop',
icon: RepeatIcon,
bgColor: '#2FB3FF',
type: 'loop',
},
{
id: 'parallel',
name: 'Parallel',
icon: SplitIcon,
bgColor: '#FEE12B',
type: 'parallel',
},
]
const blocks = [...regularBlocks, ...(filterBlocks(specialBlocks) as SearchBlockItem[])]
const allTriggers = getTriggersForSidebar()
const filteredTriggers = filterBlocks(allTriggers) as typeof allTriggers
const priorityOrder = ['Start', 'Schedule', 'Webhook']
const sortedTriggers = [...filteredTriggers].sort(
(a: (typeof filteredTriggers)[number], b: (typeof filteredTriggers)[number]) => {
const aIndex = priorityOrder.indexOf(a.name)
const bIndex = priorityOrder.indexOf(b.name)
const aHasPriority = aIndex !== -1
const bHasPriority = bIndex !== -1
if (aHasPriority && bHasPriority) return aIndex - bIndex
if (aHasPriority) return -1
if (bHasPriority) return 1
return a.name.localeCompare(b.name)
}
)
const triggers = sortedTriggers.map(
(block): SearchBlockItem => ({
id: block.type,
name: block.name,
icon: block.icon,
bgColor: block.bgColor || '#6B7280',
type: block.type,
config: block,
})
)
const allowedBlockTypes = new Set(tools.map((t) => t.type))
const toolOperations: SearchToolOperationItem[] = getToolOperationsIndex()
.filter((op) => allowedBlockTypes.has(op.blockType))
.map((op) => {
const aliasesStr = op.aliases?.length ? ` ${op.aliases.join(' ')}` : ''
return {
id: op.id,
name: op.operationName,
searchValue: `${op.serviceName} ${op.operationName}${aliasesStr}`,
icon: op.icon,
bgColor: op.bgColor,
blockType: op.blockType,
operationId: op.operationId,
}
})
set({
data: {
blocks,
tools,
triggers,
toolOperations,
docs,
isInitialized: true,
},
})
},
}),
{ name: 'search-modal-store' }
)
)