Skip to content

Commit bcd622a

Browse files
authored
Merge pull request #2323 from kev1n77/fmy/dev
fix(input): simplify file mention path display
2 parents 14c4b5c + 74ed56d commit bcd622a

4 files changed

Lines changed: 91 additions & 37 deletions

File tree

src/web-ui/src/flow_chat/components/FileMentionPicker.appearance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export const fileMentionPickerAppearanceDescriptor: AppearanceSurfaceDescriptor
55
parts: [
66
{ id: 'root' }, { id: 'header' }, { id: 'back' }, { id: 'content' },
77
{ id: 'loading' }, { id: 'empty' }, { id: 'list' }, { id: 'item' },
8-
{ id: 'itemName' }, { id: 'itemDetail' }, { id: 'footer' },
8+
{ id: 'itemName' }, { id: 'itemDetail' }, { id: 'currentDirectoryName' },
9+
{ id: 'parentDirectoryPath' }, { id: 'footer' },
910
],
1011
states: [
1112
{ id: 'selected', selector: { kind: 'self', suffix: '[data-bf-state~="selected"]' } },

src/web-ui/src/flow_chat/components/FileMentionPicker.scss

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,33 @@
8686
}
8787
}
8888

89-
&__dir-name {
89+
&__directory-label {
9090
flex: 1;
91+
min-width: 0;
92+
display: flex;
93+
align-items: baseline;
94+
gap: var(--bf-appearance-token-flowchat-inline-gap);
95+
}
96+
97+
&__dir-name,
98+
&__parent-path {
9199
overflow: hidden;
92100
text-overflow: ellipsis;
93101
white-space: nowrap;
102+
}
103+
104+
&__dir-name {
105+
flex: 0 1 auto;
106+
max-width: 55%;
94107
color: var(--bf-appearance-token-color-text-secondary);
95108
}
109+
110+
&__parent-path {
111+
flex: 1 1 auto;
112+
min-width: 0;
113+
color: var(--bf-appearance-token-color-text-muted);
114+
font-weight: 400;
115+
}
96116

97117
&__content {
98118
flex: 1;
@@ -190,11 +210,6 @@
190210
overflow: hidden;
191211
text-overflow: ellipsis;
192212
line-height: var(--bf-appearance-token-flowchat-support-line-height);
193-
194-
&--with-path {
195-
flex: 0 1 auto;
196-
max-width: 50%;
197-
}
198213
}
199214

200215
&__item-detail {
@@ -207,12 +222,6 @@
207222
white-space: nowrap;
208223
}
209224

210-
&__item-path {
211-
flex: 1 1 0;
212-
min-width: 0;
213-
max-width: none;
214-
}
215-
216225
&__expand-icon {
217226
flex-shrink: 0;
218227
opacity: 0.4;

src/web-ui/src/flow_chat/components/FileMentionPicker.tsx

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,29 @@ export const FileMentionPicker: React.FC<FileMentionPickerProps> = ({
398398
...(currentPath ? [] : referenceItems.map(item => ({ kind: 'file' as const, item }))),
399399
]
400400
), [currentFiles, currentPath, isSearchMode, referenceItems, results, sessionResults]);
401-
const currentDirName = currentPath
402-
? currentPath.replace(/\\/g, '/').split('/').pop() || ''
403-
: workspacePath?.replace(/\\/g, '/').split('/').pop() || t('fileMention.rootDirectory');
401+
const currentDirectoryDisplay = useMemo(() => {
402+
if (!workspacePath) {
403+
const rootDirectory = t('fileMention.rootDirectory');
404+
return { name: rootDirectory, parentPath: '', fullPath: rootDirectory };
405+
}
406+
407+
const normalizedWorkspace = workspacePath.replace(/\\/g, '/').replace(/\/+$/, '');
408+
const workspaceName = normalizedWorkspace.split('/').pop() || t('fileMention.rootDirectory');
409+
const directorySegments = [workspaceName];
410+
411+
if (currentPath) {
412+
const relativeCurrentPath = getRelativePath(currentPath)
413+
.replace(/\\/g, '/')
414+
.replace(/^\/+|\/+$/g, '');
415+
if (relativeCurrentPath) directorySegments.push(...relativeCurrentPath.split('/').filter(Boolean));
416+
}
417+
418+
return {
419+
name: directorySegments[directorySegments.length - 1],
420+
parentPath: directorySegments.slice(0, -1).join('/'),
421+
fullPath: directorySegments.join('/'),
422+
};
423+
}, [currentPath, getRelativePath, t, workspacePath]);
404424
const isOverlay = Boolean(anchorRef) && !position;
405425
const overlayLayout = useAnchoredPopoverPosition({
406426
open: isOpen && isOverlay,
@@ -562,7 +582,24 @@ export const FileMentionPicker: React.FC<FileMentionPickerProps> = ({
562582
</Tooltip>
563583
)}
564584
{isSearchMode ? <><Search size={11} /><span>{t('fileMention.searchResults')}</span></> : (
565-
<span className="file-mention-picker__dir-name">{currentDirName}</span>
585+
<div className="file-mention-picker__directory-label" title={currentDirectoryDisplay.fullPath}>
586+
<span
587+
data-bf-component="file-mention-picker"
588+
data-bf-part="currentDirectoryName"
589+
className="file-mention-picker__dir-name"
590+
>
591+
{currentDirectoryDisplay.name}
592+
</span>
593+
{currentDirectoryDisplay.parentPath && (
594+
<span
595+
data-bf-component="file-mention-picker"
596+
data-bf-part="parentDirectoryPath"
597+
className="file-mention-picker__parent-path"
598+
>
599+
{currentDirectoryDisplay.parentPath}
600+
</span>
601+
)}
602+
</div>
566603
)}
567604
</div>
568605
<div data-bf-component="file-mention-picker" data-bf-part="content" className="file-mention-picker__content">
@@ -602,21 +639,11 @@ export const FileMentionPicker: React.FC<FileMentionPickerProps> = ({
602639
<span
603640
data-bf-component="file-mention-picker"
604641
data-bf-part="itemName"
605-
className={`file-mention-picker__item-name${file && !file.referenceStableKey ? ' file-mention-picker__item-name--with-path' : ''}`}
642+
className="file-mention-picker__item-name"
606643
>
607644
{session?.sessionName ?? file?.name}
608645
</span>
609646
{session && <span data-bf-component="file-mention-picker" data-bf-part="itemDetail" className="file-mention-picker__item-detail">{session.workspaceLabel}</span>}
610-
{file && !file.referenceStableKey && (
611-
<span
612-
data-bf-component="file-mention-picker"
613-
data-bf-part="itemDetail"
614-
className="file-mention-picker__item-detail file-mention-picker__item-path"
615-
title={file.relativePath}
616-
>
617-
{file.relativePath}
618-
</span>
619-
)}
620647
{file?.referenceStableKey && (
621648
<span data-bf-component="file-mention-picker" data-bf-part="itemDetail" className="file-mention-picker__item-detail">
622649
{file.referenceDescription || file.path}

src/web-ui/src/flow_chat/components/FileMentionPickerOverlay.test.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,26 @@ describe('FileMentionPicker overlay', () => {
9393
);
9494
});
9595

96-
it('shows the workspace-relative path after the file name', async () => {
96+
it('shows the current directory name before its parent path', async () => {
97+
vi.mocked(workspaceAPI.getDirectoryChildren).mockResolvedValueOnce([
98+
{
99+
path: '/workspace/src',
100+
name: 'src',
101+
isDirectory: true,
102+
},
103+
]);
104+
105+
await act(async () => {
106+
root.render(<Harness />);
107+
await Promise.resolve();
108+
});
109+
110+
const item = document.querySelector<HTMLElement>('[data-bf-part="item"]');
111+
expect(document.querySelector('[data-bf-part="currentDirectoryName"]')?.textContent).toBe('workspace');
112+
expect(document.querySelector('[data-bf-part="parentDirectoryPath"]')).toBeNull();
113+
expect(item?.querySelector('[data-bf-part="itemName"]')?.textContent).toBe('src');
114+
expect(item?.querySelector('[data-bf-part="itemDetail"]')).toBeNull();
115+
97116
vi.mocked(workspaceAPI.getDirectoryChildren).mockResolvedValueOnce([
98117
{
99118
path: '/workspace/src/App.tsx',
@@ -103,17 +122,15 @@ describe('FileMentionPicker overlay', () => {
103122
]);
104123

105124
await act(async () => {
106-
root.render(<Harness />);
125+
item?.click();
107126
await Promise.resolve();
108127
});
109128

110-
const item = document.querySelector('[data-bf-part="item"]');
111-
const itemName = item?.querySelector('[data-bf-part="itemName"]');
112-
const itemPath = item?.querySelector('[data-bf-part="itemDetail"]');
113-
expect(itemName?.textContent).toBe('App.tsx');
114-
expect(itemName?.classList.contains('file-mention-picker__item-name--with-path')).toBe(true);
115-
expect(itemPath?.textContent).toBe('src/App.tsx');
116-
expect(itemPath?.classList.contains('file-mention-picker__item-path')).toBe(true);
129+
expect(document.querySelector('[data-bf-part="currentDirectoryName"]')?.textContent).toBe('src');
130+
expect(document.querySelector('[data-bf-part="parentDirectoryPath"]')?.textContent).toBe('workspace');
131+
const nestedItem = document.querySelector('[data-bf-part="item"]');
132+
expect(nestedItem?.querySelector('[data-bf-part="itemName"]')?.textContent).toBe('App.tsx');
133+
expect(nestedItem?.querySelector('[data-bf-part="itemDetail"]')).toBeNull();
117134
});
118135

119136
it('does not present a remote browse failure as an empty directory', async () => {

0 commit comments

Comments
 (0)