From 41902fd66af67ed458af2c84883cbc1367134b96 Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Fri, 22 Oct 2021 23:58:39 +0200 Subject: [PATCH 1/6] Add InsertRow action --- src/Demos/Demos.tsx | 4 +- src/Demos/InserRowDemo/InserRowDemo.test.tsx | 10 +++ src/Demos/InserRowDemo/InserRowDemo.tsx | 71 ++++++++++++++++++++ src/Demos/MenuItems.tsx | 4 +- src/lib/Reducers/kaReducer.ts | 15 +++++ src/lib/actionCreators.ts | 8 +++ src/lib/enums.ts | 1 + 7 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 src/Demos/InserRowDemo/InserRowDemo.test.tsx create mode 100644 src/Demos/InserRowDemo/InserRowDemo.tsx diff --git a/src/Demos/Demos.tsx b/src/Demos/Demos.tsx index 47d2ee11..55b3804f 100644 --- a/src/Demos/Demos.tsx +++ b/src/Demos/Demos.tsx @@ -42,10 +42,11 @@ import GroupedColumnsDemo from './GroupedColumnsDemo/GroupedColumnsDemo'; import GroupingCustomCellDemo from './GroupingCustomCellDemo/GroupingCustomCellDemo'; import GroupingCustomRowDemo from './GroupingCustomRowDemo/GroupingCustomRowDemo'; import GroupingDemo from './GroupingDemo/GroupingDemo'; -import HeaderFilterDemo from './HeaderFilterDemo/HeaderFilterDemo'; import GroupingSummaryDemo from './GroupingSummaryDemo/GroupingSummaryDemo'; +import HeaderFilterDemo from './HeaderFilterDemo/HeaderFilterDemo'; import HoverRowDemo from './HoverRowDemo/HoverRowDemo'; import InfiniteScrollingDemo from './InfiniteScrollingDemo/InfiniteScrollingDemo'; +import InserRowDemo from './InserRowDemo/InserRowDemo'; import JsonDemo from './JsonDemo/JsonDemo'; import KeyboardNavigationDemo from './KeyboardNavigationDemo/KeyboardNavigationDemo'; import LoadingDemo from './LoadingDemo/LoadingDemo'; @@ -118,6 +119,7 @@ const demos: Demo[] = [ new Demo(KeyboardNavigationDemo, '/keyboard-navigation', 'Keyboard Navigation', 'KeyboardNavigationDemo', 'https://stackblitz.com/edit/table-keyboard-navigation-js', 'https://stackblitz.com/edit/table-keyboard-navigation-ts', 'Miscellaneous'), new Demo(LoadingDemo, '/loading', 'Loading', 'LoadingDemo', 'https://stackblitz.com/edit/table-loading-js', 'https://stackblitz.com/edit/table-loading-ts', 'Miscellaneous'), new Demo(InfiniteScrollingDemo, '/infinite-scrolling', 'Infinite Scrolling', 'InfiniteScrollingDemo', 'https://stackblitz.com/edit/table-infinite-scrolling-js', 'https://stackblitz.com/edit/table-infinite-scrolling-ts', 'Virtual Scrolling'), + new Demo(InserRowDemo, '/insert-row', 'Insert Row', 'InserRowDemo', 'https://stackblitz.com/edit/table-insert-row-js', 'https://stackblitz.com/edit/table-insert-row-ts', 'Editing'), new Demo(ManyColumnsDemo, '/many-columns', 'Many Columns', 'ManyColumnsDemo', 'https://stackblitz.com/edit/table-many-columns-js', 'https://stackblitz.com/edit/table-many-columns-ts', 'Columns'), new Demo(ManyRowsDemo, '/many-rows', '100K Rows', 'ManyRowsDemo', 'https://stackblitz.com/edit/table-many-rows-js', 'https://stackblitz.com/edit/table-many-rows-ts', 'Virtual Scrolling'), new Demo(ManyRowsDynamicDemo, '/many-rows-dynamic', '10K Rows Dynamic', 'ManyRowsDynamicDemo', 'https://stackblitz.com/edit/table-many-rows-dynamic-js', 'https://stackblitz.com/edit/table-many-rows-dynamic-ts', 'Virtual Scrolling'), diff --git a/src/Demos/InserRowDemo/InserRowDemo.test.tsx b/src/Demos/InserRowDemo/InserRowDemo.test.tsx new file mode 100644 index 00000000..d7ec299a --- /dev/null +++ b/src/Demos/InserRowDemo/InserRowDemo.test.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import InserRowDemo from './InserRowDemo'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/src/Demos/InserRowDemo/InserRowDemo.tsx b/src/Demos/InserRowDemo/InserRowDemo.tsx new file mode 100644 index 00000000..d265b9ef --- /dev/null +++ b/src/Demos/InserRowDemo/InserRowDemo.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; + +import { ITableProps, kaReducer, Table } from '../../lib'; +import { insertRow } from '../../lib/actionCreators'; +import { DataType, EditingMode } from '../../lib/enums'; +import { DispatchFunc } from '../../lib/types'; + +const dataArray = Array(7).fill(undefined).map( + (_, index) => ({ + column1: `column:1 row:${index}`, + column2: `column:2 row:${index}`, + column3: `column:3 row:${index}`, + id: index, + }), +); + +let maxValue = Math.max(...dataArray.map(i => i.id)); +const generateNewId = () => { + maxValue++; + return maxValue; +}; + +const tablePropsInit: ITableProps = { + columns: [ + { + key: 'column1', + title: 'Column 1', + dataType: DataType.String + }, + { key: 'column2', title: 'Column 2', dataType: DataType.String }, + { key: 'column3', title: 'Column 3', dataType: DataType.String }, + { + key: 'insertRowColumn', + width: 200 + }, + ], + editingMode: EditingMode.Cell, + data: dataArray, + rowKeyField: 'id', +}; + +const InserRowDemo: React.FC = () => { + const [tableProps, changeTableProps] = useState(tablePropsInit); + const dispatch: DispatchFunc = (action) => { + changeTableProps((prevState: ITableProps) => kaReducer(prevState, action)); + }; + + return ( +
+ { + if (props.column.key === 'insertRowColumn'){ + return ( + + ); + } + } + }, + }} + dispatch={dispatch} + /> + + ); +}; + +export default InserRowDemo; diff --git a/src/Demos/MenuItems.tsx b/src/Demos/MenuItems.tsx index 5249fbfd..82c2667d 100644 --- a/src/Demos/MenuItems.tsx +++ b/src/Demos/MenuItems.tsx @@ -11,8 +11,8 @@ export class MenuItem { public isActive?: boolean; } -const newItems: string[] = ['HeaderFilterDemo']; -const updateItems: string[] = ['Filtering']; +const newItems: string[] = ['InsertRowDemo']; +const updateItems: string[] = ['Editing']; const MenuItems: React.FC<{ items: MenuItem[] }> = ({ items }) => { diff --git a/src/lib/Reducers/kaReducer.ts b/src/lib/Reducers/kaReducer.ts index a3c324d4..72e3e086 100644 --- a/src/lib/Reducers/kaReducer.ts +++ b/src/lib/Reducers/kaReducer.ts @@ -36,6 +36,21 @@ const kaReducer: any = (props: ITableProps, action: any): ITableProps => { } = props; switch (action.type) { + case ActionType.InsertRow: { + const { + rowData, + options + } = action; + const { afterRowKeyValue } = options || {}; + const newData = [...data]; + if (afterRowKeyValue) { + const rowIndex = newData.findIndex((d) => getValueByField(d, rowKeyField) === afterRowKeyValue); + newData.splice(rowIndex, 0, rowData); + } else { + newData.push(rowData); + } + return { ...props, data: newData }; + } case ActionType.UpdateHeaderFilterValues: { const newColumns = columns.map((c: Column) => { if (c.key === action.columnKey) { diff --git a/src/lib/actionCreators.ts b/src/lib/actionCreators.ts index d8ee7a0d..d80a3a9f 100644 --- a/src/lib/actionCreators.ts +++ b/src/lib/actionCreators.ts @@ -290,3 +290,11 @@ export const openAllEditors = () => ({ export const saveAllEditors = () => ({ type: ActionType.SaveAllEditors }); + +export const insertRow = (rowData: any, options: { + afterRowKeyValue: any +}) => ({ + rowData, + options, + type: ActionType.InsertRow +}); diff --git a/src/lib/enums.ts b/src/lib/enums.ts index 2b55b284..7c370b91 100644 --- a/src/lib/enums.ts +++ b/src/lib/enums.ts @@ -32,6 +32,7 @@ export enum ActionType { HideDetailsRow = 'HideDetailsRow', HideLoading = 'HideLoading', HideNewRow = 'HideNewRow', + InsertRow = 'InsertRow', LoadData = 'LoadData', MoveFocusedDown = 'MoveFocusedDown', MoveFocusedLeft = 'MoveFocusedLeft', From 3d6c23d3437cd7d572753934396fbe9f082a3d4f Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Fri, 22 Oct 2021 23:59:20 +0200 Subject: [PATCH 2/6] increase version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a7756a1..35e32d6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ka-table", - "version": "7.2.0", + "version": "7.3.0", "license": "MIT", "repository": "github:komarovalexander/ka-table", "homepage": "https://komarovalexander.github.io/ka-table/#/overview", From c54f7a7846f3f8c01d70e3a9e7c2286dfcaf62ce Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Sat, 23 Oct 2021 00:05:14 +0200 Subject: [PATCH 3/6] Fix zero case --- src/Demos/InserRowDemo/InserRowDemo.tsx | 15 +++++++++++---- src/lib/Reducers/kaReducer.ts | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Demos/InserRowDemo/InserRowDemo.tsx b/src/Demos/InserRowDemo/InserRowDemo.tsx index d265b9ef..283074ea 100644 --- a/src/Demos/InserRowDemo/InserRowDemo.tsx +++ b/src/Demos/InserRowDemo/InserRowDemo.tsx @@ -7,9 +7,9 @@ import { DispatchFunc } from '../../lib/types'; const dataArray = Array(7).fill(undefined).map( (_, index) => ({ - column1: `column:1 row:${index}`, - column2: `column:2 row:${index}`, - column3: `column:3 row:${index}`, + column1: `column:1 rowId:${index}`, + column2: `column:2 rowId:${index}`, + column3: `column:3 rowId:${index}`, id: index, }), ); @@ -54,7 +54,14 @@ const InserRowDemo: React.FC = () => { content: (props) => { if (props.column.key === 'insertRowColumn'){ return ( - ); diff --git a/src/lib/Reducers/kaReducer.ts b/src/lib/Reducers/kaReducer.ts index 72e3e086..ba7ec9a0 100644 --- a/src/lib/Reducers/kaReducer.ts +++ b/src/lib/Reducers/kaReducer.ts @@ -43,7 +43,7 @@ const kaReducer: any = (props: ITableProps, action: any): ITableProps => { } = action; const { afterRowKeyValue } = options || {}; const newData = [...data]; - if (afterRowKeyValue) { + if (afterRowKeyValue != null) { const rowIndex = newData.findIndex((d) => getValueByField(d, rowKeyField) === afterRowKeyValue); newData.splice(rowIndex, 0, rowData); } else { From c630d2c4ea56de55cd4175f744a406098ea01d15 Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Sun, 24 Oct 2021 18:55:11 +0200 Subject: [PATCH 4/6] add insertrowposition --- src/Demos/InserRowDemo/InserRowDemo.tsx | 2 +- .../__snapshots__/kaReducer.test.ts.snap | 76 +++++++++++++++ src/lib/Reducers/kaReducer.test.ts | 95 ++++++++++++++++++- src/lib/Reducers/kaReducer.ts | 14 ++- src/lib/actionCreators.ts | 7 +- src/lib/enums.ts | 5 + 6 files changed, 186 insertions(+), 13 deletions(-) diff --git a/src/Demos/InserRowDemo/InserRowDemo.tsx b/src/Demos/InserRowDemo/InserRowDemo.tsx index 283074ea..17362adb 100644 --- a/src/Demos/InserRowDemo/InserRowDemo.tsx +++ b/src/Demos/InserRowDemo/InserRowDemo.tsx @@ -60,7 +60,7 @@ const InserRowDemo: React.FC = () => { id, column1: `column:1 rowId:${id}`, }; - dispatch(insertRow(newRow, { afterRowKeyValue: props.rowKeyValue })) + dispatch(insertRow(newRow, { rowKeyValue: props.rowKeyValue })) }}> Insert Row Above diff --git a/src/lib/Reducers/__snapshots__/kaReducer.test.ts.snap b/src/lib/Reducers/__snapshots__/kaReducer.test.ts.snap index 9621ae0c..74aef3d6 100644 --- a/src/lib/Reducers/__snapshots__/kaReducer.test.ts.snap +++ b/src/lib/Reducers/__snapshots__/kaReducer.test.ts.snap @@ -1,5 +1,81 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`kaReducer InsertRow insert after row with id=2 1`] = ` +Array [ + Object { + "id": 1, + "val": 102, + }, + Object { + "id": 2, + "val": 10, + }, + Object { + "id": 4, + "val": 40, + }, + Object { + "id": 3, + "val": 10, + }, +] +`; + +exports[`kaReducer InsertRow insert before row with id=2 1`] = ` +Array [ + Object { + "id": 1, + "val": 102, + }, + Object { + "id": 3, + "val": 30, + }, + Object { + "id": 2, + "val": 10, + }, +] +`; + +exports[`kaReducer InsertRow insert to 0 position by default 1`] = ` +Array [ + Object { + "id": 3, + "val": 30, + }, + Object { + "id": 1, + "val": 102, + }, + Object { + "id": 2, + "val": 10, + }, +] +`; + +exports[`kaReducer InsertRow insert to last position for after mode 1`] = ` +Array [ + Object { + "id": 1, + "val": 102, + }, + Object { + "id": 2, + "val": 10, + }, + Object { + "id": 3, + "val": 10, + }, + Object { + "id": 4, + "val": 40, + }, +] +`; + exports[`kaReducer ReorderColumns default 1`] = ` Object { "columns": Array [ diff --git a/src/lib/Reducers/kaReducer.test.ts b/src/lib/Reducers/kaReducer.test.ts index ae92cabf..cb329c1c 100644 --- a/src/lib/Reducers/kaReducer.test.ts +++ b/src/lib/Reducers/kaReducer.test.ts @@ -1,11 +1,11 @@ import { ITableProps } from '../'; import { clearSingleAction, deleteRow, deselectAllFilteredRows, deselectAllRows, deselectAllVisibleRows, - deselectRow, loadData, reorderColumns, reorderRows, resizeColumn, selectAllFilteredRows, - selectAllRows, selectAllVisibleRows, selectRowsRange, selectSingleRow, setSingleAction, - updateData, updateTreeGroupsExpanded, validate, + deselectRow, insertRow, loadData, reorderColumns, reorderRows, resizeColumn, + selectAllFilteredRows, selectAllRows, selectAllVisibleRows, selectRowsRange, selectSingleRow, + setSingleAction, updateData, updateTreeGroupsExpanded, validate, } from '../actionCreators'; -import { ActionType, FilterOperatorName } from '../enums'; +import { ActionType, FilterOperatorName, InsertRowPosition } from '../enums'; import { kaReducer } from './kaReducer'; describe('kaReducer', () => { @@ -461,4 +461,91 @@ describe('kaReducer', () => { expect(newState.editableCells).toMatchSnapshot(); }); }); + describe('InsertRow', () => { + it('insert to 0 position by default', () => { + const intialState: ITableProps = { + columns: [], + data: [{ + id: 1, + val: 102 + }, { + id: 2, + val: 10 + }], + rowKeyField: 'id' + }; + const newState = kaReducer(intialState, insertRow({ + id: 3, + val: 30 + })); + expect(newState.data).toMatchSnapshot(); + }); + it('insert before row with id=2', () => { + const intialState: ITableProps = { + columns: [], + data: [{ + id: 1, + val: 102 + }, { + id: 2, + val: 10 + }], + rowKeyField: 'id' + }; + const newState = kaReducer(intialState, insertRow({ + id: 3, + val: 30 + }, { + rowKeyValue: 2 + })); + expect(newState.data).toMatchSnapshot(); + }); + it('insert after row with id=2', () => { + const intialState: ITableProps = { + columns: [], + data: [{ + id: 1, + val: 102 + }, { + id: 2, + val: 10 + }, { + id: 3, + val: 10 + }], + rowKeyField: 'id' + }; + const newState = kaReducer(intialState, insertRow({ + id: 4, + val: 40 + }, { + rowKeyValue: 2, + insertRowPosition: InsertRowPosition.after + })); + expect(newState.data).toMatchSnapshot(); + }); + it('insert to last position for after mode', () => { + const intialState: ITableProps = { + columns: [], + data: [{ + id: 1, + val: 102 + }, { + id: 2, + val: 10 + }, { + id: 3, + val: 10 + }], + rowKeyField: 'id' + }; + const newState = kaReducer(intialState, insertRow({ + id: 4, + val: 40 + }, { + insertRowPosition: InsertRowPosition.after + })); + expect(newState.data).toMatchSnapshot(); + }); + }); }); diff --git a/src/lib/Reducers/kaReducer.ts b/src/lib/Reducers/kaReducer.ts index ba7ec9a0..baaa0777 100644 --- a/src/lib/Reducers/kaReducer.ts +++ b/src/lib/Reducers/kaReducer.ts @@ -1,5 +1,6 @@ +import { insertRow } from '../actionCreators'; import { newRowId } from '../const'; -import { ActionType, SortingMode } from '../enums'; +import { ActionType, InsertRowPosition, SortingMode } from '../enums'; import { ITableProps } from '../index'; import { Column } from '../models'; import { ILoadingProps } from '../props'; @@ -41,13 +42,16 @@ const kaReducer: any = (props: ITableProps, action: any): ITableProps => { rowData, options } = action; - const { afterRowKeyValue } = options || {}; + const { rowKeyValue, insertRowPosition } = options || {}; const newData = [...data]; - if (afterRowKeyValue != null) { - const rowIndex = newData.findIndex((d) => getValueByField(d, rowKeyField) === afterRowKeyValue); + if (rowKeyValue != null) { + let rowIndex = newData.findIndex((d) => getValueByField(d, rowKeyField) === rowKeyValue); + if (insertRowPosition === InsertRowPosition.after){ + rowIndex++; + } newData.splice(rowIndex, 0, rowData); } else { - newData.push(rowData); + insertRowPosition === InsertRowPosition.after ? newData.push(rowData) : newData.unshift(rowData); } return { ...props, data: newData }; } diff --git a/src/lib/actionCreators.ts b/src/lib/actionCreators.ts index d80a3a9f..0462a82b 100644 --- a/src/lib/actionCreators.ts +++ b/src/lib/actionCreators.ts @@ -1,4 +1,4 @@ -import { ActionType } from './enums'; +import { ActionType, InsertRowPosition } from './enums'; import { Focused } from './Models/Focused'; import { PopupPosition } from './Models/PopupPosition'; import { IMoveFocusedSettings } from './Utils/NavigationUtils'; @@ -291,8 +291,9 @@ export const saveAllEditors = () => ({ type: ActionType.SaveAllEditors }); -export const insertRow = (rowData: any, options: { - afterRowKeyValue: any +export const insertRow = (rowData: any, options?: { + rowKeyValue?: any, + insertRowPosition?: InsertRowPosition }) => ({ rowData, options, diff --git a/src/lib/enums.ts b/src/lib/enums.ts index 7c370b91..46b8bdf4 100644 --- a/src/lib/enums.ts +++ b/src/lib/enums.ts @@ -116,3 +116,8 @@ export enum FilterOperatorName { IsEmpty = 'IsEmpty', IsNotEmpty = 'IsNotEmpty', } + +export enum InsertRowPosition { + before = 'before', + after = 'after' +} From 8ef3508279020a8361346065cb3b3199c2e324db Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Sun, 24 Oct 2021 19:01:22 +0200 Subject: [PATCH 5/6] update demo --- src/Demos/InserRowDemo/InserRowDemo.tsx | 26 +++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Demos/InserRowDemo/InserRowDemo.tsx b/src/Demos/InserRowDemo/InserRowDemo.tsx index 17362adb..92649961 100644 --- a/src/Demos/InserRowDemo/InserRowDemo.tsx +++ b/src/Demos/InserRowDemo/InserRowDemo.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { ITableProps, kaReducer, Table } from '../../lib'; import { insertRow } from '../../lib/actionCreators'; -import { DataType, EditingMode } from '../../lib/enums'; +import { DataType, EditingMode, InsertRowPosition } from '../../lib/enums'; import { DispatchFunc } from '../../lib/types'; const dataArray = Array(7).fill(undefined).map( @@ -30,7 +30,11 @@ const tablePropsInit: ITableProps = { { key: 'column2', title: 'Column 2', dataType: DataType.String }, { key: 'column3', title: 'Column 3', dataType: DataType.String }, { - key: 'insertRowColumn', + key: 'insertRowBeforeColumn', + width: 200 + }, + { + key: 'insertRowAfterColumn', width: 200 }, ], @@ -52,7 +56,7 @@ const InserRowDemo: React.FC = () => { childComponents={{ cell: { content: (props) => { - if (props.column.key === 'insertRowColumn'){ + if (props.column.key === 'insertRowBeforeColumn'){ return ( + ); + } + if (props.column.key === 'insertRowAfterColumn'){ + return ( + ); } From f35ce4731aadb01a37968e59070b2f138531ff3f Mon Sep 17 00:00:00 2001 From: Komarov Alexander Date: Sun, 24 Oct 2021 19:01:43 +0200 Subject: [PATCH 6/6] fix lint --- src/lib/Reducers/kaReducer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/Reducers/kaReducer.ts b/src/lib/Reducers/kaReducer.ts index baaa0777..c66e5b81 100644 --- a/src/lib/Reducers/kaReducer.ts +++ b/src/lib/Reducers/kaReducer.ts @@ -1,4 +1,3 @@ -import { insertRow } from '../actionCreators'; import { newRowId } from '../const'; import { ActionType, InsertRowPosition, SortingMode } from '../enums'; import { ITableProps } from '../index';