21764: Add more type safety to TreePicker
[arvados.git] / services / workbench2 / src / store / data-explorer / data-explorer-middleware-service.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Dispatch, MiddlewareAPI } from 'redux';
6 import { RootState } from '../store';
7 import { DataColumns } from 'components/data-table/data-table';
8 import { DataExplorer, getSortColumn } from './data-explorer-reducer';
9 import { ListResults } from 'services/common-service/common-service';
10 import { createTree } from 'models/tree';
11 import { DataTableFilters } from 'components/data-table-filters/data-table-filters-tree';
12 import { OrderBuilder, OrderDirection } from 'services/api/order-builder';
13 import { SortDirection } from 'components/data-table/data-column';
14 import { Resource } from 'models/resource';
15
16 export abstract class DataExplorerMiddlewareService {
17     protected readonly id: string;
18
19     protected constructor(id: string) {
20         this.id = id;
21     }
22
23     public getId() {
24         return this.id;
25     }
26
27     public getColumnFilters<T>(
28         columns: DataColumns<T, any>,
29         columnName: string
30     ): DataTableFilters {
31         return getDataExplorerColumnFilters(columns, columnName);
32     }
33
34     abstract requestItems(
35         api: MiddlewareAPI<Dispatch, RootState>,
36         criteriaChanged?: boolean,
37         background?: boolean
38     ): Promise<void>;
39 }
40
41 export const getDataExplorerColumnFilters = <T>(
42     columns: DataColumns<T, any>,
43     columnName: string
44 ): DataTableFilters => {
45     const column = columns.find((c) => c.name === columnName);
46     return column ? column.filters : createTree();
47 };
48
49 export const dataExplorerToListParams = (dataExplorer: DataExplorer) => ({
50     limit: dataExplorer.rowsPerPage,
51     offset: dataExplorer.page * dataExplorer.rowsPerPage,
52 });
53
54 export const getOrder = <T extends Resource = Resource>(dataExplorer: DataExplorer) => {
55     const sortColumn = getSortColumn<T>(dataExplorer);
56     const order = new OrderBuilder<T>();
57     if (sortColumn && sortColumn.sort) {
58         const sortDirection = sortColumn.sort.direction === SortDirection.ASC
59             ? OrderDirection.ASC
60             : OrderDirection.DESC;
61
62         // Use createdAt as a secondary sort column so we break ties consistently.
63         return order
64             .addOrder(sortDirection, sortColumn.sort.field)
65             .addOrder(OrderDirection.DESC, "createdAt")
66             .getOrder();
67     } else {
68         return order.getOrder();
69     }
70 };
71
72 export const listResultsToDataExplorerItemsMeta = <R>({
73     itemsAvailable,
74     offset,
75     limit,
76 }: ListResults<R>) => ({
77     itemsAvailable,
78     page: Math.floor(offset / limit),
79     rowsPerPage: limit,
80 });