From 7dc8d0f821667605be87933d685e33d6cc56781d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:40:19 +0000 Subject: [PATCH 01/11] Initial plan From 88b15b030f38b01f7a3021d827b9f35d830df849 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:47:10 +0000 Subject: [PATCH 02/11] fix: stop retaining rowTransaction payloads in wrapper state Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/94022509-da2c-4214-a58e-b9c85032e29f Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/components/AgGrid.react.js | 31 ++---------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/lib/components/AgGrid.react.js b/src/lib/components/AgGrid.react.js index ce2e1c3a..789180ef 100644 --- a/src/lib/components/AgGrid.react.js +++ b/src/lib/components/AgGrid.react.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import LazyLoader from '../LazyLoader'; -import React, {lazy, Suspense, useState, useCallback, useEffect} from 'react'; +import React, {lazy, Suspense} from 'react'; import {AllCommunityModule, ModuleRegistry} from 'ag-grid-community'; import {pick} from 'ramda'; @@ -37,39 +37,12 @@ export const defaultProps = { * Dash interface to AG Grid, a powerful tabular data component. */ function DashAgGrid(props) { - const [state, setState] = useState({ - mounted: false, - rowTransaction: null, - }); - - const buildArray = useCallback((arr1, arr2) => { - if (arr1) { - if (!arr1.includes(arr2)) { - return [...arr1, arr2]; - } - return arr1; - } - return [JSON.parse(JSON.stringify(arr2))]; - }, []); - - useEffect(() => { - if (props.rowTransaction && !state.mounted) { - setState((prevState) => ({ - ...prevState, - rowTransaction: buildArray( - prevState.rowTransaction, - props.rowTransaction - ), - })); - } - }, [props.rowTransaction, state.mounted, buildArray]); - const {enableEnterpriseModules} = props; const RealComponent = getGrid(enableEnterpriseModules); return ( - + ); } From 2b2783f85c937f14d2dcd694bda043ffe1dcabb7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:28:03 +0000 Subject: [PATCH 03/11] fix: preserve pre-mount rowTransaction buffering without leaks Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/718878d8-cc62-41f8-a36b-d22d6f657dee Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/components/AgGrid.react.js | 44 ++++++++++++++++++++++++-- src/lib/fragments/AgGrid.react.js | 33 ++++++++++++++++--- tests/test_selection_persistence.py | 49 +++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/src/lib/components/AgGrid.react.js b/src/lib/components/AgGrid.react.js index 789180ef..51f1b7f2 100644 --- a/src/lib/components/AgGrid.react.js +++ b/src/lib/components/AgGrid.react.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import LazyLoader from '../LazyLoader'; -import React, {lazy, Suspense} from 'react'; +import React, {lazy, Suspense, useState, useCallback, useEffect} from 'react'; import {AllCommunityModule, ModuleRegistry} from 'ag-grid-community'; import {pick} from 'ramda'; @@ -37,12 +37,52 @@ export const defaultProps = { * Dash interface to AG Grid, a powerful tabular data component. */ function DashAgGrid(props) { + const [state, setState] = useState({ + mounted: false, + rowTransaction: null, + }); + + const buildArray = useCallback((arr1, arr2) => { + if (arr1) { + if (!arr1.includes(arr2)) { + return [...arr1, arr2]; + } + return arr1; + } + return [JSON.parse(JSON.stringify(arr2))]; + }, []); + + useEffect(() => { + if (props.rowTransaction && !state.mounted) { + setState((prevState) => ({ + ...prevState, + rowTransaction: buildArray( + prevState.rowTransaction, + props.rowTransaction + ), + })); + } + }, [props.rowTransaction, state.mounted, buildArray]); + + const onJsGridMounted = useCallback(() => { + setState((prevState) => ({ + ...prevState, + mounted: true, + rowTransaction: null, + })); + }, []); + const {enableEnterpriseModules} = props; const RealComponent = getGrid(enableEnterpriseModules); return ( - + ); } diff --git a/src/lib/fragments/AgGrid.react.js b/src/lib/fragments/AgGrid.react.js index 6f7dad3a..4c3934a4 100644 --- a/src/lib/fragments/AgGrid.react.js +++ b/src/lib/fragments/AgGrid.react.js @@ -273,7 +273,9 @@ export function DashAgGrid(props) { const [, forceRerender] = useState({}); const [openGroups, setOpenGroups] = useState({}); const [columnState_push, setColumnState_push] = useState(true); - const [rowTransactionState, setRowTransactionState] = useState(null); + const [rowTransactionState, setRowTransactionState] = useState( + props.parentState?.rowTransaction || null + ); const components = useMemo( () => ({ @@ -297,6 +299,20 @@ export function DashAgGrid(props) { const getRowsParams = useRef(null); const pendingCellValueChanges = useRef(null); + useEffect(() => { + props.onJsGridMounted?.(); + }, [props.onJsGridMounted]); + + useEffect(() => { + if ( + !gridApi && + props.parentState?.rowTransaction && + props.parentState.rowTransaction !== rowTransactionState + ) { + setRowTransactionState(props.parentState.rowTransaction); + } + }, [props.parentState, rowTransactionState, gridApi]); + const onPaginationChanged = useCallback(() => { if (gridApi && !gridApi?.isDestroyed()) { customSetProps({ @@ -1244,7 +1260,9 @@ export function DashAgGrid(props) { const rowTransaction = rowTransactionState; if (gridApi && !gridApi?.isDestroyed()) { if (rowTransaction) { - rowTransaction.forEach(applyRowTransaction); + rowTransaction.forEach((transaction) => + applyRowTransaction(transaction) + ); setRowTransactionState(null); } applyRowTransaction(data); @@ -1543,7 +1561,10 @@ export function DashAgGrid(props) { const {id, style, className, dashGridOptions, ...restProps} = props; const passingProps = pick(PASSTHRU_PROPS, restProps); const convertedProps = convertAllProps( - omit(NO_CONVERT_PROPS, {...dashGridOptions, ...restProps}) + omit([...NO_CONVERT_PROPS, 'parentState', 'onJsGridMounted'], { + ...dashGridOptions, + ...restProps, + }) ); if ('theme' in convertedProps) { @@ -1627,7 +1648,11 @@ export function DashAgGrid(props) { ); } -DashAgGrid.propTypes = {parentState: PropTypes.any, ..._propTypes}; +DashAgGrid.propTypes = { + parentState: PropTypes.any, + onJsGridMounted: PropTypes.func, + ..._propTypes, +}; export const propTypes = DashAgGrid.propTypes; diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index 645efe99..826c3545 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -139,3 +139,52 @@ def setSelections(n, n1, n2): dash_duo.wait_for_text_to_equal( "#selectedRows", '[{"make": "Ford", "model": "Mondeo", "price": 32000}]' ) + + +def test_sp002_row_transaction_before_grid_ready(dash_duo): + app = Dash(__name__) + + rowData = [ + {"id": "Toyota_0", "make": "Toyota", "model": "Celica", "price": 35000}, + {"id": "Ford_0", "make": "Ford", "model": "Mondeo", "price": 32000}, + {"id": "Porsche_0", "make": "Porsche", "model": "Boxster", "price": 72000}, + ] + + app.layout = html.Div( + [ + dcc.Interval(id="tick", interval=1, n_intervals=0, max_intervals=1), + dag.AgGrid( + id="grid", + rowData=rowData, + columnDefs=[ + {"field": "id"}, + {"field": "make"}, + {"field": "model"}, + {"field": "price"}, + ], + defaultColDef={"flex": 1}, + getRowId="params.data.id", + ), + ] + ) + + @app.callback(Output("grid", "rowTransaction"), Input("tick", "n_intervals")) + def apply_transaction(n): + if not n: + return dash.no_update + return { + "add": [ + { + "id": "Queued_1", + "make": "Queued", + "model": "Queued", + "price": 1, + } + ] + } + + dash_duo.start_server(app) + + grid = utils.Grid(dash_duo, "grid") + grid.wait_for_cell_text(0, 0, "Toyota_0") + grid.wait_for_cell_text(3, 0, "Queued_1") From e8c7200990e7a95032efaed0a0f84a6d9e07a5c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:31:03 +0000 Subject: [PATCH 04/11] fix: make pre-mount transaction replay robust Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/718878d8-cc62-41f8-a36b-d22d6f657dee Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/components/AgGrid.react.js | 7 ++----- src/lib/fragments/AgGrid.react.js | 9 ++++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/components/AgGrid.react.js b/src/lib/components/AgGrid.react.js index 51f1b7f2..a1046c0f 100644 --- a/src/lib/components/AgGrid.react.js +++ b/src/lib/components/AgGrid.react.js @@ -44,12 +44,9 @@ function DashAgGrid(props) { const buildArray = useCallback((arr1, arr2) => { if (arr1) { - if (!arr1.includes(arr2)) { - return [...arr1, arr2]; - } - return arr1; + return [...arr1, arr2]; } - return [JSON.parse(JSON.stringify(arr2))]; + return [arr2]; }, []); useEffect(() => { diff --git a/src/lib/fragments/AgGrid.react.js b/src/lib/fragments/AgGrid.react.js index 4c3934a4..9fcac73e 100644 --- a/src/lib/fragments/AgGrid.react.js +++ b/src/lib/fragments/AgGrid.react.js @@ -74,6 +74,7 @@ const xssMessage = (context) => { }; const NO_CONVERT_PROPS = [...PASSTHRU_PROPS, ...PROPS_NOT_FOR_AG_GRID]; +const OMIT_GRID_INTERNAL_PROPS = ['parentState', 'onJsGridMounted']; const dash_clientside = window.dash_clientside || {}; @@ -298,10 +299,12 @@ export function DashAgGrid(props) { const getDetailParams = useRef(); const getRowsParams = useRef(null); const pendingCellValueChanges = useRef(null); + const onJsGridMountedRef = useRef(props.onJsGridMounted); + onJsGridMountedRef.current = props.onJsGridMounted; useEffect(() => { - props.onJsGridMounted?.(); - }, [props.onJsGridMounted]); + onJsGridMountedRef.current?.(); + }, []); useEffect(() => { if ( @@ -1561,7 +1564,7 @@ export function DashAgGrid(props) { const {id, style, className, dashGridOptions, ...restProps} = props; const passingProps = pick(PASSTHRU_PROPS, restProps); const convertedProps = convertAllProps( - omit([...NO_CONVERT_PROPS, 'parentState', 'onJsGridMounted'], { + omit([...NO_CONVERT_PROPS, ...OMIT_GRID_INTERNAL_PROPS], { ...dashGridOptions, ...restProps, }) From 651c9608ee190d20c6d601e8605ac36401f10756 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:32:32 +0000 Subject: [PATCH 05/11] test: assert existing rows remain after queued transaction replay Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/718878d8-cc62-41f8-a36b-d22d6f657dee Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- tests/test_selection_persistence.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index 826c3545..1910a868 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -187,4 +187,6 @@ def apply_transaction(n): grid = utils.Grid(dash_duo, "grid") grid.wait_for_cell_text(0, 0, "Toyota_0") + grid.wait_for_cell_text(1, 0, "Ford_0") + grid.wait_for_cell_text(2, 0, "Porsche_0") grid.wait_for_cell_text(3, 0, "Queued_1") From 5e06089d5277371e38d9c2a8b65d907f2c0c2c7d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:04:38 +0000 Subject: [PATCH 06/11] style: apply prettier to transaction queue updates Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/4f1937a5-6498-482d-81f2-16935edd8811 Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/components/AgGrid.react.js | 4 +++- src/lib/fragments/AgGrid.react.js | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/components/AgGrid.react.js b/src/lib/components/AgGrid.react.js index d30faf13..e73e46a3 100644 --- a/src/lib/components/AgGrid.react.js +++ b/src/lib/components/AgGrid.react.js @@ -48,7 +48,9 @@ function DashAgGrid(props) { } const nextSerialized = JSON.stringify(arr2); if ( - arr1.some((transaction) => JSON.stringify(transaction) === nextSerialized) + arr1.some( + (transaction) => JSON.stringify(transaction) === nextSerialized + ) ) { return arr1; } diff --git a/src/lib/fragments/AgGrid.react.js b/src/lib/fragments/AgGrid.react.js index fdb3bdfa..618aac15 100644 --- a/src/lib/fragments/AgGrid.react.js +++ b/src/lib/fragments/AgGrid.react.js @@ -1259,7 +1259,9 @@ export function DashAgGrid(props) { } const nextSerialized = JSON.stringify(arr2); if ( - arr1.some((transaction) => JSON.stringify(transaction) === nextSerialized) + arr1.some( + (transaction) => JSON.stringify(transaction) === nextSerialized + ) ) { return arr1; } @@ -1283,9 +1285,7 @@ export function DashAgGrid(props) { syncRowData(); } else { setRowTransactionState( - rowTransaction - ? buildArray(rowTransaction, data) - : [data] + rowTransaction ? buildArray(rowTransaction, data) : [data] ); } }, From fde08a012a7d02a497f2b2650fe56ea1f9ad6764 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:06:52 +0000 Subject: [PATCH 07/11] fix: de-duplicate queued row transactions by value Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/4f1937a5-6498-482d-81f2-16935edd8811 Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/components/AgGrid.react.js | 9 ++++----- src/lib/fragments/AgGrid.react.js | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib/components/AgGrid.react.js b/src/lib/components/AgGrid.react.js index e73e46a3..f03ffdbb 100644 --- a/src/lib/components/AgGrid.react.js +++ b/src/lib/components/AgGrid.react.js @@ -47,11 +47,10 @@ function DashAgGrid(props) { return [arr2]; } const nextSerialized = JSON.stringify(arr2); - if ( - arr1.some( - (transaction) => JSON.stringify(transaction) === nextSerialized - ) - ) { + const serializedTransactions = new Set( + arr1.map((transaction) => JSON.stringify(transaction)) + ); + if (serializedTransactions.has(nextSerialized)) { return arr1; } return [...arr1, arr2]; diff --git a/src/lib/fragments/AgGrid.react.js b/src/lib/fragments/AgGrid.react.js index 618aac15..e462fb7a 100644 --- a/src/lib/fragments/AgGrid.react.js +++ b/src/lib/fragments/AgGrid.react.js @@ -1258,11 +1258,10 @@ export function DashAgGrid(props) { return [arr2]; } const nextSerialized = JSON.stringify(arr2); - if ( - arr1.some( - (transaction) => JSON.stringify(transaction) === nextSerialized - ) - ) { + const serializedTransactions = new Set( + arr1.map((transaction) => JSON.stringify(transaction)) + ); + if (serializedTransactions.has(nextSerialized)) { return arr1; } return [...arr1, arr2]; From 80865ca22962106252468b04a6c2bdb54db3196e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:46:41 +0000 Subject: [PATCH 08/11] test: assert queued rowTransaction is released after replay Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/e16d6d2f-7afa-4b7b-b3f2-a3020bb975b4 Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- tests/test_selection_persistence.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index 1910a868..9fecdecd 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -153,6 +153,7 @@ def test_sp002_row_transaction_before_grid_ready(dash_duo): app.layout = html.Div( [ dcc.Interval(id="tick", interval=1, n_intervals=0, max_intervals=1), + html.Div(id="rowTransaction-state"), dag.AgGrid( id="grid", rowData=rowData, @@ -183,6 +184,12 @@ def apply_transaction(n): ] } + @app.callback( + Output("rowTransaction-state", "children"), Input("grid", "rowTransaction") + ) + def log_row_transaction(value): + return json.dumps(value) + dash_duo.start_server(app) grid = utils.Grid(dash_duo, "grid") @@ -190,3 +197,4 @@ def apply_transaction(n): grid.wait_for_cell_text(1, 0, "Ford_0") grid.wait_for_cell_text(2, 0, "Porsche_0") grid.wait_for_cell_text(3, 0, "Queued_1") + dash_duo.wait_for_text_to_equal("#rowTransaction-state", "null") From 67cf962568c0f331c3b6791428fb7e62f55d5e19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:48:16 +0000 Subject: [PATCH 09/11] test: rename rowTransaction state callback for clarity Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/e16d6d2f-7afa-4b7b-b3f2-a3020bb975b4 Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- tests/test_selection_persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index 9fecdecd..12e533bf 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -187,7 +187,7 @@ def apply_transaction(n): @app.callback( Output("rowTransaction-state", "children"), Input("grid", "rowTransaction") ) - def log_row_transaction(value): + def expose_row_transaction_state(value): return json.dumps(value) dash_duo.start_server(app) From 988e9e05158d2e800c56aadaf359c4fcb9635323 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:30:49 +0000 Subject: [PATCH 10/11] fix: avoid duplicate rowTransaction replay on grid init Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/bbbb71ee-89ae-4307-a1ed-8b20e7eda41e Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- src/lib/fragments/AgGrid.react.js | 11 ++++++----- tests/test_selection_persistence.py | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/fragments/AgGrid.react.js b/src/lib/fragments/AgGrid.react.js index e462fb7a..c3074b42 100644 --- a/src/lib/fragments/AgGrid.react.js +++ b/src/lib/fragments/AgGrid.react.js @@ -1271,13 +1271,14 @@ export function DashAgGrid(props) { (data) => { const rowTransaction = rowTransactionState; if (gridApi && !gridApi?.isDestroyed()) { - if (rowTransaction) { - rowTransaction.forEach((transaction) => - applyRowTransaction(transaction) + const isAlreadyQueued = + rowTransaction && + rowTransaction.some((transaction) => + equals(transaction, data) ); - setRowTransactionState(null); + if (!isAlreadyQueued) { + applyRowTransaction(data); } - applyRowTransaction(data); customSetProps({ rowTransaction: null, }); diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index 12e533bf..a5da4b87 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -197,4 +197,5 @@ def expose_row_transaction_state(value): grid.wait_for_cell_text(1, 0, "Ford_0") grid.wait_for_cell_text(2, 0, "Porsche_0") grid.wait_for_cell_text(3, 0, "Queued_1") + grid.wait_for_rendered_rows(4) dash_duo.wait_for_text_to_equal("#rowTransaction-state", "null") From 12b3e1bde353974f1cc4c3e31777810349b4fe04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:39:49 +0000 Subject: [PATCH 11/11] test: cover duplicate pre-mount rowTransaction buffering Agent-Logs-Url: https://github.com/plotly/dash-ag-grid/sessions/8740a8c3-4a89-42ff-9ca1-00070ea0647b Co-authored-by: BSd3v <82055130+BSd3v@users.noreply.github.com> --- tests/test_selection_persistence.py | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/test_selection_persistence.py b/tests/test_selection_persistence.py index a5da4b87..8200c432 100644 --- a/tests/test_selection_persistence.py +++ b/tests/test_selection_persistence.py @@ -199,3 +199,54 @@ def expose_row_transaction_state(value): grid.wait_for_cell_text(3, 0, "Queued_1") grid.wait_for_rendered_rows(4) dash_duo.wait_for_text_to_equal("#rowTransaction-state", "null") + + +def test_sp003_duplicate_row_transaction_before_grid_ready(dash_duo): + app = Dash(__name__) + + rowData = [ + {"id": "Toyota_0", "make": "Toyota", "model": "Celica", "price": 35000}, + {"id": "Ford_0", "make": "Ford", "model": "Mondeo", "price": 32000}, + {"id": "Porsche_0", "make": "Porsche", "model": "Boxster", "price": 72000}, + ] + + app.layout = html.Div( + [ + dcc.Interval(id="tick", interval=1, n_intervals=0, max_intervals=2), + dag.AgGrid( + id="grid", + rowData=rowData, + columnDefs=[ + {"field": "id"}, + {"field": "make"}, + {"field": "model"}, + {"field": "price"}, + ], + defaultColDef={"flex": 1}, + ), + ] + ) + + @app.callback(Output("grid", "rowTransaction"), Input("tick", "n_intervals")) + def apply_duplicate_transaction(n): + if not n: + return dash.no_update + return { + "add": [ + { + "id": "Queued_1", + "make": "Queued", + "model": "Queued", + "price": 1, + } + ] + } + + dash_duo.start_server(app) + + grid = utils.Grid(dash_duo, "grid") + grid.wait_for_cell_text(0, 0, "Toyota_0") + grid.wait_for_cell_text(1, 0, "Ford_0") + grid.wait_for_cell_text(2, 0, "Porsche_0") + grid.wait_for_cell_text(3, 0, "Queued_1") + grid.wait_for_rendered_rows(4)