Feat/table (#105)

* feat/table add react-table
* feat/table add protected table route
* feat/table upgrade dependencies
* feat/table support parsing of new properties

Co-authored-by: DeepSource Bot <bot@deepsource.io>
This commit is contained in:
Carlos Valente
2022-04-09 22:05:56 +02:00
committed by GitHub
parent 8841a02754
commit 67ddcd8c68
146 changed files with 7423 additions and 5780 deletions
+246
View File
@@ -0,0 +1,246 @@
import React, { useCallback, useContext, useEffect, useMemo } from 'react';
import { TableSettingsContext } from '../../app/context/TableSettingsContext';
import { useBlockLayout, useColumnOrder, useResizeColumns, useTable } from 'react-table';
import { Tooltip } from '@chakra-ui/tooltip';
import PropTypes from 'prop-types';
import {
closestCenter,
DndContext,
KeyboardSensor,
PointerSensor,
TouchSensor,
useSensor,
useSensors,
} from '@dnd-kit/core';
import {
horizontalListSortingStrategy,
SortableContext,
sortableKeyboardCoordinates,
} from '@dnd-kit/sortable';
import { useLocalStorage } from '../../app/hooks/useLocalStorage';
import { defaultColumnOrder, defaultHiddenColumns } from './defaults';
import { makeColumns } from './columns';
import EventRow from './tableRows/EventRow';
import DelayRow from './tableRows/DelayRow';
import BlockRow from './tableRows/BlockRow';
import SortableCell from './tableElements/SortableCell';
import TableSettings from './tableElements/TableSettings';
import style from './Table.module.scss';
export default function OntimeTable({ tableData, userFields, handleUpdate, selectedId }) {
const { followSelected, showSettings } = useContext(TableSettingsContext);
const [columnOrder, saveColumnOrder] = useLocalStorage('table-order', defaultColumnOrder);
const [columnSize, saveColumnSize] = useLocalStorage('table-sizes', {});
const [hiddenColumns, saveHiddenColumns] = useLocalStorage('table-hidden', defaultHiddenColumns);
const columns = useMemo(() => makeColumns(columnSize, userFields), [columnSize, userFields]);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
setColumnOrder,
allColumns,
setHiddenColumns,
toggleHideAllColumns,
state,
} = useTable(
{
columns,
data: tableData,
initialState: {
hiddenColumns: hiddenColumns,
},
handleUpdate,
},
useColumnOrder,
useBlockLayout,
useResizeColumns
);
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
delay: 100,
tolerance: 50,
},
}),
useSensor(TouchSensor, {
activationConstraint: {
delay: 100,
tolerance: 50,
},
}),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
})
);
const handleResetReordering = useCallback(() => {
saveColumnOrder(defaultColumnOrder);
setColumnOrder(defaultColumnOrder);
}, [saveColumnOrder, setColumnOrder]);
const handleResetResizing = useCallback(() => {
saveColumnSize({});
}, [saveColumnSize]);
const handleResetToggles = useCallback(() => {
setHiddenColumns(defaultHiddenColumns);
saveHiddenColumns(defaultHiddenColumns);
}, [saveHiddenColumns, setHiddenColumns]);
const clearToggles = useCallback(() => {
toggleHideAllColumns(false);
saveHiddenColumns([]);
}, [saveHiddenColumns, toggleHideAllColumns]);
const handleOnDragEnd = (event) => {
const { delta, active, over } = event;
// cancel if delta y is greater than 200
if (delta.y > 200) return;
// create temp object and remove hidden columns
const cols = [...columnOrder].filter((col) => !hiddenColumns.includes(col));
if (cols === null) {
return;
}
// get index of from
const fromIndex = cols.findIndex((i) => i === active.id);
// get index of to
const toIndex = cols.findIndex((i) => i === over.id);
// reorder
const [reorderedItem] = cols.splice(fromIndex, 1);
cols.splice(toIndex, 0, reorderedItem);
saveColumnOrder(cols);
setColumnOrder(cols);
};
// save hidden columns object to local storage
useEffect(() => {
saveHiddenColumns(state.hiddenColumns);
}, [saveHiddenColumns, state.hiddenColumns]);
// save column sizes to local storage
useEffect(() => {
// property changes from title of column to null on resize end
if (state.columnResizing?.isResizingColumn !== null) {
return;
}
const cols = state.columnResizing.columnWidths;
saveColumnSize((prev) => ({ ...prev, ...cols }));
}, [saveColumnSize, state.columnResizing]);
// scroll to active cue
useEffect(() => {
if (followSelected) {
const el = document.getElementById(selectedId);
if (el) {
el.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest',
});
}
}
}, [followSelected, selectedId]);
// keep order of events
let eventIndex = 0;
// keep delay (ms)
let cumulativeDelay = 0;
return (
<>
{showSettings && (
<TableSettings
columns={allColumns}
handleResetResizing={handleResetResizing}
handleResetReordering={handleResetReordering}
handleResetToggles={handleResetToggles}
handleClearToggles={clearToggles}
/>
)}
<table {...getTableProps()} className={style.ontimeTable}>
<thead className={style.tableHeader}>
{headerGroups.map((headerGroup) => {
const { key, ...restHeaderGroupProps } = headerGroup.getHeaderGroupProps();
return (
<DndContext
key={key}
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleOnDragEnd}
>
<tr {...restHeaderGroupProps}>
<th className={style.indexColumn}>
<Tooltip label='Event Order' openDelay={300}>
#
</Tooltip>
</th>
<SortableContext
key={key}
items={headerGroup.headers}
strategy={horizontalListSortingStrategy}
>
{headerGroup.headers.map((column) => {
const { key } = column.getHeaderProps();
return <SortableCell key={key} column={column} />;
})}
</SortableContext>
</tr>
</DndContext>
);
})}
</thead>
<tbody {...getTableBodyProps} className={style.tableBody}>
{/*This is saving in place of a default component*/}
{/* eslint-disable-next-line array-callback-return */}
{rows.map((row) => {
prepareRow(row);
const { key } = row.getRowProps();
const type = row.original.type;
if (type === 'event') {
eventIndex++;
return (
<EventRow
key={key}
row={row}
index={eventIndex}
selectedId={selectedId}
delay={cumulativeDelay}
/>
);
}
if (type === 'delay') {
if (row.original.duration != null) {
cumulativeDelay += row.original.duration;
}
return <DelayRow key={key} row={row} />;
}
if (type === 'block') {
cumulativeDelay = 0;
return <BlockRow key={key} row={row} />;
}
})}
</tbody>
</table>
</>
);
}
OntimeTable.propTypes = {
tableData: PropTypes.array,
userFields: PropTypes.object,
handleUpdate: PropTypes.func.isRequired,
selectedId: PropTypes.string,
showSettings: PropTypes.bool,
followSelected: PropTypes.bool,
};