diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
index 6a875d4a824..696c3fd82c2 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx
@@ -8,7 +8,6 @@ import { truncate } from '@sim/utils/string'
import { ChevronDown, ChevronUp, FileText, Pencil, Tag } from 'lucide-react'
import { useParams, useRouter } from 'next/navigation'
import { useQueryStates } from 'nuqs'
-import { SearchHighlight } from '@/components/ui/search-highlight'
import type { ChunkData } from '@/lib/knowledge/types'
import { formatTokenCount } from '@/lib/tokenization'
import type {
@@ -38,7 +37,7 @@ import {
documentParsers,
documentUrlKeys,
} from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/search-params'
-import { ActionBar } from '@/app/workspace/[workspaceId]/knowledge/[id]/components'
+import { ActionBar, SearchHighlight } from '@/app/workspace/[workspaceId]/knowledge/[id]/components'
import { getDocumentIcon } from '@/app/workspace/[workspaceId]/knowledge/components'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { useContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
index 205de1bd764..f5f988ec658 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
@@ -31,7 +31,6 @@ import { AlertCircle, Pencil, Plus, Tag, X } from 'lucide-react'
import { useParams, useRouter } from 'next/navigation'
import { useQueryState, useQueryStates } from 'nuqs'
import { usePostHog } from 'posthog-js/react'
-import { SearchHighlight } from '@/components/ui/search-highlight'
import { ALL_TAG_SLOTS, type AllTagSlot, getFieldTypeForSlot } from '@/lib/knowledge/constants'
import type { DocumentSortField, SortOrder } from '@/lib/knowledge/documents/types'
import { type FilterFieldType, getOperatorsForFieldType } from '@/lib/knowledge/filters/types'
@@ -59,6 +58,7 @@ import {
ConnectorsSection,
DocumentContextMenu,
RenameDocumentModal,
+ SearchHighlight,
} from '@/app/workspace/[workspaceId]/knowledge/[id]/components'
import {
addConnectorParam,
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts
index d26e85dc9e3..12e32ebf736 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts
@@ -6,3 +6,4 @@ export { ConnectorsSection } from './connectors-section'
export { DocumentContextMenu } from './document-context-menu'
export { EditConnectorModal } from './edit-connector-modal'
export { RenameDocumentModal } from './rename-document-modal'
+export { SearchHighlight } from './search-highlight'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/index.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/index.ts
new file mode 100644
index 00000000000..1144ed165cd
--- /dev/null
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/index.ts
@@ -0,0 +1 @@
+export { SearchHighlight } from './search-highlight'
diff --git a/apps/sim/components/ui/search-highlight.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/search-highlight.tsx
similarity index 85%
rename from apps/sim/components/ui/search-highlight.tsx
rename to apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/search-highlight.tsx
index 050ffc87b85..41062a49b00 100644
--- a/apps/sim/components/ui/search-highlight.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/search-highlight/search-highlight.tsx
@@ -4,6 +4,11 @@ interface SearchHighlightProps {
className?: string
}
+/**
+ * Renders `text` with substrings matching any whitespace-separated term of
+ * `searchQuery` wrapped in the highlight-match colors. Falls back to plain
+ * text when the query is empty.
+ */
export function SearchHighlight({ text, searchQuery, className = '' }: SearchHighlightProps) {
if (!searchQuery.trim()) {
return {text}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/command-items.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/command-items.tsx
index 315422c6ce0..39b7f75d312 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/command-items.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/command-items.tsx
@@ -6,56 +6,9 @@ import { cn } from '@sim/emcn'
import { File, Workflow } from '@sim/emcn/icons'
import { Command } from 'cmdk'
import type { CommandItemProps } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils'
-import {
- COMMAND_ITEM_CLASSNAME,
- fuzzyMatch,
-} from '@/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils'
+import { COMMAND_ITEM_CLASSNAME } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils'
import { getTileIconColorClass } from '@/blocks/icon-color'
-interface Segment {
- text: string
- hit: boolean
-}
-
-function buildSegments(text: string, positions: readonly number[]): Segment[] {
- const hits = new Set(positions)
- const segments: Segment[] = []
- for (let i = 0; i < text.length; i++) {
- const hit = hits.has(i)
- const last = segments[segments.length - 1]
- if (last && last.hit === hit) last.text += text[i]
- else segments.push({ text: text[i], hit })
- }
- return segments
-}
-
-/**
- * Renders `text` with the characters that match `query` emphasized. Falls back
- * to plain text when there is no query or no positional match against the
- * display text (e.g. the row matched on a hidden id rather than its label).
- */
-export const HighlightedText = memo(
- function HighlightedText({ text, query }: { text: string; query?: string }) {
- if (!query) return <>{text}>
- const { positions } = fuzzyMatch(text, query)
- if (positions.length === 0) return <>{text}>
- return (
- <>
- {buildSegments(text, positions).map((segment, index) =>
- segment.hit ? (
-
- {segment.text}
-
- ) : (
- {segment.text}
- )
- )}
- >
- )
- },
- (prev, next) => prev.text === next.text && prev.query === next.query
-)
-
export const MemoizedCommandItem = memo(
function CommandItem({
value,
@@ -64,7 +17,6 @@ export const MemoizedCommandItem = memo(
bgColor,
showColoredIcon,
label,
- query,
}: CommandItemProps) {
return (
@@ -81,9 +33,7 @@ export const MemoizedCommandItem = memo(
)}
/>
-
-
-
+ {label}
)
},
@@ -92,8 +42,7 @@ export const MemoizedCommandItem = memo(
prev.icon === next.icon &&
prev.bgColor === next.bgColor &&
prev.showColoredIcon === next.showColoredIcon &&
- prev.label === next.label &&
- prev.query === next.query
+ prev.label === next.label
)
export const MemoizedActionItem = memo(
@@ -103,21 +52,17 @@ export const MemoizedActionItem = memo(
icon: Icon,
name,
shortcut,
- query,
}: {
value: string
onSelect: () => void
icon: ComponentType<{ className?: string }>
name: string
shortcut?: string
- query?: string
}) {
return (
-
-
-
+ {name}
{shortcut && (
{shortcut}
@@ -130,8 +75,7 @@ export const MemoizedActionItem = memo(
prev.value === next.value &&
prev.icon === next.icon &&
prev.name === next.name &&
- prev.shortcut === next.shortcut &&
- prev.query === next.query
+ prev.shortcut === next.shortcut
)
export const MemoizedWorkflowItem = memo(
@@ -141,14 +85,12 @@ export const MemoizedWorkflowItem = memo(
name,
folderPath,
isCurrent,
- query,
}: {
value: string
onSelect: () => void
name: string
folderPath?: string[]
isCurrent?: boolean
- query?: string
}) {
return (
@@ -156,9 +98,7 @@ export const MemoizedWorkflowItem = memo(
-
-
-
+ {name}
{isCurrent && (current)}
{folderPath && folderPath.length > 0 && (
@@ -181,7 +121,6 @@ export const MemoizedWorkflowItem = memo(
prev.value === next.value &&
prev.name === next.name &&
prev.isCurrent === next.isCurrent &&
- prev.query === next.query &&
(prev.folderPath === next.folderPath ||
(prev.folderPath?.length === next.folderPath?.length &&
(prev.folderPath ?? []).every((segment, i) => segment === next.folderPath?.[i])))
@@ -193,13 +132,11 @@ export const MemoizedFileItem = memo(
onSelect,
name,
folderPath,
- query,
}: {
value: string
onSelect: () => void
name: string
folderPath?: string[]
- query?: string
}) {
return (
@@ -207,9 +144,7 @@ export const MemoizedFileItem = memo(
-
-
-
+ {name}
{folderPath && folderPath.length > 0 && (
@@ -230,7 +165,6 @@ export const MemoizedFileItem = memo(
(prev, next) =>
prev.value === next.value &&
prev.name === next.name &&
- prev.query === next.query &&
(prev.folderPath === next.folderPath ||
(prev.folderPath?.length === next.folderPath?.length &&
(prev.folderPath ?? []).every((segment, i) => segment === next.folderPath?.[i])))
@@ -241,22 +175,18 @@ export const MemoizedTaskItem = memo(
value,
onSelect,
name,
- query,
}: {
value: string
onSelect: () => void
name: string
- query?: string
}) {
return (
-
-
-
+ {name}
)
},
- (prev, next) => prev.value === next.value && prev.name === next.name && prev.query === next.query
+ (prev, next) => prev.value === next.value && prev.name === next.name
)
export const MemoizedWorkspaceItem = memo(
@@ -265,30 +195,23 @@ export const MemoizedWorkspaceItem = memo(
onSelect,
name,
isCurrent,
- query,
}: {
value: string
onSelect: () => void
name: string
isCurrent?: boolean
- query?: string
}) {
return (
-
-
-
+ {name}
{isCurrent && (current)}
)
},
(prev, next) =>
- prev.value === next.value &&
- prev.name === next.name &&
- prev.isCurrent === next.isCurrent &&
- prev.query === next.query
+ prev.value === next.value && prev.name === next.name && prev.isCurrent === next.isCurrent
)
export const MemoizedPageItem = memo(
@@ -298,21 +221,17 @@ export const MemoizedPageItem = memo(
icon: Icon,
name,
shortcut,
- query,
}: {
value: string
onSelect: () => void
icon: ComponentType<{ className?: string }>
name: string
shortcut?: string
- query?: string
}) {
return (
-
-
-
+ {name}
{shortcut && (
{shortcut}
@@ -325,8 +244,7 @@ export const MemoizedPageItem = memo(
prev.value === next.value &&
prev.icon === next.icon &&
prev.name === next.name &&
- prev.shortcut === next.shortcut &&
- prev.query === next.query
+ prev.shortcut === next.shortcut
)
export const MemoizedIconItem = memo(
@@ -335,26 +253,18 @@ export const MemoizedIconItem = memo(
onSelect,
name,
icon: Icon,
- query,
}: {
value: string
onSelect: () => void
name: string
icon: ComponentType<{ className?: string }>
- query?: string
}) {
return (
-
-
-
+ {name}
)
},
- (prev, next) =>
- prev.value === next.value &&
- prev.name === next.name &&
- prev.icon === next.icon &&
- prev.query === next.query
+ (prev, next) => prev.value === next.value && prev.name === next.name && prev.icon === next.icon
)
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/index.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/index.ts
index 49a29bec4d2..005b06db40f 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/index.ts
@@ -1,5 +1,4 @@
export {
- HighlightedText,
MemoizedActionItem,
MemoizedCommandItem,
MemoizedFileItem,
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/search-groups/search-groups.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/search-groups/search-groups.tsx
index 4a6eaed1524..f8e071be9d0 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/search-groups/search-groups.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/search-groups/search-groups.tsx
@@ -33,11 +33,9 @@ import type {
export const ActionsGroup = memo(function ActionsGroup({
items,
onSelect,
- query,
}: {
items: ActionItem[]
onSelect: (action: ActionItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -50,7 +48,6 @@ export const ActionsGroup = memo(function ActionsGroup({
icon={action.icon}
name={action.name}
shortcut={action.shortcut}
- query={query}
/>
))}
@@ -60,11 +57,9 @@ export const ActionsGroup = memo(function ActionsGroup({
export const BlocksGroup = memo(function BlocksGroup({
items,
onSelect,
- query,
}: {
items: SearchBlockItem[]
onSelect: (block: SearchBlockItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -78,7 +73,6 @@ export const BlocksGroup = memo(function BlocksGroup({
bgColor={block.bgColor}
showColoredIcon
label={block.name}
- query={query}
/>
))}
@@ -88,11 +82,9 @@ export const BlocksGroup = memo(function BlocksGroup({
export const ToolsGroup = memo(function ToolsGroup({
items,
onSelect,
- query,
}: {
items: SearchBlockItem[]
onSelect: (tool: SearchBlockItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -106,7 +98,6 @@ export const ToolsGroup = memo(function ToolsGroup({
bgColor={tool.bgColor}
showColoredIcon
label={tool.name}
- query={query}
/>
))}
@@ -116,11 +107,9 @@ export const ToolsGroup = memo(function ToolsGroup({
export const TriggersGroup = memo(function TriggersGroup({
items,
onSelect,
- query,
}: {
items: SearchBlockItem[]
onSelect: (trigger: SearchBlockItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -134,7 +123,6 @@ export const TriggersGroup = memo(function TriggersGroup({
bgColor={trigger.bgColor}
showColoredIcon
label={trigger.name}
- query={query}
/>
))}
@@ -144,11 +132,9 @@ export const TriggersGroup = memo(function TriggersGroup({
export const ToolOpsGroup = memo(function ToolOpsGroup({
items,
onSelect,
- query,
}: {
items: SearchToolOperationItem[]
onSelect: (op: SearchToolOperationItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -162,7 +148,6 @@ export const ToolOpsGroup = memo(function ToolOpsGroup({
bgColor={op.bgColor}
showColoredIcon
label={op.name}
- query={query}
/>
))}
@@ -172,11 +157,9 @@ export const ToolOpsGroup = memo(function ToolOpsGroup({
export const DocsGroup = memo(function DocsGroup({
items,
onSelect,
- query,
}: {
items: SearchDocItem[]
onSelect: (doc: SearchDocItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -190,7 +173,6 @@ export const DocsGroup = memo(function DocsGroup({
bgColor='#6B7280'
showColoredIcon
label={doc.name}
- query={query}
/>
))}
@@ -200,11 +182,9 @@ export const DocsGroup = memo(function DocsGroup({
export const WorkflowsGroup = memo(function WorkflowsGroup({
items,
onSelect,
- query,
}: {
items: WorkflowItem[]
onSelect: (workflow: WorkflowItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -217,7 +197,6 @@ export const WorkflowsGroup = memo(function WorkflowsGroup({
name={workflow.name}
folderPath={workflow.folderPath}
isCurrent={workflow.isCurrent}
- query={query}
/>
))}
@@ -227,11 +206,9 @@ export const WorkflowsGroup = memo(function WorkflowsGroup({
export const ChatsGroup = memo(function ChatsGroup({
items,
onSelect,
- query,
}: {
items: TaskItem[]
onSelect: (task: TaskItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -242,7 +219,6 @@ export const ChatsGroup = memo(function ChatsGroup({
value={`${task.name} task-${task.id}`}
onSelect={() => onSelect(task)}
name={task.name}
- query={query}
/>
))}
@@ -252,11 +228,9 @@ export const ChatsGroup = memo(function ChatsGroup({
export const WorkspacesGroup = memo(function WorkspacesGroup({
items,
onSelect,
- query,
}: {
items: WorkspaceItem[]
onSelect: (workspace: WorkspaceItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -268,7 +242,6 @@ export const WorkspacesGroup = memo(function WorkspacesGroup({
onSelect={() => onSelect(workspace)}
name={workspace.name}
isCurrent={workspace.isCurrent}
- query={query}
/>
))}
@@ -278,11 +251,9 @@ export const WorkspacesGroup = memo(function WorkspacesGroup({
export const PagesGroup = memo(function PagesGroup({
items,
onSelect,
- query,
}: {
items: PageItem[]
onSelect: (page: PageItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -295,7 +266,6 @@ export const PagesGroup = memo(function PagesGroup({
icon={page.icon}
name={page.name}
shortcut={page.shortcut}
- query={query}
/>
))}
@@ -311,11 +281,9 @@ export const IntegrationsGroup = createColoredIconGroup('Integrations', 'integra
export const FilesGroup = memo(function FilesGroup({
items,
onSelect,
- query,
}: {
items: FileItem[]
onSelect: (file: FileItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -327,7 +295,6 @@ export const FilesGroup = memo(function FilesGroup({
onSelect={() => onSelect(file)}
name={file.name}
folderPath={file.folderPath}
- query={query}
/>
))}
@@ -344,11 +311,9 @@ function createColoredIconGroup(heading: string, prefix: string) {
return memo(function ColoredIconGroup({
items,
onSelect,
- query,
}: {
items: IntegrationSearchItem[]
onSelect: (item: IntegrationSearchItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -362,7 +327,6 @@ function createColoredIconGroup(heading: string, prefix: string) {
bgColor={item.bgColor}
showColoredIcon
label={item.name}
- query={query}
/>
))}
@@ -378,11 +342,9 @@ function createIconGroup(
return memo(function IconGroup({
items,
onSelect,
- query,
}: {
items: TaskItem[]
onSelect: (item: TaskItem) => void
- query?: string
}) {
if (items.length === 0) return null
return (
@@ -394,7 +356,6 @@ function createIconGroup(
onSelect={() => onSelect(item)}
name={item.name}
icon={icon}
- query={query}
/>
))}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
index ec1dc3e630f..6968fbc91f9 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
@@ -712,105 +712,53 @@ export function SearchModal({
{showSection('actions') && (
-
+
)}
{showSection('connectedAccounts') && (
)}
{showSection('integrations') && (
)}
{showSection('blocks') && (
-
+
)}
{showSection('tools') && (
-
+
)}
{showSection('triggers') && (
-
+
)}
{showSection('chats') && (
-
+
)}
{showSection('workflows') && (
-
+
)}
{showSection('tables') && (
-
+
)}
{showSection('files') && (
-
+
)}
{showSection('knowledgeBases') && (
-
+
)}
{showSection('toolOperations') && (
-
+
)}
{showSection('workspaces') && (
-
- )}
- {showSection('docs') && (
-
+
)}
+ {showSection('docs') && }
{showSection('pages') && (
-
+
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts
index a9f3fe9dbbe..5b046c31a52 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts
@@ -91,10 +91,8 @@ export interface CommandItemProps {
icon: ComponentType<{ className?: string }>
bgColor: string
showColoredIcon?: boolean
- /** Primary text. Matched characters are highlighted against {@link query}. */
+ /** Primary text of the row. */
label: string
- /** Active search query, used to bold matched characters. */
- query?: string
}
export const GROUP_HEADING_CLASSNAME =
@@ -181,9 +179,8 @@ function tokenFallback(lowerText: string, lowerQuery: string): FuzzyResult {
* (`message slack` matches "Slack Send Message") which a strict left-to-right
* subsequence would miss.
*
- * Contiguous substring matches report the indices of the substring itself, so
- * highlighting always bolds the run the user actually matched rather than an
- * earlier scattered occurrence of the same characters.
+ * Contiguous substring matches report the indices of the substring itself
+ * rather than an earlier scattered occurrence of the same characters.
*/
export function fuzzyMatch(text: string, query: string): FuzzyResult {
if (!query) return { matched: true, score: 1, positions: [] }
diff --git a/apps/sim/components/ui/index.ts b/apps/sim/components/ui/index.ts
index 40ccab62097..234f6f50a60 100644
--- a/apps/sim/components/ui/index.ts
+++ b/apps/sim/components/ui/index.ts
@@ -1,7 +1,6 @@
export { Button, buttonVariants } from './button'
export { GeneratedPasswordInput } from './generated-password-input'
export { Progress } from './progress'
-export { SearchHighlight } from './search-highlight'
export {
Select,
SelectContent,