Skip to content

Commit 9cb7ad9

Browse files
authored
Merge pull request #1442 from nickgros/SWC-6910
2 parents 1fcb672 + 5e87476 commit 9cb7ad9

23 files changed

+559
-634
lines changed

packages/synapse-react-client/src/components/ChallengeDataDownload/ChallengeDataDownload.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ export function ChallengeDataDownload({
5151
)
5252

5353
const onAddClick = useCallback(() => {
54-
const entities = selectedEntities.toArray().map(entity => {
54+
const entities = Array.from(selectedEntities.values()).map(reference => {
5555
return {
56-
fileEntityId: entity[0],
57-
versionNumber: entity[1],
56+
fileEntityId: reference.targetId,
57+
versionNumber: reference.targetVersionNumber,
5858
}
5959
})
6060
addBatchToDownloadList(entities)

packages/synapse-react-client/src/components/ChallengeDataDownload/ChallengeDataTable.tsx

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
isContainerType,
1818
isVersionableEntityType,
1919
} from '../../utils/functions/EntityTypeUtils'
20-
import { NO_VERSION_NUMBER } from '../EntityFinder/EntityFinder'
2120
import { VersionSelectionType } from '../EntityFinder/VersionSelectionType'
2221
import {
2322
CellRendererProps,
@@ -130,14 +129,7 @@ export const ChallengeDataTable: React.FunctionComponent<DetailsViewProps> = ({
130129
return selected.has(e.id)
131130
})
132131
.map(e => {
133-
const selectedVersion = selected.get(e.id)
134-
return {
135-
targetId: e.id,
136-
targetVersionNumber:
137-
selectedVersion === NO_VERSION_NUMBER
138-
? undefined
139-
: selectedVersion,
140-
}
132+
return selected.get(e.id)!
141133
}),
142134
)
143135
} else {
@@ -231,13 +223,12 @@ export const ChallengeDataTable: React.FunctionComponent<DetailsViewProps> = ({
231223
// only include entities that should not be hidden
232224
const entityType = getEntityTypeFromHeader(entity)
233225

234-
const currentSelectedVersion = selected.get(entity.id)
226+
const currentSelectedVersion = selected.get(
227+
entity.id,
228+
)?.targetVersionNumber
235229
let versionNumber: number | undefined = undefined
236230
if ('versionNumber' in entity) {
237-
if (
238-
currentSelectedVersion != null &&
239-
currentSelectedVersion !== NO_VERSION_NUMBER
240-
) {
231+
if (currentSelectedVersion != null) {
241232
// if a version is selected, the row should show that version's data
242233
versionNumber = currentSelectedVersion
243234
} else if (versionSelection === VersionSelectionType.REQUIRED) {
@@ -406,10 +397,7 @@ export const ChallengeDataTable: React.FunctionComponent<DetailsViewProps> = ({
406397

407398
toggleSelection({
408399
targetId: id,
409-
targetVersionNumber:
410-
currentSelectedVersion === NO_VERSION_NUMBER
411-
? undefined
412-
: currentSelectedVersion,
400+
targetVersionNumber: currentSelectedVersion,
413401
})
414402
}
415403
},

packages/synapse-react-client/src/components/EntityFileBrowser/EntityFileBrowser.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const EntityFileBrowser: React.FunctionComponent<
5151
[setBreadcrumbsProps],
5252
)
5353
const projectId = entityBundle?.path.path[1].id ?? undefined
54-
const emptyMap = Map<string, number>()
54+
const emptyMap = Map<string, Reference>()
5555
const types: EntityType[] = [
5656
EntityType.FOLDER,
5757
EntityType.FILE,
@@ -66,7 +66,7 @@ export const EntityFileBrowser: React.FunctionComponent<
6666
},
6767
}
6868
return (
69-
<div className="EntityFinderReflexContainer">
69+
<div className="EntityFileBrowser EntityFinderReflexContainer">
7070
<SizeMe>
7171
{({ size }) => (
7272
<ReflexContainer

packages/synapse-react-client/src/components/EntityFinder/EntityFinder.stories.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import EntityFinder from './EntityFinder'
44
import { FinderScope } from './tree/EntityTree'
55
import { EntityType } from '@sage-bionetworks/synapse-types'
66
import { VersionSelectionType } from './VersionSelectionType'
7+
import { fn } from '@storybook/test'
78

89
const meta = {
910
title: 'Synapse/EntityFinder',
@@ -24,37 +25,30 @@ export const DualPane: Story = {
2425
args: {
2526
treeOnly: false,
2627
initialScope: FinderScope.CURRENT_PROJECT,
27-
projectId: 'syn23567475',
28-
initialContainer: 'syn24183903',
28+
projectId: 'syn5550376',
29+
initialContainer: 'syn5550376',
2930
selectMultiple: true,
3031
visibleTypesInList: Object.values(EntityType),
3132
versionSelection: VersionSelectionType.TRACKED,
32-
onSelectedChange: selected => {
33-
console.log('Selection changed:', selected)
34-
},
33+
onSelectedChange: fn(),
3534
selectableTypes: Object.values(EntityType),
36-
selectedCopy: count => {
37-
return `${count} Item${count > 1 ? 's' : ''} Selected`
38-
},
3935
},
4036
}
4137

4238
export const SinglePane: Story = {
4339
args: {
4440
treeOnly: true,
4541
initialScope: FinderScope.CURRENT_PROJECT,
46-
projectId: 'syn23567475',
47-
initialContainer: 'syn24183903',
42+
projectId: 'syn5550376',
43+
initialContainer: 'syn5550376',
4844
selectMultiple: false,
4945
visibleTypesInTree: [
5046
EntityType.PROJECT,
5147
EntityType.FOLDER,
5248
EntityType.TABLE,
5349
],
5450
versionSelection: VersionSelectionType.DISALLOWED,
55-
onSelectedChange: selected => {
56-
console.log('Selection changed:', selected)
57-
},
51+
onSelectedChange: fn(),
5852
selectableTypes: [EntityType.PROJECT, EntityType.FOLDER],
5953
},
6054
}

packages/synapse-react-client/test/containers/entity_finder/EntityFinder.test.tsx renamed to packages/synapse-react-client/src/components/EntityFinder/EntityFinder.test.tsx

Lines changed: 72 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
} from '../../../src/components/EntityFinder/details/EntityDetailsList'
1111
import EntityFinder, {
1212
EntityFinderProps,
13-
NO_VERSION_NUMBER,
1413
} from '../../../src/components/EntityFinder/EntityFinder'
1514
import * as EntityTreeModule from '../../../src/components/EntityFinder/tree/EntityTree'
1615
import { FinderScope } from '../../../src/components/EntityFinder/tree/EntityTree'
@@ -27,6 +26,7 @@ import {
2726
import { Map } from 'immutable'
2827
import * as useEntityBundleModule from '../../../src/synapse-queries/entity/useEntityBundle'
2928
import SynapseClient from '../../../src/synapse-client'
29+
import { getUseQuerySuccessMock } from '../../testutils/ReactQueryMockUtils'
3030

3131
jest.mock('react-reflex', () => {
3232
return {
@@ -42,14 +42,14 @@ jest.mock('react-reflex', () => {
4242

4343
const mockUseGetEntityBundle = jest.spyOn(useEntityBundleModule, 'default')
4444

45-
const mockEntityTree = jest
45+
jest
4646
.spyOn(EntityTreeModule, 'EntityTree')
4747
.mockImplementation(({ toggleSelection, setDetailsViewConfiguration }) => {
4848
invokeToggleSelectionViaTree = reference => {
49-
toggleSelection(reference)
49+
toggleSelection!(reference)
5050
}
5151
invokeSetConfigViaTree = configuration => {
52-
setDetailsViewConfiguration(configuration)
52+
setDetailsViewConfiguration!(configuration)
5353
}
5454
return <div role="tree"></div>
5555
})
@@ -85,30 +85,34 @@ const defaultProps: EntityFinderProps = {
8585
visibleTypesInTree: [EntityType.PROJECT, EntityType.FOLDER],
8686
selectableTypes: Object.values(EntityType),
8787
treeOnly: false,
88-
selectedCopy: 'Chosen Entities',
8988
}
9089

9190
function renderComponent(propOverrides?: Partial<EntityFinderProps>) {
92-
return render(
91+
const user = userEvent.setup()
92+
render(
9393
<SynapseTestContext>
9494
<EntityFinder {...defaultProps} {...propOverrides} />
9595
</SynapseTestContext>,
9696
)
97+
98+
const searchInput = screen.getByRole('textbox')
99+
100+
return { user, searchInput }
97101
}
98102

99103
describe('EntityFinder tests', () => {
100104
beforeEach(() => {
101105
jest.clearAllMocks()
102106

103-
mockUseGetEntityBundle.mockReturnValue({
104-
data: {
107+
mockUseGetEntityBundle.mockReturnValue(
108+
getUseQuerySuccessMock({
105109
entity: {
106110
id: 'syn123',
107111
name: 'My file entity',
108112
concreteType: 'org.sagebionetworks.repo.model.FileEntity',
109113
},
110-
},
111-
})
114+
}),
115+
)
112116
})
113117

114118
describe('single-select toggleSelection validation', () => {
@@ -328,7 +332,9 @@ describe('EntityFinder tests', () => {
328332
await waitFor(() =>
329333
expect(mockDetailsList).toHaveBeenLastCalledWith(
330334
expect.objectContaining({
331-
selected: Map([[reference.targetId, NO_VERSION_NUMBER]]),
335+
selected: Map([
336+
[reference.targetId, { targetId: reference.targetId }],
337+
]),
332338
}),
333339
{},
334340
),
@@ -355,61 +361,24 @@ describe('EntityFinder tests', () => {
355361
})
356362

357363
describe('Search', () => {
358-
it('Updates the search button text when only one type is selectable', async () => {
359-
// Folders are the only selectable type, so only folders will appear in search.
360-
renderComponent({ selectableTypes: [EntityType.FOLDER] })
361-
362-
// Search button text should match
363-
await screen.findByText('Search for Folders')
364-
})
365-
366-
it('Updates the search button text when only table types are selectable', async () => {
367-
// Datasets and entity views are table types
368-
renderComponent({
369-
selectableTypes: [EntityType.DATASET, EntityType.ENTITY_VIEW],
364+
it('handles searching for terms', async () => {
365+
const { user, searchInput } = renderComponent({
366+
treeOnly: true,
367+
selectableTypes: [EntityType.FILE],
370368
})
371369

372-
// Search button text should match
373-
await screen.findByText('Search for Tables')
374-
})
375-
376-
it('clicking the search button opens the input field', async () => {
377-
renderComponent({ treeOnly: true })
378-
379370
// Tree should be visible before we start search. No table should be visible
380-
expect(() => screen.getByRole('tree')).not.toThrowError()
381-
expect(() => screen.getByRole('table')).toThrowError()
382-
383-
// Don't show the search box before the button is clicked
384-
expect(() => screen.getByRole('textbox')).toThrowError()
385-
386-
await userEvent.click(screen.getByText('Search all of Synapse'))
387-
await waitFor(() => screen.getByRole('textbox'))
388-
389-
// The tree should be hidden when searching. The table of search results should be visible
390-
expect(() => screen.getByRole('tree')).toThrowError()
391-
expect(() => screen.getByRole('table')).not.toThrowError()
392-
393-
// Close the search
394-
await userEvent.click(screen.getByText('Back to Browse'))
395-
396-
// Tree should come back, table should be gone
397-
await waitFor(() => screen.getByRole('tree'))
398-
expect(() => screen.getByRole('table')).toThrowError()
399-
400-
// Search input field should be gone too
401-
expect(() => screen.getByRole('textbox')).toThrowError()
402-
})
403-
404-
it('handles searching for terms', async () => {
405-
renderComponent({ selectableTypes: [EntityType.FILE] })
371+
expect(() => screen.getByRole('tree')).not.toThrow()
372+
expect(() => screen.getByRole('table')).toThrow()
406373

407374
const query = 'my search terms '
408375
const queryTerms = ['my', 'search', 'terms']
409-
await userEvent.click(screen.getByText('Search for Files'))
410-
await waitFor(() => screen.getByRole('textbox'))
411-
await userEvent.type(screen.getByRole('textbox'), query)
412-
await userEvent.type(screen.getByRole('textbox'), '{enter}')
376+
await user.type(searchInput, query)
377+
await user.type(searchInput, '{enter}')
378+
379+
// The tree should be hidden when searching. The table of search results should be visible
380+
expect(() => screen.getByRole('tree')).toThrow()
381+
expect(() => screen.getByRole('table')).not.toThrow()
413382

414383
await waitFor(() =>
415384
expect(mockDetailsList).toBeCalledWith(
@@ -453,19 +422,51 @@ describe('EntityFinder tests', () => {
453422
{},
454423
),
455424
)
425+
426+
// Clear the search results and verify we go back to the original view
427+
await user.click(screen.getByRole('button', { name: 'Clear Search' }))
428+
429+
// Tree should be visible once again and table should be hidden
430+
expect(() => screen.getByRole('tree')).not.toThrow()
431+
expect(() => screen.getByRole('table')).toThrow()
456432
})
457433

458434
it('handles searching for a synId', async () => {
459-
renderComponent()
435+
const { user, searchInput } = renderComponent()
460436

461437
const entityId = 'syn123'
462438
const version = 2
463439

464-
const entityHeaderResult = { results: [{ id: entityId }] }
465-
const entityHeaderResultWithVersion: PaginatedResults<
466-
Partial<EntityHeader>
467-
> = {
468-
results: [{ id: entityId, versionNumber: version }],
440+
const entityHeaderResult: PaginatedResults<EntityHeader> = {
441+
results: [
442+
{
443+
id: entityId,
444+
name: 'foo',
445+
benefactorId: 123,
446+
type: 'org.sagebionetworks.repo.model.FileEntity',
447+
createdOn: '',
448+
modifiedOn: '',
449+
createdBy: '',
450+
modifiedBy: '',
451+
isLatestVersion: false,
452+
},
453+
],
454+
}
455+
const entityHeaderResultWithVersion: PaginatedResults<EntityHeader> = {
456+
results: [
457+
{
458+
id: entityId,
459+
versionNumber: version,
460+
name: 'foo',
461+
benefactorId: 123,
462+
type: 'org.sagebionetworks.repo.model.FileEntity',
463+
createdOn: '',
464+
modifiedOn: '',
465+
createdBy: '',
466+
modifiedBy: '',
467+
isLatestVersion: true,
468+
},
469+
],
469470
}
470471

471472
when(mockGetEntityHeaders)
@@ -479,10 +480,8 @@ describe('EntityFinder tests', () => {
479480
)
480481
.mockResolvedValue(entityHeaderResultWithVersion)
481482

482-
await userEvent.click(screen.getByText('Search all of Synapse'))
483-
await waitFor(() => screen.getByRole('textbox'))
484-
await userEvent.type(screen.getByRole('textbox'), entityId)
485-
await userEvent.type(screen.getByRole('textbox'), '{enter}')
483+
await user.type(searchInput, entityId)
484+
await user.type(searchInput, '{enter}')
486485

487486
await waitFor(() =>
488487
expect(mockDetailsList).toBeCalledWith(
@@ -498,12 +497,9 @@ describe('EntityFinder tests', () => {
498497
expect(mockGetEntityHeaders).toBeCalledTimes(1)
499498

500499
// Search with a version number
501-
await userEvent.clear(screen.getByRole('textbox'))
502-
await userEvent.type(
503-
screen.getByRole('textbox'),
504-
`${entityId}.${version}`,
505-
)
506-
await userEvent.type(screen.getByRole('textbox'), '{enter}')
500+
await user.clear(searchInput)
501+
await user.type(searchInput, `${entityId}.${version}`)
502+
await user.type(searchInput, '{enter}')
507503
await waitFor(() =>
508504
expect(mockDetailsList).toBeCalledWith(
509505
expect.objectContaining({

0 commit comments

Comments
 (0)