From c829f81406770f4791596fbd83b78cbe1b6102df Mon Sep 17 00:00:00 2001 From: Bill Leoutsakos Date: Mon, 17 Aug 2026 18:08:06 -0700 Subject: [PATCH 1/3] fix(chat): disambiguate folder mentions --- .../plus-menu-dropdown/plus-menu-dropdown.tsx | 40 +++++++++ .../resource-mention-items.test.ts | 83 +++++++++++++++++++ .../resource-mention-items.ts | 52 ++++++++++++ 3 files changed, 175 insertions(+) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx index a16be8f1c04..825294369d3 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx @@ -16,6 +16,7 @@ import { import { getResourceConfig } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry' import type { PlusMenuHandle } from '@/app/workspace/[workspaceId]/home/components/user-input/components/constants' import { + buildFolderMentionLocationMap, resourceMentionMatches, withDesktopTabMentions, } from '@/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items' @@ -41,6 +42,35 @@ const NON_ATTACHABLE_RESOURCE_TYPES = new Set(['browser' const EMPTY_BROWSER_TABS = [] as const const EMPTY_TERMINAL_TABS = [] as const +interface FolderMentionPathProps { + segments: readonly string[] +} + +/** Right-aligned folder location whose middle ancestors yield space first. */ +function FolderMentionPath({ segments }: FolderMentionPathProps) { + const family = segments[0] + const parentNames = segments.slice(1) + const nearestParent = parentNames.at(-1) + const middleParents = parentNames.slice(0, -1) + + return ( + + {family} + {middleParents.length > 0 && ( + + {` / ${middleParents.join(' / ')}`} + + )} + {nearestParent && ( + <> + / + {nearestParent} + + )} + + ) +} + interface PlusMenuDropdownProps { workspaceId: string /** @@ -119,6 +149,11 @@ export const PlusMenuDropdown = React.memo( return attachable.filter(({ type }) => !MENTION_ONLY_RESOURCE_TYPES.has(type)) }, [availableResources, browserTabs, isMention, terminalTabs]) + const folderMentionLocations = useMemo( + () => buildFolderMentionLocationMap(visibleResources), + [visibleResources] + ) + const treeSections = useResourceTreeSections({ groups: visibleResources, structureFolders, @@ -334,6 +369,10 @@ export const PlusMenuDropdown = React.memo( filteredItems.map(({ type, item }, index) => { const config = getResourceConfig(type) const isActive = index === activeIndex + const location = folderMentionLocations.get(`${type}:${item.id}`) + const locationPath = location + ? [getResourceConfig(location.familyType).label, ...location.parentNames] + : null return ( ) }) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.test.ts b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.test.ts index bed14025882..bf23bdf83be 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.test.ts @@ -4,6 +4,7 @@ import { TERMINAL_SESSION_RESOURCE_ID, } from '@/lib/copilot/resources/types' import { + buildFolderMentionLocationMap, resourceMentionMatches, withDesktopTabMentions, } from '@/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items' @@ -20,6 +21,88 @@ const groups = [ }, ] +describe('buildFolderMentionLocationMap', () => { + it('distinguishes same-named top-level workflow and file folders by family', () => { + const locations = buildFolderMentionLocationMap([ + { + type: 'folder', + items: [{ id: 'enterprise', name: 'Enterprise', parentId: null }], + }, + { + type: 'filefolder', + items: [{ id: 'enterprise', name: 'Enterprise', parentId: null }], + }, + ]) + + expect(locations.get('folder:enterprise')).toEqual({ + familyType: 'workflow', + parentNames: [], + }) + expect(locations.get('filefolder:enterprise')).toEqual({ + familyType: 'file', + parentNames: [], + }) + }) + + it('returns root-first parents without repeating the current folder name', () => { + const locations = buildFolderMentionLocationMap([ + { + type: 'folder', + items: [ + { id: 'engineering', name: 'Engineering', parentId: null }, + { id: 'accounts', name: 'Accounts', parentId: 'engineering' }, + { id: 'enterprise', name: 'Enterprise', parentId: 'accounts' }, + ], + }, + ]) + + expect(locations.get('folder:enterprise')).toEqual({ + familyType: 'workflow', + parentNames: ['Engineering', 'Accounts'], + }) + }) + + it('falls back to the family when a parent is missing', () => { + const locations = buildFolderMentionLocationMap([ + { + type: 'filefolder', + items: [{ id: 'enterprise', name: 'Enterprise', parentId: 'missing' }], + }, + ]) + + expect(locations.get('filefolder:enterprise')).toEqual({ + familyType: 'file', + parentNames: [], + }) + }) + + it('terminates cyclic ancestry without repeating the current folder', () => { + const locations = buildFolderMentionLocationMap([ + { + type: 'folder', + items: [ + { id: 'enterprise', name: 'Enterprise', parentId: 'accounts' }, + { id: 'accounts', name: 'Accounts', parentId: 'enterprise' }, + ], + }, + ]) + + expect(locations.get('folder:enterprise')).toEqual({ + familyType: 'workflow', + parentNames: ['Accounts'], + }) + }) + + it('does not add locations for non-folder resources', () => { + const locations = buildFolderMentionLocationMap([ + { type: 'workflow', items: [{ id: 'workflow-1', name: 'Enterprise' }] }, + { type: 'file', items: [{ id: 'file-1', name: 'Enterprise' }] }, + ]) + + expect(locations.size).toBe(0) + }) +}) + describe('withDesktopTabMentions', () => { it('keeps Browser and Terminal as flat resource mentions with no live tabs', () => { const result = withDesktopTabMentions(groups, [], []) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.ts b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.ts index bbbe84ad29e..a8faa8be477 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items.ts @@ -4,6 +4,7 @@ import { BROWSER_SESSION_RESOURCE_ID, TERMINAL_SESSION_RESOURCE_ID, } from '@/lib/copilot/resources/types' +import { folderAncestorChain } from '@/lib/folders/tree' import type { AvailableItem } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown/resource-folder-tree' import { browserTabTitle } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-tab-label' import type { MothershipResourceType } from '@/app/workspace/[workspaceId]/home/types' @@ -15,6 +16,57 @@ export interface ResourceMentionGroup { export type ResourceMentionLevel = 'resource' | 'tab' +export interface FolderMentionLocation { + familyType: 'workflow' | 'file' + parentNames: string[] +} + +interface FolderMentionNode { + id: string + name: string + parentId: string | null +} + +function folderFamilyType( + type: MothershipResourceType +): FolderMentionLocation['familyType'] | null { + if (type === 'folder') return 'workflow' + if (type === 'filefolder') return 'file' + return null +} + +/** Builds display-only locations for the folder rows in the flat resource picker. */ +export function buildFolderMentionLocationMap( + groups: readonly ResourceMentionGroup[] +): Map { + const locations = new Map() + + for (const group of groups) { + const familyType = folderFamilyType(group.type) + if (!familyType) continue + + const nodes = new Map( + group.items.map((item) => [ + item.id, + { + id: item.id, + name: item.name, + parentId: typeof item.parentId === 'string' ? item.parentId : null, + }, + ]) + ) + + for (const node of nodes.values()) { + const parentNames = folderAncestorChain(node.parentId, (id) => nodes.get(id)) + .filter((parent) => parent.id !== node.id) + .map((parent) => parent.name) + locations.set(`${group.type}:${node.id}`, { familyType, parentNames }) + } + } + + return locations +} + /** A family query such as "browser" keeps that resource's live tabs visible. */ export function resourceMentionMatches(item: AvailableItem, query: string): boolean { const normalized = query.toLowerCase().trim() From 99a22d8b3c194b608077adf7e30a23b5f7ee4f1d Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 17 Aug 2026 18:24:11 -0700 Subject: [PATCH 2/3] refactor(chat): one folder-path label for the mention menu and cmd-K MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mention menu's folder location and the cmd-K row's folder receipt were two copies of the same flex-shrink layout. Both now render `FolderPathLabel`, which collapses ancestors past the third into a single `…` segment so a deep path drops whole folders instead of clipping one mid-word. Mention rows also cap the name at 65% and fix the popover at 380px, so the location column keeps a stable right edge and can never be squeezed out by a long resource name. --- .../plus-menu-dropdown/plus-menu-dropdown.tsx | 57 ++++++----------- .../command-items/command-items.tsx | 28 ++------ .../components/ui/folder-path-label.test.ts | 28 ++++++++ apps/sim/components/ui/folder-path-label.tsx | 64 +++++++++++++++++++ apps/sim/components/ui/index.ts | 5 ++ 5 files changed, 122 insertions(+), 60 deletions(-) create mode 100644 apps/sim/components/ui/folder-path-label.test.ts create mode 100644 apps/sim/components/ui/folder-path-label.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx index 825294369d3..25678855824 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx @@ -8,6 +8,7 @@ import { DropdownMenuSearchInput, DropdownMenuTrigger, } from '@sim/emcn' +import { FolderPathLabel } from '@/components/ui' import { ResourceMenuSections, useAvailableResources, @@ -42,35 +43,6 @@ const NON_ATTACHABLE_RESOURCE_TYPES = new Set(['browser' const EMPTY_BROWSER_TABS = [] as const const EMPTY_TERMINAL_TABS = [] as const -interface FolderMentionPathProps { - segments: readonly string[] -} - -/** Right-aligned folder location whose middle ancestors yield space first. */ -function FolderMentionPath({ segments }: FolderMentionPathProps) { - const family = segments[0] - const parentNames = segments.slice(1) - const nearestParent = parentNames.at(-1) - const middleParents = parentNames.slice(0, -1) - - return ( - - {family} - {middleParents.length > 0 && ( - - {` / ${middleParents.join(' / ')}`} - - )} - {nearestParent && ( - <> - / - {nearestParent} - - )} - - ) -} - interface PlusMenuDropdownProps { workspaceId: string /** @@ -333,7 +305,9 @@ export const PlusMenuDropdown = React.memo( // Plus-click shows short fixed labels (Workflows, Tables, …) — let it size // to its content via the emcn DropdownMenuContent default max-w. // Mention mode renders resource names directly, so widen for breathing room. - isMention && 'max-w-[min(300px,calc(100vw-32px))]' + // Wide enough that a folder row fits its name and its right-aligned + // location column without either collapsing to a stub. + isMention && 'w-[min(380px,calc(100vw-32px))] max-w-[calc(100vw-32px)]' )} onCloseAutoFocus={handleCloseAutoFocus} onOpenAutoFocus={handleOpenAutoFocus} @@ -370,9 +344,6 @@ export const PlusMenuDropdown = React.memo( const config = getResourceConfig(type) const isActive = index === activeIndex const location = folderMentionLocations.get(`${type}:${item.id}`) - const locationPath = location - ? [getResourceConfig(location.familyType).label, ...location.parentNames] - : null return ( ) }) 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 c67b2089917..02c3a3accdc 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 @@ -4,6 +4,7 @@ import type { ComponentType } from 'react' import { memo } from 'react' import { File, Workflow } from '@sim/emcn/icons' import { Command } from 'cmdk' +import { FolderPathLabel } from '@/components/ui' import { HEX_COLOR_REGEX } from '@/lib/branding' import type { CommandItemProps } 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' @@ -23,27 +24,6 @@ function ItemMeta({ meta }: ItemMetaProps) { ) } -interface ItemFolderPathProps { - folderPath: string[] -} - -/** Trailing folder-path receipt whose head segments yield space to the leaf. */ -function ItemFolderPath({ folderPath }: ItemFolderPathProps) { - return ( - - {folderPath.length > 1 && ( - <> - - {folderPath.slice(0, -1).join(' / ')} - - / - - )} - {folderPath[folderPath.length - 1]} - - ) -} - /** Structural equality for the optional folder-path prop in memo comparators. */ function sameFolderPath(prev?: string[], next?: string[]): boolean { return ( @@ -167,7 +147,7 @@ export const MemoizedWorkflowItem = memo( {meta ? ( ) : folderPath && folderPath.length > 0 ? ( - + ) : null} ) @@ -204,7 +184,7 @@ export const MemoizedFileItem = memo( {meta ? ( ) : folderPath && folderPath.length > 0 ? ( - + ) : null} ) @@ -349,7 +329,7 @@ export const MemoizedIconItem = memo( {meta ? ( ) : folderPath && folderPath.length > 0 ? ( - + ) : null} ) diff --git a/apps/sim/components/ui/folder-path-label.test.ts b/apps/sim/components/ui/folder-path-label.test.ts new file mode 100644 index 00000000000..e479e87a6df --- /dev/null +++ b/apps/sim/components/ui/folder-path-label.test.ts @@ -0,0 +1,28 @@ +/** + * @vitest-environment node + */ +import { describe, expect, it } from 'vitest' +import { collapseFolderPath } from '@/components/ui/folder-path-label' + +describe('collapseFolderPath', () => { + it('leaves a shallow chain untouched', () => { + expect(collapseFolderPath([])).toEqual([]) + expect(collapseFolderPath(['Growth'])).toEqual(['Growth']) + expect(collapseFolderPath(['Growth', 'Campaigns', 'Q3'])).toEqual(['Growth', 'Campaigns', 'Q3']) + }) + + it('drops whole ancestors rather than clipping one mid-word', () => { + expect(collapseFolderPath(['Growth', 'Campaigns', 'Paid', 'Q3'])).toEqual(['Growth', '…', 'Q3']) + }) + + it('keeps the root and the leaf however deep the chain runs', () => { + const deep = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] + expect(collapseFolderPath(deep)).toEqual(['A', '…', 'G']) + }) + + it('does not mutate the input', () => { + const segments = ['A', 'B', 'C', 'D'] + collapseFolderPath(segments) + expect(segments).toEqual(['A', 'B', 'C', 'D']) + }) +}) diff --git a/apps/sim/components/ui/folder-path-label.tsx b/apps/sim/components/ui/folder-path-label.tsx new file mode 100644 index 00000000000..3bf9bca267d --- /dev/null +++ b/apps/sim/components/ui/folder-path-label.tsx @@ -0,0 +1,64 @@ +import { cn } from '@sim/emcn' + +/** + * Ancestors kept before the path collapses. Three is the widest chain that still + * reads at the ~30% of a menu row this label is allowed to occupy. + */ +const MAX_VISIBLE_SEGMENTS = 3 +const ELLIPSIS = '…' + +/** + * Collapses a root-first folder chain so an over-long path drops whole ancestors + * instead of clipping one mid-word: `Growth / … / Q3` rather than `Growth / Mark…`. + * + * The root orients and the leaf disambiguates, so those are the two that survive; + * everything between them is what the reader can least act on. + */ +export function collapseFolderPath(segments: readonly string[]): string[] { + if (segments.length <= MAX_VISIBLE_SEGMENTS) return [...segments] + return [segments[0], ELLIPSIS, segments[segments.length - 1]] +} + +export interface FolderPathLabelProps { + /** Root-first ancestor names of the row's resource. */ + segments: readonly string[] + /** + * Pinned lead-in that never clips — the resource family (`Files`, `Workflows`) + * when the label doubles as the row's disambiguator. + */ + prefix?: string + className?: string +} + +/** + * Right-aligned location receipt for a menu row. Head segments yield their space + * first so the leaf — the segment that tells two same-named rows apart — is the + * last thing to clip. + */ +export function FolderPathLabel({ segments, prefix, className }: FolderPathLabelProps) { + const visible = collapseFolderPath(segments) + const leaf = visible.at(-1) + const head = visible.slice(0, -1) + const hasLeadIn = Boolean(prefix) || head.length > 0 + + if (!hasLeadIn && !leaf) return null + + return ( + + {prefix && {prefix}} + {head.length > 0 && ( + + {prefix ? ` / ${head.join(' / ')}` : head.join(' / ')} + + )} + {leaf && ( + <> + {hasLeadIn && / } + {leaf} + + )} + + ) +} diff --git a/apps/sim/components/ui/index.ts b/apps/sim/components/ui/index.ts index 234f6f50a60..fc7e4cb55b1 100644 --- a/apps/sim/components/ui/index.ts +++ b/apps/sim/components/ui/index.ts @@ -1,4 +1,9 @@ export { Button, buttonVariants } from './button' +export { + collapseFolderPath, + FolderPathLabel, + type FolderPathLabelProps, +} from './folder-path-label' export { GeneratedPasswordInput } from './generated-password-input' export { Progress } from './progress' export { From a9a5c7f4ce2fe4499d82e640349b4f73ae1fa0dd Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 17 Aug 2026 18:53:00 -0700 Subject: [PATCH 3/3] fix(chat): keep the log row's timestamp pinned to the row edge The name wrapper added for folder locations was applied to every flat mention row, which broke the log row: it pins its timestamp with `ml-auto`, and that only reaches the right edge while the row button is its flex parent. Inside a content-sized wrapper the timestamp collapsed back beside the workflow name. `MentionRowContent` now wraps only the rows that actually render a location and carries the invariant in one place, with a test that fails if the unwrapped path regresses. --- .../mention-row-content.test.tsx | 67 +++++++++++++++++++ .../mention-row-content.tsx | 40 +++++++++++ .../plus-menu-dropdown/plus-menu-dropdown.tsx | 21 ++---- 3 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.test.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.test.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.test.tsx new file mode 100644 index 00000000000..4e8384d804e --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.test.tsx @@ -0,0 +1,67 @@ +/** + * @vitest-environment jsdom + */ +import { act } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { MentionRowContent } from '@/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content' + +let container: HTMLDivElement +let root: Root + +/** Stands in for a family renderer that pins trailing content with `ml-auto`, as the log row does. */ +function LogLikeRow() { + return ( + <> + Daily digest + + 2m ago + + + ) +} + +function renderRow(node: React.ReactNode) { + act(() => { + root.render() + }) +} + +beforeEach(() => { + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) +}) + +afterEach(() => { + act(() => root.unmount()) + container.remove() +}) + +describe('MentionRowContent', () => { + it('leaves a location-less row unwrapped so `ml-auto` still reaches the row edge', () => { + renderRow( + + + + ) + + const trailing = container.querySelector('[data-testid="trailing"]') + expect(trailing).not.toBeNull() + expect(trailing?.parentElement?.tagName).toBe('BUTTON') + }) + + it('wraps and caps the name only when a location follows it', () => { + renderRow( + + Enterprise + + ) + + const name = container.querySelector('button > span') + expect(name?.className).toContain('max-w-[65%]') + expect(name?.className).toContain('flex-shrink-0') + expect(container.textContent).toContain('Files') + expect(container.textContent).toContain('Growth') + }) +}) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.tsx new file mode 100644 index 00000000000..ef8c1a1ff35 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content.tsx @@ -0,0 +1,40 @@ +'use client' + +import type { ReactNode } from 'react' +import { FolderPathLabel } from '@/components/ui' +import { getResourceConfig } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry' +import type { FolderMentionLocation } from '@/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/resource-mention-items' + +export interface MentionRowContentProps { + /** The resource family's own row rendering, a fragment of the row's flex children. */ + children: ReactNode + /** Present only for folder rows, which need a location to disambiguate same-named siblings. */ + location?: FolderMentionLocation +} + +/** + * Body of one flat mention row. + * + * Rows without a location render their family output as direct children of the row + * button, unwrapped. That is load-bearing rather than incidental: renderers such as + * the log row pin trailing content with `ml-auto`, which only reaches the row's right + * edge while the button is its flex parent. Wrapping every row would silently pull + * those timestamps back beside the name. + */ +export function MentionRowContent({ children, location }: MentionRowContentProps) { + if (!location) return <>{children} + + return ( + <> + {/* Capped rather than shrinkable so a long name cannot squeeze out the segment + that tells two same-named folders apart. */} + + {children} + + + + ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx index 25678855824..bd6fa5f247b 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/plus-menu-dropdown.tsx @@ -8,7 +8,6 @@ import { DropdownMenuSearchInput, DropdownMenuTrigger, } from '@sim/emcn' -import { FolderPathLabel } from '@/components/ui' import { ResourceMenuSections, useAvailableResources, @@ -16,6 +15,7 @@ import { } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown' import { getResourceConfig } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry' import type { PlusMenuHandle } from '@/app/workspace/[workspaceId]/home/components/user-input/components/constants' +import { MentionRowContent } from '@/app/workspace/[workspaceId]/home/components/user-input/components/plus-menu-dropdown/mention-row-content' import { buildFolderMentionLocationMap, resourceMentionMatches, @@ -355,27 +355,14 @@ export const PlusMenuDropdown = React.memo( handleSelect({ type, id: item.id, title: item.name }) }} className={cn( - 'relative flex w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-[5px] px-2 py-1.5 text-left text-[var(--text-body)] text-caption outline-none transition-colors duration-0 [&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0 [&_svg]:text-[var(--text-icon)]', + 'relative flex w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-[5px] px-2 py-1.5 text-left text-[var(--text-body)] text-caption outline-none transition-colors duration-0 [&>span]:min-w-0 [&>span]:truncate [&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0 [&_svg]:text-[var(--text-icon)]', /* `activeIndex` is the cursor, not a selection — hover surface. */ isActive && 'bg-[var(--surface-hover)]' )} > - {/* Capped, not shrinkable: a long name must never squeeze out the - location that tells two same-named folders apart. */} - span]:min-w-0 [&>span]:truncate', - location && 'max-w-[65%] flex-shrink-0' - )} - > + {config.renderDropdownItem({ item })} - - {location && ( - - )} + ) })