Skip to content

Commit 74e46b2

Browse files
authored
feat(features): Show preview upon clicking the item name (#1620)
1 parent 63efa10 commit 74e46b2

File tree

5 files changed

+90
-24
lines changed

5 files changed

+90
-24
lines changed

src/common/types/metadataQueries.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type FlattenedMetadataQueryResponseEntry = {
4646
id: string,
4747
metadata: FlattenedMetadataQueryResponseEntryMetadata,
4848
name?: string,
49+
permissions?: BoxItemPermission,
4950
size?: number,
5051
};
5152

src/features/metadata-based-view/MetadataBasedItemList.js

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,27 @@ import classNames from 'classnames';
55
import { injectIntl, type IntlShape } from 'react-intl';
66
import MultiGrid from 'react-virtualized/dist/es/MultiGrid/MultiGrid';
77
import AutoSizer from 'react-virtualized/dist/es/AutoSizer';
8+
import getProp from 'lodash/get';
89
import FileIcon from '../../icons/file-icon';
910
import messages from '../../elements/common/messages';
11+
import PlainButton from '../../components/plain-button';
1012
import { getFileExtension } from '../../utils/file';
1113
import './MetadataBasedItemList.scss';
1214

13-
import type { FlattenedMetadataQueryResponseCollection } from '../../common/types/metadataQueries';
15+
import type {
16+
FlattenedMetadataQueryResponseCollection,
17+
FlattenedMetadataQueryResponseEntry,
18+
} from '../../common/types/metadataQueries';
1419

15-
const FILE_ICON_SIZE = 32;
20+
const FILE_ICON_COLUMN_INDEX = 0;
1621
const FILE_ICON_COLUMN_WIDTH = 54;
17-
const FILENAME_COLUMN_WIDTH = 350;
18-
const MIN_METADATA_COLUMN_WIDTH = 250;
22+
const FILE_ICON_SIZE = 32;
23+
const FILE_NAME_COLUMN_INDEX = 1;
24+
const FILE_NAME_COLUMN_WIDTH = 350;
1925
const FIXED_COLUMNS_NUMBER = 2; // 2 Sticky columns - 1. file-icon, 2. file-name for each row
2026
const FIXED_ROW_NUMBER = 1; // Header row
27+
const HEADER_ROW_INDEX = 0;
28+
const MIN_METADATA_COLUMN_WIDTH = 250;
2129

2230
type State = {
2331
hoveredRowIndex: number,
@@ -27,6 +35,7 @@ type Props = {
2735
currentCollection: FlattenedMetadataQueryResponseCollection,
2836
intl: IntlShape,
2937
metadataColumnsToShow: Array<string>,
38+
onItemClick: FlattenedMetadataQueryResponseEntry => void,
3039
} & InjectIntlProvidedProps;
3140

3241
type CellRendererArgs = {
@@ -53,35 +62,55 @@ class MetadataBasedItemList extends React.Component<Props, State> {
5362
const { metadataColumnsToShow }: Props = this.props;
5463

5564
return ({ index }: { index: number }): number => {
56-
if (index === 0) {
65+
if (index === FILE_ICON_COLUMN_INDEX) {
5766
return FILE_ICON_COLUMN_WIDTH;
5867
}
5968

60-
if (index === 1) {
61-
return FILENAME_COLUMN_WIDTH;
69+
if (index === FILE_NAME_COLUMN_INDEX) {
70+
return FILE_NAME_COLUMN_WIDTH;
6271
}
6372

64-
const availableWidth = width - FILENAME_COLUMN_WIDTH - FILE_ICON_COLUMN_WIDTH; // total width minus width of sticky columns
73+
const availableWidth = width - FILE_NAME_COLUMN_WIDTH - FILE_ICON_COLUMN_WIDTH; // total width minus width of sticky columns
6574
// Maintain min column width, else occupy the rest of the space equally
6675
return Math.max(availableWidth / metadataColumnsToShow.length, MIN_METADATA_COLUMN_WIDTH);
6776
};
6877
}
6978

70-
getGridCellData(columnIndex: number, rowIndex: number): Element<typeof FileIcon> | string {
71-
const { currentCollection, metadataColumnsToShow }: Props = this.props;
72-
const { items } = currentCollection;
73-
const { name = '', metadata = {} } = items[rowIndex - 1];
79+
handleOnClick(item: FlattenedMetadataQueryResponseEntry): void {
80+
const { onItemClick }: Props = this.props;
81+
/*
82+
- @TODO: Remove permissions object once its part of API response.
83+
- In Content Explorer element, if can_preview permission is false, there is no action taken onClick(item).
84+
- Until the response has permissions, add "can_preview: true" so that users can click to launch the Preview modal. If users don't have access, they will see the error when Preview loads.
85+
*/
86+
const permissions = { can_preview: true };
87+
const itemWithPreviewPermission = { ...item, permissions };
88+
89+
onItemClick(itemWithPreviewPermission);
90+
}
91+
92+
getGridCellData(columnIndex: number, rowIndex: number): Element<typeof FileIcon | typeof PlainButton> | string {
93+
const {
94+
currentCollection: { items },
95+
metadataColumnsToShow,
96+
}: Props = this.props;
97+
const item = items[rowIndex - 1];
98+
const { name } = item;
7499
let cellData;
75100

76101
switch (columnIndex) {
77-
case 0:
102+
case FILE_ICON_COLUMN_INDEX:
78103
cellData = <FileIcon dimension={FILE_ICON_SIZE} extension={getFileExtension(name)} />;
79104
break;
80-
case 1:
81-
cellData = name;
105+
case FILE_NAME_COLUMN_INDEX:
106+
cellData = (
107+
<PlainButton type="button" onClick={() => this.handleOnClick(item)}>
108+
{name}
109+
</PlainButton>
110+
);
82111
break;
83112
default: {
84-
const { data = {} } = metadata;
113+
const data = getProp(item, 'metadata.data', {});
85114
const mdFieldName = metadataColumnsToShow[columnIndex - FIXED_COLUMNS_NUMBER];
86115
cellData = data[mdFieldName];
87116
}
@@ -95,11 +124,11 @@ class MetadataBasedItemList extends React.Component<Props, State> {
95124

96125
let headerData;
97126

98-
if (columnIndex === 1) {
127+
if (columnIndex === FILE_NAME_COLUMN_INDEX) {
99128
headerData = intl.formatMessage(messages.name); // "Name" column header
100129
}
101130

102-
if (columnIndex > 1) {
131+
if (columnIndex > FILE_NAME_COLUMN_INDEX) {
103132
headerData = metadataColumnsToShow[columnIndex - FIXED_COLUMNS_NUMBER]; // column header
104133
}
105134

@@ -112,11 +141,17 @@ class MetadataBasedItemList extends React.Component<Props, State> {
112141

113142
cellRenderer = ({ columnIndex, rowIndex, key, style }: CellRendererArgs): Element<'div'> => {
114143
const { hoveredRowIndex } = this.state;
115-
const data = rowIndex === 0 ? this.getGridHeaderData(columnIndex) : this.getGridCellData(columnIndex, rowIndex);
144+
const isHeaderRow = rowIndex === HEADER_ROW_INDEX;
145+
const isFileIconCell = !isHeaderRow && columnIndex === FILE_ICON_COLUMN_INDEX;
146+
const isFileNameCell = !isHeaderRow && columnIndex === FILE_NAME_COLUMN_INDEX;
147+
const isGridRowHovered = !isHeaderRow && rowIndex === hoveredRowIndex;
148+
149+
const data = isHeaderRow ? this.getGridHeaderData(columnIndex) : this.getGridCellData(columnIndex, rowIndex);
150+
116151
const classes = classNames('bdl-MetadataBasedItemList-cell', {
117-
'bdl-MetadataBasedItemList-cell--fileIcon': rowIndex > 0 && columnIndex === 0, // file icon cell
118-
'bdl-MetadataBasedItemList-cell--filename': columnIndex === 1, // file name cell
119-
'bdl-MetadataBasedItemList-cell--hover': rowIndex > 0 && rowIndex === hoveredRowIndex,
152+
'bdl-MetadataBasedItemList-cell--fileIcon': isFileIconCell,
153+
'bdl-MetadataBasedItemList-cell--filename': isFileNameCell,
154+
'bdl-MetadataBasedItemList-cell--hover': isGridRowHovered,
120155
});
121156

122157
return (

src/features/metadata-based-view/MetadataBasedItemList.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121

2222
.bdl-MetadataBasedItemList-cell--filename {
2323
color: $bdl-gray;
24+
25+
& .btn-plain {
26+
outline: none;
27+
}
2428
}
2529

2630
.bdl-MetadataBasedItemList-cell--hover {

src/features/metadata-based-view/__tests__/MetadataBasedItemList-test.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22
import FileIcon from '../../../icons/file-icon';
3+
import PlainButton from '../../../components/plain-button';
34

45
import { MetadataBasedItemListComponent as MetadataBasedItemList } from '../MetadataBasedItemList';
56

@@ -9,6 +10,8 @@ describe('features/metadata-based-view/MetadataBasedItemList', () => {
910
let wrapper;
1011
let instance;
1112
const intl = { formatMessage: jest.fn().mockReturnValue('Name') };
13+
const onItemClick = jest.fn();
14+
const onClick = expect.any(Function);
1215
const currentCollection = {
1316
items: [
1417
{
@@ -27,13 +30,25 @@ describe('features/metadata-based-view/MetadataBasedItemList', () => {
2730
nextMarker: 'abc',
2831
};
2932
const metadataColumnsToShow = ['type', 'amount'];
33+
34+
const pdfNameButton = (
35+
<PlainButton onClick={onClick} type="button">
36+
{currentCollection.items[0].name}
37+
</PlainButton>
38+
);
39+
const mp4NameButton = (
40+
<PlainButton onClick={onClick} type="button">
41+
{currentCollection.items[1].name}
42+
</PlainButton>
43+
);
3044
const pdfIcon = <FileIcon dimension={32} extension="pdf" />;
3145
const mp4Icon = <FileIcon dimension={32} extension="mp4" />;
3246

3347
const defaultProps = {
3448
currentCollection,
3549
metadataColumnsToShow,
3650
intl,
51+
onItemClick,
3752
};
3853

3954
const getWrapper = (props = defaultProps) => mount(<MetadataBasedItemList {...props} />);
@@ -60,11 +75,11 @@ describe('features/metadata-based-view/MetadataBasedItemList', () => {
6075
test.each`
6176
columnIndex | rowIndex | cellData
6277
${0} | ${1} | ${pdfIcon}
63-
${1} | ${1} | ${'name1.pdf'}
78+
${1} | ${1} | ${pdfNameButton}
6479
${2} | ${1} | ${'bill'}
6580
${3} | ${1} | ${500}
6681
${0} | ${2} | ${mp4Icon}
67-
${1} | ${2} | ${'name2.mp4'}
82+
${1} | ${2} | ${mp4NameButton}
6883
${2} | ${2} | ${'receipt'}
6984
${3} | ${2} | ${200}
7085
`('cellData for row: $rowIndex, column: $columnIndex', ({ columnIndex, rowIndex, cellData }) => {
@@ -86,6 +101,16 @@ describe('features/metadata-based-view/MetadataBasedItemList', () => {
86101
});
87102
});
88103

104+
describe('handleOnClick(item)', () => {
105+
test('should invoke the onItemClick after adding can_preview permissions', () => {
106+
const permissions = { can_preview: true };
107+
const item = currentCollection.items[0];
108+
const itemWithPreviewPermission = { ...item, ...{ permissions } };
109+
instance.handleOnClick(item);
110+
expect(onItemClick).toHaveBeenCalledWith(itemWithPreviewPermission);
111+
});
112+
});
113+
89114
describe('handleMouseEnter()', () => {
90115
test('should handle mouse over event by setting state accordingly', () => {
91116
instance.handleMouseEnter(5);

src/features/metadata-based-view/__tests__/__snapshots__/MetadataBasedItemList-test.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ exports[`features/metadata-based-view/MetadataBasedItemList render() should rend
3838
"amount",
3939
]
4040
}
41+
onItemClick={[MockFunction]}
4142
>
4243
<Component>
4344
AutoSizer

0 commit comments

Comments
 (0)