diff --git a/Changelog.md b/Changelog.md index ccf690fb4c..6bcc5f39c2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ ### 🚨 Breaking changes ### ✨ New features and improvements +- Migrated `AnnotationUsagePanel` component to use `react-table` v8 (#8021) - Migrated `SummaryPanel` component to React Table V8 (#8019) - Migrated `graders_manager.jsx` file's `GradersTable`, `GroupsTable`, `CriteriaTable` to use `react-table` v8 (#8014) - Added CSV upload support for criterion marks in the assignment Grades tab (#8008) diff --git a/app/javascript/Components/annotation_usage_panel.jsx b/app/javascript/Components/annotation_usage_panel.jsx index 204c1efc84..c11c56dbd0 100644 --- a/app/javascript/Components/annotation_usage_panel.jsx +++ b/app/javascript/Components/annotation_usage_panel.jsx @@ -1,15 +1,17 @@ import React from "react"; -import ReactTable from "react-table"; import {createRoot} from "react-dom/client"; -import ReactDOM from "react-dom"; +import {createColumnHelper} from "@tanstack/react-table"; +import Table from "./table/table"; -import {caseSensitiveIncludes, caseSensitiveTextFilter} from "./Helpers/table_helpers"; +import {caseSensitiveIncludes} from "./Helpers/table_helpers"; +const columnHelper = createColumnHelper(); class AnnotationUsagePanel extends React.Component { constructor(props) { super(props); this.state = { applications: null, + columnFilters: [], details: false, }; } @@ -23,44 +25,57 @@ class AnnotationUsagePanel extends React.Component { }; columns = [ - { - Header: I18n.t("annotations.used_by"), - accessor: row => "(" + row["user_name"] + ") " + row["first_name"] + " " + row["last_name"], - id: "user", - minWidth: 200, - PivotValue: ({value}) => value, - }, - { - Header: I18n.t("activerecord.models.submission.one"), - accessor: "group_name", - aggregate: (vals, pivots) => { - let usageCount = pivots.reduce((accumulator, p) => accumulator + p._original["count"], 0); - return I18n.t("annotations.used_times", {count: usageCount}); + columnHelper.accessor( + row => "(" + row.user_name + ") " + row.first_name + " " + row.last_name, + { + header: I18n.t("annotations.used_by"), + id: "user", + minSize: 200, + cell: ({getValue, row}) => { + if (row.getIsGrouped()) { + return getValue(); + } + return null; + }, + } + ), + columnHelper.accessor("group_name", { + header: I18n.t("activerecord.models.submission.one"), + enableSorting: false, + aggregationFn: (columnId, leafRows, childRows) => { + return leafRows.reduce((acc, row) => acc + row.original.count, 0); }, - sortable: false, - Aggregated: row => "(" + row.value + ")", - Filter: caseSensitiveTextFilter, - filterMethod: (filter, row) => { - const {filterValue, caseSensitive} = filter.value; - if (!filterValue) { - return true; - } else if (row._subRows === undefined) { - return caseSensitiveIncludes(row[filter.id], filterValue, caseSensitive); - } else { - return row._subRows.some(sr => - caseSensitiveIncludes(sr["group_name"], filterValue, caseSensitive) - ); + cell: props => { + if (props.row.getIsGrouped()) { + return I18n.t("annotations.used_times", { + count: props.row.getValue("group_name"), + }); } - }, - Cell: row => { + return ( - - {row.original["group_name"] + - (row.original["count"] > 1 ? " (" + row.original["count"] + ")" : "")} + + {props.row.original.group_name + + (props.row.original.count > 1 ? ` (${props.row.original.count})` : "")} ); }, - }, + filterFn: (row, columnId, filterValue) => { + const value = filterValue?.value; + const caseSensitive = filterValue?.caseSensitive; + + if (!value) return true; + + return caseSensitiveIncludes(row.original[columnId], value, caseSensitive); + }, + meta: { + filterVariant: "case-sensitive-text", + }, + }), ]; fetchData = () => { @@ -97,12 +112,23 @@ class AnnotationUsagePanel extends React.Component { ); if (this.state.details) { let annotation_table = ( - { + this.setState(prevState => { + let newFilters = + typeof updaterOrValue === "function" + ? updaterOrValue(prevState.columnFilters) + : updaterOrValue; + return {columnFilters: newFilters}; + }); + }} + renderSubRows={true} /> ); return ( diff --git a/app/javascript/Components/table/case_sensitive_search_filter.jsx b/app/javascript/Components/table/case_sensitive_search_filter.jsx index 5db3293567..569d802c94 100644 --- a/app/javascript/Components/table/case_sensitive_search_filter.jsx +++ b/app/javascript/Components/table/case_sensitive_search_filter.jsx @@ -31,7 +31,7 @@ export default function CaseSensitiveSearchFilter({column, filterValue}) { }); }} aria-label={I18n.t("table.case_sensitive_search")} - data-testid={`${column.columnDef.id}_case_sensitive`} + data-testid={`${column.id}_case_sensitive`} /> {I18n.t("table.case_sensitive_indicator")} diff --git a/app/javascript/Components/table/table.jsx b/app/javascript/Components/table/table.jsx index 77fb977b5d..b98000254e 100644 --- a/app/javascript/Components/table/table.jsx +++ b/app/javascript/Components/table/table.jsx @@ -9,6 +9,7 @@ import { getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, + getGroupedRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; @@ -84,6 +85,7 @@ export default function Table({ initialState, loading, renderSubComponent, + renderSubRows, getRowCanExpand, getRowId, enableRowSelection, @@ -100,6 +102,7 @@ export default function Table({ }); const [expanded, setExpanded] = React.useState({}); const [internalRowSelection, setInternalRowSelection] = React.useState({}); + const [grouping, setGrouping] = React.useState(initialState?.grouping ?? []); const columnFilters = React.useMemo( () => (externalColumnFilters !== undefined ? externalColumnFilters : internalColumnFilters), @@ -129,11 +132,11 @@ export default function Table({ if (enableRowSelection) { cols = [selectionColumn, ...cols]; } - if (renderSubComponent) { + if (renderSubComponent || renderSubRows) { cols = [expanderColumn, ...cols]; } return cols; - }, [columns, enableRowSelection, renderSubComponent]); + }, [columns, enableRowSelection, renderSubComponent, renderSubRows]); const table = useReactTable({ data, @@ -144,21 +147,25 @@ export default function Table({ columnVisibility, expanded, rowSelection, + grouping, }, initialState: initialState, onColumnFiltersChange: handleColumnFiltersChange, onColumnSizingChange: setColumnSizing, onColumnVisibilityChange: setColumnVisibility, onExpandedChange: setExpanded, + onGroupingChange: setGrouping, onRowSelectionChange: handleRowSelectionChange, getCoreRowModel: getCoreRowModel(), getExpandedRowModel: getExpandedRowModel(), getFilteredRowModel: getFilteredRowModel(), + getGroupedRowModel: getGroupedRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), getFacetedRowModel: getFacetedRowModel(), getRowCanExpand, getRowId, + groupedColumnMode: false, enableSortingRemoval: false, enableColumnResizing: true, enableRowSelection: enableRowSelection, @@ -224,6 +231,7 @@ export default function Table({ @@ -15,13 +15,14 @@ function TableRow({row, isSelected, isExpanded, renderSubComponent}) { ); })} - {isExpanded && {renderSubComponent({row})}} + {isExpanded && !isGrouped && {renderSubComponent({row})}} ); }