From: Michal Klobukowski Date: Wed, 21 Nov 2018 08:52:34 +0000 (+0100) Subject: Update data-explorer to use table filters tree X-Git-Tag: 1.3.0~12^2^2~1^2~5^2~1 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/dade8b5aa00fa21c7c20b92767cddedabcf612cd Update data-explorer to use table filters tree Feature #14258 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- diff --git a/src/components/data-explorer/data-explorer.tsx b/src/components/data-explorer/data-explorer.tsx index 08f52d00..c9009c8a 100644 --- a/src/components/data-explorer/data-explorer.tsx +++ b/src/components/data-explorer/data-explorer.tsx @@ -8,9 +8,10 @@ import MoreVertIcon from "@material-ui/icons/MoreVert"; import { ColumnSelector } from "../column-selector/column-selector"; import { DataTable, DataColumns } from "../data-table/data-table"; import { DataColumn, SortDirection } from "../data-table/data-column"; -import { DataTableFilterItem } from '../data-table-filters/data-table-filters'; import { SearchInput } from '../search-input/search-input'; import { ArvadosTheme } from "~/common/custom-theme"; +import { createTree } from '~/models/tree'; +import { DataTableFilters } from '../data-table-filters/data-table-filters-tree'; type CssRules = 'searchBox' | "toolbar" | "footer" | "root" | 'moreOptionsButton'; @@ -53,7 +54,7 @@ interface DataExplorerActionProps { onColumnToggle: (column: DataColumn) => void; onContextMenu: (event: React.MouseEvent, item: T) => void; onSortToggle: (column: DataColumn) => void; - onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn) => void; + onFiltersChange: (filters: DataTableFilters, column: DataColumn) => void; onChangePage: (page: number) => void; onChangeRowsPerPage: (rowsPerPage: number) => void; extractKey?: (item: T) => React.Key; @@ -137,7 +138,7 @@ export const DataExplorer = withStyles(styles)( selected: true, configurable: false, sortDirection: SortDirection.NONE, - filters: [], + filters: createTree(), key: "context-actions", render: this.renderContextMenuTrigger }; diff --git a/src/components/data-table/data-column.ts b/src/components/data-table/data-column.ts index a5f95506..28e93bee 100644 --- a/src/components/data-table/data-column.ts +++ b/src/components/data-table/data-column.ts @@ -3,15 +3,16 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from "react"; -import { DataTableFilterItem } from "../data-table-filters/data-table-filters"; +import { DataTableFilters } from "../data-table-filters/data-table-filters-tree"; +import { createTree } from '~/models/tree'; -export interface DataColumn { +export interface DataColumn { key?: React.Key; name: string; selected: boolean; configurable: boolean; sortDirection?: SortDirection; - filters: F[]; + filters: DataTableFilters; render: (item: T) => React.ReactElement; renderHeader?: () => React.ReactElement; } @@ -34,13 +35,13 @@ export const resetSortDirection = (column: DataColumn): DataColumn => { return column.sortDirection ? { ...column, sortDirection: SortDirection.NONE } : column; }; -export const createDataColumn = (dataColumn: Partial>): DataColumn => ({ +export const createDataColumn = (dataColumn: Partial>): DataColumn => ({ key: '', name: '', selected: true, configurable: true, sortDirection: SortDirection.NONE, - filters: [], + filters: createTree(), render: () => React.createElement('span'), ...dataColumn, }); diff --git a/src/components/data-table/data-table.tsx b/src/components/data-table/data-table.tsx index 25d81c62..d9157a6a 100644 --- a/src/components/data-table/data-table.tsx +++ b/src/components/data-table/data-table.tsx @@ -5,10 +5,12 @@ import * as React from 'react'; import { Table, TableBody, TableRow, TableCell, TableHead, TableSortLabel, StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core'; import { DataColumn, SortDirection } from './data-column'; -import { DataTableFilters, DataTableFilterItem } from "../data-table-filters/data-table-filters"; import { DataTableDefaultView } from '../data-table-default-view/data-table-default-view'; +import { DataTableFilters } from '../data-table-filters/data-table-filters-tree'; +import { DataTableFiltersPopover } from '../data-table-filters/data-table-filters-popover'; +import { countNodes } from '~/models/tree'; -export type DataColumns = Array>; +export type DataColumns = Array>; export interface DataTableDataProps { items: T[]; @@ -17,7 +19,7 @@ export interface DataTableDataProps { onContextMenu: (event: React.MouseEvent, item: T) => void; onRowDoubleClick: (event: React.MouseEvent, item: T) => void; onSortToggle: (column: DataColumn) => void; - onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn) => void; + onFiltersChange: (filters: DataTableFilters, column: DataColumn) => void; extractKey?: (item: T) => React.Key; working?: boolean; defaultView?: React.ReactNode; @@ -81,15 +83,15 @@ export const DataTable = withStyles(styles)( return {renderHeader ? renderHeader() : - filters.length > 0 - ? 0 + ? onFiltersChange && onFiltersChange(filters, column)} filters={filters}> {name} - + : sortDirection ? (tree: Tree): string[] export const getNodeDescendants = (id: string, limit = Infinity) => (tree: Tree) => mapIdsToNodes(getNodeDescendantsIds(id, limit)(tree))(tree); +export const countNodes = (tree: Tree) => + getNodeDescendantsIds('')(tree).length; + export const getNodeDescendantsIds = (id: string, limit = Infinity) => (tree: Tree): string[] => { const node = getNode(id)(tree); const children = node ? node.children : diff --git a/src/store/data-explorer/data-explorer-action.ts b/src/store/data-explorer/data-explorer-action.ts index a58d20ed..7797ae6c 100644 --- a/src/store/data-explorer/data-explorer-action.ts +++ b/src/store/data-explorer/data-explorer-action.ts @@ -3,14 +3,14 @@ // SPDX-License-Identifier: AGPL-3.0 import { unionize, ofType, UnionOf } from "~/common/unionize"; -import { DataTableFilterItem } from "~/components/data-table-filters/data-table-filters"; import { DataColumns } from "~/components/data-table/data-table"; +import { DataTableFilters } from '~/components/data-table-filters/data-table-filters-tree'; export const dataExplorerActions = unionize({ RESET_PAGINATION: ofType<{ id: string }>(), REQUEST_ITEMS: ofType<{ id: string }>(), SET_COLUMNS: ofType<{ id: string, columns: DataColumns }>(), - SET_FILTERS: ofType<{ id: string, columnName: string, filters: DataTableFilterItem[] }>(), + SET_FILTERS: ofType<{ id: string, columnName: string, filters: DataTableFilters }>(), SET_ITEMS: ofType<{ id: string, items: any[], page: number, rowsPerPage: number, itemsAvailable: number }>(), SET_PAGE: ofType<{ id: string, page: number }>(), SET_ROWS_PER_PAGE: ofType<{ id: string, rowsPerPage: number }>(), @@ -28,7 +28,7 @@ export const bindDataExplorerActions = (id: string) => ({ dataExplorerActions.REQUEST_ITEMS({ id }), SET_COLUMNS: (payload: { columns: DataColumns }) => dataExplorerActions.SET_COLUMNS({ ...payload, id }), - SET_FILTERS: (payload: { columnName: string, filters: DataTableFilterItem[] }) => + SET_FILTERS: (payload: { columnName: string, filters: DataTableFilters }) => dataExplorerActions.SET_FILTERS({ ...payload, id }), SET_ITEMS: (payload: { items: any[], page: number, rowsPerPage: number, itemsAvailable: number }) => dataExplorerActions.SET_ITEMS({ ...payload, id }), diff --git a/src/store/data-explorer/data-explorer-middleware-service.ts b/src/store/data-explorer/data-explorer-middleware-service.ts index 934af7be..80ab514c 100644 --- a/src/store/data-explorer/data-explorer-middleware-service.ts +++ b/src/store/data-explorer/data-explorer-middleware-service.ts @@ -5,9 +5,10 @@ import { Dispatch, MiddlewareAPI } from "redux"; import { RootState } from "../store"; import { DataColumns } from "~/components/data-table/data-table"; -import { DataTableFilterItem } from "~/components/data-table-filters/data-table-filters"; import { DataExplorer } from './data-explorer-reducer'; import { ListResults } from '~/services/common-service/common-resource-service'; +import { createTree } from "~/models/tree"; +import { DataTableFilters } from "~/components/data-table-filters/data-table-filters-tree"; export abstract class DataExplorerMiddlewareService { protected readonly id: string; @@ -20,20 +21,19 @@ export abstract class DataExplorerMiddlewareService { return this.id; } - public getColumnFilters(columns: DataColumns, columnName: string): F[] { - const column = columns.find(c => c.name === columnName); - return column ? column.filters.filter(f => f.selected) : []; + public getColumnFilters(columns: DataColumns, columnName: string): DataTableFilters { + return getDataExplorerColumnFilters(columns, columnName); } abstract requestItems(api: MiddlewareAPI): void; } -export const getDataExplorerColumnFilters = (columns: DataColumns, columnName: string): F[] => { +export const getDataExplorerColumnFilters = (columns: DataColumns, columnName: string): DataTableFilters => { const column = columns.find(c => c.name === columnName); - return column ? column.filters.filter(f => f.selected) : []; + return column ? column.filters : createTree(); }; -export const dataExplorerToListParams = (dataExplorer: DataExplorer) => ({ +export const dataExplorerToListParams = (dataExplorer: DataExplorer) => ({ limit: dataExplorer.rowsPerPage, offset: dataExplorer.page * dataExplorer.rowsPerPage, }); diff --git a/src/store/data-explorer/data-explorer-middleware.test.ts b/src/store/data-explorer/data-explorer-middleware.test.ts index 814d5855..00931bf8 100644 --- a/src/store/data-explorer/data-explorer-middleware.test.ts +++ b/src/store/data-explorer/data-explorer-middleware.test.ts @@ -8,6 +8,8 @@ import { MiddlewareAPI } from "redux"; import { DataColumns } from "~/components/data-table/data-table"; import { dataExplorerActions } from "./data-explorer-action"; import { SortDirection } from "~/components/data-table/data-column"; +import { createTree } from '~/models/tree'; +import { DataTableFilterItem } from "~/components/data-table-filters/data-table-filters-tree"; describe("DataExplorerMiddleware", () => { @@ -20,7 +22,7 @@ describe("DataExplorerMiddleware", () => { selected: true, configurable: false, sortDirection: SortDirection.NONE, - filters: [], + filters: createTree(), render: jest.fn() }], requestItems: jest.fn(), @@ -48,7 +50,7 @@ describe("DataExplorerMiddleware", () => { selected: true, configurable: false, sortDirection: SortDirection.NONE, - filters: [], + filters: createTree(), render: jest.fn() }], requestItems: jest.fn(), @@ -115,7 +117,7 @@ describe("DataExplorerMiddleware", () => { }; const next = jest.fn(); const middleware = dataExplorerMiddleware(service)(api)(next); - middleware(dataExplorerActions.SET_FILTERS({ id: service.getId(), columnName: "", filters: [] })); + middleware(dataExplorerActions.SET_FILTERS({ id: service.getId(), columnName: "", filters: createTree() })); expect(api.dispatch).toHaveBeenCalledTimes(2); }); diff --git a/src/store/data-explorer/data-explorer-reducer.ts b/src/store/data-explorer/data-explorer-reducer.ts index 1657ab70..613bf278 100644 --- a/src/store/data-explorer/data-explorer-reducer.ts +++ b/src/store/data-explorer/data-explorer-reducer.ts @@ -4,8 +4,8 @@ import { DataColumn, toggleSortDirection, resetSortDirection, SortDirection } from "~/components/data-table/data-column"; import { dataExplorerActions, DataExplorerAction } from "./data-explorer-action"; -import { DataTableFilterItem } from "~/components/data-table-filters/data-table-filters"; import { DataColumns } from "~/components/data-table/data-table"; +import { DataTableFilters } from "~/components/data-table-filters/data-table-filters-tree"; export interface DataExplorer { columns: DataColumns; @@ -103,7 +103,7 @@ const toggleColumn = (columnName: string) => ? { ...column, selected: !column.selected } : column; -const setFilters = (columnName: string, filters: DataTableFilterItem[]) => +const setFilters = (columnName: string, filters: DataTableFilters) => (column: DataColumn) => column.name === columnName ? { ...column, filters } : column;