Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(table): add infinite scroll & virtualization support in table #2530

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions core/components/atoms/progressBar/ProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { BaseProps, extractBaseProps } from '@/utils/types';
import styles from '@css/components/progressBar.module.css';

export type ProgressBarSize = 'small' | 'regular';
export type ProgressBarState = 'default' | 'indeterminate';

export interface ProgressBarProps extends BaseProps {
/**
* Specifies how much of the task that has been completed. Value should lie between 0 to max,
*/
value: number;
value?: number;
/**
* Describes how much work the task indicated by the `Progress Bar` requires
*/
Expand All @@ -18,28 +19,37 @@ export interface ProgressBarProps extends BaseProps {
* Size of `Progress Bar`
*/
size: ProgressBarSize;
/**
* State of `Progress Bar`
*/
state?: ProgressBarState;
}

export const ProgressBar = (props: ProgressBarProps) => {
const { max, value, className, size } = props;
const { max, value, className, size, state } = props;

const baseProps = extractBaseProps(props);

const style = {
width: value > 0 ? `${(Math.min(value, max) * 100) / max}%` : '0',
};
const style =
state !== 'indeterminate'
? {
width: value && value > 0 ? `${(Math.min(value, max) * 100) / max}%` : '0',
}
: {};

const ProgressBarClass = classNames(
{
[styles.ProgressBar]: true,
[styles['ProgressBar-indicator--small']]: size === 'small',
[styles['ProgressBar-indicator--regular']]: size === 'regular',
['position-relative overflow-hidden']: state === 'indeterminate',
},
className
);

const ProgressIndicatorClass = classNames({
[styles['ProgressBar-indicator']]: true,
[styles['ProgressBar-indicator--small']]: size === 'small',
[styles['ProgressBar-indicator--regular']]: size === 'regular',
[styles['ProgressBar-indicator--indeterminate']]: state === 'indeterminate',
});

return (
Expand All @@ -53,6 +63,7 @@ ProgressBar.displayName = 'ProgressBar';
ProgressBar.defaultProps = {
max: 100,
size: 'regular',
state: 'default',
};

export default ProgressBar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { ProgressBar } from '@/index';

// CSF format story
export const indeterminateState = () => {
return <ProgressBar className="w-50" state="indeterminate" />;
};

export default {
title: 'Components/Progress Indicators/ProgressBar/Indeterminate State',
component: ProgressBar,
};

This file was deleted.

11 changes: 10 additions & 1 deletion core/components/atoms/progressBar/__tests__/ProgressBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import ProgressBar, { ProgressBarProps as Props, ProgressBarSize } from '../Prog
import { testHelper, filterUndefined, valueHelper, testMessageHelper } from '@/utils/testHelper';

const sizeList: ProgressBarSize[] = ['regular', 'small'];
const stateList = ['default', 'indeterminate'];

describe('ProgressBar component', () => {
const mapper = {
value: valueHelper(10, { required: true }),
size: valueHelper(sizeList, { required: true, iterate: true }),
state: valueHelper(stateList, { required: true, iterate: true }),
};

const testFunc = (props: Record<string, any>): void => {
Expand Down Expand Up @@ -51,7 +53,14 @@ describe('ProgressBar component size variant', () => {
sizeList.forEach((size) => {
it(`check for ${size} size of progress bar`, () => {
const { getByTestId } = render(<ProgressBar size={size} value={50} />);
expect(getByTestId('DesignSystem-ProgressBar-Indicator')).toHaveClass(`ProgressBar-indicator--${size}`);
expect(getByTestId('DesignSystem-ProgressBar')).toHaveClass(`ProgressBar-indicator--${size}`);
});
});
});

describe('ProgressBar component state variant', () => {
it('check for indeterminate state of progress bar', () => {
const { getByTestId } = render(<ProgressBar state="indeterminate" value={50} />);
expect(getByTestId('DesignSystem-ProgressBar-Indicator')).toHaveClass('ProgressBar-indicator--indeterminate');
});
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ProgressBar component
value: 10, size: "regular"
value: 10, size: "regular", state: "default"
1`] = `
<body>
<div>
<div
class="ProgressBar"
class="ProgressBar ProgressBar-indicator--regular"
data-test="DesignSystem-ProgressBar"
>
<div
class="ProgressBar-indicator ProgressBar-indicator--regular"
class="ProgressBar-indicator"
data-test="DesignSystem-ProgressBar-Indicator"
style="width: 10%;"
/>
Expand All @@ -20,20 +20,56 @@ exports[`ProgressBar component
`;

exports[`ProgressBar component
value: 10, size: "small"
value: 10, size: "regular", state: "indeterminate"
1`] = `
<body>
<div>
<div
class="ProgressBar"
class="ProgressBar ProgressBar-indicator--regular position-relative overflow-hidden"
data-test="DesignSystem-ProgressBar"
>
<div
class="ProgressBar-indicator ProgressBar-indicator--small"
class="ProgressBar-indicator ProgressBar-indicator--indeterminate"
data-test="DesignSystem-ProgressBar-Indicator"
/>
</div>
</div>
</body>
`;

exports[`ProgressBar component
value: 10, size: "small", state: "default"
1`] = `
<body>
<div>
<div
class="ProgressBar ProgressBar-indicator--small"
data-test="DesignSystem-ProgressBar"
>
<div
class="ProgressBar-indicator"
data-test="DesignSystem-ProgressBar-Indicator"
style="width: 10%;"
/>
</div>
</div>
</body>
`;

exports[`ProgressBar component
value: 10, size: "small", state: "indeterminate"
1`] = `
<body>
<div>
<div
class="ProgressBar ProgressBar-indicator--small position-relative overflow-hidden"
data-test="DesignSystem-ProgressBar"
>
<div
class="ProgressBar-indicator ProgressBar-indicator--indeterminate"
data-test="DesignSystem-ProgressBar-Indicator"
/>
</div>
</div>
</body>
`;
92 changes: 83 additions & 9 deletions core/components/organisms/grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type fetchDataFunction = (options: FetchDataOptions) => Promise<{
count: number;
data: Data;
schema: Schema;
totalRowsCount?: number;
}>;

export type updateSortingListFunction = (newSortingList: GridProps['sortingList']) => void;
Expand Down Expand Up @@ -156,6 +157,29 @@ export type GridSize = 'comfortable' | 'standard' | 'compressed' | 'tight';
export type GridType = 'resource' | 'data';
export type Data = RowData[];
export type Schema = ColumnSchema[];
export type thresholdTypes = 'early' | 'balanced' | 'lazy' | 'at-end';

export interface VirtualRowProps {
/**
* Number of rows to be rendered within the visible viewport.
*/
visibleRows?: number;
/**
* Number of additional rows to render before and after the visible rows.
*/
buffer?: number;
}

export interface InfiniteScrollProps {
/**
* Number of rows to Pre-fetch at a time in case of async table
*/
fetchRowsCount: number;
/**
* the distance from the end of the scrollable content at which new data should start fetching in case of async table.
*/
fetchThreshold: thresholdTypes;
}

export interface GridProps extends BaseProps {
/**
Expand Down Expand Up @@ -238,7 +262,7 @@ export interface GridProps extends BaseProps {
* Shows checkbox in the left most column
*/
withCheckbox?: boolean;
/***
/**
* Defines position of checkbox in the row
*/
checkboxAlignment?: 'top' | 'center' | 'bottom';
Expand Down Expand Up @@ -295,6 +319,30 @@ export interface GridProps extends BaseProps {
* Show filters in Head Cell
*/
showFilters: boolean;
/**
* Enable row virtualization
*/
enableRowVirtualization?: boolean;
/**
* Virtual Scroll Options
*/
virtualRowOptions: VirtualRowProps;
/**
* Enable infinite scroll of rows in case of async table & without pagination
*/
enableInfiniteScroll?: boolean;
/**
* Infinite Scroll Options
*/
infiniteScrollOptions: InfiniteScrollProps;
/**
* Callback to be triggered on scroll
*/
onScroll?: (event: Event) => void;
/**
* Fetch Data Function to be called on scroll when threshold is reached in case of async table
*/
fetchDataOnScroll?: (props: { page: number; rowsCount: number }) => Promise<Data>;
}

export interface GridState {
Expand Down Expand Up @@ -510,7 +558,23 @@ export class Grid extends React.Component<GridProps, GridState> {

const { init, prevPageInfo } = this.state;

const { type, size, showHead, className, page, loading, loaderSchema } = this.props;
const {
type,
size,
showHead,
className,
page,
loading,
loaderSchema,
virtualRowOptions,
infiniteScrollOptions,
enableInfiniteScroll,
enableRowVirtualization,
onScroll,
fetchDataOnScroll,
error,
errorTemplate,
} = this.props;

const schema = getSchema(this.props.schema, loading, loaderSchema);

Expand Down Expand Up @@ -548,13 +612,23 @@ export class Grid extends React.Component<GridProps, GridState> {
reorderColumn={this.reorderColumn.bind(this)}
/>
)}
<GridBody
key={`${page}`}
schema={schema}
prevPageInfo={prevPageInfo}
updatePrevPageInfo={this.updatePrevPageInfo.bind(this)}
onSelect={this.onSelect.bind(this)}
/>
{!loading && error ? (
errorTemplate && (typeof errorTemplate === 'function' ? errorTemplate({}) : errorTemplate)
) : (
<GridBody
key={`${page}`}
schema={schema}
prevPageInfo={prevPageInfo}
updatePrevPageInfo={this.updatePrevPageInfo.bind(this)}
onSelect={this.onSelect.bind(this)}
enableRowVirtualization={enableRowVirtualization}
virtualRowOptions={virtualRowOptions}
infiniteScrollOptions={infiniteScrollOptions}
enableInfiniteScroll={enableInfiniteScroll}
onScroll={onScroll}
fetchDataOnScroll={fetchDataOnScroll}
/>
)}
</GridProvider>
)}
</div>
Expand Down
Loading