From 6729b27f7db77c06de9a0c9d6ee406adea0963cf Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 16 Aug 2024 17:50:33 +0530 Subject: [PATCH 1/6] RunList: Use custom filter - Use custom filter to show filter inputs outside the table - Add a button to expand/hide filter options - Display sort button only on hover over the column title - Disable column action buttons (all of it's functions can be performed with sort, filter, and show/hide column buttons) Signed-off-by: Vallari Agrawal --- src/components/RunList/index.tsx | 66 +++++++++++++++++++++++++++----- src/lib/table.ts | 13 +++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/components/RunList/index.tsx b/src/components/RunList/index.tsx index 6a5eff4..b575fd4 100644 --- a/src/components/RunList/index.tsx +++ b/src/components/RunList/index.tsx @@ -1,5 +1,8 @@ import { useMemo } from 'react'; +import { useState } from "react"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; +import Grid from '@mui/material/Grid'; +import Button from '@mui/material/Button'; import type { DecodedValueMap, QueryParamConfigMap, @@ -9,6 +12,7 @@ import { useDebounce } from "usehooks-ts"; import { useMaterialReactTable, MaterialReactTable, + MRT_TableHeadCellFilterContainer, type MRT_ColumnDef, type MRT_PaginationState, type MRT_Updater, @@ -38,6 +42,14 @@ const NON_FILTER_PARAMS = [ "page", "pageSize", ]; +const FILTER_COLUMNS = [ + "status", + "scheduled", + "suite", + "branch", + "machine_type", + "sha1", +] const _columns: MRT_ColumnDef[] = [ { @@ -45,7 +57,6 @@ const _columns: MRT_ColumnDef[] = [ header: "link", maxSize: 12, enableColumnFilter: false, - enableColumnActions: false, Cell: ({ row }) => { return ( @@ -62,14 +73,14 @@ const _columns: MRT_ColumnDef[] = [ return row.original.status.replace("finished ", ""); }, filterSelectOptions: Object.values(RunStatuses), - size: 40, - enableColumnActions: false, + maxSize: 25, }, { accessorKey: "user", header: "user", maxSize: 45, enableColumnActions: false, + enableColumnFilter: false, }, { id: "scheduled", @@ -81,7 +92,7 @@ const _columns: MRT_ColumnDef[] = [ const date_: string[] = row.original.scheduled.split(" "); return
{date_[0]}
{date_[1]}
}, - size: 50, + size: 35, }, { id: "started", @@ -89,7 +100,7 @@ const _columns: MRT_ColumnDef[] = [ accessorFn: (row: Run) => formatDate(row.started), enableColumnFilter: false, sortingFn: "datetime", - size: 125, + size: 35, }, { id: "posted", @@ -97,7 +108,7 @@ const _columns: MRT_ColumnDef[] = [ accessorFn: (row: Run) => formatDate(row.posted), enableColumnFilter: false, sortingFn: "datetime", - size: 125, + maxSize: 35, }, { id: "runtime", @@ -115,12 +126,12 @@ const _columns: MRT_ColumnDef[] = [ { accessorKey: "suite", header: "suite", - size: 70, + size: 50, }, { accessorKey: "branch", header: "branch", - maxSize: 75, + maxSize: 70, }, { accessorKey: "machine_type", @@ -200,6 +211,11 @@ type RunListProps = { } export default function RunList(props: RunListProps) { + const [openFilterMenu, setOpenFilterMenu] = useState(false); + + const toggleFilterMenu = (isOpen: boolean) => () => { + setOpenFilterMenu(isOpen); + }; const { params, setter, tableOptions } = props; const options = useDefaultTableOptions(); const debouncedParams = useDebounce(params, 500); @@ -267,12 +283,17 @@ export default function RunList(props: RunListProps) { data: data, manualPagination: true, manualFiltering: true, + enableColumnActions: false, onPaginationChange, rowCount: Infinity, muiPaginationProps: { showLastButton: false, }, onColumnFiltersChange, + columnFilterDisplayMode: 'custom', + muiFilterTextFieldProps: ({ column }) => ({ + label: `Filter by ${column.columnDef.header}`, + }), initialState: { ...options.initialState, columnVisibility: { @@ -300,5 +321,32 @@ export default function RunList(props: RunListProps) { ...tableOptions, }); if (query.isError) return null; - return + return ( +
+ { openFilterMenu? ( + + {table.getLeafHeaders().map((header) => { + console.log(header.id) + if (FILTER_COLUMNS.includes(header.id)) { + return ( + + + + ) + } + })} + ) + : ""} + + +
+ ) } diff --git a/src/lib/table.ts b/src/lib/table.ts index 4db9d87..7cbc21f 100644 --- a/src/lib/table.ts +++ b/src/lib/table.ts @@ -24,6 +24,19 @@ export default function useDefaultTableOptions(): Par mrtTheme: { baseBackgroundColor: theme.palette.background.default, }, + muiTableHeadCellProps: { + sx: { + '& .Mui-TableHeadCell-Content': { + fontSize: "0.8em", + }, + '& .MuiTableSortLabel-root': { + display: "none", + }, + '&:hover .MuiTableSortLabel-root': { + display: "block", + }, + }, + }, muiTableBodyCellProps: { sx: { color: "black", From a1299318b22ef557d38c943ad7e87634ef83264a Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Wed, 13 Nov 2024 17:06:02 +0530 Subject: [PATCH 2/6] RunList: Show filters in 3 sections Show the RunList custom filter in 3 sections: build details, run details, result details. This commit also does the following: 1. Hides the default filter icon from table 2. Hides filter icon present in filtered columns Signed-off-by: Vallari Agrawal --- src/components/RunList/index.tsx | 99 +++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/src/components/RunList/index.tsx b/src/components/RunList/index.tsx index b575fd4..750ff23 100644 --- a/src/components/RunList/index.tsx +++ b/src/components/RunList/index.tsx @@ -18,6 +18,7 @@ import { type MRT_Updater, type MRT_ColumnFiltersState, type MRT_TableOptions, + type MRT_TableInstance, } from 'material-react-table'; import { type Theme } from "@mui/material/styles"; import { parse } from "date-fns"; @@ -35,6 +36,8 @@ import { RunStatuses, } from "../../lib/paddles.d"; import useDefaultTableOptions from "../../lib/table"; +import Typography from '@mui/material/Typography'; +import Box from '@mui/material/Box'; const DEFAULT_PAGE_SIZE = 25; @@ -42,14 +45,6 @@ const NON_FILTER_PARAMS = [ "page", "pageSize", ]; -const FILTER_COLUMNS = [ - "status", - "scheduled", - "suite", - "branch", - "machine_type", - "sha1", -] const _columns: MRT_ColumnDef[] = [ { @@ -135,7 +130,7 @@ const _columns: MRT_ColumnDef[] = [ }, { accessorKey: "machine_type", - header: "machine_type", + header: "machine type", size: 30, }, { @@ -291,8 +286,10 @@ export default function RunList(props: RunListProps) { }, onColumnFiltersChange, columnFilterDisplayMode: 'custom', + enableColumnFilters: false, muiFilterTextFieldProps: ({ column }) => ({ - label: `Filter by ${column.columnDef.header}`, + label: column.columnDef.header, + placeholder: '', }), initialState: { ...options.initialState, @@ -323,30 +320,76 @@ export default function RunList(props: RunListProps) { if (query.isError) return null; return (
- { openFilterMenu? ( - + + + +
+ ) +} + + +// FilterMenu + +type FilterMenuProps = { + isOpen: boolean; + table: MRT_TableInstance; +}; + + +const FILTER_SECTIONS = ["run", "build", "result"] +const FILTER_SECTIONS_COLUMNS = [ + ["scheduled", "suite", "machine_type", "user"], + ["branch", "sha1"], + ["status"], +] + +function FilterMenu({ isOpen, table}: FilterMenuProps) { + if (!isOpen) { + return null; + } + + return ( + + {FILTER_SECTIONS_COLUMNS.map((_, sectionIndex) => ( + + + Filter by {FILTER_SECTIONS[sectionIndex]} details... + + {table.getLeafHeaders().map((header) => { - console.log(header.id) - if (FILTER_COLUMNS.includes(header.id)) { + if (FILTER_SECTIONS_COLUMNS[sectionIndex].includes(header.id)) { return ( - + - ) - } + ); + } + return null; })} - ) - : ""} - - - - ) + + + ))} + + ) } From 2d48b823446054d163c51c4ed44f7f7bce2b15f4 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 15 Nov 2024 00:26:41 +0530 Subject: [PATCH 3/6] RunList: show Badge for number of filters applied Signed-off-by: Vallari Agrawal --- src/components/RunList/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/RunList/index.tsx b/src/components/RunList/index.tsx index 750ff23..6e1f94f 100644 --- a/src/components/RunList/index.tsx +++ b/src/components/RunList/index.tsx @@ -38,6 +38,7 @@ import { import useDefaultTableOptions from "../../lib/table"; import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; +import Badge from '@mui/material/Badge'; const DEFAULT_PAGE_SIZE = 25; @@ -320,9 +321,14 @@ export default function RunList(props: RunListProps) { if (query.isError) return null; return (
- + (filter.value ? count + 1 : count), 0)} + > + +
From 250b5975bab5b4d5a5329beffa652fcd7654ec9a Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 15 Nov 2024 11:31:29 +0530 Subject: [PATCH 4/6] RunList: Make FilterMenu as a popover menu Make FilterMenu more compact and turn it into a pop-over menu instead of having it open above the table. Signed-off-by: Vallari Agrawal --- src/components/RunList/index.tsx | 55 ++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/components/RunList/index.tsx b/src/components/RunList/index.tsx index 6e1f94f..da5dedd 100644 --- a/src/components/RunList/index.tsx +++ b/src/components/RunList/index.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { SetStateAction, useMemo } from 'react'; import { useState } from "react"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; import Grid from '@mui/material/Grid'; @@ -39,6 +39,7 @@ import useDefaultTableOptions from "../../lib/table"; import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; import Badge from '@mui/material/Badge'; +import Menu from '@mui/material/Menu'; const DEFAULT_PAGE_SIZE = 25; @@ -207,11 +208,9 @@ type RunListProps = { } export default function RunList(props: RunListProps) { - const [openFilterMenu, setOpenFilterMenu] = useState(false); + const [openFilterMenu, setOpenFilterMenu] = useState(false); + const [dropMenuAnchorEl, setDropMenuAnchor] = useState(null); - const toggleFilterMenu = (isOpen: boolean) => () => { - setOpenFilterMenu(isOpen); - }; const { params, setter, tableOptions } = props; const options = useDefaultTableOptions(); const debouncedParams = useDebounce(params, 500); @@ -232,6 +231,15 @@ export default function RunList(props: RunListProps) { pageIndex: params.page || 0, pageSize: params.pageSize || DEFAULT_PAGE_SIZE, }; + const toggleFilterMenu = (event: { currentTarget: SetStateAction; }) => { + if (dropMenuAnchorEl) { + setDropMenuAnchor(null); + setOpenFilterMenu(false); + } else { + setDropMenuAnchor(event.currentTarget); + setOpenFilterMenu(true); + } + } const onColumnFiltersChange = (updater: MRT_Updater) => { if ( ! ( updater instanceof Function ) ) return; const result: RunListParams = {pageSize: pagination.pageSize}; @@ -318,18 +326,35 @@ export default function RunList(props: RunListProps) { }, ...tableOptions, }); + if (query.isError) return null; return (
- + (filter.value ? count + 1 : count), 0)} + > + - + Filters Runs + + + + +
) @@ -359,19 +384,17 @@ function FilterMenu({ isOpen, table}: FilterMenuProps) { return ( {FILTER_SECTIONS_COLUMNS.map((_, sectionIndex) => ( @@ -382,7 +405,7 @@ function FilterMenu({ isOpen, table}: FilterMenuProps) { {table.getLeafHeaders().map((header) => { if (FILTER_SECTIONS_COLUMNS[sectionIndex].includes(header.id)) { return ( - + Date: Fri, 15 Nov 2024 12:34:14 +0530 Subject: [PATCH 5/6] RunList: Put filter button inside the table menu - use renderTopToolbarCustomActions to add the filter button inside the table menu - Show what filters are applied at top right of the table. Signed-off-by: Vallari Agrawal --- src/components/RunList/index.tsx | 46 +++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/components/RunList/index.tsx b/src/components/RunList/index.tsx index da5dedd..19748ab 100644 --- a/src/components/RunList/index.tsx +++ b/src/components/RunList/index.tsx @@ -324,25 +324,39 @@ export default function RunList(props: RunListProps) { if ( category ) return { className: category }; return {}; }, + renderTopToolbarCustomActions: ({ table }) => ( + + (filter.value ? count + 1 : count), 0)} + > + + + + ), ...tableOptions, }); if (query.isError) return null; return ( -
- +
- (filter.value ? count + 1 : count), 0)} - > - - + + { table.getState().columnFilters.map((column) => { + let filterValue = column.value; + if (column.id == "scheduled") { + const parsedDate = new Date(column.value as string); + filterValue = (parsedDate.toISOString().split('T')[0]) + } + return (column.value ? `${column.id}: '${filterValue}' ` : "") + } )} + -
- -
+
+ + ) } From 9d6cacc5839ce98ed940188df1bc31e2ac881887 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 15 Nov 2024 15:24:02 +0530 Subject: [PATCH 6/6] src/lib/paddles.ts: allow machine_type filter for useRuns This is to handle difference in machine_type filter in two endpoints /node/?machine_type=xyz and /runs/machine_type/xyz Fixes machine_type filter for RunList. Signed-off-by: Vallari Agrawal --- src/lib/paddles.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/paddles.ts b/src/lib/paddles.ts index 905b79d..321e3f1 100644 --- a/src/lib/paddles.ts +++ b/src/lib/paddles.ts @@ -54,12 +54,19 @@ function getURL(endpoint: string, params?: GetURLParams) { } function useRuns(params: GetURLParams): UseQueryResult { + let baseUrl = "/runs/"; const params_ = { ...params }; if (params_.pageSize) { params_.count = params.pageSize; delete params_.pageSize; } - const url = getURL("/runs/", params); + if (params_.machine_type) { + // this is to handle difference in machine_type filter + // in two endpoints /node/?machine_type=xyz and /runs/machine_type/xyz + baseUrl += "machine_type/" + params_.machine_type + "/"; + delete params_.machine_type; + } + const url = getURL(baseUrl, params); const query = useQuery(["runs", { url }], { select: (data: Run[]) => data.map((item) => {