Skip to content

Commit

Permalink
Data-grid filter improvements (+ external paginator) (#3162)
Browse files Browse the repository at this point in the history
* feat(data-grid): Implement design changes for filtering

* feat(data-grid): Add externalPaginator prop

* feat(data-grid): Tweak design after talking w/ Birte

* fix test setup?

* Fix linter errors

---------

Co-authored-by: oddvernes <[email protected]>
  • Loading branch information
yusijs and oddvernes authored Dec 1, 2023
1 parent c77f133 commit f6fed15
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 106 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"build:storybook:data-grid": "pnpm --filter ./packages/eds-data-grid-react run build:storybook",
"test": "pnpm run test:utils && pnpm run test:core-react && pnpm run test:lab && pnpm run test:data-grid-react",
"test:core-react": "pnpm --filter @equinor/eds-core-react run test",
"test:data-grid-react": "pnpm --filter @equinor/eds-core-react run test",
"test:data-grid-react": "pnpm --filter @equinor/eds-data-grid-react run test",
"test:lab": "pnpm --filter @equinor/eds-lab-react run test",
"test:utils": "pnpm --filter @equinor/eds-utils run test",
"test:watch:core-react": "pnpm --filter @equinor/eds-core-react run test:watch",
Expand Down
2 changes: 2 additions & 0 deletions packages/eds-data-grid-react/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const config: Config = {
'<rootDir>/node_modules/@equinor/eds-utils/src/test/__mocks__/styleMock.js',
'^react$': '<rootDir>/node_modules/react',
'^styled-components$': '<rootDir>/node_modules/styled-components',
'^@equinor/eds-core-react$':
'<rootDir>/node_modules/@equinor/eds-core-react/dist/esm/index.js',
},
testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
testEnvironment: 'jest-environment-jsdom',
Expand Down
38 changes: 37 additions & 1 deletion packages/eds-data-grid-react/src/EdsDataGrid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { EdsDataGrid, EdsDataGridProps } from './EdsDataGrid'
import { columns, groupedColumns, Photo } from './stories/columns'
import { data } from './stories/data'
import { CSSProperties, useEffect, useState } from 'react'
import { Button, Checkbox, Paper, Typography } from '@equinor/eds-core-react'
import {
Button,
Checkbox,
Pagination,
Paper,
Typography,
} from '@equinor/eds-core-react'
import page from './EdsDataGrid.docs.mdx'
import { Column, Row } from '@tanstack/react-table'
import { tokens } from '@equinor/eds-tokens'
import { action } from '@storybook/addon-actions'

const meta: Meta<typeof EdsDataGrid<Photo>> = {
title: 'EDS Data grid',
Expand Down Expand Up @@ -57,6 +64,35 @@ Paging.args = {
pageSize: 10,
}

export const ExternalPaging: StoryFn<EdsDataGridProps<Photo>> = (args) => {
return (
<>
<div>
<Typography variant={'body_long'}>
Using externalPaginator gives you control over setting the appropriate
rows yourself.
</Typography>
<Typography variant={'body_long'}>
This is useful for e.g server-side pagination
</Typography>
</div>
<EdsDataGrid
{...args}
externalPaginator={
<Pagination
itemsPerPage={10}
totalItems={40}
withItemIndicator
onChange={(event, page) => {
action(`Page changed`)(page)
}}
/>
}
/>
</>
)
}

export const ColumnGrouping: StoryFn<EdsDataGridProps<Photo>> = (args) => {
return <EdsDataGrid {...args} />
}
Expand Down
32 changes: 21 additions & 11 deletions packages/eds-data-grid-react/src/EdsDataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ export type EdsDataGridProps<T> = {
* @default 25
*/
pageSize?: number
/**
* Add this if you want to implement a custom pagination component
* Useful for e.g server-side paging
*/
externalPaginator?: ReactElement
/**
* The message to display when there are no rows
* @default undefined
Expand Down Expand Up @@ -191,6 +196,7 @@ export function EdsDataGrid<T>({
rowStyle,
headerClass,
headerStyle,
externalPaginator,
}: EdsDataGridProps<T>) {
const [sorting, setSorting] = useState<SortingState>([])
const [selection, setSelection] = useState<RowSelectionState>(
Expand Down Expand Up @@ -467,17 +473,21 @@ export function EdsDataGrid<T>({
.rows.map((row) => <TableRow key={row.id} row={row} />)}
</Table.Body>
</Table>
{enablePagination && (
<div style={{ maxWidth: `${table.getTotalSize()}px` }}>
<Pagination
totalItems={table.getFilteredRowModel().rows.length}
withItemIndicator={true}
itemsPerPage={page.pageSize}
onChange={(e, p) => setPage((s) => ({ ...s, pageIndex: p - 1 }))}
defaultPage={1}
/>
</div>
)}
{externalPaginator
? externalPaginator
: enablePagination && (
<div style={{ maxWidth: `${table.getTotalSize()}px` }}>
<Pagination
totalItems={table.getFilteredRowModel().rows.length}
withItemIndicator={true}
itemsPerPage={page.pageSize}
onChange={(e, p) =>
setPage((s) => ({ ...s, pageIndex: p - 1 }))
}
defaultPage={1}
/>
</div>
)}
</div>
{debug && enableVirtual && (
<span>
Expand Down
87 changes: 63 additions & 24 deletions packages/eds-data-grid-react/src/components/DebouncedInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* istanbul ignore file */
import { ChangeEvent, InputHTMLAttributes, useEffect, useState } from 'react'
import { Autocomplete, EdsProvider, Input } from '@equinor/eds-core-react'
import {
Autocomplete,
InputWrapper,
Input,
Chip,
} from '@equinor/eds-core-react'

type Value = string | number | Array<string | number>
// File ignored, as relevant actions are covered via Filter.test.tsx
Expand All @@ -9,12 +14,14 @@ export function DebouncedInput({
values,
onChange,
debounce = 500,
label,
...props
}: {
value: Value
values: Array<string | number>
onChange: (value: Value) => void
debounce?: number
label?: string
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange'>) {
const [value, setValue] = useState<Value>(initialValue)

Expand All @@ -32,31 +39,63 @@ export function DebouncedInput({
}, [value])

return (
<EdsProvider density="compact">
<>
{props.type === 'number' ? (
<Input
type={'number'}
placeholder={props.placeholder ?? 'Search'}
value={value}
onChange={(e: ChangeEvent) =>
setValue((e.target as HTMLInputElement).valueAsNumber)
}
/>
<InputWrapper label={props.placeholder}>
<Input
type={'number'}
placeholder={'0'}
value={value}
onChange={(e: ChangeEvent) =>
setValue((e.target as HTMLInputElement).valueAsNumber)
}
/>
</InputWrapper>
) : (
<Autocomplete
options={values}
multiple={true}
optionComponent={(opt) =>
opt === 'NULL_OR_UNDEFINED' ? '<Blank>' : opt
}
data-testid={'autocomplete'}
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
// @ts-ignore
label={null}
placeholder={props.placeholder ?? 'Search'}
onOptionsChange={(c) => setValue(c.selectedItems)}
/>
<>
<Autocomplete
options={values}
autoWidth={true}
multiple={true}
optionComponent={(opt) =>
opt === 'NULL_OR_UNDEFINED' ? '<Blank>' : opt
}
data-testid={'autocomplete'}
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
label={`Select ${label ?? ''}`}
placeholder={props.placeholder ?? 'Search'}
disablePortal={
false /*TODO: Check with Oddbjørn re. sizing/position*/
}
selectedOptions={value as Array<string>}
onOptionsChange={(c) => setValue(c.selectedItems)}
/>
<div style={{ display: 'flex', flexWrap: 'wrap', marginTop: '8px' }}>
{(value as Array<string>).map((v) => (
<Chip
title={v}
onKeyDownCapture={(event) => {
if (['Backspace', 'Delete'].includes(event.key)) {
onChange(
(value as Array<string>).filter((item) => item !== v),
)
}
}}
style={{ margin: '4px' }}
onDelete={() =>
onChange(
(value as Array<string>).filter((item) => item !== v),
)
}
key={v}
>
{v.slice(0, 20)}
{v.length > 20 ? '...' : ''}
</Chip>
))}
</div>
</>
)}
</EdsProvider>
</>
)
}
Loading

0 comments on commit f6fed15

Please sign in to comment.