Skip to content

Commit ce7d7d8

Browse files
author
Daniel Duong
committed
feat: display eye for selected file in details if multiple selected
1 parent d86d639 commit ce7d7d8

4 files changed

Lines changed: 334 additions & 10 deletions

File tree

packages/automl/frontend/src/app/components/common/FileExplorer/FileExplorer.tsx

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,13 @@ const FileDetails: React.FC<FileDetailsProps> = ({ file }) => (
680680

681681
interface SelectedFilesDataListProps {
682682
selectedFiles: Files;
683+
filesToView?: Files;
683684
onViewDetails: (file: File) => void;
684685
onRemoveSelection: (file: File) => void;
685686
}
686687
const SelectedFilesDataList: React.FC<SelectedFilesDataListProps> = ({
687688
selectedFiles,
689+
filesToView,
688690
onViewDetails,
689691
onRemoveSelection,
690692
}) => {
@@ -710,11 +712,28 @@ const SelectedFilesDataList: React.FC<SelectedFilesDataListProps> = ({
710712
<DataListItemCells
711713
dataListCells={[
712714
<DataListCell key="name">
713-
<Truncate
714-
id={`selected-file-${sanitizeId(file.path)}`}
715-
content={file.name}
716-
tooltipPosition="right"
717-
/>
715+
<Flex
716+
spaceItems={{ default: 'spaceItemsSm' }}
717+
alignItems={{ default: 'alignItemsCenter' }}
718+
flexWrap={{ default: 'nowrap' }}
719+
>
720+
<FlexItem>
721+
<Truncate
722+
id={`selected-file-${sanitizeId(file.path)}`}
723+
content={file.name}
724+
tooltipPosition="right"
725+
/>
726+
</FlexItem>
727+
{selectedFiles.length > 1 &&
728+
Array.isArray(filesToView) &&
729+
filesToView.some((f) => f.path === file.path) && (
730+
<FlexItem>
731+
<OutlinedEyeIcon
732+
title={defaults.labels.detailsViewingDetailsOfThisFile}
733+
/>
734+
</FlexItem>
735+
)}
736+
</Flex>
718737
</DataListCell>,
719738
]}
720739
/>
@@ -821,6 +840,7 @@ const DetailsPanel: React.FC<DetailsPanelProps> = ({
821840
{Array.isArray(selectedFiles) && selectedFiles.length > 0 && (
822841
<SelectedFilesDataList
823842
selectedFiles={selectedFiles}
843+
filesToView={filesToView}
824844
onViewDetails={onViewDetails}
825845
onRemoveSelection={onRemoveSelection}
826846
/>

packages/automl/frontend/src/app/components/common/FileExplorer/__tests__/FileExplorer.spec.tsx

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,148 @@ describe('FileExplorer', () => {
794794
expect(mockOnClose).toHaveBeenCalled();
795795
});
796796
});
797+
describe('eye icon indicator in selected files list', () => {
798+
it('should show eye icon next to file being viewed when multiple files are selected', () => {
799+
const files = mockFiles(3);
800+
render(<FileExplorer {...defaultProps} files={files} selection="checkbox" />);
801+
802+
const row1 = screen.getByTestId('file-explorer-row--file-1-json');
803+
const row2 = screen.getByTestId('file-explorer-row--file-2-json');
804+
805+
// Select two files
806+
fireEvent.click(within(row1).getByRole('checkbox'));
807+
fireEvent.click(within(row2).getByRole('checkbox'));
808+
809+
// Click "View details" on first file
810+
const kebab1 = within(row1).getByRole('button', { name: /file-1\.json actions/i });
811+
fireEvent.click(kebab1);
812+
const viewDetailsAction = screen.getByText('View details');
813+
fireEvent.click(viewDetailsAction);
814+
815+
// Eye icon should appear next to file-1 in selected files list
816+
const selectedFilesList = screen.getByTestId('file-explorer-selected-files');
817+
const file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
818+
expect(file1Item).toBeInTheDocument();
819+
820+
// Eye icon should be present for file-1
821+
const eyeIcon = within(file1Item!).getByTitle('Viewing details');
822+
expect(eyeIcon).toBeInTheDocument();
823+
});
824+
it('should NOT show eye icon when only one file is selected', () => {
825+
const files = mockFiles(3);
826+
render(<FileExplorer {...defaultProps} files={files} selection="checkbox" />);
827+
828+
const row1 = screen.getByTestId('file-explorer-row--file-1-json');
829+
830+
// Select only one file
831+
fireEvent.click(within(row1).getByRole('checkbox'));
832+
833+
// Selected files list should exist
834+
const selectedFilesList = screen.getByTestId('file-explorer-selected-files');
835+
const file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
836+
expect(file1Item).toBeInTheDocument();
837+
838+
// Eye icon should NOT be present when only one file selected
839+
const eyeIcon = within(file1Item!).queryByTitle('Viewing details');
840+
expect(eyeIcon).not.toBeInTheDocument();
841+
});
842+
it('should move eye icon when viewing different file in multi-selection', () => {
843+
const files = mockFiles(3);
844+
render(<FileExplorer {...defaultProps} files={files} selection="checkbox" />);
845+
846+
const row1 = screen.getByTestId('file-explorer-row--file-1-json');
847+
const row2 = screen.getByTestId('file-explorer-row--file-2-json');
848+
849+
// Select two files
850+
fireEvent.click(within(row1).getByRole('checkbox'));
851+
fireEvent.click(within(row2).getByRole('checkbox'));
852+
853+
// View details of first file
854+
const kebab1 = within(row1).getByRole('button', { name: /file-1\.json actions/i });
855+
fireEvent.click(kebab1);
856+
fireEvent.click(screen.getByText('View details'));
857+
858+
const selectedFilesList = screen.getByTestId('file-explorer-selected-files');
859+
const file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
860+
const file2Item = within(selectedFilesList).getByText('file-2.json').closest('li');
861+
862+
// Eye should be on file-1
863+
expect(within(file1Item!).queryByTitle('Viewing details')).toBeInTheDocument();
864+
expect(within(file2Item!).queryByTitle('Viewing details')).not.toBeInTheDocument();
865+
866+
// Click on file-2 in selected files list to view its details
867+
fireEvent.click(within(file2Item!).getByText('file-2.json'));
868+
869+
// Eye should now be on file-2
870+
expect(within(file1Item!).queryByTitle('Viewing details')).not.toBeInTheDocument();
871+
expect(within(file2Item!).queryByTitle('Viewing details')).toBeInTheDocument();
872+
});
873+
it('should remove eye icon when deselecting down to one file', () => {
874+
const files = mockFiles(3);
875+
render(<FileExplorer {...defaultProps} files={files} selection="checkbox" />);
876+
877+
const row1 = screen.getByTestId('file-explorer-row--file-1-json');
878+
const row2 = screen.getByTestId('file-explorer-row--file-2-json');
879+
880+
// Select two files
881+
fireEvent.click(within(row1).getByRole('checkbox'));
882+
fireEvent.click(within(row2).getByRole('checkbox'));
883+
884+
// View details of first file
885+
const kebab1 = within(row1).getByRole('button', { name: /file-1\.json actions/i });
886+
fireEvent.click(kebab1);
887+
fireEvent.click(screen.getByText('View details'));
888+
889+
const selectedFilesList = screen.getByTestId('file-explorer-selected-files');
890+
let file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
891+
892+
// Eye icon should be visible with 2 files selected
893+
expect(within(file1Item!).queryByTitle('Viewing details')).toBeInTheDocument();
894+
895+
// Deselect file-2 (leaving only file-1 selected)
896+
fireEvent.click(within(row2).getByRole('checkbox'));
897+
898+
// Eye icon should disappear when only 1 file remains selected
899+
file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
900+
expect(within(file1Item!).queryByTitle('Viewing details')).not.toBeInTheDocument();
901+
});
902+
it('should move eye icon to newly selected file', () => {
903+
const files = mockFiles(3);
904+
render(<FileExplorer {...defaultProps} files={files} selection="checkbox" />);
905+
906+
const row1 = screen.getByTestId('file-explorer-row--file-1-json');
907+
const row2 = screen.getByTestId('file-explorer-row--file-2-json');
908+
const row3 = screen.getByTestId('file-explorer-row--file-3-json');
909+
910+
// Select two files
911+
fireEvent.click(within(row1).getByRole('checkbox'));
912+
fireEvent.click(within(row2).getByRole('checkbox'));
913+
914+
// View details of file-2
915+
const kebab2 = within(row2).getByRole('button', { name: /file-2\.json actions/i });
916+
fireEvent.click(kebab2);
917+
fireEvent.click(screen.getByText('View details'));
918+
919+
const selectedFilesList = screen.getByTestId('file-explorer-selected-files');
920+
let file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
921+
let file2Item = within(selectedFilesList).getByText('file-2.json').closest('li');
922+
923+
// Eye should be on file-2
924+
expect(within(file2Item!).queryByTitle('Viewing details')).toBeInTheDocument();
925+
926+
// Select third file (selecting a file shows its details)
927+
fireEvent.click(within(row3).getByRole('checkbox'));
928+
929+
file1Item = within(selectedFilesList).getByText('file-1.json').closest('li');
930+
file2Item = within(selectedFilesList).getByText('file-2.json').closest('li');
931+
const file3Item = within(selectedFilesList).getByText('file-3.json').closest('li');
932+
933+
// Eye should now be on file-3 (the newly selected file)
934+
expect(within(file1Item!).queryByTitle('Viewing details')).not.toBeInTheDocument();
935+
expect(within(file2Item!).queryByTitle('Viewing details')).not.toBeInTheDocument();
936+
expect(within(file3Item!).queryByTitle('Viewing details')).toBeInTheDocument();
937+
});
938+
});
797939
});
798940

799941
describe('isFolder', () => {

packages/autorag/frontend/src/app/components/common/FileExplorer/FileExplorer.tsx

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,13 @@ const FileDetails: React.FC<FileDetailsProps> = ({ file }) => (
680680

681681
interface SelectedFilesDataListProps {
682682
selectedFiles: Files;
683+
filesToView?: Files;
683684
onViewDetails: (file: File) => void;
684685
onRemoveSelection: (file: File) => void;
685686
}
686687
const SelectedFilesDataList: React.FC<SelectedFilesDataListProps> = ({
687688
selectedFiles,
689+
filesToView,
688690
onViewDetails,
689691
onRemoveSelection,
690692
}) => {
@@ -710,11 +712,28 @@ const SelectedFilesDataList: React.FC<SelectedFilesDataListProps> = ({
710712
<DataListItemCells
711713
dataListCells={[
712714
<DataListCell key="name">
713-
<Truncate
714-
id={`selected-file-${sanitizeId(file.path)}`}
715-
content={file.name}
716-
tooltipPosition="right"
717-
/>
715+
<Flex
716+
spaceItems={{ default: 'spaceItemsSm' }}
717+
alignItems={{ default: 'alignItemsCenter' }}
718+
flexWrap={{ default: 'nowrap' }}
719+
>
720+
<FlexItem>
721+
<Truncate
722+
id={`selected-file-${sanitizeId(file.path)}`}
723+
content={file.name}
724+
tooltipPosition="right"
725+
/>
726+
</FlexItem>
727+
{selectedFiles.length > 1 &&
728+
Array.isArray(filesToView) &&
729+
filesToView.some((f) => f.path === file.path) && (
730+
<FlexItem>
731+
<OutlinedEyeIcon
732+
title={defaults.labels.detailsViewingDetailsOfThisFile}
733+
/>
734+
</FlexItem>
735+
)}
736+
</Flex>
718737
</DataListCell>,
719738
]}
720739
/>
@@ -821,6 +840,7 @@ const DetailsPanel: React.FC<DetailsPanelProps> = ({
821840
{Array.isArray(selectedFiles) && selectedFiles.length > 0 && (
822841
<SelectedFilesDataList
823842
selectedFiles={selectedFiles}
843+
filesToView={filesToView}
824844
onViewDetails={onViewDetails}
825845
onRemoveSelection={onRemoveSelection}
826846
/>

0 commit comments

Comments
 (0)