forked from Sage-Bionetworks/synapse-web-monorepo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Sage-Bionetworks#599 from jay-hodgson/SWC-6614
SWC-6614
- Loading branch information
Showing
14 changed files
with
1,759 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react' | ||
|
||
const AddAd = (props: React.SVGProps<SVGSVGElement>) => ( | ||
<svg | ||
width="24" | ||
height="24" | ||
viewBox="0 0 24 24" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<mask | ||
id="mask0_6722_37828" | ||
style={{ maskType: 'alpha' }} | ||
maskUnits="userSpaceOnUse" | ||
x="0" | ||
y="0" | ||
width="24" | ||
height="24" | ||
> | ||
<rect width="24" height="24" fill="#D9D9D9" /> | ||
</mask> | ||
<g mask="url(#mask0_6722_37828)"> | ||
<path | ||
d="M18 20V17H15V15H18V12H20V15H23V17H20V20H18ZM3 21C2.45 21 1.97917 20.8042 1.5875 20.4125C1.19583 20.0208 1 19.55 1 19V5C1 4.45 1.19583 3.97917 1.5875 3.5875C1.97917 3.19583 2.45 3 3 3H17C17.55 3 18.0208 3.19583 18.4125 3.5875C18.8042 3.97917 19 4.45 19 5V10H17V8H3V19H16V21H3ZM3 6H17V5H3V6Z" | ||
fill="#395979" | ||
/> | ||
</g> | ||
</svg> | ||
) | ||
|
||
export default AddAd |
53 changes: 53 additions & 0 deletions
53
packages/synapse-react-client/src/components/EntityHeaderTable/DebouncedInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import React, { useState } from 'react' | ||
import { TextField, TextFieldProps, Autocomplete } from '@mui/material' | ||
import { useDebouncedEffect } from '../../utils/hooks' | ||
|
||
// A debounced input react component | ||
|
||
export function DebouncedInput({ | ||
initialValue, | ||
onChange, | ||
options, | ||
delay = 250, | ||
...textFieldProps | ||
}: { | ||
initialValue: string | ||
onChange: (value: string) => void | ||
options: string[] | ||
delay?: number | ||
} & Pick< | ||
React.InputHTMLAttributes<TextFieldProps>, | ||
'type' | 'min' | 'max' | 'value' | 'placeholder' | 'className' | 'list' | ||
>) { | ||
const [value, setValue] = useState(initialValue) | ||
useDebouncedEffect( | ||
() => { | ||
onChange(value) | ||
}, | ||
[value], | ||
delay, | ||
) | ||
|
||
return ( | ||
<Autocomplete | ||
disablePortal | ||
isOptionEqualToValue={(option, value) => | ||
value.length == 0 || option === value | ||
} | ||
options={options} | ||
value={value} | ||
onChange={(event, newValue) => { | ||
setValue(newValue ?? '') | ||
}} | ||
sx={{ marginRight: '10px' }} | ||
renderInput={params => ( | ||
<TextField | ||
{...params} | ||
{...textFieldProps} | ||
value={value} | ||
onChange={e => setValue(e.target.value)} | ||
/> | ||
)} | ||
/> | ||
) | ||
} |
106 changes: 106 additions & 0 deletions
106
...apse-react-client/src/components/EntityHeaderTable/EntityHeaderTable.integration.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { render, screen } from '@testing-library/react' | ||
import React from 'react' | ||
import { createWrapper } from '../../testutils/TestingLibraryUtils' | ||
import { MOCK_REPO_ORIGIN } from '../../utils/functions/getEndpoint' | ||
import { ReferenceList } from '@sage-bionetworks/synapse-types' | ||
import { server } from '../../mocks/msw/server' | ||
import { getEntityHandlers } from '../../mocks/msw/handlers/entityHandlers' | ||
import { EntityHeaderTable, EntityHeaderTableProps } from './EntityHeaderTable' | ||
|
||
import * as EntityFinderModule from '../EntityFinder/EntityFinderModal' | ||
import mockFileEntityData, { | ||
MOCK_FILE_ENTITY_ID, | ||
MOCK_FILE_NAME, | ||
} from '../../mocks/entity/mockFileEntity' | ||
import mockDatasetData, { | ||
MOCK_DATASET_ENTITY_ID, | ||
MOCK_DATASET_NAME, | ||
} from '../../mocks/entity/mockDataset' | ||
import userEvent from '@testing-library/user-event' | ||
|
||
function renderTable(props: EntityHeaderTableProps) { | ||
return render(<EntityHeaderTable {...props} />, { | ||
wrapper: createWrapper(), | ||
}) | ||
} | ||
|
||
jest.spyOn(EntityFinderModule, 'EntityFinderModal').mockImplementation(() => { | ||
return <div data-testid="EntityFinderModal"></div> | ||
}) | ||
|
||
describe('EntityHeaderTable tests', () => { | ||
beforeAll(() => { | ||
server.listen() | ||
}) | ||
beforeEach(() => { | ||
server.use(...getEntityHandlers(MOCK_REPO_ORIGIN)) | ||
}) | ||
afterEach(() => server.restoreHandlers()) | ||
afterAll(() => server.close()) | ||
|
||
it('renders table (not editable)', async () => { | ||
const refs: ReferenceList = [ | ||
{ targetId: mockFileEntityData.id }, | ||
{ targetId: mockDatasetData.id }, | ||
] | ||
renderTable({ references: refs, isEditable: false }) | ||
expect(await screen.findAllByRole('columnheader')).toHaveLength(3) | ||
expect(await screen.findAllByRole('row')).toHaveLength(3) // 1 header row and 2 data rows | ||
expect(await screen.findByText(MOCK_FILE_NAME)).toBeInTheDocument() | ||
expect(await screen.findByText(MOCK_FILE_ENTITY_ID)).toBeInTheDocument() | ||
expect(await screen.findByText(MOCK_DATASET_NAME)).toBeInTheDocument() | ||
expect(await screen.findByText(MOCK_DATASET_ENTITY_ID)).toBeInTheDocument() | ||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument() | ||
expect(screen.queryByRole('textbox')).not.toBeInTheDocument() | ||
}) | ||
|
||
it('renders editable table, with ability to add items', async () => { | ||
const mockOnUpdate = jest.fn() | ||
const refs: ReferenceList = [ | ||
{ targetId: mockFileEntityData.id }, | ||
{ targetId: mockDatasetData.id }, | ||
] | ||
renderTable({ references: refs, isEditable: true, onUpdate: mockOnUpdate }) | ||
|
||
const textField = await screen.findByRole('textbox') | ||
expect(textField.getAttribute('type')).toBe('text') | ||
await userEvent.click(textField) | ||
await userEvent.paste('syn123, syn456') | ||
const button = await screen.findByRole('button', { | ||
name: 'Add Entities', | ||
}) | ||
await userEvent.click(button) | ||
|
||
expect(mockOnUpdate).toHaveBeenCalledWith([ | ||
{ targetId: MOCK_FILE_ENTITY_ID }, | ||
{ targetId: MOCK_DATASET_ENTITY_ID }, | ||
{ targetId: 'syn123' }, | ||
{ targetId: 'syn456' }, | ||
]) | ||
}) | ||
|
||
it('renders editable table, with ability to remove items', async () => { | ||
const mockOnUpdate = jest.fn() | ||
const refs: ReferenceList = [ | ||
{ targetId: mockFileEntityData.id }, | ||
{ targetId: mockDatasetData.id }, | ||
] | ||
const removeEntitiesButtonText = 'Remove Test Entities' | ||
renderTable({ | ||
references: refs, | ||
isEditable: true, | ||
onUpdate: mockOnUpdate, | ||
removeSelectedRowsButtonText: removeEntitiesButtonText, | ||
}) | ||
|
||
const checkBoxes = await screen.findAllByRole('checkbox') | ||
// Click the 'Select All' checkbox | ||
await userEvent.click(checkBoxes[0]) | ||
const button = await screen.findByRole('button', { | ||
name: removeEntitiesButtonText, | ||
}) | ||
await userEvent.click(button) | ||
|
||
expect(mockOnUpdate).toHaveBeenCalledWith([]) | ||
}) | ||
}) |
Oops, something went wrong.