Skip to content

Commit 59cde6d

Browse files
authored
fix: hide caret for loaded empty destination folders (Issue #7772) (#22)
1 parent d8f98fc commit 59cde6d

3 files changed

Lines changed: 175 additions & 1 deletion

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { render } from '@testing-library/react';
2+
import { describe, expect, test, vi } from 'vitest';
3+
import { DialFileManager } from './FileManager';
4+
5+
const destinationPopupRender = vi.hoisted(() => vi.fn());
6+
7+
vi.mock('@epam/ai-dial-ui-kit', async (importOriginal) => {
8+
const actual = await importOriginal<typeof import('@epam/ai-dial-ui-kit')>();
9+
10+
return {
11+
...actual,
12+
DialGrid: () => <div role="grid" aria-label="File Manager Grid View" />,
13+
};
14+
});
15+
16+
vi.mock('./components/DestinationFolderPopup/DestinationFolderPopup', () => ({
17+
DialDestinationFolderPopup: (props: unknown) => {
18+
destinationPopupRender(props);
19+
return null;
20+
},
21+
}));
22+
23+
vi.mock('./components/ConflictResolutionPopup/ConflictResolutionPopup', () => ({
24+
ConflictResolutionPopup: () => null,
25+
}));
26+
27+
vi.mock(
28+
'./components/FileManagerDeleteConfirmationPopup/FileManagerDeleteConfirmationPopup',
29+
() => ({ FileManagerDeleteConfirmationPopup: () => null }),
30+
);
31+
32+
vi.mock('./components/FileMetadataPopup/FileMetadataPopup', () => ({
33+
FileMetadataPopup: () => null,
34+
}));
35+
36+
describe('Dial UI Kit :: FileManager destination folder popup', () => {
37+
test('forwards folder loading state without forwarding outer expansion state', () => {
38+
const loadedPaths = new Set(['All files/Loaded empty folder']);
39+
const loadingPaths = new Set(['All files/Loading folder']);
40+
41+
render(
42+
<div style={{ height: 640, width: 1100 }}>
43+
<DialFileManager
44+
items={[]}
45+
showNavigationPanel={false}
46+
treeOptions={{
47+
header: 'Folder tree',
48+
expandedPaths: new Set(['All files']),
49+
loadedPaths,
50+
loadingPaths,
51+
}}
52+
/>
53+
</div>,
54+
);
55+
56+
expect(destinationPopupRender).toHaveBeenLastCalledWith(
57+
expect.objectContaining({
58+
treeOptions: {
59+
header: 'Folder tree',
60+
loadedPaths,
61+
loadingPaths,
62+
},
63+
}),
64+
);
65+
});
66+
});

src/components/FileManager/FileManager.stories.tsx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
PrimaryButton,
2828
} from '@epam/ai-dial-ui-kit';
2929
import type { Meta, StoryObj } from '@storybook/react-vite';
30+
import { userEvent, within } from 'storybook/test';
3031
import {
3132
IconBuildingCommunity,
3233
IconFileDescription,
@@ -274,6 +275,109 @@ export const HandleTableFileClick: Story = {
274275
},
275276
};
276277

278+
const destinationPopupCaretItems: DialFile[] = [
279+
{
280+
id: 'destination-root',
281+
name: 'All files',
282+
path: 'All files',
283+
parentPath: '',
284+
nodeType: DialFileNodeType.FOLDER,
285+
folderId: 'destination-root',
286+
items: [
287+
{
288+
id: 'source-file',
289+
name: 'source.txt',
290+
path: 'All files/source.txt',
291+
parentPath: 'All files',
292+
nodeType: DialFileNodeType.ITEM,
293+
resourceType: DialFileResourceType.FILE,
294+
folderId: 'destination-root',
295+
},
296+
{
297+
id: 'loaded-empty-folder',
298+
name: 'Loaded empty folder',
299+
path: 'All files/Loaded empty folder',
300+
parentPath: 'All files',
301+
nodeType: DialFileNodeType.FOLDER,
302+
folderId: 'destination-root',
303+
items: [],
304+
},
305+
{
306+
id: 'not-loaded-folder',
307+
name: 'Not loaded folder',
308+
path: 'All files/Not loaded folder',
309+
parentPath: 'All files',
310+
nodeType: DialFileNodeType.FOLDER,
311+
folderId: 'destination-root',
312+
items: [],
313+
},
314+
],
315+
},
316+
];
317+
318+
const destinationPopupCaretRootItem: DialRootFolder = {
319+
...destinationPopupCaretItems[0],
320+
label: 'All files',
321+
};
322+
323+
const DestinationPopupLoadedEmptyFolderComponent = (
324+
args: DialFileManagerProps,
325+
) => {
326+
const [destinationPath, setDestinationPath] = useState('All files');
327+
328+
return (
329+
<div className="h-[720px] min-h-[480px]">
330+
<DialFileManager
331+
{...args}
332+
items={destinationPopupCaretItems}
333+
rootItem={destinationPopupCaretRootItem}
334+
defaultPath="All files"
335+
defaultSelectedPaths={new Set(['All files/source.txt'])}
336+
gridOptions={{
337+
...args.gridOptions,
338+
selectionMode: GridSelectionMode.MULTIPLE,
339+
}}
340+
treeOptions={{
341+
...args.treeOptions,
342+
expandedPaths: new Set(['All files']),
343+
loadedPaths: new Set(['All files', 'All files/Loaded empty folder']),
344+
header: 'Folder tree',
345+
}}
346+
bulkActionsToolbarOptions={{
347+
getSelectionLabel: (selectedCount) =>
348+
`${selectedCount} item(s) selected`,
349+
actionLabels: {
350+
[DialFileManagerActions.Copy]: 'Copy to',
351+
},
352+
}}
353+
destinationFolderPopupOptions={{
354+
destinationFolderPath: destinationPath,
355+
setDestinationFolderPath: setDestinationPath,
356+
getCopyHeader: () => 'Copy source.txt',
357+
}}
358+
onCopyFiles={() => undefined}
359+
/>
360+
</div>
361+
);
362+
};
363+
364+
export const DestinationPopupLoadedEmptyFolder: Story = {
365+
render: DestinationPopupLoadedEmptyFolderComponent,
366+
play: async ({ canvasElement }) => {
367+
await userEvent.click(
368+
await within(canvasElement).findByRole('button', { name: 'Copy to' }),
369+
);
370+
},
371+
parameters: {
372+
docs: {
373+
description: {
374+
story:
375+
'Click "Copy to" to open the destination popup. "Loaded empty folder" must not show a caret, while "Not loaded folder" keeps its caret until its contents are loaded. Resize the canvas to verify the same state in the mobile layout.',
376+
},
377+
},
378+
},
379+
};
380+
277381
const PopupComponent = (args: DialFileManagerProps) => {
278382
const [isOpen, setIsOpen] = useState(false);
279383
const { activeTab, handleTabChange, tabs } = useDialFileManagerTabs({

src/components/FileManager/FileManager.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,11 @@ export const DialFileManagerView: FC = () => {
15761576
sourceFolder={
15771577
destinationFolderPopupOptions?.sourceFolder ?? currentPath
15781578
}
1579-
treeOptions={{ header: treeOptions?.header }}
1579+
treeOptions={{
1580+
header: treeOptions?.header,
1581+
loadedPaths: treeOptions?.loadedPaths,
1582+
loadingPaths: treeOptions?.loadingPaths,
1583+
}}
15801584
onFolderPopupPathChange={onFolderPopupPathChange}
15811585
showHiddenFileSwitcher={showHiddenFileSwitcherInDestinationPopup}
15821586
showCreateFolderButton={showCreateFolderButtonInDestinationPopup}

0 commit comments

Comments
 (0)