From: Michal Klobukowski Date: Mon, 25 Jun 2018 11:52:13 +0000 (+0200) Subject: Create data explorer actions and reducer X-Git-Tag: 1.2.0~63^2~14 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/055c1f7ec3450e6e36abfc34d7515e57d9481bdc Create data explorer actions and reducer Feature #13678 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- diff --git a/src/store/data-explorer/data-explorer-action.ts b/src/store/data-explorer/data-explorer-action.ts new file mode 100644 index 00000000..70359991 --- /dev/null +++ b/src/store/data-explorer/data-explorer-action.ts @@ -0,0 +1,28 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { default as unionize, ofType, UnionOf } from "unionize"; +import { SortDirection, DataColumn } from "../../components/data-table/data-column"; +import { DataTableFilterItem } from "../../components/data-table-filters/data-table-filters"; + +type WithId = T & { id: string }; + +const actions = unionize({ + SET_COLUMNS: ofType> }>>(), + SET_FILTERS: ofType>(), + SET_ITEMS: ofType>(), + SET_PAGE: ofType>(), + SET_ROWS_PER_PAGE: ofType>(), + TOGGLE_COLUMN: ofType>(), + TOGGLE_SORT: ofType>(), + SET_SEARCH_VALUE: ofType>() +}, { tag: "type", value: "payload" }); + +export type DataExplorerAction = UnionOf; + +export default actions; + + + + diff --git a/src/store/data-explorer/data-explorer-reducer.test.tsx b/src/store/data-explorer/data-explorer-reducer.test.tsx new file mode 100644 index 00000000..2a9e56ce --- /dev/null +++ b/src/store/data-explorer/data-explorer-reducer.test.tsx @@ -0,0 +1,73 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import dataExplorerReducer, { initialDataExplorer } from "./data-explorer-reducer"; +import actions from "./data-explorer-action"; +import { DataColumn } from "../../components/data-table/data-column"; +import { DataTableFilterItem } from "../../components/data-table-filters/data-table-filters"; + +describe('data-explorer-reducer', () => { + it('should set columns', () => { + const columns: Array> = [{ + name: "Column 1", + render: jest.fn(), + selected: true + }]; + const state = dataExplorerReducer(undefined, + actions.SET_COLUMNS({ id: "Data explorer", columns })); + expect(state["Data explorer"].columns).toEqual(columns); + }); + + it('should toggle sorting', () => { + const columns: Array> = [{ + name: "Column 1", + render: jest.fn(), + selected: true, + sortDirection: "asc" + }, { + name: "Column 2", + render: jest.fn(), + selected: true, + sortDirection: "none", + }]; + const state = dataExplorerReducer({ "Data explorer": { ...initialDataExplorer, columns } }, + actions.TOGGLE_SORT({ id: "Data explorer", columnName: "Column 2" })); + expect(state["Data explorer"].columns[0].sortDirection).toEqual("none"); + expect(state["Data explorer"].columns[1].sortDirection).toEqual("asc"); + }); + + it('should set filters', () => { + const columns: Array> = [{ + name: "Column 1", + render: jest.fn(), + selected: true, + }]; + + const filters: DataTableFilterItem[] = [{ + name: "Filter 1", + selected: true + }]; + const state = dataExplorerReducer({ "Data explorer": { ...initialDataExplorer, columns } }, + actions.SET_FILTERS({ id: "Data explorer", columnName: "Column 1", filters })); + expect(state["Data explorer"].columns[0].filters).toEqual(filters); + }); + + it('should set items', () => { + const state = dataExplorerReducer({ "Data explorer": undefined }, + actions.SET_ITEMS({ id: "Data explorer", items: ["Item 1", "Item 2"] })); + expect(state["Data explorer"].items).toEqual(["Item 1", "Item 2"]); + }); + + it('should set page', () => { + const state = dataExplorerReducer({ "Data explorer": undefined }, + actions.SET_PAGE({ id: "Data explorer", page: 2 })); + expect(state["Data explorer"].page).toEqual(2); + }); + + it('should set rows per page', () => { + const state = dataExplorerReducer({ "Data explorer": undefined }, + actions.SET_ROWS_PER_PAGE({ id: "Data explorer", rowsPerPage: 5 })); + expect(state["Data explorer"].rowsPerPage).toEqual(5); + }); +}); diff --git a/src/store/data-explorer/data-explorer-reducer.ts b/src/store/data-explorer/data-explorer-reducer.ts new file mode 100644 index 00000000..1f782778 --- /dev/null +++ b/src/store/data-explorer/data-explorer-reducer.ts @@ -0,0 +1,65 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { DataColumn, toggleSortDirection, resetSortDirection } from "../../components/data-table/data-column"; +import actions, { DataExplorerAction } from "./data-explorer-action"; +import { DataTableFilterItem } from "../../components/data-table-filters/data-table-filters"; + +interface DataExplorer { + columns: Array>; + items: any[]; + page: number; + rowsPerPage: number; +} + +export const initialDataExplorer: DataExplorer = { + columns: [], + items: [], + page: 0, + rowsPerPage: 0 +}; + +export type DataExplorerState = Record; + +const dataExplorerReducer = (state: DataExplorerState = {}, action: DataExplorerAction) => + actions.match(action, { + SET_COLUMNS: ({ id, columns }) => update(state, id, setColumns(columns)), + SET_FILTERS: ({ id, columnName, filters }) => update(state, id, mapColumns(setFilters(columnName, filters))), + SET_ITEMS: ({ id, items }) => update(state, id, explorer => ({ ...explorer, items })), + SET_PAGE: ({ id, page }) => update(state, id, explorer => ({ ...explorer, page })), + SET_ROWS_PER_PAGE: ({ id, rowsPerPage }) => update(state, id, explorer => ({ ...explorer, rowsPerPage })), + TOGGLE_SORT: ({ id, columnName }) => update(state, id, mapColumns(toggleSort(columnName))), + TOGGLE_COLUMN: ({ id, columnName }) => update(state, id, mapColumns(toggleColumn(columnName))), + default: () => state + }); + +export default dataExplorerReducer; + +const get = (state: DataExplorerState, id: string) => state[id] || initialDataExplorer; + +const update = (state: DataExplorerState, id: string, updateFn: (dataExplorer: DataExplorer) => DataExplorer) => + ({ ...state, [id]: updateFn(get(state, id)) }); + +const setColumns = (columns: Array>) => + (dataExplorer: DataExplorer) => + ({ ...dataExplorer, columns }); + +const mapColumns = (mapFn: (column: DataColumn) => DataColumn) => + (dataExplorer: DataExplorer) => + ({ ...dataExplorer, columns: dataExplorer.columns.map(mapFn) }); + +const toggleSort = (columnName: string) => + (column: DataColumn) => column.name === columnName + ? toggleSortDirection(column) + : resetSortDirection(column); + +const toggleColumn = (columnName: string) => + (column: DataColumn) => column.name === columnName + ? { ...column, selected: !column.selected } + : column; + +const setFilters = (columnName: string, filters: DataTableFilterItem[]) => + (column: DataColumn) => column.name === columnName + ? { ...column, filters } + : column;