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';
onColumnToggle: (column: DataColumn<T>) => void;
onContextMenu: (event: React.MouseEvent<HTMLElement>, item: T) => void;
onSortToggle: (column: DataColumn<T>) => void;
- onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn<T>) => void;
+ onFiltersChange: (filters: DataTableFilters, column: DataColumn<T>) => void;
onChangePage: (page: number) => void;
onChangeRowsPerPage: (rowsPerPage: number) => void;
extractKey?: (item: T) => React.Key;
selected: true,
configurable: false,
sortDirection: SortDirection.NONE,
- filters: [],
+ filters: createTree(),
key: "context-actions",
render: this.renderContextMenuTrigger
};
// 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<T, F extends DataTableFilterItem = DataTableFilterItem> {
+export interface DataColumn<T> {
key?: React.Key;
name: string;
selected: boolean;
configurable: boolean;
sortDirection?: SortDirection;
- filters: F[];
+ filters: DataTableFilters;
render: (item: T) => React.ReactElement<any>;
renderHeader?: () => React.ReactElement<any>;
}
return column.sortDirection ? { ...column, sortDirection: SortDirection.NONE } : column;
};
-export const createDataColumn = <T, F extends DataTableFilterItem>(dataColumn: Partial<DataColumn<T, F>>): DataColumn<T, F> => ({
+export const createDataColumn = <T>(dataColumn: Partial<DataColumn<T>>): DataColumn<T> => ({
key: '',
name: '',
selected: true,
configurable: true,
sortDirection: SortDirection.NONE,
- filters: [],
+ filters: createTree(),
render: () => React.createElement('span'),
...dataColumn,
});
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<T, F extends DataTableFilterItem = DataTableFilterItem> = Array<DataColumn<T, F>>;
+export type DataColumns<T> = Array<DataColumn<T>>;
export interface DataTableDataProps<T> {
items: T[];
onContextMenu: (event: React.MouseEvent<HTMLElement>, item: T) => void;
onRowDoubleClick: (event: React.MouseEvent<HTMLTableRowElement>, item: T) => void;
onSortToggle: (column: DataColumn<T>) => void;
- onFiltersChange: (filters: DataTableFilterItem[], column: DataColumn<T>) => void;
+ onFiltersChange: (filters: DataTableFilters, column: DataColumn<T>) => void;
extractKey?: (item: T) => React.Key;
working?: boolean;
defaultView?: React.ReactNode;
return <TableCell key={key || index}>
{renderHeader ?
renderHeader() :
- filters.length > 0
- ? <DataTableFilters
+ countNodes(filters) > 0
+ ? <DataTableFiltersPopover
name={`${name} filters`}
onChange={filters =>
onFiltersChange &&
onFiltersChange(filters, column)}
filters={filters}>
{name}
- </DataTableFilters>
+ </DataTableFiltersPopover>
: sortDirection
? <TableSortLabel
active={sortDirection !== SortDirection.NONE}
export const getNodeDescendants = (id: string, limit = Infinity) => <T>(tree: Tree<T>) =>
mapIdsToNodes(getNodeDescendantsIds(id, limit)(tree))(tree);
+export const countNodes = <T>(tree: Tree<T>) =>
+ getNodeDescendantsIds('')(tree).length;
+
export const getNodeDescendantsIds = (id: string, limit = Infinity) => <T>(tree: Tree<T>): string[] => {
const node = getNode(id)(tree);
const children = node ? node.children :
// 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<any> }>(),
- 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 }>(),
dataExplorerActions.REQUEST_ITEMS({ id }),
SET_COLUMNS: (payload: { columns: DataColumns<any> }) =>
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 }),
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;
return this.id;
}
- public getColumnFilters<T, F extends DataTableFilterItem>(columns: DataColumns<T, F>, columnName: string): F[] {
- const column = columns.find(c => c.name === columnName);
- return column ? column.filters.filter(f => f.selected) : [];
+ public getColumnFilters<T>(columns: DataColumns<T>, columnName: string): DataTableFilters {
+ return getDataExplorerColumnFilters(columns, columnName);
}
abstract requestItems(api: MiddlewareAPI<Dispatch, RootState>): void;
}
-export const getDataExplorerColumnFilters = <T, F extends DataTableFilterItem>(columns: DataColumns<T, F>, columnName: string): F[] => {
+export const getDataExplorerColumnFilters = <T>(columns: DataColumns<T>, 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 = <R>(dataExplorer: DataExplorer) => ({
+export const dataExplorerToListParams = (dataExplorer: DataExplorer) => ({
limit: dataExplorer.rowsPerPage,
offset: dataExplorer.page * dataExplorer.rowsPerPage,
});
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", () => {
selected: true,
configurable: false,
sortDirection: SortDirection.NONE,
- filters: [],
+ filters: createTree<DataTableFilterItem>(),
render: jest.fn()
}],
requestItems: jest.fn(),
selected: true,
configurable: false,
sortDirection: SortDirection.NONE,
- filters: [],
+ filters: createTree<DataTableFilterItem>(),
render: jest.fn()
}],
requestItems: jest.fn(),
};
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);
});
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<any>;
? { ...column, selected: !column.selected }
: column;
-const setFilters = (columnName: string, filters: DataTableFilterItem[]) =>
+const setFilters = (columnName: string, filters: DataTableFilters) =>
(column: DataColumn<any>) => column.name === columnName
? { ...column, filters }
: column;