re-structure to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 01:02:31 +02:00
parent 8242ec64ba
commit 7a0a13f9d5
10400 changed files with 46966 additions and 17223 deletions

View File

@@ -0,0 +1,30 @@
// @ts-nocheck
import React from 'react';
import { get } from 'lodash';
import { getForceWidth } from '@/utils';
export function CellForceWidth({
value,
column: { forceWidthAccess },
row: { original },
}) {
const forceWidthValue = forceWidthAccess
? get(original, forceWidthAccess)
: value;
return <ForceWidth forceValue={forceWidthValue}>{value}</ForceWidth>;
}
export function ForceWidth({ children, forceValue }) {
const forceWidthValue = forceValue || children;
return (
<span
className={'force-width'}
style={{ minWidth: getForceWidth(forceWidthValue) }}
>
{children}
</span>
);
}

View File

@@ -0,0 +1,6 @@
// @ts-nocheck
import React from 'react';
export function CellTextSpan({ cell: { value } }) {
return (<span class="cell-text">{ value }</span>)
}

View File

@@ -0,0 +1,231 @@
// @ts-nocheck
import React, { useEffect, useRef } from 'react';
import {
useTable,
useExpanded,
useRowSelect,
usePagination,
useResizeColumns,
useSortBy,
useFlexLayout,
useAsyncDebounce,
} from 'react-table';
import { useSticky } from 'react-table-sticky';
import { useUpdateEffect } from '@/hooks';
import { saveInvoke } from '@/utils';
import '@/style/components/DataTable/DataTable.scss';
import TableNoResultsRow from './TableNoResultsRow';
import TableLoadingRow from './TableLoading';
import TableHeader from './TableHeader';
import TablePage from './TablePage';
import TableFooter from './TableFooter';
import TableRow from './TableRow';
import TableRows from './TableRows';
import TableCell from './TableCell';
import TableTBody from './TableTBody';
import TableContext from './TableContext';
import TablePagination from './TablePagination';
import TableWrapper from './TableWrapper';
import TableIndeterminateCheckboxRow from './TableIndeterminateCheckboxRow';
import TableIndeterminateCheckboxHeader from './TableIndeterminateCheckboxHeader';
import { useResizeObserver } from './utils';
/**
* Datatable component.
*/
export function DataTable(props) {
const {
columns,
data,
onFetchData,
onSelectedRowsChange,
manualSortBy = false,
manualPagination = true,
selectionColumn = false,
expandSubRows = true,
expanded = {},
rowClassNames,
payload,
expandable = false,
noInitialFetch = false,
pagesCount: controlledPageCount,
// Pagination props.
initialPageIndex = 0,
initialPageSize = 10,
updateDebounceTime = 200,
selectionColumnWidth = 42,
autoResetPage,
autoResetExpanded,
autoResetGroupBy,
autoResetSelectedRows,
autoResetSortBy,
autoResetFilters,
autoResetRowState,
// Components
TableHeaderRenderer,
TablePageRenderer,
TableWrapperRenderer,
TableTBodyRenderer,
TablePaginationRenderer,
TableFooterRenderer,
onColumnResizing,
initialColumnsWidths,
...restProps
} = props;
const selectionColumnObj = {
id: 'selection',
disableResizing: true,
minWidth: selectionColumnWidth,
width: selectionColumnWidth,
maxWidth: selectionColumnWidth,
skeletonWidthMin: 100,
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: TableIndeterminateCheckboxHeader,
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: TableIndeterminateCheckboxRow,
className: 'selection',
...(typeof selectionColumn === 'object' ? selectionColumn : {}),
};
const table = useTable(
{
columns,
data,
initialState: {
pageIndex: initialPageIndex,
pageSize: initialPageSize,
expanded,
columnResizing: {
columnWidths: initialColumnsWidths || {},
},
},
manualPagination,
pageCount: controlledPageCount,
getSubRows: (row) => row.children,
manualSortBy,
expandSubRows,
payload,
autoResetPage,
autoResetExpanded,
autoResetGroupBy,
autoResetSelectedRows,
autoResetSortBy,
autoResetFilters,
autoResetRowState,
...restProps,
},
useSortBy,
useExpanded,
useResizeColumns,
useFlexLayout,
useSticky,
usePagination,
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
...(selectionColumn ? [selectionColumnObj] : []),
...columns,
]);
},
);
const {
selectedFlatRows,
state: { pageIndex, pageSize, sortBy, selectedRowIds },
} = table;
const isInitialMount = useRef(noInitialFetch);
const onFetchDataDebounced = useAsyncDebounce((...args) => {
saveInvoke(onFetchData, ...args);
}, updateDebounceTime);
// When these table states change, fetch new data!
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
onFetchDataDebounced({ pageIndex, pageSize, sortBy });
}
}, [pageIndex, pageSize, sortBy, onFetchDataDebounced]);
useUpdateEffect(() => {
saveInvoke(onSelectedRowsChange, selectedFlatRows);
}, [selectedRowIds, onSelectedRowsChange]);
// Column resizing observer.
useResizeObserver(table.state, (current, columnWidth, columnsResizing) => {
onColumnResizing && onColumnResizing(current, columnWidth, columnsResizing);
});
return (
<TableContext.Provider value={{ table, props }}>
<TableWrapperRenderer>
<TableHeaderRenderer />
<TableTBodyRenderer>
<TablePageRenderer />
</TableTBodyRenderer>
<TableFooterRenderer />
</TableWrapperRenderer>
<TablePaginationRenderer />
</TableContext.Provider>
);
}
DataTable.defaultProps = {
pagination: false,
hidePaginationNoPages: true,
hideTableHeader: false,
size: null,
spinnerProps: { size: 30 },
expandToggleColumn: 1,
expandColumnSpace: 0.8,
autoResetPage: true,
autoResetExpanded: true,
autoResetGroupBy: true,
autoResetSelectedRows: true,
autoResetSortBy: true,
autoResetFilters: true,
autoResetRowState: true,
TableHeaderRenderer: TableHeader,
TableFooterRenderer: TableFooter,
TableLoadingRenderer: TableLoadingRow,
TablePageRenderer: TablePage,
TableRowsRenderer: TableRows,
TableRowRenderer: TableRow,
TableCellRenderer: TableCell,
TableWrapperRenderer: TableWrapper,
TableTBodyRenderer: TableTBody,
TablePaginationRenderer: TablePagination,
TableNoResultsRowRenderer: TableNoResultsRow,
noResults: '',
payload: {},
};

View File

@@ -0,0 +1,116 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { DataTable } from './DataTable';
/**
* Editable datatable.
*/
export function DataTableEditable({
totalRow = false,
actions,
name,
...tableProps
}) {
return (
<DatatableEditableRoot>
<DataTable {...tableProps} />
</DatatableEditableRoot>
);
}
const DatatableEditableRoot = styled.div`
.bp3-form-group {
margin-bottom: 0;
}
.table {
border: 1px solid #d2dce2;
border-radius: 5px;
background-color: #fff;
.th,
.td {
border-left: 1px solid #e2e2e2;
&:first-of-type {
border-left: 0;
}
}
.thead {
.tr .th {
padding: 9px 14px;
background-color: #f2f3fb;
font-size: 13px;
color: #415060;
border-bottom: 1px solid #d2dce2;
&,
.inner-resizer {
border-left-color: transparent;
}
}
}
.tbody {
.tr .td {
border-bottom: 0;
border-bottom: 1px solid #d8d8d8;
min-height: 38px;
padding: 4px 14px;
&.td-field-type,
&.td-button-type {
padding: 2px;
}
}
.tr:last-of-type .td {
border-bottom: 0;
}
.tr {
&:hover .td,
.bp3-input {
background-color: transparent;
}
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
.form-group--select-list .bp3-button {
border-color: #ffffff;
color: #222;
border-radius: 3px;
text-align: inherit;
}
.bp3-form-group:not(.bp3-intent-danger) .bp3-input {
border-radius: 2px;
padding-left: 14px;
padding-right: 14px;
&:focus {
box-shadow: 0 0 0 2px #116cd0;
}
}
.form-group--select-list .bp3-button {
padding-left: 6px;
padding-right: 6px;
&:after {
display: none;
}
}
.form-group--select-list,
.bp3-form-group {
&.bp3-intent-danger {
.bp3-button:not(.bp3-minimal),
.bp3-input {
border-color: #f7b6b6;
}
}
}
.td.actions {
.bp3-button {
color: #80858f;
}
}
}
}
}
`;

View File

@@ -0,0 +1,230 @@
// @ts-nocheck
import React, { useReducer, useEffect } from 'react';
import classNames from 'classnames';
import { Button, ButtonGroup, Intent, HTMLSelect } from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import PropTypes from 'prop-types';
import { range } from 'lodash';
import { Icon } from '@/components';
import '@/style/components/DataTable/Pagination.scss';
const TYPE = {
PAGE_CHANGE: 'PAGE_CHANGE',
PAGE_SIZE_CHANGE: 'PAGE_SIZE_CHANGE',
INITIALIZE: 'INITIALIZE',
};
const getState = ({ currentPage, size, total }) => {
const totalPages = Math.ceil(total / size);
const visibleItems = 5;
const halfVisibleItems = Math.ceil(visibleItems / 2);
// create an array of pages to ng-repeat in the pager control
let startPage, endPage;
if (totalPages <= visibleItems) {
// less than {visibleItems} total pages so show
startPage = 1;
endPage = totalPages;
} else {
// more than {visibleItems} total pages so calculate start and end pages
if (currentPage <= halfVisibleItems) {
startPage = 1;
endPage = visibleItems;
} else if (currentPage + (halfVisibleItems - 1) >= totalPages) {
startPage = totalPages - (visibleItems - 1);
endPage = totalPages;
} else {
startPage = currentPage - halfVisibleItems;
endPage = currentPage + halfVisibleItems - 1;
}
}
const pages = [...Array(endPage + 1 - startPage).keys()].map(
(i) => startPage + i,
);
// Too large or small currentPage
let correctCurrentpage = currentPage;
if (currentPage > totalPages) correctCurrentpage = totalPages;
if (currentPage <= 0) correctCurrentpage = 1;
return {
currentPage: correctCurrentpage,
size,
total,
pages,
totalPages,
};
};
const reducer = (state, action) => {
switch (action.type) {
case TYPE.PAGE_CHANGE:
return getState({
currentPage: action.page,
size: state.size,
total: state.total,
});
case TYPE.PAGE_SIZE_CHANGE:
return getState({
currentPage: state.currentPage,
size: action.size,
total: state.total,
});
case TYPE.INITIALIZE:
return getState({
currentPage: action.page,
size: action.size,
total: action.total,
});
default:
throw new Error();
}
};
export function Pagination({
currentPage,
total,
size,
pageSizesOptions = [20, 30, 50, 75, 100, 150],
onPageChange,
onPageSizeChange,
}) {
const [state, dispatch] = useReducer(
reducer,
{ currentPage, total, size },
getState,
);
useEffect(() => {
dispatch({
type: TYPE.INITIALIZE,
total,
size,
page: currentPage,
});
}, [total, size, currentPage]);
return (
<div class="pagination">
<div class="pagination__buttons-group">
<ButtonGroup>
<Button
disabled={state.currentPage <= 1}
onClick={() => {
dispatch({ type: 'PAGE_CHANGE', page: state.currentPage - 1 });
const page = state.currentPage - 1;
const { size: pageSize } = state;
onPageChange({ page, pageSize });
}}
minimal={true}
className={'pagination__item pagination__item--previous'}
icon={<Icon icon={'arrow-back-24'} iconSize={12} />}
>
<T id="previous" />
</Button>
{state.pages.map((page) => (
<Button
key={page}
intent={state.currentPage === page ? Intent.PRIMARY : Intent.NONE}
disabled={state.currentPage === page}
onClick={() => {
dispatch({ type: 'PAGE_CHANGE', page });
const { size: pageSize } = state;
onPageChange({ page, pageSize });
}}
minimal={true}
className={classNames(
'pagination__item',
'pagination__item--page',
{
'is-active': state.currentPage === page,
},
)}
>
{page}
</Button>
))}
<Button
disabled={state.currentPage === state.totalPages}
onClick={() => {
dispatch({
type: 'PAGE_CHANGE',
page: state.currentPage + 1,
});
const page = state.currentPage + 1;
const { size: pageSize } = state;
onPageChange({ page, pageSize });
}}
minimal={true}
className={'pagination__item pagination__item--next'}
icon={<Icon icon={'arrow-forward-24'} iconSize={12} />}
>
<T id="next" />
</Button>
</ButtonGroup>
</div>
<div class="pagination__controls">
<div class="pagination__goto-control">
Go to
<HTMLSelect
minimal={true}
options={range(1, state.totalPages + 1)}
value={state.currentPage}
onChange={(event) => {
const page = parseInt(event.currentTarget.value, 10);
const { size: pageSize } = state;
dispatch({ type: 'PAGE_CHANGE', page });
onPageChange({ page, pageSize });
}}
/>
</div>
<div class="pagination__pagesize-control">
<T id={'page_size'} />
<HTMLSelect
minimal={true}
options={pageSizesOptions}
value={size}
onChange={(event) => {
const pageSize = parseInt(event.currentTarget.value, 10);
dispatch({ type: 'PAGE_SIZE_CHANGE', size: pageSize });
dispatch({ type: 'PAGE_CHANGE', page: 1 });
onPageSizeChange({ pageSize, page: 1 });
}}
/>
</div>
</div>
<div class="pagination__info">
{intl.get('showing_current_page_to_total', {
currentPage: state.currentPage,
totalPages: state.totalPages,
total: total,
})}
</div>
</div>
);
}
Pagination.propTypes = {
currentPage: PropTypes.number.isRequired,
size: PropTypes.number.isRequired,
total: PropTypes.number.isRequired,
onPageChange: PropTypes.func,
onPageSizeChange: PropTypes.func,
};
Pagination.defaultProps = {
currentPage: 1,
size: 25,
};

View File

@@ -0,0 +1,12 @@
// @ts-nocheck
export default function TableBody({}) {
return (
<ScrollSyncPane>
<div {...getTableBodyProps()} className="tbody">
<div class="tbody-inner" style={{ minWidth: totalColumnsWidth }}></div>
</div>
</ScrollSyncPane>
);
}

View File

@@ -0,0 +1,115 @@
// @ts-nocheck
import React, { useContext } from 'react';
import classNames from 'classnames';
import { camelCase} from 'lodash';
import { If, Skeleton } from '@/components';
import { useAppIntlContext } from '@/components/AppIntlProvider';
import TableContext from './TableContext';
import { saveInvoke, ignoreEventFromSelectors } from '@/utils';
import { isCellLoading } from './utils';
const ROW_CLICK_SELECTORS_INGORED = ['.expand-toggle', '.selection-checkbox'];
/**
* Table cell.
*/
export default function TableCell({ cell, row, index }) {
const { index: rowIndex, depth, getToggleRowExpandedProps, isExpanded } = row;
const {
props: {
expandToggleColumn,
expandColumnSpace,
expandable,
cellsLoading,
cellsLoadingCoords,
onCellClick,
},
} = useContext(TableContext);
const isExpandColumn = expandToggleColumn === index;
const { skeletonWidthMax = 100, skeletonWidthMin = 40 } = {};
// Application intl context.
const { isRTL } = useAppIntlContext();
// Detarmines whether the current cell is loading.
const cellLoading = isCellLoading(
cellsLoading,
cellsLoadingCoords,
rowIndex,
cell.column.id,
);
if (cellLoading) {
return (
<div
{...cell.getCellProps({
className: classNames(cell.column.className, 'td'),
})}
>
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
</div>
);
}
// Handle cell click action.
const handleCellClick = (event) => {
if (ignoreEventFromSelectors(event, ROW_CLICK_SELECTORS_INGORED)) {
return;
}
saveInvoke(onCellClick, cell, event);
};
const cellType = camelCase(cell.column.Cell.cellType) || 'text';
return (
<div
{...cell.getCellProps({
className: classNames(cell.column.className, 'td', {
'is-text-overview': cell.column.textOverview,
clickable: cell.column.clickable,
'align-right': cell.column.align === 'right',
'align-center': cell.column.align === 'center',
[`td-${cell.column.id}`]: cell.column.id,
[`td-${cellType}-type`]: !!cellType,
}),
onClick: handleCellClick,
})}
>
<div
className={classNames(
{
'text-overview': cell.column.textOverview,
},
'cell-inner',
)}
style={{
[isRTL ? 'paddingRight' : 'paddingLeft']:
isExpandColumn && expandable
? `${depth * expandColumnSpace}rem`
: '',
}}
>
{
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter
// to build the toggle for expanding a row
}
<If condition={cell.row.canExpand && expandable && isExpandColumn}>
<span
{...getToggleRowExpandedProps({
className: 'expand-toggle',
})}
style={{}}
>
<span
className={classNames('expand-arrow', {
'is-expanded': isExpanded,
})}
/>
</span>
</If>
{cell.render('Cell')}
</div>
</div>
);
}

View File

@@ -0,0 +1,4 @@
// @ts-nocheck
import { createContext } from 'react';
export default createContext();

View File

@@ -0,0 +1,21 @@
// @ts-nocheck
import React, { memo } from 'react';
import TableCell from './TableCell';
export function TableFastCell({ cell, row, index }) {
return <TableCell cell={cell} row={row} index={index} />;
}
export default memo(TableFastCell, (prevProps, nextProps) => {
if (
prevProps.row.canExpand === nextProps.row.canExpand &&
prevProps.row.isExpanded === nextProps.row.isExpanded &&
prevProps.cell.value === nextProps.cell.value &&
prevProps.cell.maxWidth === nextProps.cell.maxWidth &&
prevProps.cell.width === nextProps.cell.width
) {
return true;
} else {
return false;
}
});

View File

@@ -0,0 +1,37 @@
// @ts-nocheck
import React, { useContext } from 'react';
import classNames from 'classnames';
import TableContext from './TableContext';
/**
* Table footer.
*/
export default function TableFooter() {
const {
props: { footer },
table: { footerGroups },
} = useContext(TableContext);
// Can't contiunue if the footer is disabled.
if (!footer) { return null; }
return (
<div class="tfooter">
{footerGroups.map((group) => (
<div {...group.getFooterGroupProps({ className: 'tr' })}>
{group.headers.map((column) => (
<div
{...column.getFooterProps({
className: classNames(column.className || '', 'td'),
})}
>
<div className={'cell-inner'}>
{column.render('Footer')}
</div>
</div>
))}
</div>
))}
</div>
);
}

View File

@@ -0,0 +1,113 @@
// @ts-nocheck
import React, { useContext } from 'react';
import classNames from 'classnames';
import { ScrollSyncPane } from 'react-scroll-sync';
import { If, MaterialProgressBar } from '@/components';
import TableContext from './TableContext';
function TableHeaderCell({ column, index }) {
const {
table: { getToggleAllRowsExpandedProps, isAllRowsExpanded },
props: { expandable, expandToggleColumn },
} = useContext(TableContext);
return (
<div
{...column.getHeaderProps({
className: classNames(column.className || '', 'th', {
[`align-${column.align}`]: column.align,
}),
})}
>
<If condition={expandable && index + 1 === expandToggleColumn}>
<span {...getToggleAllRowsExpandedProps()} className="expand-toggle">
<span
className={classNames({
'arrow-down': isAllRowsExpanded,
'arrow-right': !isAllRowsExpanded,
})}
/>
</span>
</If>
<div
{...column.getSortByToggleProps({
className: classNames('cell-inner', {
'text-overview': column.textOverview,
}),
})}
>
{column.render('Header')}
<If condition={column.isSorted}>
<span
className={classNames(
{
'sort-icon--desc': column.isSortedDesc,
'sort-icon--asc': !column.isSortedDesc,
},
'sort-icon',
)}
></span>
</If>
</div>
{column.canResize && (
<div
{...column.getResizerProps()}
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
>
<div class="inner-resizer" />
</div>
)}
</div>
);
}
function TableHeaderGroup({ headerGroup }) {
return (
<div {...headerGroup.getHeaderGroupProps()} className="tr">
{headerGroup.headers.map((column, index) => (
<TableHeaderCell key={index} column={column} index={index} />
))}
</div>
);
}
/**
* Table header.
*/
export default function TableHeader() {
const {
table: { headerGroups, page },
props: {
TableHeaderSkeletonRenderer,
headerLoading,
progressBarLoading,
hideTableHeader,
},
} = useContext(TableContext);
// Can't contiunue if the thead is disabled.
if (hideTableHeader) {
return null;
}
if (headerLoading && TableHeaderSkeletonRenderer) {
return <TableHeaderSkeletonRenderer />;
}
return (
<ScrollSyncPane>
<div className="thead">
<div className={'thead-inner'}>
{headerGroups.map((headerGroup, index) => (
<TableHeaderGroup key={index} headerGroup={headerGroup} />
))}
<If condition={progressBarLoading}>
<MaterialProgressBar />
</If>
</div>
</div>
</ScrollSyncPane>
);
}

View File

@@ -0,0 +1,50 @@
// @ts-nocheck
import React, { useContext } from 'react';
import clsx from 'classnames';
import TableContext from './TableContext';
import { Skeleton } from '@/components';
function TableHeaderCell({ column }) {
const { skeletonWidthMax = 100, skeletonWidthMin = 40 } = column;
return (
<div
{...column.getHeaderProps({
className: clsx(
'th',
{
[`align-${column.align}`]: column.align,
},
column.className,
),
})}
>
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
</div>
);
}
/**
* Table skeleton rows.
*/
export function TableSkeletonHeader({}) {
const {
table: { headerGroups },
} = useContext(TableContext);
return (
<div class="thead">
{headerGroups.map((headerGroup) => (
<div
{...headerGroup.getHeaderGroupProps({
className: 'tr',
})}
>
{headerGroup.headers.map((column) => (
<TableHeaderCell column={column} />
))}
</div>
))}
</div>
);
}

View File

@@ -0,0 +1,13 @@
// @ts-nocheck
import React from 'react';
import { Checkbox } from '@blueprintjs/core';
export default function TableIndeterminateCheckboxHeader({
getToggleAllRowsSelectedProps,
}) {
return (
<div>
<Checkbox {...getToggleAllRowsSelectedProps()} />
</div>
);
}

View File

@@ -0,0 +1,13 @@
// @ts-nocheck
import React from 'react';
import { Checkbox } from '@blueprintjs/core';
import { CellType } from '@/constants';
export default function TableIndeterminateCheckboxRow({ row }) {
return (
<div class="selection-checkbox">
<Checkbox {...row.getToggleRowSelectedProps()} />
</div>
);
}
TableIndeterminateCheckboxRow.cellType = CellType.Field;

View File

@@ -0,0 +1,16 @@
// @ts-nocheck
import React from 'react';
import { Spinner } from '@blueprintjs/core';
/**
* Table loading component.
*/
export default function TableLoading({
spinnerProps
}) {
return (
<div class="loading">
<Spinner {...spinnerProps} />
</div>
);
}

View File

@@ -0,0 +1,22 @@
// @ts-nocheck
import React, { useContext } from 'react';
import intl from 'react-intl-universal';
import TableContext from './TableContext';
/**
* Table no-results row text.
*/
export default function TableNoResultsRow() {
const {
props: { noResults },
} = useContext(TableContext);
const noResultText =
noResults || intl.get('there_is_no_results_in_the_table');
return (
<div className={'tr no-results'}>
<div class="td">{noResultText}</div>
</div>
);
}

View File

@@ -0,0 +1,27 @@
// @ts-nocheck
import React, { useContext } from 'react';
import TableContext from './TableContext';
/**
* Table page.
*/
export default function TablePage() {
const {
table: { page },
props: {
spinnerProps,
loading,
TableRowsRenderer,
TableLoadingRenderer,
TableNoResultsRowRenderer,
},
} = useContext(TableContext);
if (loading) {
return <TableLoadingRenderer spinnerProps={spinnerProps} />;
}
if (page.length === 0) {
return <TableNoResultsRowRenderer />;
}
return (<TableRowsRenderer />);
}

View File

@@ -0,0 +1,69 @@
// @ts-nocheck
import React, { useCallback, useContext } from 'react';
import { If, Pagination } from '@/components';
import TableContext from './TableContext';
import { saveInvoke } from '@/utils';
/**
* Table pagination.
*/
export default function TablePagination() {
const {
table: {
gotoPage,
setPageSize,
pageCount,
state: { pageIndex, pageSize },
},
props: { pagination, loading, onPaginationChange, hidePaginationNoPages },
} = useContext(TableContext);
const triggerOnPaginationChange = useCallback(
(payload) => {
saveInvoke(onPaginationChange, payload);
},
[onPaginationChange],
);
// Handles the page changing.
const handlePageChange = useCallback(
({ page, pageSize }) => {
const pageIndex = page - 1;
gotoPage(pageIndex);
triggerOnPaginationChange({ pageIndex, pageSize });
},
[gotoPage, triggerOnPaginationChange],
);
// Handles the page size changing.
const handlePageSizeChange = useCallback(
({ pageSize, page }) => {
const pageIndex = 0;
gotoPage(pageIndex);
setPageSize(pageSize);
triggerOnPaginationChange({ pageIndex, pageSize });
},
[gotoPage, setPageSize, triggerOnPaginationChange],
);
// Detarmines when display the pagination.
const showPagination =
pagination &&
((hidePaginationNoPages && pageCount > 1) || !hidePaginationNoPages) &&
!loading;
return (
showPagination && (
<Pagination
currentPage={pageIndex + 1}
total={pageSize * pageCount}
size={pageSize}
onPageChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
/>
)
);
}

View File

@@ -0,0 +1,91 @@
// @ts-nocheck
import React, { useCallback, useContext } from 'react';
import { ContextMenu } from '@/components';
import classNames from 'classnames';
import useContextMenu from 'react-use-context-menu';
import TableContext from './TableContext';
import { saveInvoke, ConditionalWrapper } from '@/utils';
/**
* Table row context wrapper.
*/
function TableRowContextMenu({ children, row }) {
// Table context.
const {
props: { ContextMenu: ContextMenuContent },
table,
} = useContext(TableContext);
const [
bindMenu,
bindMenuItem,
useContextTrigger,
{ coords, setVisible, isVisible },
] = useContextMenu();
const [bindTrigger] = useContextTrigger({
collect: () => 'Title',
});
const handleClose = useCallback(() => {
setVisible(false);
}, [setVisible]);
return (
<div class="tr-context" {...bindTrigger}>
{children}
<ContextMenu
bindMenu={bindMenu}
isOpen={isVisible}
coords={coords}
onClosed={handleClose}
>
<ContextMenuContent {...table} row={row} />
</ContextMenu>
</div>
);
}
/**
* Table row.
*/
export default function TableRow({ row, className, style }) {
const {
props: {
TableCellRenderer,
rowClassNames,
ContextMenu: ContextMenuContent,
},
} = useContext(TableContext);
return (
<div
{...row.getRowProps({
className: classNames(
'tr',
{ 'is-expanded': row.isExpanded && row.canExpand },
saveInvoke(rowClassNames, row),
className,
),
style,
})}
>
<ConditionalWrapper
condition={ContextMenuContent}
wrapper={TableRowContextMenu}
row={row}
>
{row.cells.map((cell, index) => (
<TableCellRenderer
key={index}
cell={cell}
row={row}
index={index + 1}
/>
))}
</ConditionalWrapper>
</div>
);
}

View File

@@ -0,0 +1,18 @@
// @ts-nocheck
import React, { useContext } from "react";
import TableContext from "./TableContext";
/**
* Table rows.
*/
export default function TableRows() {
const {
table: { prepareRow, page },
props: { TableRowRenderer, TableCellRenderer },
} = useContext(TableContext);
return page.map((row, index) => {
prepareRow(row);
return <TableRowRenderer key={index} row={row} TableCellRenderer={TableCellRenderer} />;
});
}

View File

@@ -0,0 +1,52 @@
// @ts-nocheck
import React, { useContext } from 'react';
import clsx from 'classnames';
import TableContext from './TableContext';
import { Skeleton } from '../Skeleton';
/**
* Table header cell.
*/
function TableHeaderCell({ column }) {
const { skeletonWidthMax = 100, skeletonWidthMin = 40 } = column;
return (
<div
{...column.getHeaderProps({
className: clsx(
'td',
{
[`align-${column.align}`]: column.align,
},
column.className,
),
})}
>
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
</div>
);
}
/**
* Table skeleton rows.
*/
export function TableSkeletonRows({}) {
const {
table: { headerGroups },
} = useContext(TableContext);
const skeletonRows = 10;
return Array.from({ length: skeletonRows }).map(() => {
return headerGroups.map((headerGroup) => (
<div
{...headerGroup.getHeaderGroupProps({
className: 'tr',
})}
>
{headerGroup.headers.map((column) => (
<TableHeaderCell column={column} />
))}
</div>
));
});
}

View File

@@ -0,0 +1,22 @@
// @ts-nocheck
import React, { useContext } from 'react';
import { ScrollSyncPane } from 'react-scroll-sync';
import TableContext from './TableContext';
export default function TableTBody({
children
}) {
const {
table: { getTableBodyProps }
} = useContext(TableContext);
return (
<ScrollSyncPane>
<div {...getTableBodyProps()} className="tbody">
<div class="tbody-inner">
{ children }
</div>
</div>
</ScrollSyncPane>
);
}

View File

@@ -0,0 +1,65 @@
// @ts-nocheck
import React, { useContext } from 'react';
import { WindowScroller, AutoSizer, List } from 'react-virtualized';
import { CLASSES } from '@/constants/classes';
import TableContext from './TableContext';
/**
* Table virtualized list row.
*/
function TableVirtualizedListRow({ index, isScrolling, isVisible, style }) {
const {
table: { page, prepareRow },
props: { TableRowRenderer },
} = useContext(TableContext);
const row = page[index];
prepareRow(row);
return <TableRowRenderer row={row} style={style} />;
}
/**
* Table virtualized list rows.
*/
export function TableVirtualizedListRows() {
const {
table: { page },
props: { vListrowHeight, vListOverscanRowCount },
} = useContext(TableContext);
// Dashboard content pane.
const dashboardContentPane = React.useMemo(
() => document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`),
[],
);
const rowRenderer = React.useCallback(
({ key, ...args }) => <TableVirtualizedListRow {...args} key={key} />,
[],
);
return (
<WindowScroller scrollElement={dashboardContentPane}>
{({ height, isScrolling, onChildScroll, scrollTop }) => (
<AutoSizer disableHeight>
{({ width }) => (
<List
autoHeight={true}
className={'List'}
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
overscanRowCount={vListOverscanRowCount}
rowCount={page.length}
rowHeight={vListrowHeight}
rowRenderer={rowRenderer}
scrollTop={scrollTop}
width={width}
/>
)}
</AutoSizer>
)}
</WindowScroller>
);
}

View File

@@ -0,0 +1,48 @@
// @ts-nocheck
import React, { useContext } from 'react';
import clsx from 'classnames';
import { ScrollSync } from 'react-scroll-sync';
import TableContext from './TableContext';
/**
* Table wrapper.
*/
export default function TableWrapper({ children }) {
const {
table: { getTableProps },
props: {
sticky,
pagination,
loading,
expandable,
virtualizedRows,
className,
styleName,
size,
},
} = useContext(TableContext);
return (
<div
className={clsx('bigcapital-datatable', className, {
'has-sticky': sticky,
'has-pagination': pagination,
'is-expandable': expandable,
'is-loading': loading,
'has-virtualized-rows': virtualizedRows,
[`table--${styleName}`]: styleName,
})}
>
<ScrollSync>
<div
{...getTableProps({ style: { minWidth: 'none' } })}
className={clsx('table', {
[`table-size--${size}`]: size,
})}
>
{children}
</div>
</ScrollSync>
</div>
);
}

View File

@@ -0,0 +1,9 @@
// @ts-nocheck
export * from './CellForceWidth';
export * from './DataTable';
export * from './DatatableEditable';
export * from './TableHeaderSkeleton'
export * from './TableSkeletonRows'
export * from './TableVirtualizedRows'
export * from './TableFastCell';
export * from './Pagination'

View File

@@ -0,0 +1,36 @@
// @ts-nocheck
import React from 'react';
export const isCellLoading = (loading, cellsCoords, rowIndex, columnId) => {
if (!loading) {
return false;
}
return !cellsCoords
? true
: cellsCoords.some(
(cellCoord) => cellCoord[0] === rowIndex && cellCoord[1] === columnId,
);
};
export const useResizeObserver = (state, callback) => {
// This Ref will contain the id of the column being resized or undefined
const columnResizeRef = React.useRef();
React.useEffect(() => {
// We are interested in calling the resize event only when "state.columnResizing?.isResizingColumn" changes from
// a string to undefined, because it indicates that it WAS resizing but it no longer is.
if (
state.columnResizing &&
!state.columnResizing?.isResizingColumn &&
columnResizeRef.current
) {
// Trigger resize event
callback(
columnResizeRef.current,
state.columnResizing.columnWidths[columnResizeRef.current],
state.columnResizing,
);
}
columnResizeRef.current = state.columnResizing?.isResizingColumn;
}, [callback, state.columnResizing]);
};