Browse Source

fix: Table rowSelection header checkbox status bug #325 (#1484)

Co-authored-by: shijia.me <[email protected]>
走鹃 2 years ago
parent
commit
1ad38ebda8

+ 15 - 0
cypress/integration/table.spec.js

@@ -128,4 +128,19 @@ describe('table', () => {
         cy.get('.semi-table-body .semi-table-row').eq(2).contains('Semi Pro');
         cy.contains('显示第 1 条-第 10 条,共 23 条');
     });
+
+    it('fixed row selection header state', () => {
+        cy.visit('http://localhost:6006/iframe.html?id=table--fix-select-all-325&args=&viewMode=story');
+        cy.get('.semi-table-row-head .semi-checkbox-inner-display').click();
+        cy.get('.semi-checkbox-checked').should('have.length', 3);
+        cy.get('.semi-page-item').contains('2').click();
+        cy.get('.semi-table-row-head .semi-checkbox-checked');
+        cy.get('.semi-table-row-head .semi-checkbox-indeterminate').should('not.exist');
+        cy.get('.semi-checkbox-checked').should('have.length', 4);
+        cy.get('.semi-table-tbody .semi-checkbox-inner-display').eq(0).click();
+        cy.get('.semi-table-row-head .semi-checkbox-indeterminate');
+        cy.get('.semi-table-row-head .semi-checkbox-inner-display').click();
+        cy.get('.semi-table-row-head .semi-checkbox-checked');
+        cy.get('.semi-checkbox-checked').should('have.length', 4);
+    });
 });

+ 13 - 2
packages/semi-foundation/table/foundation.ts

@@ -82,6 +82,9 @@ export interface TableAdapter<RecordType> extends DefaultAdapter {
     getCachedFilteredSortedDataSource: () => RecordType[];
     getCachedFilteredSortedRowKeys: () => BaseRowKeyType[];
     getCachedFilteredSortedRowKeysSet: () => Set<BaseRowKeyType>;
+    setAllDisabledRowKeys: (allDisabledRowKeys: BaseRowKeyType[]) => void;
+    getAllDisabledRowKeys: () => BaseRowKeyType[];
+    getAllDisabledRowKeysSet: () => Set<BaseRowKeyType>;
     notifyFilterDropdownVisibleChange: (visible: boolean, dataIndex: string) => void;
     notifyChange: (changeInfo: { pagination: BasePagination; filters: BaseChangeInfoFilter<RecordType>[]; sorter: BaseChangeInfoSorter<RecordType>; extra: any }) => void;
     notifyExpand: (expanded?: boolean, record?: BaseIncludeGroupRecord<RecordType>, mouseEvent?: any) => void;
@@ -174,12 +177,14 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
         const dataSource = [...this.getProp('dataSource')];
         const { queries } = this._adapter.getStates();
         const filteredSortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
+        const allDataDisabledRowKeys = this.getAllDisabledRowKeys(filteredSortedDataSource);
         const pageData = this.getCurrentPageData(filteredSortedDataSource);
         this.setAdapterPageData(pageData);
         this.initExpandedRowKeys(pageData);
         this.initSelectedRowKeys(pageData);
         // cache dataSource after mount, and then calculate it on demand
         this.setCachedFilteredSortedDataSource(filteredSortedDataSource);
+        this.setAllDisabledRowKeys(allDataDisabledRowKeys);
     }
 
     initExpandedRowKeys({ groups }: { groups?: Map<string, RecordType[]> } = {}) {
@@ -553,6 +558,10 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
 
     destroy() { }
 
+    setAllDisabledRowKeys(disabledRowKeys) {
+        this._adapter.setAllDisabledRowKeys(disabledRowKeys);
+    }
+
     handleClick(e: any) { }
 
     handleMouseEnter(e: any) { }
@@ -784,8 +793,8 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
             let selectedRowKeys = [...curSelectedRowKeys];
             const selectedRowKeysSet = this._getSelectedRowKeysSet();
             let allRowKeys = [...this._adapter.getCachedFilteredSortedRowKeys()];
-            const disabledRowKeys = this.getAllDisabledRowKeys();
-            const disabledRowKeysSet = new Set(disabledRowKeys);
+            const disabledRowKeys = this._adapter.getAllDisabledRowKeys();
+            const disabledRowKeysSet = this._adapter.getAllDisabledRowKeysSet();
             let changedRowKeys;
 
             // Select all, if not disabled && not in selectedRowKeys
@@ -1130,7 +1139,9 @@ class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType
     handleClickFilterOrSorter(queries: BaseColumnProps<RecordType>[]) {
         const dataSource = [...this.getProp('dataSource')];
         const sortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
+        const allDataDisabledRowKeys = this.getAllDisabledRowKeys(sortedDataSource);
         this.setCachedFilteredSortedDataSource(sortedDataSource);
+        this.setAllDisabledRowKeys(allDataDisabledRowKeys);
         const pageData = this.getCurrentPageData(sortedDataSource);
         this.setAdapterPageData(pageData);
     }

+ 2 - 1
packages/semi-ui/table/ColumnSelection.tsx

@@ -14,7 +14,7 @@ export interface TableSelectionCellProps {
     columnTitle?: string; // TODO: future api
     getCheckboxProps?: () => CheckboxProps;
     type?: string; // TODO: future api
-    onChange?: (value: any, e: TableSelectionCellEvent) => void;
+    onChange?: (checked: boolean, e: TableSelectionCellEvent) => void;
     selected?: boolean;
     disabled?: boolean;
     indeterminate?: boolean; // Intermediate state, shown as a solid horizontal line
@@ -53,6 +53,7 @@ export default class TableSelectionCell extends BaseComponent<TableSelectionCell
         };
     }
 
+    foundation: TableSelectionCellFoundation;
     constructor(props: TableSelectionCellProps) {
         super(props);
         this.foundation = new TableSelectionCellFoundation(this.adapter);

+ 29 - 8
packages/semi-ui/table/Table.tsx

@@ -96,7 +96,15 @@ export interface NormalTableState<RecordType extends Record<string, any> = Data>
     bodyHasScrollBar?: boolean;
     prePropRowSelection?: TableStateRowSelection<RecordType>;
     tableWidth?: number;
-    prePagination?: Pagination
+    prePagination?: Pagination;
+    /**
+    * Disabled row keys in sorted and filtered data
+    */
+    allDisabledRowKeys?: BaseRowKeyType[];
+    /**
+     * Disabled row keys set in sorted and filtered data
+     */
+    allDisabledRowKeysSet?: Set<BaseRowKeyType>
 }
 
 export type TableStateRowSelection<RecordType extends Record<string, any> = Data> = (RowSelectionProps<RecordType> & { selectedRowKeysSet?: Set<(string | number)> }) | boolean;
@@ -244,11 +252,17 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
                 this.cachedFilteredSortedRowKeys = filteredSortedRowKeys;
                 this.cachedFilteredSortedRowKeysSet = new Set(filteredSortedRowKeys);
             },
+            setAllDisabledRowKeys: allDisabledRowKeys => {
+                const allDisabledRowKeysSet = new Set(allDisabledRowKeys);
+                this.setState({ allDisabledRowKeys, allDisabledRowKeysSet });
+            },
             getCurrentPage: () => get(this.state, 'pagination.currentPage', 1),
             getCurrentPageSize: () => get(this.state, 'pagination.pageSize', numbers.DEFAULT_PAGE_SIZE),
             getCachedFilteredSortedDataSource: () => this.cachedFilteredSortedDataSource,
             getCachedFilteredSortedRowKeys: () => this.cachedFilteredSortedRowKeys,
             getCachedFilteredSortedRowKeysSet: () => this.cachedFilteredSortedRowKeysSet,
+            getAllDisabledRowKeys: () => this.state.allDisabledRowKeys,
+            getAllDisabledRowKeysSet: () => this.state.allDisabledRowKeysSet,
             notifyFilterDropdownVisibleChange: (visible, dataIndex) =>
                 this._invokeColumnFn(dataIndex, 'onFilterDropdownVisibleChange', visible),
             notifyChange: (...args) => this.props.onChange(...args),
@@ -410,6 +424,8 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
             allRowKeys: [], // row keys after paging
             disabledRowKeys: [], // disabled row keys after paging
             disabledRowKeysSet: new Set(),
+            allDisabledRowKeys: [],
+            allDisabledRowKeysSet: new Set(),
             headWidths: [], // header cell width
             bodyHasScrollBar: false,
             prePropRowSelection: undefined,
@@ -471,8 +487,11 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
             // The return value of getCheckboxProps affects the disabled rows
             if (isFunction(getCheckboxProps)) {
                 const disabledRowKeys = getAllDisabledRowKeys({ dataSource, getCheckboxProps, childrenRecordName, rowKey });
+                const disabledRowKeysSet = new Set(disabledRowKeys);
                 willUpdateStates.disabledRowKeys = disabledRowKeys;
-                willUpdateStates.disabledRowKeysSet = new Set(disabledRowKeys);
+                willUpdateStates.disabledRowKeysSet = disabledRowKeysSet;
+                willUpdateStates.allDisabledRowKeys = disabledRowKeys;
+                willUpdateStates.allDisabledRowKeysSet = disabledRowKeysSet;
             }
             willUpdateStates.rowSelection = newSelectionStates;
             willUpdateStates.prePropRowSelection = rowSelection;
@@ -567,7 +586,9 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
             // Temporarily use _dataSource=[...dataSource] for processing
             const _dataSource = [...dataSource];
             const filteredSortedDataSource = this.foundation.getFilteredSortedDataSource(_dataSource, stateQueries);
+            const allDataDisabledRowKeys = this.foundation.getAllDisabledRowKeys(filteredSortedDataSource);
             this.foundation.setCachedFilteredSortedDataSource(filteredSortedDataSource);
+            this.foundation.setAllDisabledRowKeys(allDataDisabledRowKeys);
             states.dataSource = filteredSortedDataSource;
 
             if (this.props.groupBy) {
@@ -814,7 +835,7 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
     };
 
     renderSelection = (record = {} as any, inHeader = false): React.ReactNode => {
-        const { rowSelection, disabledRowKeysSet } = this.state;
+        const { rowSelection, allDisabledRowKeysSet } = this.state;
 
         if (rowSelection && typeof rowSelection === 'object') {
             const { selectedRowKeys = [], selectedRowKeysSet = new Set(), getCheckboxProps, disabled } = rowSelection;
@@ -823,7 +844,7 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
                 const columnKey = get(rowSelection, 'key', strings.DEFAULT_KEY_COLUMN_SELECTION);
                 const allRowKeys = this.cachedFilteredSortedRowKeys;
                 const allRowKeysSet = this.cachedFilteredSortedRowKeysSet;
-                const allIsSelected = this.foundation.allIsSelected(selectedRowKeysSet, disabledRowKeysSet, allRowKeys);
+                const allIsSelected = this.foundation.allIsSelected(selectedRowKeysSet, allDisabledRowKeysSet, allRowKeys);
                 const hasRowSelected = this.foundation.hasRowSelected(selectedRowKeys, allRowKeysSet);
                 return (
                     <ColumnSelection
@@ -832,8 +853,8 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
                         key={columnKey}
                         selected={allIsSelected}
                         indeterminate={hasRowSelected && !allIsSelected}
-                        onChange={(status, e) => {
-                            this.toggleSelectAllRow(status, e);
+                        onChange={(selected, e) => {
+                            this.toggleSelectAllRow(selected, e);
                         }}
                     />
                 );
@@ -1005,8 +1026,8 @@ class Table<RecordType extends Record<string, any>> extends BaseComponent<Normal
         this.foundation.handleSelectRow(realKey, selected, e);
     };
 
-    toggleSelectAllRow = (status: boolean, e: TableSelectionCellEvent) => {
-        this.foundation.handleSelectAllRow(status, e);
+    toggleSelectAllRow = (selected: boolean, e: TableSelectionCellEvent) => {
+        this.foundation.handleSelectAllRow(selected, e);
     };
 
     /**

+ 7 - 2
packages/semi-ui/table/_story/Demos/rowSelection.jsx

@@ -1,7 +1,10 @@
-import React from 'react';
+import React, { useMemo } from 'react';
 import { Table, Avatar } from '@douyinfe/semi-ui';
 import { IconMore } from '@douyinfe/semi-icons';
 
+/**
+ * test in cypress
+ */
 function App() {
     const columns = [
         {
@@ -127,4 +130,6 @@ function App() {
     return <Table columns={columns} dataSource={data} rowSelection={rowSelection} pagination={pagination} />;
 }
 
-render(App);
+App.storyName = 'fixed rowSelection #325';
+
+export default App;

+ 1 - 0
packages/semi-ui/table/_story/table.stories.jsx

@@ -77,6 +77,7 @@ export { default as TableSpan } from './TableSpan';
 export { default as FixRenderReturnProps } from './FixRenderReturnProps';
 export { default as WarnColumnWithoutDataIndex } from './WarnColumnWithoutDataIndex';
 export * from './v2';
+export { default as FixSelectAll325 } from './Demos/rowSelection';
 
 // empty table