From 663eb81bbcc227026bbd6131443bda6b25cdfa4b Mon Sep 17 00:00:00 2001 From: Chris Davies Date: Thu, 7 Nov 2019 11:19:40 -0500 Subject: [PATCH 1/4] fix(content-picker): fix issues; see if tests pass --- src/elements/content-picker/Content.js | 3 + src/elements/content-picker/ContentPicker.js | 75 ++++++------------- src/elements/content-picker/ItemList.js | 23 +++++- .../__tests__/cellRendererHelper.test.js | 66 ++++++++++------ .../__tests__/selectionCellRenderer.test.js | 13 +++- .../content-picker/cellRendererHelper.js | 5 +- .../content-picker/selectionCellRenderer.js | 8 +- .../content-picker/shareAccessCellRenderer.js | 7 +- 8 files changed, 111 insertions(+), 89 deletions(-) diff --git a/src/elements/content-picker/Content.js b/src/elements/content-picker/Content.js index 61c88198ed..c57c69ec40 100644 --- a/src/elements/content-picker/Content.js +++ b/src/elements/content-picker/Content.js @@ -27,6 +27,7 @@ type Props = { rootElement?: HTMLElement, rootId: string, selectableType: string, + selected: Array, tableRef: Function, view: View, }; @@ -60,6 +61,7 @@ const Content = ({ onShareAccessChange, onFocusChange, extensionsWhitelist, + selected, }: Props) => (
{view === VIEW_ERROR || view === VIEW_SELECTED ? null : ( @@ -85,6 +87,7 @@ const Content = ({ onFocusChange={onFocusChange} onShareAccessChange={onShareAccessChange} extensionsWhitelist={extensionsWhitelist} + selected={selected} /> )}
diff --git a/src/elements/content-picker/ContentPicker.js b/src/elements/content-picker/ContentPicker.js index 531890f0c1..4db5fce0ce 100644 --- a/src/elements/content-picker/ContentPicker.js +++ b/src/elements/content-picker/ContentPicker.js @@ -102,7 +102,7 @@ type State = { isUploadModalOpen: boolean, rootName: string, searchQuery: string, - selected: { [string]: BoxItem }, + selected: Array, sortBy: SortBy, sortDirection: SortDirection, view: View, @@ -199,7 +199,7 @@ class ContentPicker extends Component { currentCollection: {}, currentOffset: initialPageSize * (initialPage - 1), currentPageSize: initialPageSize, - selected: {}, + selected: [], searchQuery: '', view: VIEW_FOLDER, isCreateFolderModalOpen: false, @@ -287,11 +287,10 @@ class ContentPicker extends Component { choose = (): void => { const { selected }: State = this.state; const { onChoose }: Props = this.props; - const results: BoxItem[] = Object.keys(selected).map(key => { - const clone: BoxItem = { ...selected[key] }; - delete clone.selected; - return clone; + const results: BoxItem[] = selected.map(selectedItem => { + return { ...selectedItem }; }); + onChoose(results); }; @@ -304,13 +303,9 @@ class ContentPicker extends Component { */ cancel = (): void => { const { onCancel }: Props = this.props; - const { selected }: State = this.state; - - // Clear out the selected field - Object.keys(selected).forEach(key => delete selected[key].selected); // Reset the selected state - this.setState({ selected: {} }, () => onCancel()); + this.setState({ selected: [] }, () => onCancel()); }; /** @@ -563,7 +558,7 @@ class ContentPicker extends Component { sortBy, sortDirection, percentLoaded: 100, - items: Object.keys(selected).map(key => this.api.getCache().get(key)), + items: selected, }, }, this.finishNavigation, @@ -782,46 +777,26 @@ class ContentPicker extends Component { return; } - const selectedKeys: Array = Object.keys(selected); - const selectedCount: number = selectedKeys.length; - const hasHitSelectionLimit: boolean = selectedCount === maxSelectable; const isSingleFileSelection: boolean = maxSelectable === 1; - const cacheKey: string = this.api.getAPI(type).getCacheKey(id); - const existing: BoxItem = selected[cacheKey]; - const existingFromCache: BoxItem = this.api.getCache().get(cacheKey); - const existInSelected = selectedKeys.indexOf(cacheKey) !== -1; + const newSelected: Array = isSingleFileSelection ? [] : [...selected]; + const selectedCount: number = newSelected.length; + const hasHitSelectionLimit: boolean = selectedCount === maxSelectable; + const existingIndex: number = newSelected.findIndex(sel => sel.id === id && sel.type === type); + const isAlreadySelected = + existingIndex !== -1 || + (isSingleFileSelection && selected[0] && selected[0].id === id && selected[0].type === type); const itemCanSetShareAccess = getProp(item, 'permissions.can_set_share_access', false); - // Existing object could have mutated and we just need to update the - // reference in the selected map. In that case treat it like a new selection. - if (existing && existing === existingFromCache) { + if (isAlreadySelected) { // We are selecting the same item that was already // selected. Unselect it in this case. Toggle case. - delete existing.selected; - delete selected[cacheKey]; + newSelected.splice(existingIndex, 1); } else { - // We are selecting a new item that was never - // selected before. However if we are in a single - // item selection mode, we should also unselect any - // prior item that was item that was selected. - - // Check if we hit the selection limit and if selection - // is not already currently in the selected data structure. - // Ignore when in single file selection mode. - if (hasHitSelectionLimit && !isSingleFileSelection && !existInSelected) { + if (hasHitSelectionLimit) { return; } - // Clear out the prior item for single file selection mode - if (selectedCount > 0 && isSingleFileSelection) { - const prior = selectedKeys[0]; // only one item - delete selected[prior].selected; - delete selected[prior]; - } - - // Select the new item - item.selected = true; - selected[cacheKey] = item; + newSelected.push(item); // If can set share access, fetch the shared link properties of the item // In the case where another item is selected, any in flight XHR will get @@ -832,7 +807,7 @@ class ContentPicker extends Component { } const focusedRow = items.findIndex((i: BoxItem) => i.id === item.id); - this.setState({ selected, focusedRow }, () => { + this.setState({ selected: newSelected, focusedRow }, () => { if (view === VIEW_SELECTED) { // Need to refresh the selected view this.showSelected(); @@ -881,14 +856,8 @@ class ContentPicker extends Component { if (!item[FIELD_SHARED_LINK]) { this.changeShareAccess(null, item); } else { - const { selected } = this.state; - const { id, type } = item; - const cacheKey = this.api.getAPI(type).getCacheKey(id); // if shared link already exists, update the collection in state this.updateItemInCollection(item); - if (item.selected && item !== selected[cacheKey]) { - this.select(item, { forceSharedLink: false }); - } } }; @@ -918,9 +887,6 @@ class ContentPicker extends Component { this.api.getAPI(type).share(item, access, (updatedItem: BoxItem) => { this.updateItemInCollection(updatedItem); - if (item.selected) { - this.select(updatedItem, { forceSharedLink: false }); - } }); }; @@ -1152,7 +1118,7 @@ class ContentPicker extends Component { }: State = this.state; const { id, offset, permissions, totalCount }: Collection = currentCollection; const { can_upload }: BoxItemPermission = permissions || {}; - const selectedCount: number = Object.keys(selected).length; + const { length: selectedCount } = selected; const isSingleSelect = maxSelectable === 1; const hasHitSelectionLimit: boolean = selectedCount === maxSelectable && !isSingleSelect; const allowUpload: boolean = canUpload && !!can_upload; @@ -1202,6 +1168,7 @@ class ContentPicker extends Component { onItemClick={this.onItemClick} onFocusChange={this.onFocusChange} onShareAccessChange={this.changeShareAccess} + selected={selected} />