Skip to content

Commit e70e1ec

Browse files
authored
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
1 parent 4c474e0 commit e70e1ec

File tree

5 files changed

+132
-0
lines changed

5 files changed

+132
-0
lines changed

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/_components/command-items.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,27 @@ export const MemoizedPageItem = memo(
163163
prev.name === next.name &&
164164
prev.shortcut === next.shortcut
165165
)
166+
167+
export const MemoizedIconItem = memo(
168+
function IconItem({
169+
value,
170+
onSelect,
171+
name,
172+
icon: Icon,
173+
}: {
174+
value: string
175+
onSelect: () => void
176+
name: string
177+
icon: ComponentType<{ className?: string }>
178+
}) {
179+
return (
180+
<Command.Item value={value} onSelect={onSelect} className={COMMAND_ITEM_CLASSNAME}>
181+
<div className='relative flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center'>
182+
<Icon className='h-[14px] w-[14px] text-[var(--text-icon)]' />
183+
</div>
184+
<span className='truncate font-base text-[var(--text-body)]'>{name}</span>
185+
</Command.Item>
186+
)
187+
},
188+
(prev, next) => prev.value === next.value && prev.name === next.name && prev.icon === next.icon
189+
)

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/_components/search-groups.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
'use client'
22

3+
import type { ComponentType } from 'react'
34
import { memo } from 'react'
45
import { Command } from 'cmdk'
6+
import { Database, File, Table } from '@/components/emcn/icons'
57
import type {
68
SearchBlockItem,
79
SearchDocItem,
@@ -11,6 +13,7 @@ import type { PageItem, TaskItem, WorkflowItem, WorkspaceItem } from '../utils'
1113
import { GROUP_HEADING_CLASSNAME } from '../utils'
1214
import {
1315
MemoizedCommandItem,
16+
MemoizedIconItem,
1417
MemoizedPageItem,
1518
MemoizedTaskItem,
1619
MemoizedWorkflowItem,
@@ -239,3 +242,36 @@ export const PagesGroup = memo(function PagesGroup({
239242
</Command.Group>
240243
)
241244
})
245+
246+
export const TablesGroup = createIconGroup('Tables', 'table', Table)
247+
export const FilesGroup = createIconGroup('Files', 'file', File)
248+
export const KnowledgeBasesGroup = createIconGroup('Knowledge Bases', 'knowledge-base', Database)
249+
250+
function createIconGroup(
251+
heading: string,
252+
prefix: string,
253+
icon: ComponentType<{ className?: string }>
254+
) {
255+
return memo(function IconGroup({
256+
items,
257+
onSelect,
258+
}: {
259+
items: TaskItem[]
260+
onSelect: (item: TaskItem) => void
261+
}) {
262+
if (items.length === 0) return null
263+
return (
264+
<Command.Group heading={heading} className={GROUP_HEADING_CLASSNAME}>
265+
{items.map((item) => (
266+
<MemoizedIconItem
267+
key={item.id}
268+
value={`${item.name} ${prefix}-${item.id}`}
269+
onSelect={() => onSelect(item)}
270+
name={item.name}
271+
icon={icon}
272+
/>
273+
))}
274+
</Command.Group>
275+
)
276+
})
277+
}

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import type {
2121
import {
2222
BlocksGroup,
2323
DocsGroup,
24+
FilesGroup,
25+
KnowledgeBasesGroup,
2426
PagesGroup,
27+
TablesGroup,
2528
TasksGroup,
2629
ToolOpsGroup,
2730
ToolsGroup,
@@ -40,6 +43,9 @@ export function SearchModal({
4043
workflows = [],
4144
workspaces = [],
4245
tasks = [],
46+
tables = [],
47+
files = [],
48+
knowledgeBases = [],
4349
isOnWorkflowPage = false,
4450
}: SearchModalProps) {
4551
const params = useParams()
@@ -284,6 +290,20 @@ export function SearchModal({
284290
return filterAndSort(docs, (d) => `${d.name} docs documentation doc-${d.id}`, deferredSearch)
285291
}, [isOnWorkflowPage, docs, deferredSearch])
286292

293+
const filteredTables = useMemo(
294+
() => filterAndSort(tables, (t) => `${t.name} table-${t.id}`, deferredSearch),
295+
[tables, deferredSearch]
296+
)
297+
const filteredFiles = useMemo(
298+
() => filterAndSort(files, (f) => `${f.name} file-${f.id}`, deferredSearch),
299+
[files, deferredSearch]
300+
)
301+
const filteredKnowledgeBases = useMemo(
302+
() =>
303+
filterAndSort(knowledgeBases, (kb) => `${kb.name} knowledge-base-${kb.id}`, deferredSearch),
304+
[knowledgeBases, deferredSearch]
305+
)
306+
287307
const filteredWorkflows = useMemo(
288308
() => filterAndSort(workflows, (w) => `${w.name} workflow-${w.id}`, deferredSearch),
289309
[workflows, deferredSearch]
@@ -346,6 +366,9 @@ export function SearchModal({
346366
<TriggersGroup items={filteredTriggers} onSelect={handleBlockSelectAsTrigger} />
347367
<WorkflowsGroup items={filteredWorkflows} onSelect={handleWorkflowSelect} />
348368
<TasksGroup items={filteredTasks} onSelect={handleTaskSelect} />
369+
<TablesGroup items={filteredTables} onSelect={handleTaskSelect} />
370+
<FilesGroup items={filteredFiles} onSelect={handleTaskSelect} />
371+
<KnowledgeBasesGroup items={filteredKnowledgeBases} onSelect={handleTaskSelect} />
349372
<ToolOpsGroup items={filteredToolOps} onSelect={handleToolOperationSelect} />
350373
<WorkspacesGroup items={filteredWorkspaces} onSelect={handleWorkspaceSelect} />
351374
<DocsGroup items={filteredDocs} onSelect={handleDocSelect} />

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ export interface SearchModalProps {
3737
workflows?: WorkflowItem[]
3838
workspaces?: WorkspaceItem[]
3939
tasks?: TaskItem[]
40+
tables?: TaskItem[]
41+
files?: TaskItem[]
42+
knowledgeBases?: TaskItem[]
4043
isOnWorkflowPage?: boolean
4144
}
4245

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ import {
7777
} from '@/app/workspace/[workspaceId]/w/hooks'
7878
import { getBrandConfig } from '@/ee/whitelabeling'
7979
import { useFolders } from '@/hooks/queries/folders'
80+
import { useKnowledgeBasesQuery } from '@/hooks/queries/kb/knowledge'
81+
import { useTablesList } from '@/hooks/queries/tables'
8082
import {
8183
useDeleteTask,
8284
useDeleteTasks,
@@ -85,6 +87,7 @@ import {
8587
useRenameTask,
8688
useTasks,
8789
} from '@/hooks/queries/tasks'
90+
import { useWorkspaceFiles } from '@/hooks/queries/workspace-files'
8891
import { usePermissionConfig } from '@/hooks/use-permission-config'
8992
import { useSettingsNavigation } from '@/hooks/use-settings-navigation'
9093
import { useTaskEvents } from '@/hooks/use-task-events'
@@ -745,6 +748,46 @@ export const Sidebar = memo(function Sidebar() {
745748
[fetchedTasks, workspaceId]
746749
)
747750

751+
const { data: fetchedTables = [] } = useTablesList(workspaceId)
752+
const { data: fetchedFiles = [] } = useWorkspaceFiles(workspaceId)
753+
const { data: fetchedKnowledgeBases = [] } = useKnowledgeBasesQuery(workspaceId)
754+
755+
const searchModalTables = useMemo(
756+
() =>
757+
permissionConfig.hideTablesTab
758+
? []
759+
: fetchedTables.map((t) => ({
760+
id: t.id,
761+
name: t.name,
762+
href: `/workspace/${workspaceId}/tables/${t.id}`,
763+
})),
764+
[fetchedTables, workspaceId, permissionConfig.hideTablesTab]
765+
)
766+
767+
const searchModalFiles = useMemo(
768+
() =>
769+
permissionConfig.hideFilesTab
770+
? []
771+
: fetchedFiles.map((f) => ({
772+
id: f.id,
773+
name: f.name,
774+
href: `/workspace/${workspaceId}/files/${f.id}`,
775+
})),
776+
[fetchedFiles, workspaceId, permissionConfig.hideFilesTab]
777+
)
778+
779+
const searchModalKnowledgeBases = useMemo(
780+
() =>
781+
permissionConfig.hideKnowledgeBaseTab
782+
? []
783+
: fetchedKnowledgeBases.map((kb) => ({
784+
id: kb.id,
785+
name: kb.name,
786+
href: `/workspace/${workspaceId}/knowledge/${kb.id}`,
787+
})),
788+
[fetchedKnowledgeBases, workspaceId, permissionConfig.hideKnowledgeBaseTab]
789+
)
790+
748791
const taskIds = useMemo(() => tasks.map((t) => t.id).filter((id) => id !== 'new'), [tasks])
749792

750793
const { selectedTasks, handleTaskClick } = useTaskSelection({ taskIds })
@@ -1671,6 +1714,9 @@ export const Sidebar = memo(function Sidebar() {
16711714
workflows={searchModalWorkflows}
16721715
workspaces={searchModalWorkspaces}
16731716
tasks={tasks}
1717+
tables={searchModalTables}
1718+
files={searchModalFiles}
1719+
knowledgeBases={searchModalKnowledgeBases}
16741720
isOnWorkflowPage={!!workflowId}
16751721
/>
16761722

0 commit comments

Comments
 (0)