Skip to content

Commit

Permalink
Generics and tests for DataView (#2425)
Browse files Browse the repository at this point in the history
OKTA-836796 test: flesh out DataView tests
test: removing vestigial expects
test: remove testID selectors
Merge branch 'main' into jk-dataview-tests
Merge branch 'main' into jk-dataview-tests
fix: fix broken test
refactor: remove circular references
refactor: changing a11y roles
Merge branch 'main' into jk-dataview-tests
test: refactor all the DataView tests
refactor: replace "it" with "test"
Merge branch 'main' into jk-dataview-tests
fix: update one test
refactor: update aria-controls on closed menus
Merge branch 'main' into jk-dataview-tests
chore: adding generics to everything
refactor: remove generics that break consumers
Merge branch 'main' into jk-dataview-generics
Merge branch 'main' into jk-dataview-tests
fix: add proper TValue generic to DataColumns
fix: add tabindex to tableBody
fix: fix broken ariaControls on datafilter menu
fix: update broken type
Merge branch 'jk-dataview-tests' into jk-dataview-generics-and-tests
Merge branch 'jk-dataview-generics' into jk-dataview-generics-and-tests
fix: update imports
Merge branch 'main' into jk-dataview-generics-and-tests
refactor: improve tests based on Kevin feedback
  • Loading branch information
jordankoschei-okta authored and bryancunningham-okta committed Dec 3, 2024
1 parent 549e05d commit 1e67f35
Show file tree
Hide file tree
Showing 24 changed files with 1,568 additions and 295 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import { MRT_RowData } from "material-react-table";
* @param newIndex - The new index to move the row to.
* @returns A new array of data with the row moved to the specified index.
*/
export const reorderDataRowsLocally = ({
export const reorderDataRowsLocally = <TData extends MRT_RowData>({
currentData,
rowId,
newRowIndex,
}: {
currentData: MRT_RowData[];
currentData: TData[];
rowId: string;
newRowIndex: number;
}): MRT_RowData[] => {
}): TData[] => {
const updatedData = [...currentData];
const rowIndex = updatedData.findIndex((row) => row.id === rowId);

Expand Down
39 changes: 16 additions & 23 deletions packages/odyssey-react-mui/src/DataTable/useRowReordering.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { reorderDataRowsLocally } from "./reorderDataRowsLocally";
import { useOdysseyDesignTokens } from "../OdysseyDesignTokensContext";
import { MRT_Row, MRT_RowData, MRT_TableInstance } from "material-react-table";

export const useRowReordering = ({
export const useRowReordering = <TData extends MRT_RowData>({
totalRows,
onReorderRows,
data,
Expand All @@ -28,12 +28,10 @@ export const useRowReordering = ({
}: {
totalRows: DataTableProps["totalRows"];
onReorderRows: DataTableProps["onReorderRows"];
data: MRT_RowData[];
setData: Dispatch<SetStateAction<MRT_RowData[]>>;
draggingRow?: MRT_Row<MRT_RowData> | null;
setDraggingRow: Dispatch<
SetStateAction<MRT_Row<MRT_RowData> | null | undefined>
>;
data: TData[];
setData: Dispatch<SetStateAction<TData[]>>;
draggingRow?: MRT_Row<TData> | null;
setDraggingRow: Dispatch<SetStateAction<MRT_Row<TData> | null | undefined>>;
resultsPerPage: number;
page: number;
}) => {
Expand Down Expand Up @@ -68,7 +66,6 @@ export const useRowReordering = ({
const dragHandleStyles = {
padding: odysseyDesignTokens.Spacing1,
borderRadius: odysseyDesignTokens.BorderRadiusMain,

"&:focus-visible": {
boxShadow: `0 0 0 2px ${odysseyDesignTokens.HueNeutralWhite}, 0 0 0 4px ${odysseyDesignTokens.PalettePrimaryMain}`,
outline: "2px solid transparent",
Expand Down Expand Up @@ -106,12 +103,12 @@ export const useRowReordering = ({
return undefined;
};

const setHoveredRow = (
table: MRT_TableInstance<MRT_RowData>,
id: MRT_RowData["id"],
) => {
const setHoveredRow = (table: MRT_TableInstance<TData>, id: TData["id"]) => {
if (id) {
const nextRow: MRT_RowData = table.getRow(id);
// The `as MRT_Row<TData>` is necessary here to overcome some type/generic
// issues with the type of `setHoveredRow` defined by MRT. It's not ideal code,
// but it's the only way that works without a much larger rewrite.
const nextRow = table.getRow(id) as MRT_Row<TData>;

if (nextRow) {
table.setHoveredRow(nextRow);
Expand All @@ -120,8 +117,8 @@ export const useRowReordering = ({
};

type HandleDragHandleKeyDownArgs = {
table: MRT_TableInstance<MRT_RowData>;
row: MRT_Row<MRT_RowData>;
table: MRT_TableInstance<TData>;
row: MRT_Row<TData>;
event: KeyboardEvent<HTMLButtonElement>;
};

Expand Down Expand Up @@ -192,32 +189,28 @@ export const useRowReordering = ({
}
};

const handleDragHandleOnDragEnd = (table: MRT_TableInstance<MRT_RowData>) => {
const handleDragHandleOnDragEnd = (table: MRT_TableInstance<TData>) => {
const cols = table.getAllColumns();
cols[0].toggleVisibility();

const { draggingRow, hoveredRow } = table.getState();
if (draggingRow) {
updateRowOrder({
rowId: draggingRow.id,
newRowIndex: (hoveredRow as MRT_RowData).index,
newRowIndex: (hoveredRow as TData).index,
});
}

setDraggingRow(null);
};

const handleDragHandleOnDragCapture = (
table: MRT_TableInstance<MRT_RowData>,
) => {
const handleDragHandleOnDragCapture = (table: MRT_TableInstance<TData>) => {
if (!draggingRow && table.getState().draggingRow?.id) {
setDraggingRow(table.getState().draggingRow);
}
};

const resetDraggingAndHoveredRow = (
table: MRT_TableInstance<MRT_RowData>,
) => {
const resetDraggingAndHoveredRow = (table: MRT_TableInstance<TData>) => {
setDraggingRow(null);
table.setHoveredRow(null);
};
Expand Down
4 changes: 2 additions & 2 deletions packages/odyssey-react-mui/src/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { paginationTypeValues } from "./constants";
import { usePagination } from "./usePagination";
import { useTranslation } from "react-i18next";

const PaginationContainer = styled("div")({
const PaginationContainer = styled("nav")({
display: "flex",
alignItems: "center",
justifyContent: "space-between",
Expand Down Expand Up @@ -330,7 +330,7 @@ const Pagination = ({
);

return variant === "paged" ? (
<PaginationContainer>
<PaginationContainer aria-label={t("pagination.label")}>
<PaginationSegment odysseyDesignTokens={odysseyDesignTokens}>
{hasRowCountInput && (
<Box>
Expand Down
10 changes: 7 additions & 3 deletions packages/odyssey-react-mui/src/labs/DataFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,9 @@ const DataFilters = ({
<>
<Box>
<Button
aria-controls={isFiltersMenuOpen ? "filters-menu" : undefined}
aria-expanded={isFiltersMenuOpen ? "true" : undefined}
aria-haspopup="true"
ariaControls={isFiltersMenuOpen ? "filters-menu" : undefined}
ariaExpanded={isFiltersMenuOpen ? "true" : undefined}
ariaHasPopup="true"
ariaLabel={t("filters.filters.arialabel")}
isDisabled={isDisabled}
endIcon={<FilterIcon />}
Expand Down Expand Up @@ -469,6 +469,7 @@ const DataFilters = ({
return (
<MuiMenuItem
key={filter.id}
aria-controls={isFilterPopoverOpen ? "filter-form" : undefined}
onClick={(event) => {
setIsFilterPopoverOpen(true);
setFilterPopoverAnchorElement(event.currentTarget);
Expand Down Expand Up @@ -563,6 +564,7 @@ const DataFilters = ({
{filterMenu}
{/* Filter popover */}
<MuiPopover
id="filter-form"
anchorEl={filterPopoverAnchorElement}
// Positions the popover flush with the edge of the parent menu
// and at the right shadow elevation. These magic values are simply
Expand Down Expand Up @@ -630,6 +632,7 @@ const DataFilters = ({
variant="primary"
endIcon={<CheckIcon />}
type="submit"
ariaLabel={t("filters.submit.label")}
/>
</AutocompleteOuterContainer>
)}
Expand Down Expand Up @@ -697,6 +700,7 @@ const DataFilters = ({
variant="primary"
endIcon={<CheckIcon />}
type="submit"
ariaLabel={t("filters.submit.label")}
/>
</Box>
)}
Expand Down
59 changes: 30 additions & 29 deletions packages/odyssey-react-mui/src/labs/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export type {

// The shape of the table columns,
// with props named to match their MRT_ColumnDef counterparts
export type DataTableColumn = {
export type DataTableColumn<TData extends MRT_RowData> = {
/**
* The unique ID of the column
*/
Expand All @@ -82,12 +82,12 @@ export type DataTableColumn = {
* Customize the way each cell in the column is
* displayed via a custom React component.
*/
Cell?: MRT_ColumnDef<MRT_RowData>["Cell"];
Cell?: MRT_ColumnDef<TData>["Cell"];
/**
* The UI control that will be used to filter the column.
* Defaults to a standard text input.
*/
filterVariant?: MRT_ColumnDef<MRT_RowData>["filterVariant"];
filterVariant?: MRT_ColumnDef<TData>["filterVariant"];
/**
* If the filter control has preset options (such as a select or multi-select),
* these are the options provided.
Expand Down Expand Up @@ -127,16 +127,16 @@ export type DataTableColumn = {
enableHiding?: boolean;
};

export type DataTableProps = {
export type DataTableProps<TData extends MRT_RowData> = {
/**
* The columns that make up the table
*/
columns: DataTableColumn[];
columns: DataTableColumn<TData>[];
/**
* The data that goes into the table, which will be displayed
* as the table rows
*/
data: MRT_TableOptions<MRT_RowData>["data"];
data: MRT_TableOptions<TData>["data"];
/**
* The total number of rows in the table. Optional, because it's sometimes impossible
* to calculate. Used in table pagination to know when to disable the "next"/"more" button.
Expand All @@ -145,7 +145,7 @@ export type DataTableProps = {
/**
* The function to get the ID of a row
*/
getRowId?: MRT_TableOptions<MRT_RowData>["getRowId"];
getRowId?: MRT_TableOptions<TData>["getRowId"];
/**
* The initial density of the table. This is available even if the table density
* isn't changeable.
Expand Down Expand Up @@ -219,7 +219,7 @@ export type DataTableProps = {
search?: string;
filters?: DataFilter[];
sort?: MRT_SortingState;
}) => MRT_TableOptions<MRT_RowData>["data"];
}) => MRT_TableOptions<TData>["data"];
/**
* Callback that fires when the user reorders rows within the table. Can be used
* to propogate order change to the backend.
Expand Down Expand Up @@ -248,24 +248,24 @@ export type DataTableProps = {
* Action buttons to display in each row
*/
rowActionButtons?: (
row: MRT_RowData,
row: TData,
) => ReactElement<typeof Button | typeof Fragment>;
/**
* Menu items to include in the optional actions menu on each row.
*/
rowActionMenuItems?: (
row: MRT_RowData,
row: TData,
) => ReactElement<typeof MenuItem | typeof Fragment>;
};

type TableType = MRT_TableInstance<MRT_RowData>;
type TableType<TData extends MRT_RowData> = MRT_TableInstance<TData>;

const reorderDataRowsLocally = ({
const reorderDataRowsLocally = <TData extends MRT_RowData>({
currentData,
rowId,
newIndex,
}: {
currentData: MRT_TableOptions<MRT_RowData>["data"];
currentData: MRT_TableOptions<TData>["data"];
rowId: string;
newIndex: number;
}) => {
Expand All @@ -284,7 +284,7 @@ const reorderDataRowsLocally = ({
return updatedData;
};

const DataTable = ({
const DataTable = <TData extends MRT_RowData>({
columns,
data: dataProp,
getRowId,
Expand All @@ -309,13 +309,12 @@ const DataTable = ({
hasRowSelection,
hasSearch,
hasSorting,
}: DataTableProps) => {
}: DataTableProps<TData>) => {
const odysseyDesignTokens = useOdysseyDesignTokens();
const { t } = useTranslation();
const [draggingRow, setDraggingRow] = useState<MRT_Row<MRT_RowData> | null>();
const [draggingRow, setDraggingRow] = useState<MRT_Row<TData> | null>();
const [showSkeletons, setShowSkeletons] = useState<boolean>(true);
const [data, setData] =
useState<MRT_TableOptions<MRT_RowData>["data"]>(dataProp);
const [data, setData] = useState<MRT_TableOptions<TData>["data"]>(dataProp);
const [page, setPage] = useState<number>(pageProp);
const [resultsPerPage, setResultsPerPage] =
useState<number>(resultsPerPageProp);
Expand Down Expand Up @@ -428,24 +427,24 @@ const DataTable = ({
const rowVirtualizerInstanceRef =
useRef<MRT_RowVirtualizer<HTMLDivElement, HTMLTableRowElement>>(null);

const setHoveredRow = (table: TableType, id: MRT_RowData["id"]) => {
const setHoveredRow = (table: TableType<TData>, id: TData["id"]) => {
if (id) {
const nextRow: MRT_RowData = table.getRow(id);
const nextRow = table.getRow(id) as MRT_Row<TData>;

if (nextRow) {
table.setHoveredRow(nextRow);
}
}
};

const resetDraggingAndHoveredRow = (table: TableType) => {
const resetDraggingAndHoveredRow = (table: TableType<TData>) => {
setDraggingRow(null);
table.setHoveredRow(null);
};

type HandleDragHandleKeyDownArgs = {
table: TableType;
row: MRT_Row<MRT_RowData>;
table: TableType<TData>;
row: MRT_Row<TData>;
event: KeyboardEvent<HTMLButtonElement>;
};

Expand Down Expand Up @@ -515,23 +514,25 @@ const DataTable = ({
[
data,
draggingRow,
odysseyDesignTokens,
odysseyDesignTokens.TransitionDurationMainAsNumber,
page,
resetDraggingAndHoveredRow,
resultsPerPage,
setHoveredRow,
updateRowOrder,
],
);

const handleDragHandleOnDragEnd = useCallback(
(table: TableType) => {
(table: TableType<TData>) => {
const cols = table.getAllColumns();
cols[0].toggleVisibility();

const { draggingRow, hoveredRow } = table.getState();
if (draggingRow) {
updateRowOrder({
rowId: draggingRow.id,
newIndex: (hoveredRow as MRT_RowData).index,
newIndex: (hoveredRow as TData).index,
});
}

Expand All @@ -541,7 +542,7 @@ const DataTable = ({
);

const handleDragHandleOnDragCapture = useCallback(
(table: TableType) => {
(table: TableType<TData>) => {
if (!draggingRow && table.getState().draggingRow?.id) {
setDraggingRow(table.getState().draggingRow);
}
Expand Down Expand Up @@ -683,7 +684,7 @@ const DataTable = ({

return (
<Box sx={{ display: "flex" }}>
{rowActionButtons?.(row)}
{rowActionButtons?.(row.original)}
{(rowActionMenuItems || hasRowReordering) && (
<MenuButton
endIcon={<MoreIcon />}
Expand All @@ -694,7 +695,7 @@ const DataTable = ({
>
{rowActionMenuItems && (
<>
{rowActionMenuItems(row)}
{rowActionMenuItems(row.original)}
<hr />
</>
)}
Expand Down
Loading

0 comments on commit 1e67f35

Please sign in to comment.