1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
11 } from 'components/data-table/data-column';
15 DataTableRequestState,
16 } from './data-explorer-action';
19 } from 'components/data-table/data-table';
20 import { DataTableFilters } from 'components/data-table-filters/data-table-filters';
22 export interface DataExplorer {
23 fetchMode: DataTableFetchMode;
24 columns: DataColumns<any, any>;
26 itemsAvailable: number;
27 loadingItemsAvailable: boolean;
30 rowsPerPageOptions: number[];
33 requestState: DataTableRequestState;
34 countRequestState: DataTableRequestState;
38 export const initialDataExplorer: DataExplorer = {
39 fetchMode: DataTableFetchMode.PAGINATED,
43 loadingItemsAvailable: false,
46 rowsPerPageOptions: [10, 20, 50, 100, 200, 500],
48 requestState: DataTableRequestState.IDLE,
49 countRequestState: DataTableRequestState.IDLE,
53 export type DataExplorerState = Record<string, DataExplorer>;
55 export const dataExplorerReducer = (
56 state: DataExplorerState = {},
57 action: DataExplorerAction
59 return dataExplorerActions.match(action, {
61 update(state, id, (explorer) => ({
68 RESET_PAGINATION: ({ id }) =>
69 update(state, id, (explorer) => ({ ...explorer, page: 0 })),
71 SET_FETCH_MODE: ({ id, fetchMode }) =>
72 update(state, id, (explorer) => ({ ...explorer, fetchMode })),
74 SET_COLUMNS: ({ id, columns }) => update(state, id, setColumns(columns)),
76 SET_FILTERS: ({ id, columnName, filters }) =>
77 update(state, id, mapColumns(setFilters(columnName, filters))),
79 SET_ITEMS: ({ id, items, itemsAvailable, page, rowsPerPage }) => (
80 update(state, id, (explorer) => {
81 // Reject updates to pages other than current,
82 // DataExplorer middleware should retry
83 // Also reject update if DE is pending, reduces flicker and appearance of race
84 const updatedPage = page || 0;
85 if (explorer.page === updatedPage && explorer.requestState === DataTableRequestState.PENDING) {
89 itemsAvailable: itemsAvailable || explorer.itemsAvailable,
99 SET_LOADING_ITEMS_AVAILABLE: ({ id, loadingItemsAvailable }) =>
100 update(state, id, (explorer) => ({
102 loadingItemsAvailable,
105 SET_ITEMS_AVAILABLE: ({ id, itemsAvailable }) =>
106 update(state, id, (explorer) => {
107 // Ignore itemsAvailable updates if another countRequest is requested
108 if (explorer.countRequestState === DataTableRequestState.PENDING) {
112 loadingItemsAvailable: false,
119 RESET_ITEMS_AVAILABLE: ({ id }) =>
120 update(state, id, (explorer) => ({ ...explorer, itemsAvailable: 0 })),
122 APPEND_ITEMS: ({ id, items, itemsAvailable, page, rowsPerPage }) =>
123 update(state, id, (explorer) => ({
125 items: explorer.items.concat(items),
126 itemsAvailable: explorer.itemsAvailable + (itemsAvailable || 0),
131 SET_PAGE: ({ id, page }) =>
132 update(state, id, (explorer) => ({ ...explorer, page })),
134 SET_ROWS_PER_PAGE: ({ id, rowsPerPage }) =>
135 update(state, id, (explorer) => ({ ...explorer, rowsPerPage })),
137 SET_EXPLORER_SEARCH_VALUE: ({ id, searchValue }) =>
138 update(state, id, (explorer) => ({ ...explorer, searchValue })),
140 RESET_EXPLORER_SEARCH_VALUE: ({ id }) =>
141 update(state, id, (explorer) => ({ ...explorer, searchValue: '' })),
143 SET_REQUEST_STATE: ({ id, requestState }) =>
144 update(state, id, (explorer) => ({ ...explorer, requestState })),
146 SET_COUNT_REQUEST_STATE: ({ id, countRequestState }) =>
147 update(state, id, (explorer) => ({ ...explorer, countRequestState })),
149 TOGGLE_SORT: ({ id, columnName }) =>
150 update(state, id, mapColumns(toggleSort(columnName))),
152 TOGGLE_COLUMN: ({ id, columnName }) =>
153 update(state, id, mapColumns(toggleColumn(columnName))),
155 SET_IS_NOT_FOUND: ({ id, isNotFound }) =>
156 update(state, id, (explorer) => ({ ...explorer, isNotFound })),
158 default: () => state,
161 export const getDataExplorer = (state: DataExplorerState, id: string) => {
162 const returnValue = state[id] || initialDataExplorer;
166 export const getSortColumn = <R>(dataExplorer: DataExplorer): DataColumn<any, R> | undefined =>
167 dataExplorer.columns.find(
168 (c: DataColumn<any, R>) => !!c.sort && c.sort.direction !== SortDirection.NONE
172 state: DataExplorerState,
174 updateFn: (dataExplorer: DataExplorer) => DataExplorer
175 ) => ({ ...state, [id]: updateFn(getDataExplorer(state, id)) });
177 const canUpdateColumns = (
178 prevColumns: DataColumns<any, any>,
179 nextColumns: DataColumns<any, any>
181 if (prevColumns.length !== nextColumns.length) {
184 for (let i = 0; i < nextColumns.length; i++) {
185 const pc = prevColumns[i];
186 const nc = nextColumns[i];
187 if (pc.key !== nc.key || pc.name !== nc.name) {
195 (columns: DataColumns<any, any>) => (dataExplorer: DataExplorer) => ({
197 columns: canUpdateColumns(dataExplorer.columns, columns)
199 : dataExplorer.columns,
203 (mapFn: (column: DataColumn<any, any>) => DataColumn<any, any>) =>
204 (dataExplorer: DataExplorer) => ({
206 columns: dataExplorer.columns.map(mapFn),
209 const toggleSort = (columnName: string) => (column: DataColumn<any, any>) =>
210 column.name === columnName
211 ? toggleSortDirection(column)
212 : resetSortDirection(column);
214 const toggleColumn = (columnName: string) => (column: DataColumn<any, any>) =>
215 column.name === columnName
216 ? { ...column, selected: !column.selected }
220 (columnName: string, filters: DataTableFilters) =>
221 (column: DataColumn<any, any>) =>
222 column.name === columnName ? { ...column, filters } : column;