mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
feat(search): add tables, files, knowledge bases, and jobs to cmd-k search (#3800)
* feat(search): add tables, files, knowledge bases, and jobs to cmd-k search * fix(search): address PR feedback — drop files/jobs, add onSelect to memo * fix(search): add files back with per-file deep links, keep jobs out * fix(search): remove onSelect from memo comparator to match existing pattern
This commit is contained in:
@@ -163,3 +163,27 @@ export const MemoizedPageItem = memo(
|
||||
prev.name === next.name &&
|
||||
prev.shortcut === next.shortcut
|
||||
)
|
||||
|
||||
export const MemoizedIconItem = memo(
|
||||
function IconItem({
|
||||
value,
|
||||
onSelect,
|
||||
name,
|
||||
icon: Icon,
|
||||
}: {
|
||||
value: string
|
||||
onSelect: () => void
|
||||
name: string
|
||||
icon: ComponentType<{ className?: string }>
|
||||
}) {
|
||||
return (
|
||||
<Command.Item value={value} onSelect={onSelect} className={COMMAND_ITEM_CLASSNAME}>
|
||||
<div className='relative flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center'>
|
||||
<Icon className='h-[14px] w-[14px] text-[var(--text-icon)]' />
|
||||
</div>
|
||||
<span className='truncate font-base text-[var(--text-body)]'>{name}</span>
|
||||
</Command.Item>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.value === next.value && prev.name === next.name && prev.icon === next.icon
|
||||
)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import type { ComponentType } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { Command } from 'cmdk'
|
||||
import { Database, File, Table } from '@/components/emcn/icons'
|
||||
import type {
|
||||
SearchBlockItem,
|
||||
SearchDocItem,
|
||||
@@ -11,6 +13,7 @@ import type { PageItem, TaskItem, WorkflowItem, WorkspaceItem } from '../utils'
|
||||
import { GROUP_HEADING_CLASSNAME } from '../utils'
|
||||
import {
|
||||
MemoizedCommandItem,
|
||||
MemoizedIconItem,
|
||||
MemoizedPageItem,
|
||||
MemoizedTaskItem,
|
||||
MemoizedWorkflowItem,
|
||||
@@ -239,3 +242,36 @@ export const PagesGroup = memo(function PagesGroup({
|
||||
</Command.Group>
|
||||
)
|
||||
})
|
||||
|
||||
export const TablesGroup = createIconGroup('Tables', 'table', Table)
|
||||
export const FilesGroup = createIconGroup('Files', 'file', File)
|
||||
export const KnowledgeBasesGroup = createIconGroup('Knowledge Bases', 'knowledge-base', Database)
|
||||
|
||||
function createIconGroup(
|
||||
heading: string,
|
||||
prefix: string,
|
||||
icon: ComponentType<{ className?: string }>
|
||||
) {
|
||||
return memo(function IconGroup({
|
||||
items,
|
||||
onSelect,
|
||||
}: {
|
||||
items: TaskItem[]
|
||||
onSelect: (item: TaskItem) => void
|
||||
}) {
|
||||
if (items.length === 0) return null
|
||||
return (
|
||||
<Command.Group heading={heading} className={GROUP_HEADING_CLASSNAME}>
|
||||
{items.map((item) => (
|
||||
<MemoizedIconItem
|
||||
key={item.id}
|
||||
value={`${item.name} ${prefix}-${item.id}`}
|
||||
onSelect={() => onSelect(item)}
|
||||
name={item.name}
|
||||
icon={icon}
|
||||
/>
|
||||
))}
|
||||
</Command.Group>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ import type {
|
||||
import {
|
||||
BlocksGroup,
|
||||
DocsGroup,
|
||||
FilesGroup,
|
||||
KnowledgeBasesGroup,
|
||||
PagesGroup,
|
||||
TablesGroup,
|
||||
TasksGroup,
|
||||
ToolOpsGroup,
|
||||
ToolsGroup,
|
||||
@@ -40,6 +43,9 @@ export function SearchModal({
|
||||
workflows = [],
|
||||
workspaces = [],
|
||||
tasks = [],
|
||||
tables = [],
|
||||
files = [],
|
||||
knowledgeBases = [],
|
||||
isOnWorkflowPage = false,
|
||||
}: SearchModalProps) {
|
||||
const params = useParams()
|
||||
@@ -284,6 +290,20 @@ export function SearchModal({
|
||||
return filterAndSort(docs, (d) => `${d.name} docs documentation doc-${d.id}`, deferredSearch)
|
||||
}, [isOnWorkflowPage, docs, deferredSearch])
|
||||
|
||||
const filteredTables = useMemo(
|
||||
() => filterAndSort(tables, (t) => `${t.name} table-${t.id}`, deferredSearch),
|
||||
[tables, deferredSearch]
|
||||
)
|
||||
const filteredFiles = useMemo(
|
||||
() => filterAndSort(files, (f) => `${f.name} file-${f.id}`, deferredSearch),
|
||||
[files, deferredSearch]
|
||||
)
|
||||
const filteredKnowledgeBases = useMemo(
|
||||
() =>
|
||||
filterAndSort(knowledgeBases, (kb) => `${kb.name} knowledge-base-${kb.id}`, deferredSearch),
|
||||
[knowledgeBases, deferredSearch]
|
||||
)
|
||||
|
||||
const filteredWorkflows = useMemo(
|
||||
() => filterAndSort(workflows, (w) => `${w.name} workflow-${w.id}`, deferredSearch),
|
||||
[workflows, deferredSearch]
|
||||
@@ -346,6 +366,9 @@ export function SearchModal({
|
||||
<TriggersGroup items={filteredTriggers} onSelect={handleBlockSelectAsTrigger} />
|
||||
<WorkflowsGroup items={filteredWorkflows} onSelect={handleWorkflowSelect} />
|
||||
<TasksGroup items={filteredTasks} onSelect={handleTaskSelect} />
|
||||
<TablesGroup items={filteredTables} onSelect={handleTaskSelect} />
|
||||
<FilesGroup items={filteredFiles} onSelect={handleTaskSelect} />
|
||||
<KnowledgeBasesGroup items={filteredKnowledgeBases} onSelect={handleTaskSelect} />
|
||||
<ToolOpsGroup items={filteredToolOps} onSelect={handleToolOperationSelect} />
|
||||
<WorkspacesGroup items={filteredWorkspaces} onSelect={handleWorkspaceSelect} />
|
||||
<DocsGroup items={filteredDocs} onSelect={handleDocSelect} />
|
||||
|
||||
@@ -37,6 +37,9 @@ export interface SearchModalProps {
|
||||
workflows?: WorkflowItem[]
|
||||
workspaces?: WorkspaceItem[]
|
||||
tasks?: TaskItem[]
|
||||
tables?: TaskItem[]
|
||||
files?: TaskItem[]
|
||||
knowledgeBases?: TaskItem[]
|
||||
isOnWorkflowPage?: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,8 @@ import {
|
||||
} from '@/app/workspace/[workspaceId]/w/hooks'
|
||||
import { getBrandConfig } from '@/ee/whitelabeling'
|
||||
import { useFolders } from '@/hooks/queries/folders'
|
||||
import { useKnowledgeBasesQuery } from '@/hooks/queries/kb/knowledge'
|
||||
import { useTablesList } from '@/hooks/queries/tables'
|
||||
import {
|
||||
useDeleteTask,
|
||||
useDeleteTasks,
|
||||
@@ -85,6 +87,7 @@ import {
|
||||
useRenameTask,
|
||||
useTasks,
|
||||
} from '@/hooks/queries/tasks'
|
||||
import { useWorkspaceFiles } from '@/hooks/queries/workspace-files'
|
||||
import { usePermissionConfig } from '@/hooks/use-permission-config'
|
||||
import { useSettingsNavigation } from '@/hooks/use-settings-navigation'
|
||||
import { useTaskEvents } from '@/hooks/use-task-events'
|
||||
@@ -745,6 +748,46 @@ export const Sidebar = memo(function Sidebar() {
|
||||
[fetchedTasks, workspaceId]
|
||||
)
|
||||
|
||||
const { data: fetchedTables = [] } = useTablesList(workspaceId)
|
||||
const { data: fetchedFiles = [] } = useWorkspaceFiles(workspaceId)
|
||||
const { data: fetchedKnowledgeBases = [] } = useKnowledgeBasesQuery(workspaceId)
|
||||
|
||||
const searchModalTables = useMemo(
|
||||
() =>
|
||||
permissionConfig.hideTablesTab
|
||||
? []
|
||||
: fetchedTables.map((t) => ({
|
||||
id: t.id,
|
||||
name: t.name,
|
||||
href: `/workspace/${workspaceId}/tables/${t.id}`,
|
||||
})),
|
||||
[fetchedTables, workspaceId, permissionConfig.hideTablesTab]
|
||||
)
|
||||
|
||||
const searchModalFiles = useMemo(
|
||||
() =>
|
||||
permissionConfig.hideFilesTab
|
||||
? []
|
||||
: fetchedFiles.map((f) => ({
|
||||
id: f.id,
|
||||
name: f.name,
|
||||
href: `/workspace/${workspaceId}/files/${f.id}`,
|
||||
})),
|
||||
[fetchedFiles, workspaceId, permissionConfig.hideFilesTab]
|
||||
)
|
||||
|
||||
const searchModalKnowledgeBases = useMemo(
|
||||
() =>
|
||||
permissionConfig.hideKnowledgeBaseTab
|
||||
? []
|
||||
: fetchedKnowledgeBases.map((kb) => ({
|
||||
id: kb.id,
|
||||
name: kb.name,
|
||||
href: `/workspace/${workspaceId}/knowledge/${kb.id}`,
|
||||
})),
|
||||
[fetchedKnowledgeBases, workspaceId, permissionConfig.hideKnowledgeBaseTab]
|
||||
)
|
||||
|
||||
const taskIds = useMemo(() => tasks.map((t) => t.id).filter((id) => id !== 'new'), [tasks])
|
||||
|
||||
const { selectedTasks, handleTaskClick } = useTaskSelection({ taskIds })
|
||||
@@ -1671,6 +1714,9 @@ export const Sidebar = memo(function Sidebar() {
|
||||
workflows={searchModalWorkflows}
|
||||
workspaces={searchModalWorkspaces}
|
||||
tasks={tasks}
|
||||
tables={searchModalTables}
|
||||
files={searchModalFiles}
|
||||
knowledgeBases={searchModalKnowledgeBases}
|
||||
isOnWorkflowPage={!!workflowId}
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user