Skip to content

Commit

Permalink
Merge pull request #1606 from gettakaro/feat/select-pagination
Browse files Browse the repository at this point in the history
Improved internals of pagination and infinite loading  + Add expandable tables
  • Loading branch information
emielvanseveren authored Oct 13, 2024
2 parents 8119ed4 + 9578692 commit 9126f73
Show file tree
Hide file tree
Showing 82 changed files with 1,360 additions and 4,267 deletions.
1 change: 1 addition & 0 deletions containers/generic-app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ENV TAKARO_VERSION=${TAKARO_VERSION}
ENV TAKARO_COMMIT=${TAKARO_COMMIT}
ENV TAKARO_BUILD_DATE=${TAKARO_BUILD_DATE}
ENV TAKARO_FULL_VERSION=${TAKARO_VERSION}-${TAKARO_COMMIT}-${TAKARO_BUILD_DATE}
ENV VITE_TAKARO_VERSION=${TAKARO_FULL_VERSION}

WORKDIR /app

Expand Down
2 changes: 2 additions & 0 deletions containers/generic-web/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ echo " VITE_API: \"$VITE_API\"," >>"$FILE_LOCATION"
echo " VITE_ORY_URL: \"$VITE_ORY_URL\"," >>"$FILE_LOCATION"
echo " VITE_POSTHOG_PUBLIC_API_KEY: \"$VITE_POSTHOG_PUBLIC_API_KEY\"," >>"$FILE_LOCATION"
echo " VITE_POSTHOG_API_URL: \"$VITE_POSTHOG_API_URL\"," >>"$FILE_LOCATION"
echo " VITE_TAKARO_VERSION: \"$VITE_TAKARO_VERSION\"," >>"$FILE_LOCATION"

echo "}" >>"$FILE_LOCATION"

nginx -g "daemon off;"
1 change: 1 addition & 0 deletions containers/takaro/dev.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ ENV TAKARO_VERSION=${TAKARO_VERSION}
ENV TAKARO_COMMIT=${TAKARO_COMMIT}
ENV TAKARO_BUILD_DATE=${TAKARO_BUILD_DATE}
ENV TAKARO_FULL_VERSION=${TAKARO_VERSION}-${TAKARO_COMMIT}-${TAKARO_BUILD_DATE}
ENV VITE_TAKARO_VERSION=${TAKARO_FULL_VERSION}

CMD ["npm", "run", "start:dev"]
8 changes: 4 additions & 4 deletions deploy/compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,22 @@ services:
env_file:
- .env
environment:
POSTGRES_HOST: postgresql
POSTGRES_HOST: postgresql
takaro_connector:
image: ghcr.io/gettakaro/takaro-app-connector:latest
container_name: takaro_connector
environment:
REDIS_HOST: "redis"
TAKARO_SERVICE: "app-connector"
TAKARO_SERVICE: "app-connector"
TAKARO_HOST: http://takaro_api:3000
env_file:
- .env
- .env
restart: unless-stopped

takaro_web:
image: ghcr.io/gettakaro/takaro-web-main:latest
ports:
- 13001:80
- 13001:80
environment:
VITE_API: http://127.0.0.1:13000
VITE_ORY_URL: http://127.0.0.1:4433
Expand Down
3,470 changes: 39 additions & 3,431 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default {
args: {
exclusive: true,
orientation: 'horizontal',
defaultValue: 'left',
fullWidth: false,
},
} as Meta<ToggleButtonGroupProps>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const ToggleButton = forwardRef<HTMLButtonElement, ToggleButtonProps>(fun
{ selected = false, disabled = false, onClick = undefined, value, parentClickEvent = () => {}, children, tooltip },
ref,
) {
const handleOnClick = () => {
const handleOnClick = (m: MouseEvent) => {
m.preventDefault();
m.stopPropagation();
if (disabled) return;
parentClickEvent(value);
if (onClick) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ export const ToggleButtonGroup: FC<ToggleButtonGroupProps> & SubComponents = ({
const m = new Map<string, boolean>();
Children.forEach(children, (child) => {
if (isValidElement(child)) {
m.set(child.props.value, false);
console.log(child.props.value, defaultValue);
if (child.props.value === defaultValue) {
m.set(child.props.value, true);
} else {
m.set(child.props.value, false);
}
}
});
return m;
Expand All @@ -65,7 +70,16 @@ export const ToggleButtonGroup: FC<ToggleButtonGroupProps> & SubComponents = ({
}
return setSelected(value);
}
// handle case that each button has a seperate state

// In case there always has to be one value selected, the clicked value is true and there is currently only one value selected then we don't do anything
if (
!canSelectNone &&
(selected as Map<string, boolean>).get(value) === true &&
Array.from((selected as Map<string, boolean>).values()).filter(Boolean).length === 1
) {
return;
}

setSelected(new Map((selected as Map<string, boolean>).set(value, !(selected as Map<string, boolean>).get(value))));
};

Expand Down
125 changes: 93 additions & 32 deletions packages/lib-components/src/components/data/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ import {
VisibilityState,
ColumnPinningState,
RowSelectionState,
ExpandedState,
getExpandedRowModel,
Row,
} from '@tanstack/react-table';
import { Wrapper, StyledTable, Toolbar, Flex, TableWrapper } from './style';
import { Button, Empty, Spinner, ToggleButtonGroup } from '../../../components';
import { AiOutlinePicCenter as RelaxedDensityIcon, AiOutlinePicRight as TightDensityIcon } from 'react-icons/ai';

import { Button, Empty, IconButton, Spinner, ToggleButtonGroup } from '../../../components';
import {
AiOutlinePicCenter as RelaxedDensityIcon,
AiOutlinePicRight as TightDensityIcon,
AiOutlineRight as ExpandIcon,
AiOutlineUp as CollapseIcon,
} from 'react-icons/ai';
import { ColumnHeader } from './subcomponents/ColumnHeader';
import { ColumnVisibility } from './subcomponents/ColumnVisibility';
import { Filter } from './subcomponents/Filter';
Expand All @@ -37,8 +44,12 @@ export interface TableProps<DataType extends object> {
data: DataType[];
isLoading?: boolean;

// currently not possible to type this properly: https://github.com/TanStack/table/issues/4241
/// Condition for row to be expandable
canExpand?: (row: Row<DataType>) => boolean;
/// What to render when row can be expanded
renderDetailPanel?: (row: Row<DataType>) => JSX.Element;

/// currently not possible to type this properly: https://github.com/TanStack/table/issues/4241
columns: ColumnDef<DataType, any>[];

/// Renders actions that are always visible
Expand Down Expand Up @@ -83,7 +94,9 @@ export function Table<DataType extends object>({
title,
rowSelection,
columnSearch,
renderDetailPanel,
renderToolbar,
canExpand = () => false,
renderRowSelectionActions,
isLoading = false,
}: TableProps<DataType>) {
Expand Down Expand Up @@ -111,9 +124,13 @@ export function Table<DataType extends object>({
{} as Record<string, boolean>,
);
});

const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({});
const { storedValue: density, setValue: setDensity } = useLocalStorage<Density>(`table-density-${id}`, 'tight');

// Might because potentially none fullfil the canExpand condtion.
const rowsMightExpand = renderDetailPanel ? true : false;
const [expanded, setExpanded] = useState<ExpandedState>({});
const [openColumnVisibilityTooltip, setOpenColumnVisibilityTooltip] = useState<boolean>(false);
const [hasShownColumnVisibilityTooltip, setHasShownColumnVisibilityTooltip] = useState<boolean>(false);
const [columnOrder, setColumnOrder] = useState<ColumnOrderState>(
Expand All @@ -126,6 +143,7 @@ export function Table<DataType extends object>({
);

const ROW_SELECTION_COL_SPAN = rowSelection ? 1 : 0;
const EXPAND_ROW_COL_SPAN = rowsMightExpand ? 1 : 0;
const MINIMUM_ROW_COUNT_FOR_PAGINATION = 5;

// handles the column visibility tooltip (shows tooltip when the first column is hidden)
Expand Down Expand Up @@ -154,6 +172,7 @@ export function Table<DataType extends object>({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
pageCount: pagination?.pageOptions.pageCount ?? -1,
manualPagination: true,
paginateExpandedRows: true, // Expanded rows will be paginated this means that rows that take up more space will be shown on next page.
Expand All @@ -169,6 +188,7 @@ export function Table<DataType extends object>({
enablePinning: true,
enableHiding: !!columnVisibility,
enableRowSelection: !!rowSelection,
getRowCanExpand: canExpand,
autoResetPageIndex: false,

columnResizeMode: 'onChange',
Expand All @@ -180,6 +200,7 @@ export function Table<DataType extends object>({
onColumnOrderChange: setColumnOrder,
onColumnPinningChange: setColumnPinning,
onRowSelectionChange: rowSelection ? rowSelection?.setRowSelectionState : undefined,
onExpandedChange: setExpanded,

initialState: {
columnVisibility,
Expand All @@ -194,6 +215,7 @@ export function Table<DataType extends object>({
state: {
columnVisibility,
columnOrder,
expanded,
sorting: sorting.sortingState,
columnFilters: columnFiltering.columnFiltersState,
globalFilter: columnSearch.columnSearchState,
Expand All @@ -204,6 +226,7 @@ export function Table<DataType extends object>({
});

const tableHasNoData = isLoading === false && table.getRowModel().rows.length === 0;
const tableHasData = isLoading === false && table.getRowModel().rows.length !== 0;

// rowSelection.rowSelectionState has the following shape: { [rowId: string]: boolean }
const hasRowSelection = useMemo(() => {
Expand Down Expand Up @@ -254,7 +277,7 @@ export function Table<DataType extends object>({
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{rowSelection && table.getRowModel().rows.length !== 0 && !isLoading && (
{rowSelection && tableHasData && (
<Th
isActive={false}
isRight={false}
Expand All @@ -276,6 +299,17 @@ export function Table<DataType extends object>({
</div>
</Th>
)}
{rowsMightExpand && tableHasData && (
<Th
isActive={false}
isRight={false}
isDragging={false}
canDrag={false}
isRowSelection={true}
width={15}
/>
)}

{headerGroup.headers.map((header) => (
<ColumnHeader
header={header}
Expand All @@ -291,7 +325,7 @@ export function Table<DataType extends object>({
{/* loading state */}
{isLoading && (
<tr>
<td colSpan={table.getAllColumns().length + ROW_SELECTION_COL_SPAN}>
<td colSpan={table.getAllColumns().length + ROW_SELECTION_COL_SPAN + EXPAND_ROW_COL_SPAN}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '15px' }}>
<Spinner size="small" />
</div>
Expand All @@ -302,7 +336,7 @@ export function Table<DataType extends object>({
{/* empty state */}
{tableHasNoData && (
<tr>
<td colSpan={table.getAllColumns().length + ROW_SELECTION_COL_SPAN}>
<td colSpan={table.getAllColumns().length + ROW_SELECTION_COL_SPAN + EXPAND_ROW_COL_SPAN}>
<div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Empty
header=""
Expand All @@ -323,30 +357,51 @@ export function Table<DataType extends object>({

{!isLoading &&
table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getCanSelect() && (
<td style={{ paddingRight: '10px', width: '15px' }}>
<CheckBox
value={row.getIsSelected()}
id={row.id}
name={row.id}
hasError={false}
disabled={!row.getCanSelect()}
onChange={() => row.toggleSelected()}
hasDescription={false}
size="small"
/>
</td>
)}
{row.getVisibleCells().map(({ column, id, getContext }) => (
<td key={id}>{flexRender(column.columnDef.cell, getContext())}</td>
))}
{row.getIsExpanded() && (
<tr>
<td colSpan={table.getVisibleLeafColumns().length} />
</tr>
)}
</tr>
<>
<tr key={row.id}>
{row.getCanExpand() ? (
<td style={{ paddingRight: '10px', width: '15px' }}>
{row.getIsExpanded() ? (
<IconButton
size="tiny"
icon={<CollapseIcon />}
ariaLabel="Collapse expanded row"
onClick={() => row.toggleExpanded(false)}
/>
) : (
<IconButton
size="tiny"
icon={<ExpandIcon />}
ariaLabel="expand row"
onClick={() => row.toggleExpanded(true)}
/>
)}
</td>
) : rowsMightExpand ? (
<td />
) : (
<></>
)}
{row.getCanSelect() && (
<td style={{ paddingRight: '10px', width: '15px' }}>
<CheckBox
value={row.getIsSelected()}
id={row.id}
name={row.id}
hasError={false}
disabled={!row.getCanSelect()}
onChange={() => row.toggleSelected()}
hasDescription={false}
size="small"
/>
</td>
)}
{row.getVisibleCells().map(({ column, id, getContext }) => (
<td key={id}>{flexRender(column.columnDef.cell, getContext())}</td>
))}
</tr>
{row.getIsExpanded() && renderDetailPanel!(row)}
</>
))}
</tbody>

Expand All @@ -355,9 +410,15 @@ export function Table<DataType extends object>({
<tr>
{/* This is the row selection */}
{ROW_SELECTION_COL_SPAN ? <td colSpan={1} /> : null}
{/* This is for the row expansion icon */}
{EXPAND_ROW_COL_SPAN ? <td colSpan={1} /> : null}
{pagination && (
<>
<td colSpan={table.getVisibleLeafColumns().length - 3 - ROW_SELECTION_COL_SPAN} />
<td
colSpan={
table.getVisibleLeafColumns().length - 3 - ROW_SELECTION_COL_SPAN - EXPAND_ROW_COL_SPAN
}
/>
<td colSpan={1}>
<span>
showing {table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}-
Expand Down
21 changes: 21 additions & 0 deletions packages/lib-components/src/components/data/Table/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ export const StyledTable = styled.table<{ density: Density }>`
border-bottom: none;
}
tr.subrow {
border-bottom: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
&:nth-child(even) {
background-color: ${({ theme }) => theme.colors.background};
}
&:nth-child(odd) {
background-color: ${({ theme }) => theme.colors.backgroundAlt};
}
td {
&:first-child {
padding-left: 0;
padding-bottom: 0;
}
padding: ${({ theme, density }) =>
density === 'tight' ? `${theme.spacing['0_5']} 0` : `${theme.spacing['0_5']} 0`};
}
}
td {
border-right: none;
border-bottom: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const PageSizeSelect: FC<PageSizeSelectProps> = ({ onPageSizeChange, page
id="page-size"
multiple={false}
name="pageSize"
inPortal={true}
value={pageSize.toString() || '10'}
onChange={onPageSizeChange}
render={(selectedItems) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ export const AbsoluteSubmit = () => {
name="date"
required={false}
loading={false}
description={'The role will be automatically removed after this date'}
description={'The role will be automatically removed after this date.'}
popOverPlacement={'bottom'}
timePickerOptions={{ interval: 30 }}
allowPastDates={false}
Expand Down
Loading

0 comments on commit 9126f73

Please sign in to comment.