Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 34 additions & 20 deletions src/lib/components/AgGrid.react.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import LazyLoader from '../LazyLoader';
import React, {lazy, Suspense, useState, useCallback, useEffect} from 'react';
import {pick} from 'ramda';

const RealAgGrid = lazy(LazyLoader.agGrid);
const RealAgGridEnterprise = lazy(LazyLoader.agGridEnterprise);
Expand All @@ -9,6 +10,25 @@ function getGrid(enable) {
return enable ? RealAgGridEnterprise : RealAgGrid;
}

export const defaultProps = {
className: 'ag-theme-alpine',
resetColumnState: false,
exportDataAsCsv: false,
selectAll: false,
deselectAll: false,
enableEnterpriseModules: false,
updateColumnState: false,
persisted_props: ['selectedRows'],
persistence_type: 'local',
suppressDragLeaveHidesColumns: true,
dangerously_allow_code: false,
rowModelType: 'clientSide',
dashGridOptions: {},
filterModel: {},
paginationGoTo: null,
selectedRows: [],
};

/**
* Dash interface to AG Grid, a powerful tabular data component.
*/
Expand Down Expand Up @@ -45,31 +65,26 @@ function DashAgGrid(props) {

return (
<Suspense fallback={null}>
<RealComponent parentState={state} {...props} />
<RealComponent parentState={state} {...defaultProps} {...props} />
</Suspense>
);
}

const REACT_VERSION_DASH2_COMPAT = 18.3;
if (
parseFloat(React.version.substring(0, React.version.lastIndexOf('.'))) <
REACT_VERSION_DASH2_COMPAT
) {
DashAgGrid.defaultProps = defaultProps;
} else {
DashAgGrid.dashPersistence = pick(
['persisted_props', 'persistence_type'],
defaultProps
);
}

DashAgGrid.dashRenderType = true;

DashAgGrid.defaultProps = {
className: 'ag-theme-alpine',
resetColumnState: false,
exportDataAsCsv: false,
selectAll: false,
deselectAll: false,
enableEnterpriseModules: false,
updateColumnState: false,
persisted_props: ['selectedRows'],
persistence_type: 'local',
suppressDragLeaveHidesColumns: true,
dangerously_allow_code: false,
rowModelType: 'clientSide',
dashGridOptions: {},
filterModel: {},
paginationGoTo: null,
selectedRows: [],
};
DashAgGrid.propTypes = {
/********************************
* DASH PROPS
Expand Down Expand Up @@ -751,7 +766,6 @@ DashAgGrid.propTypes = {
};

export const propTypes = DashAgGrid.propTypes;
export const defaultProps = DashAgGrid.defaultProps;

export default DashAgGrid;

Expand Down
14 changes: 4 additions & 10 deletions src/lib/fragments/AgGrid.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import {
assoc,
assocPath,
} from 'ramda';
import {
propTypes as _propTypes,
defaultProps as _defaultProps,
apiGetters,
} from '../components/AgGrid.react';
import {propTypes as _propTypes, apiGetters} from '../components/AgGrid.react';
import {
COLUMN_DANGEROUS_FUNCTIONS,
COLUMN_MAYBE_FUNCTIONS,
Expand Down Expand Up @@ -1342,10 +1338,10 @@ export function DashAgGrid(props) {

// Handle gridApi initialization - column state application
useEffect(() => {
if (gridApi && gridApi !== prevGridApi && props.columnState) {
if (gridApi && gridApi !== prevGridApi && columnState_push) {
setColumnState();
}
}, [gridApi, prevGridApi, props.columnState, setColumnState]);
}, [gridApi, prevGridApi, columnState_push]);

// Handle gridApi initialization - finalization
useEffect(() => {
Expand Down Expand Up @@ -1378,7 +1374,7 @@ export function DashAgGrid(props) {
setColumnState_push(true);
}
}
}, [props.columnState, props.loading_state, columnState_push]);
}, [props.columnState, props.loading_state]);

// Handle ID changes
useEffect(() => {
Expand Down Expand Up @@ -1605,11 +1601,9 @@ export function DashAgGrid(props) {
);
}

DashAgGrid.defaultProps = _defaultProps;
DashAgGrid.propTypes = {parentState: PropTypes.any, ..._propTypes};

export const propTypes = DashAgGrid.propTypes;
export const defaultProps = DashAgGrid.defaultProps;

var dagfuncs = (window.dash_ag_grid = window.dash_ag_grid || {});
dagfuncs.useGridFilter = useGridFilter;
Expand Down
3 changes: 3 additions & 0 deletions src/lib/utils/propCategories.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export const PASSTHRU_PROPS = ['rowData'];
*/
export const PROPS_NOT_FOR_AG_GRID = [
'children',
'dashRenderType',
'licenseKey',
'setProps',
'loading_state',
'enableEnterpriseModules',
Expand Down Expand Up @@ -354,6 +356,7 @@ export const PROPS_NOT_FOR_AG_GRID = [
'scrollTo',
'eventListeners',
'eventData',
'paginationInfo',
];

/**
Expand Down
210 changes: 206 additions & 4 deletions tests/test_column_state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dash import Dash, html, Output, Input, no_update, State, ctx
from dash import Dash, html, Output, Input, no_update, State, ctx, Patch
import dash_ag_grid as dag
import plotly.express as px
import json
Expand Down Expand Up @@ -84,7 +84,7 @@
alt_colState = [
{
"colId": "price",
"width": 198,
"width": 200,
"hide": False,
"pinned": None,
"sort": "asc",
Expand Down Expand Up @@ -239,7 +239,7 @@ def loadState(n):

dash_duo.find_element("#get-column-state-button").click()
testState = colState.copy()
testState[1]["width"] = 198
testState[1]["width"] = 200
until(
lambda: json.dumps(testState)
in dash_duo.find_element("#reset-column-state-grid-pre").text,
Expand Down Expand Up @@ -315,4 +315,206 @@ def make_grid(n):
for x in range(10):
dash_duo.find_element("#add-grid").click()
time.sleep(2) # pausing to emulate separation because user inputs
assert list(filter(lambda i: i.get("level") != "WARNING", dash_duo.get_logs())) == []
assert list(filter(lambda i: i.get("level") != "WARNING", dash_duo.get_logs())) == []

def test_cs003_column_state(dash_duo):
data = [
{
"localTime": "5:00am",
"a": 0.231,
"b": 0.523,
"c": 0.423,
"d": 0.527,
},
{
"localTime": "5:15am",
"a": 0.423,
"b": 0.452,
"c": 0.523,
"d": 0.543,
},
{
"localTime": "5:30am",
"a": 0.537,
"b": 0.246,
"c": 0.426,
"d": 0.421,
},
{
"localTime": "5:45am",
"a": 0.893,
"b": 0.083,
"c": 0.532,
"d": 0.983,
},
{
"localTime": "6:00am",
"a": 0.231,
"b": 0.523,
"c": 0.423,
"d": 0.527,
},
{
"localTime": "6:15am",
"a": 0.423,
"b": 0.452,
"c": 0.523,
"d": 0.543,
},
{
"localTime": "6:30am",
"a": 0.537,
"b": 0.246,
"c": 0.426,
"d": 0.421,
},
{
"localTime": "6:45am",
"a": 0.893,
"b": 0.083,
"c": 0.532,
"d": 0.983,
},
{
"localTime": "7:00am",
"a": 0.231,
"b": 0.523,
"c": 0.423,
"d": 0.527,
},
{
"localTime": "7:15am",
"a": 0.423,
"b": 0.452,
"c": 0.523,
"d": 0.543,
},
{
"localTime": "7:30am",
"a": 0.537,
"b": 0.246,
"c": 0.426,
"d": 0.421,
},
{
"localTime": "7:45am",
"a": 0.893,
"b": 0.083,
"c": 0.532,
"d": 0.983,
},
{
"localTime": "8:00am",
"a": 0.231,
"b": 0.523,
"c": 0.423,
"d": 0.527,
},
{
"localTime": "8:15am",
"a": 0.423,
"b": 0.452,
"c": 0.523,
"d": 0.543,
},
{
"localTime": "8:30am",
"a": 0.537,
"b": 0.246,
"c": 0.426,
"d": 0.421,
},
{
"localTime": "8:45am",
"a": 0.893,
"b": 0.083,
"c": 0.532,
"d": 0.983,
},
{
"localTime": "8:00am",
"a": 0.231,
"b": 0.523,
"c": 0.423,
"d": 0.527,
},
{
"localTime": "8:15am",
"a": 0.423,
"b": 0.452,
"c": 0.523,
"d": 0.543,
},
{
"localTime": "8:30am",
"a": 0.537,
"b": 0.246,
"c": 0.426,
"d": 0.421,
},
{
"localTime": "8:45am",
"a": 0.893,
"b": 0.083,
"c": 0.532,
"d": 0.983,
},
]

columnDefs = [
{"field": "localTime"},
{"field": "a"},
{"field": "b"},
{"field": "c"},
{"field": "d"},
]

app = Dash(__name__)

app.layout = html.Div(
[
html.Div(
[
html.Button("Remove Column", id="remove-column", n_clicks=0),
html.Div(
id="grid-holder",
children=[
dag.AgGrid(
id=f"grid",
columnDefs=columnDefs,
rowData=data,
columnSize="autoSize",
)
],
),
],
),
]
)

@app.callback(
Output("grid", "columnDefs"),
Input("remove-column", "n_clicks"),
)
def remove_column(n):
if n:
cols = Patch()
if n < 3:
del cols[0]
return cols
return no_update

dash_duo.start_server(
app,
debug=True,
use_reloader=False,
use_debugger=True,
dev_tools_hot_reload=False,
dev_tools_props_check=True,
dev_tools_disable_version_check=True,
)

for x in range(3):
dash_duo.find_element("#remove-column").click()
time.sleep(2) # pausing to emulate separation because user inputs
assert list(filter(lambda i: i.get("level") != "ERROR", dash_duo.get_logs())) == []