Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Add column order and dimensions to the portable state #3816

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fdcd5a1
[DataGrid] Add column order and dimensions to the portable state
flaviendelangle Feb 2, 2022
066aed0
Work
flaviendelangle Feb 2, 2022
4ed8a46
Work
flaviendelangle Feb 3, 2022
0405f5a
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 9, 2022
d1f08ec
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 10, 2022
df5be23
Work
flaviendelangle Feb 10, 2022
cdb70e0
Fix
flaviendelangle Feb 10, 2022
41e4ce3
Work
flaviendelangle Feb 10, 2022
8011d94
Fix
flaviendelangle Feb 10, 2022
436fe47
Merge
flaviendelangle Feb 14, 2022
2258fa3
Code review: Matheus
flaviendelangle Feb 15, 2022
70cf322
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 18, 2022
cee4119
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 24, 2022
108090b
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 24, 2022
975f565
Merge
flaviendelangle Feb 25, 2022
e5ae7b7
Merge
flaviendelangle Feb 25, 2022
ff39cb6
Merge branch 'master' into state-columns-import-export
flaviendelangle Feb 28, 2022
75d4c27
Fix
flaviendelangle Feb 28, 2022
a9be458
Merge
flaviendelangle Mar 1, 2022
fd300b9
Code review: Matheus
flaviendelangle Mar 1, 2022
0410a1e
Merge
flaviendelangle Mar 2, 2022
e4ad627
Merge branch 'master' into state-columns-import-export
flaviendelangle Mar 3, 2022
e1608d8
Merge
flaviendelangle Mar 4, 2022
f059ed3
Work
flaviendelangle Mar 4, 2022
44eccc2
Merge branch 'master' into state-columns-import-export
flaviendelangle Mar 7, 2022
3899d87
Merge branch 'master' into state-columns-import-export
flaviendelangle Mar 7, 2022
5fe44ac
Work
flaviendelangle Mar 7, 2022
0c75a1b
Merge branch 'master' into state-columns-import-export
flaviendelangle Mar 8, 2022
c07a044
Work
flaviendelangle Mar 8, 2022
09d1d53
Merge branch 'master' into state-columns-import-export
flaviendelangle Mar 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/data/data-grid/state/RestoreStateApiRef.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ ViewListItem.propTypes = {
value: PropTypes.shape({
columns: PropTypes.shape({
columnVisibilityModel: PropTypes.object,
dimensions: PropTypes.object,
orderedFields: PropTypes.arrayOf(PropTypes.string),
}),
detailPanel: PropTypes.shape({
expandedRowIds: PropTypes.arrayOf(
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/api-docs/data-grid/selectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "allGridColumnsFieldsSelector",
"returnType": "string[]",
"description": "",
"supportsApiRef": false
"supportsApiRef": true
},
{
"name": "allGridColumnsSelector",
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/x/api/data-grid/selectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "allGridColumnsFieldsSelector",
"returnType": "string[]",
"description": "",
"supportsApiRef": false
"supportsApiRef": true
},
{
"name": "allGridColumnsSelector",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { GridRowId, GridApiCommon } from '../../../models';
import { GridApiCommunity } from '../../../models/api/gridApiCommunity';
import { GridColDef, GridStateColDef } from '../../../models/colDef/gridColDef';
import type { GridColumnDimensionProperties } from './gridColumnsUtils';

export type GridColumnLookup<Api extends GridApiCommon = GridApiCommunity> = {
[field: string]: GridStateColDef<Api>;
Expand All @@ -11,13 +12,20 @@ export type GridColumnRawLookup<Api extends GridApiCommon = GridApiCommunity> =
};

export interface GridColumnsState<Api extends GridApiCommon = GridApiCommunity> {
/**
* TODO v6: Rename `orderedFields`
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
*/
all: string[];
lookup: GridColumnLookup<Api>;
columnVisibilityModel: GridColumnVisibilityModel;
}

export type GridColumnDimensions = Pick<GridStateColDef, GridColumnDimensionProperties>;

export interface GridColumnsInitialState {
columnVisibilityModel?: GridColumnVisibilityModel;
orderedFields?: string[];
dimensions?: Record<string, GridColumnDimensions>;
}

export type GridColumnsRawState<Api extends GridApiCommon = GridApiCommunity> = Omit<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { GridStateCommunity } from '../../../models/gridStateCommunity';
export const gridColumnsSelector = (state: GridStateCommunity) => state.columns;

// It includes even the hidden columns
export const allGridColumnsFieldsSelector = (state: GridStateCommunity) => state.columns.all;
export const allGridColumnsFieldsSelector = createSelector(
gridColumnsSelector,
(columns) => columns.all,
);

export const gridColumnLookupSelector = (state: GridStateCommunity) => state.columns.lookup;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
GridColumnsState,
GridColumnsRawState,
GridColumnVisibilityModel,
GridColumnRawLookup,
GridColumnsInitialState,
} from './gridColumnsInterfaces';
import {
DEFAULT_GRID_COL_TYPE_KEY,
Expand All @@ -16,6 +18,10 @@ import { GridColDef, GridStateColDef } from '../../../models/colDef/gridColDef';
import { gridColumnsSelector, gridColumnVisibilityModelSelector } from './gridColumnsSelector';
import { clamp } from '../../../utils/utils';

export const COLUMNS_DIMENSION_PROPERTIES = ['maxWidth', 'minWidth', 'width', 'flex'] as const;

export type GridColumnDimensionProperties = typeof COLUMNS_DIMENSION_PROPERTIES[number];

export const computeColumnTypes = (customColumnTypes: GridColumnTypesRecord = {}) => {
const allColumnTypes = { ...getGridDefaultColumnTypes(), ...customColumnTypes };
const mergedColumnTypes: GridColumnTypesRecord = {};
Expand Down Expand Up @@ -91,6 +97,61 @@ export const hydrateColumnsWidth = (

let columnTypeWarnedOnce = false;

/**
* Apply the order and the dimensions of the initial state.
* The columns not registered in `orderedFields` will be placed after the imported columns.
*/
export const applyInitialState = (
columnsState: Omit<GridColumnsRawState, 'columnVisibilityModel'>,
initialState: GridColumnsInitialState | undefined,
) => {
if (!initialState) {
return columnsState;
}

const { orderedFields = [], dimensions = {} } = initialState;

const columnsWithUpdatedDimensions = Object.keys(dimensions);
if (columnsWithUpdatedDimensions.length === 0 && orderedFields.length === 0) {
return columnsState;
}

const orderedFieldsLookup: Record<string, true> = {};
const cleanOrderedFields: string[] = [];

for (let i = 0; i < orderedFields.length; i += 1) {
const field = orderedFields[i];

// Ignores the fields in the initialState that matches no field on the current column state
if (columnsState.lookup[field]) {
orderedFieldsLookup[field] = true;
cleanOrderedFields.push(field);
}
}

const newOrderedFields =
cleanOrderedFields.length === 0
? columnsState.all
: [...cleanOrderedFields, ...columnsState.all.filter((field) => !orderedFieldsLookup[field])];

const newColumnLookup: GridColumnRawLookup = { ...columnsState.lookup };
for (let i = 0; i < columnsWithUpdatedDimensions.length; i += 1) {
const field = columnsWithUpdatedDimensions[i];
newColumnLookup[field] = {
...newColumnLookup[field],
...dimensions[field],
hasBeenResized: true,
};
}

const newColumnsState: Omit<GridColumnsRawState, 'columnVisibilityModel'> = {
all: newOrderedFields,
lookup: newColumnLookup,
};

return newColumnsState;
};

/**
* @deprecated Should have been internal only, you can inline the logic.
*/
Expand Down Expand Up @@ -124,19 +185,26 @@ export const getGridColDef = (
export const createColumnsState = ({
apiRef,
columnsToUpsert,
initialState,
columnsTypes,
currentColumnVisibilityModel = gridColumnVisibilityModelSelector(apiRef),
shouldRegenColumnVisibilityModelFromColumns,
reset,
}: {
columnsToUpsert: GridColDef[];
initialState: GridColumnsInitialState | undefined;
columnsTypes: GridColumnTypesRecord;
currentColumnVisibilityModel?: GridColumnVisibilityModel;
shouldRegenColumnVisibilityModelFromColumns: boolean;
apiRef: React.MutableRefObject<GridApiCommunity>;
reset: boolean;
}) => {
let columnsStateWithoutColumnVisibilityModel: Omit<GridColumnsRawState, 'columnVisibilityModel'>;
let columnsStateWithoutColumnVisibilityModel: Omit<
GridColumnsRawState,
'columnVisibilityModel' | 'lookup'
> & {
lookup: { [field: string]: Omit<GridStateColDef, 'computedWidth'> };
};
if (reset) {
columnsStateWithoutColumnVisibilityModel = {
all: [],
Expand All @@ -161,10 +229,19 @@ export const createColumnsState = ({
};
columnsStateWithoutColumnVisibilityModel.all.push(newColumn.field);
} else {
columnsStateWithoutColumnVisibilityModel.lookup[newColumn.field] = {
const mergedColumn = {
...columnsStateWithoutColumnVisibilityModel.lookup[newColumn.field],
...newColumn,
};

if (
!mergedColumn.hasBeenResized &&
COLUMNS_DIMENSION_PROPERTIES.some((propertyName) => newColumn[propertyName] !== undefined)
) {
mergedColumn.hasBeenResized = true;
}

columnsStateWithoutColumnVisibilityModel.lookup[newColumn.field] = mergedColumn;
}
});

Expand Down Expand Up @@ -217,8 +294,13 @@ export const createColumnsState = ({
columnVisibilityModel = currentColumnVisibilityModel;
}

const columnsStateWithPortableColumns = applyInitialState(
columnsStateWithPreProcessing,
initialState,
);

const columnsState: GridColumnsRawState = {
...columnsStateWithPreProcessing,
...columnsStateWithPortableColumns,
columnVisibilityModel,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ import { DataGridProcessedProps } from '../../../models/props/DataGridProps';
import { useGridStateInit } from '../../utils/useGridStateInit';
import { GridColumnVisibilityChangeParams } from '../../../models';
import { GridPreProcessor, useGridRegisterPreProcessor } from '../../core/preProcessing';
import { GridColumnsState, GridColumnVisibilityModel } from './gridColumnsInterfaces';
import {
GridColumnDimensions,
GridColumnsInitialState,
GridColumnsState,
GridColumnVisibilityModel,
} from './gridColumnsInterfaces';
import {
hydrateColumnsWidth,
computeColumnTypes,
createColumnsState,
setColumnsState,
COLUMNS_DIMENSION_PROPERTIES,
} from './gridColumnsUtils';
import { GridStateColDef } from '../../../models/colDef/gridColDef';

Expand Down Expand Up @@ -70,6 +76,7 @@ export function useGridColumns(
apiRef,
columnsTypes,
columnsToUpsert: props.columns,
initialState: props.initialState?.columns,
shouldRegenColumnVisibilityModelFromColumns: !shouldUseVisibleColumnModel,
currentColumnVisibilityModel:
props.columnVisibilityModel ?? props.initialState?.columns?.columnVisibilityModel ?? {},
Expand Down Expand Up @@ -153,6 +160,7 @@ export function useGridColumns(
apiRef,
columnsTypes,
columnsToUpsert: [],
initialState: undefined,
shouldRegenColumnVisibilityModelFromColumns: false,
currentColumnVisibilityModel: model,
reset: false,
Expand All @@ -170,6 +178,7 @@ export function useGridColumns(
apiRef,
columnsTypes,
columnsToUpsert: columns,
initialState: undefined,
shouldRegenColumnVisibilityModelFromColumns: true,
reset: false,
});
Expand Down Expand Up @@ -217,7 +226,7 @@ export function useGridColumns(

const setColumnIndex = React.useCallback<GridColumnApi['setColumnIndex']>(
(field, targetIndexPosition) => {
const allColumns = allGridColumnsFieldsSelector(apiRef.current.state);
const allColumns = allGridColumnsFieldsSelector(apiRef);
const oldIndexPosition = allColumns.findIndex((col) => col === field);
if (oldIndexPosition === targetIndexPosition) {
return;
Expand Down Expand Up @@ -280,23 +289,40 @@ export function useGridColumns(
*/
const stateExportPreProcessing = React.useCallback<GridPreProcessor<'exportState'>>(
(prevState) => {
if (!shouldUseVisibleColumnModel) {
return prevState;
const columnsStateToExport: GridColumnsInitialState = {};

if (shouldUseVisibleColumnModel) {
const columnVisibilityModelToExport = gridColumnVisibilityModelSelector(apiRef);
const hasHiddenColumns = Object.values(columnVisibilityModelToExport).some(
(value) => value === false,
);

if (hasHiddenColumns) {
columnsStateToExport.columnVisibilityModel = columnVisibilityModelToExport;
}
}

const columnVisibilityModelToExport = gridColumnVisibilityModelSelector(apiRef);
const hasHiddenColumns = Object.values(columnVisibilityModelToExport).some(
(value) => value === false,
);
if (!hasHiddenColumns) {
return prevState;
columnsStateToExport.orderedFields = allGridColumnsFieldsSelector(apiRef);

const columns = allGridColumnsSelector(apiRef);
const dimensions: Record<string, GridColumnDimensions> = {};
columns.forEach((colDef) => {
if (colDef.hasBeenResized) {
const colDefDimensions = {};
COLUMNS_DIMENSION_PROPERTIES.forEach((propertyName) => {
colDefDimensions[propertyName] = colDef[propertyName];
});
dimensions[colDef.field] = colDefDimensions;
}
});

if (Object.keys(dimensions).length > 0) {
columnsStateToExport.dimensions = dimensions;
}

return {
...prevState,
columns: {
columnVisibilityModel: columnVisibilityModelToExport,
},
columns: columnsStateToExport,
};
},
[apiRef, shouldUseVisibleColumnModel],
Expand All @@ -308,17 +334,23 @@ export function useGridColumns(
return params;
}

const columnVisibilityModel = context.stateToRestore.columns?.columnVisibilityModel;
if (columnVisibilityModel != null) {
const columnVisibilityModelToImport = context.stateToRestore.columns?.columnVisibilityModel;
const initialState = context.stateToRestore.columns;
if (columnVisibilityModelToImport != null || initialState != null) {
const columnsState = createColumnsState({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only restores the dimension for those columns that were resized before apiRef.current.exportState is called. If one column is resized after the call, restoring the state won't restore the size of this last column. Should we reset the size of columns that have hasBeenResized=false?

Copy link
Member Author

@flaviendelangle flaviendelangle Feb 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps
Exporting everything was simpler to avoid this kind of "problems".
But if we want to only export what's interesting.
That means storing an additional initialDimensions key inside the columns state to be able to access this data right ?

apiRef,
columnsTypes,
columnsToUpsert: [],
initialState,
shouldRegenColumnVisibilityModelFromColumns: false,
currentColumnVisibilityModel: columnVisibilityModel,
currentColumnVisibilityModel: columnVisibilityModelToImport,
reset: false,
});
apiRef.current.setState(setColumnsState(columnsState));

if (initialState != null) {
apiRef.current.publishEvent(GridEvents.columnsChange, columnsState.all);
}
}
return params;
},
Expand All @@ -345,6 +377,7 @@ export function useGridColumns(
apiRef,
columnsTypes,
columnsToUpsert: [],
initialState: undefined,
shouldRegenColumnVisibilityModelFromColumns: !shouldUseVisibleColumnModel,
reset: false,
});
Expand Down Expand Up @@ -389,6 +422,7 @@ export function useGridColumns(
const columnsState = createColumnsState({
apiRef,
columnsTypes,
initialState: undefined,
// If the user provides a model, we don't want to set it in the state here because it has it's dedicated `useEffect` which calls `setColumnVisibilityModel`
shouldRegenColumnVisibilityModelFromColumns: !shouldUseVisibleColumnModel,
columnsToUpsert: props.columns,
Expand Down
4 changes: 4 additions & 0 deletions packages/grid/_modules_/grid/models/colDef/gridColDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ export type GridColTypeDef<Api extends GridApiCommon = GridApiCommunity> = Omit<
export type GridStateColDef<Api extends GridApiCommon = GridApiCommunity> =
GridEnrichedColDef<Api> & {
computedWidth: number;
/**
* If `true`, it means that at least one of the dimension's property of this column has been modified since the last time the column prop has changed.
*/
hasBeenResized?: boolean;
};

/**
Expand Down
Loading