Skip to content
This repository has been archived by the owner on Jan 16, 2025. It is now read-only.

Commit

Permalink
Revert delete unused files in custom Katalon plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
triquanminh committed Apr 25, 2024
1 parent 49d742d commit 7879367
Show file tree
Hide file tree
Showing 51 changed files with 4,602 additions and 2 deletions.
397 changes: 397 additions & 0 deletions superset-frontend/src/katalon/CustomDataTable/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,397 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, {
useCallback,
useRef,
ReactNode,
HTMLProps,
MutableRefObject,
CSSProperties,
} from 'react';
import {

Check failure on line 27 in superset-frontend/src/katalon/CustomDataTable/DataTable/DataTable.tsx

View workflow job for this annotation

GitHub Actions / frontend-build

'@types/react-table' should be listed in the project's dependencies. Run 'npm i -S @types/react-table' to add it
useTable,
usePagination,
useSortBy,
useGlobalFilter,
useColumnOrder,
PluginHook,
TableOptions,
FilterType,
IdType,
Row,
} from 'react-table';
import { matchSorter, rankings } from 'match-sorter';
import { typedMemo, usePrevious } from '@superset-ui/core';
import { isEqual } from 'lodash';
import GlobalFilter, { GlobalFilterProps } from './components/GlobalFilter';
import SelectPageSize, {
SelectPageSizeProps,
SizeOption,
} from './components/SelectPageSize';
import SimplePagination from './components/Pagination';
import useSticky from './hooks/useSticky';
import { PAGE_SIZE_OPTIONS } from '../consts';
import { sortAlphanumericCaseInsensitive } from './utils/sortAlphanumericCaseInsensitive';

export interface DataTableProps<D extends object> extends TableOptions<D> {
tableClassName?: string;
searchInput?: boolean | GlobalFilterProps<D>['searchInput'];
selectPageSize?: boolean | SelectPageSizeProps['selectRenderer'];
pageSizeOptions?: SizeOption[]; // available page size options
maxPageItemCount?: number;
hooks?: PluginHook<D>[]; // any additional hooks
width?: string | number;
height?: string | number;
serverPagination?: boolean;
onServerPaginationChange: (pageNumber: number, pageSize: number) => void;
serverPaginationData: { pageSize?: number; currentPage?: number };
pageSize?: number;
noResults?: string | ((filterString: string) => ReactNode);
sticky?: boolean;
rowCount: number;
wrapperRef?: MutableRefObject<HTMLDivElement>;
onColumnOrderChange: () => void;
}

export interface RenderHTMLCellProps extends HTMLProps<HTMLTableCellElement> {
cellContent: ReactNode;
}

const sortTypes = {
alphanumeric: sortAlphanumericCaseInsensitive,
};

// Be sure to pass our updateMyData and the skipReset option
export default typedMemo(function DataTable<D extends object>({
tableClassName,
columns,
data,
serverPaginationData,
width: initialWidth = '100%',
height: initialHeight = 300,
pageSize: initialPageSize = 0,
initialState: initialState_ = {},
pageSizeOptions = PAGE_SIZE_OPTIONS,
maxPageItemCount = 9,
sticky: doSticky,
searchInput = true,
onServerPaginationChange,
rowCount,
selectPageSize,
noResults: noResultsText = 'No data found',
hooks,
serverPagination,
wrapperRef: userWrapperRef,
onColumnOrderChange,
...moreUseTableOptions
}: DataTableProps<D>): JSX.Element {
const tableHooks: PluginHook<D>[] = [
useGlobalFilter,
useSortBy,
usePagination,
useColumnOrder,
doSticky ? useSticky : [],
hooks || [],
].flat();
const columnNames = Object.keys(data?.[0] || {});
const previousColumnNames = usePrevious(columnNames);
const resultsSize = serverPagination ? rowCount : data.length;
const sortByRef = useRef([]); // cache initial `sortby` so sorting doesn't trigger page reset
const pageSizeRef = useRef([initialPageSize, resultsSize]);
const hasPagination = initialPageSize > 0 && resultsSize > 0; // pageSize == 0 means no pagination
const hasGlobalControl = hasPagination || !!searchInput;
const initialState = {
...initialState_,
// zero length means all pages, the `usePagination` plugin does not
// understand pageSize = 0
sortBy: sortByRef.current,
pageSize: initialPageSize > 0 ? initialPageSize : resultsSize || 10,
};
const defaultWrapperRef = useRef<HTMLDivElement>(null);
const globalControlRef = useRef<HTMLDivElement>(null);
const paginationRef = useRef<HTMLDivElement>(null);
const wrapperRef = userWrapperRef || defaultWrapperRef;
const paginationData = JSON.stringify(serverPaginationData);

const defaultGetTableSize = useCallback(() => {
if (wrapperRef.current) {
// `initialWidth` and `initialHeight` could be also parameters like `100%`
// `Number` returns `NaN` on them, then we fallback to computed size
const width = Number(initialWidth) || wrapperRef.current.clientWidth;
const height =
(Number(initialHeight) || wrapperRef.current.clientHeight) -
(globalControlRef.current?.clientHeight || 0) -
(paginationRef.current?.clientHeight || 0);
return { width, height };
}
return undefined;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
initialHeight,
initialWidth,
wrapperRef,
hasPagination,
hasGlobalControl,
paginationRef,
resultsSize,
paginationData,
]);

const defaultGlobalFilter: FilterType<D> = useCallback(
(rows: Row<D>[], columnIds: IdType<D>[], filterValue: string) => {
// allow searching by "col1_value col2_value"
const joinedString = (row: Row<D>) =>
columnIds.map(x => row.values[x]).join(' ');
return matchSorter(rows, filterValue, {
keys: [...columnIds, joinedString],
threshold: rankings.ACRONYM,
}) as typeof rows;
},
[],
);

const {
getTableProps,
getTableBodyProps,
prepareRow,
headerGroups,
footerGroups,
page,
pageCount,
gotoPage,
preGlobalFilteredRows,
setGlobalFilter,
setPageSize: setPageSize_,
wrapStickyTable,
setColumnOrder,
allColumns,
state: { pageIndex, pageSize, globalFilter: filterValue, sticky = {} },
} = useTable<D>(
{
columns,
data,
initialState,
getTableSize: defaultGetTableSize,
globalFilter: defaultGlobalFilter,
sortTypes,
autoResetSortBy: !isEqual(columnNames, previousColumnNames),
...moreUseTableOptions,
},
...tableHooks,
);
// make setPageSize accept 0
const setPageSize = (size: number) => {
if (serverPagination) {
onServerPaginationChange(0, size);
}
// keep the original size if data is empty
if (size || resultsSize !== 0) {
setPageSize_(size === 0 ? resultsSize : size);
}
};

const noResults =
typeof noResultsText === 'function'
? noResultsText(filterValue as string)
: noResultsText;

const getNoResults = () => <div className="dt-no-results">{noResults}</div>;

if (!columns || columns.length === 0) {
return (
wrapStickyTable ? wrapStickyTable(getNoResults) : getNoResults()
) as JSX.Element;
}

const shouldRenderFooter = columns.some(x => !!x.Footer);

let columnBeingDragged = -1;

const onDragStart = (e: React.DragEvent) => {
const el = e.target as HTMLTableCellElement;
columnBeingDragged = allColumns.findIndex(
col => col.id === el.dataset.columnName,
);
e.dataTransfer.setData('text/plain', `${columnBeingDragged}`);
};

const onDrop = (e: React.DragEvent) => {
const el = e.target as HTMLTableCellElement;
const newPosition = allColumns.findIndex(
col => col.id === el.dataset.columnName,
);

if (newPosition !== -1) {
const currentCols = allColumns.map(c => c.id);
const colToBeMoved = currentCols.splice(columnBeingDragged, 1);
currentCols.splice(newPosition, 0, colToBeMoved[0]);
setColumnOrder(currentCols);
// toggle value in TableChart to trigger column width recalc
onColumnOrderChange();
}
e.preventDefault();
};

const renderTable = () => (
<table {...getTableProps({ className: tableClassName })}>
<thead>
{headerGroups.map(headerGroup => {
const { key: headerGroupKey, ...headerGroupProps } =
headerGroup.getHeaderGroupProps();
return (
<tr key={headerGroupKey || headerGroup.id} {...headerGroupProps}>
{headerGroup.headers.map(column =>
column.render('Header', {
key: column.id,
...column.getSortByToggleProps(),
onDragStart,
onDrop,
}),
)}
</tr>
);
})}
</thead>
<tbody {...getTableBodyProps()}>
{page && page.length > 0 ? (
page.map(row => {
prepareRow(row);
const { key: rowKey, ...rowProps } = row.getRowProps();
return (
<tr key={rowKey || row.id} {...rowProps}>
{row.cells.map(cell =>
cell.render('Cell', { key: cell.column.id }),
)}
</tr>
);
})
) : (
<tr>
<td className="dt-no-results" colSpan={columns.length}>
{noResults}
</td>
</tr>
)}
</tbody>
{shouldRenderFooter && (
<tfoot>
{footerGroups.map(footerGroup => {
const { key: footerGroupKey, ...footerGroupProps } =
footerGroup.getHeaderGroupProps();
return (
<tr key={footerGroupKey || footerGroup.id} {...footerGroupProps}>
{footerGroup.headers.map(column =>
column.render('Footer', { key: column.id }),
)}
</tr>
);
})}
</tfoot>
)}
</table>
);

// force update the pageSize when it's been update from the initial state
if (
pageSizeRef.current[0] !== initialPageSize ||
// when initialPageSize stays as zero, but total number of records changed,
// we'd also need to update page size
(initialPageSize === 0 && pageSizeRef.current[1] !== resultsSize)
) {
pageSizeRef.current = [initialPageSize, resultsSize];
setPageSize(initialPageSize);
}

const paginationStyle: CSSProperties = sticky.height
? {}
: { visibility: 'hidden' };

let resultPageCount = pageCount;
let resultCurrentPageSize = pageSize;
let resultCurrentPage = pageIndex;
let resultOnPageChange: (page: number) => void = gotoPage;
if (serverPagination) {
const serverPageSize = serverPaginationData?.pageSize ?? initialPageSize;
resultPageCount = Math.ceil(rowCount / serverPageSize);
if (!Number.isFinite(resultPageCount)) {
resultPageCount = 0;
}
resultCurrentPageSize = serverPageSize;
const foundPageSizeIndex = pageSizeOptions.findIndex(
([option]) => option >= resultCurrentPageSize,
);
if (foundPageSizeIndex === -1) {
resultCurrentPageSize = 0;
}
resultCurrentPage = serverPaginationData?.currentPage ?? 0;
resultOnPageChange = (pageNumber: number) =>
onServerPaginationChange(pageNumber, serverPageSize);
}
return (
<div
ref={wrapperRef}
style={{ width: initialWidth, height: initialHeight }}
>
{hasGlobalControl ? (
<div ref={globalControlRef} className="form-inline dt-controls">
<div className="row">
<div className="col-sm-6">
{hasPagination ? (
<SelectPageSize
total={resultsSize}
current={resultCurrentPageSize}
options={pageSizeOptions}
selectRenderer={
typeof selectPageSize === 'boolean'
? undefined
: selectPageSize
}
onChange={setPageSize}
/>
) : null}
</div>
{searchInput ? (
<div className="col-sm-6">
<GlobalFilter<D>
searchInput={
typeof searchInput === 'boolean' ? undefined : searchInput
}
preGlobalFilteredRows={preGlobalFilteredRows}
setGlobalFilter={setGlobalFilter}
filterValue={filterValue}
/>
</div>
) : null}
</div>
</div>
) : null}
{wrapStickyTable ? wrapStickyTable(renderTable) : renderTable()}
{hasPagination && resultPageCount > 1 ? (
<SimplePagination
ref={paginationRef}
style={paginationStyle}
maxPageItemCount={maxPageItemCount}
pageCount={resultPageCount}
currentPage={resultCurrentPage}
onPageChange={resultOnPageChange}
/>
) : null}
</div>
);
});
Loading

0 comments on commit 7879367

Please sign in to comment.