From 7bc44d4e8ec836c458ad213a28abf6a92f01dbe8 Mon Sep 17 00:00:00 2001 From: Rahman Date: Tue, 3 Feb 2026 16:28:19 +0100 Subject: [PATCH 1/4] fix(custom-chart-web): add reaction for updating editorStore on chart data change --- .../custom-chart-web/src/hooks/useCustomChart.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts index 5f72215182..eed6f31242 100644 --- a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts +++ b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts @@ -2,6 +2,7 @@ import { EditorStoreState, initStateFromProps, PlaygroundData, useEditorStore } import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider"; import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst"; import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup"; +import { reaction } from "mobx"; import { CSSProperties, Ref, RefCallback, useEffect } from "react"; import { CustomChartControllerHost } from "src/controllers/CustomChartControllerHost"; import { mergeRefs } from "src/utils/mergeRefs"; @@ -44,6 +45,16 @@ export function useCustomChart(props: CustomChartContainerProps): UseCustomChart editorStateGateProvider.setProps(editorStore.state); }); + useEffect(() => { + const dispose = reaction( + () => chartPropsController.data, + data => { + editorStore.reset(initStateFromProps(data)()); + } + ); + return dispose; + }, [chartPropsController, editorStore]); + const containerStyle: CSSProperties = { width: props.widthUnit === "percentage" ? `${props.width}%` : `${props.width}px` }; From 3069a3bb327ffa6f63044f0ae2cf11a700803f3f Mon Sep 17 00:00:00 2001 From: Rahman Date: Tue, 3 Feb 2026 16:38:46 +0100 Subject: [PATCH 2/4] fix(custom-chart-web): update changelog --- packages/pluggableWidgets/custom-chart-web/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/pluggableWidgets/custom-chart-web/CHANGELOG.md b/packages/pluggableWidgets/custom-chart-web/CHANGELOG.md index b57b370abb..91fb3ed864 100644 --- a/packages/pluggableWidgets/custom-chart-web/CHANGELOG.md +++ b/packages/pluggableWidgets/custom-chart-web/CHANGELOG.md @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - We changed how "Static" data and "Source attribute" data are merged. Previously, traces were appended as separate chart elements. Now, traces are merged by index, where source attribute values override static values for the same trace position. This enables proper customization of chart traces through dynamic data. +### Fixed + +- We fixed an issue when conditional visibility enabled charts wouldn't re-draw as expected when the data changes. + ## [1.2.3] - 2025-10-10 ### Changed From 92e5c9289331a8e870b8f519d245fc2516e78dcd Mon Sep 17 00:00:00 2001 From: Rahman Date: Wed, 4 Feb 2026 14:56:29 +0100 Subject: [PATCH 3/4] fix(custom-chart-web): switch to useEffect based solution --- .../src/hooks/useCustomChart.ts | 14 ++------------ .../shared/charts/src/helpers/useEditorStore.ts | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts index eed6f31242..54264e3ab5 100644 --- a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts +++ b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts @@ -2,7 +2,6 @@ import { EditorStoreState, initStateFromProps, PlaygroundData, useEditorStore } import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider"; import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst"; import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup"; -import { reaction } from "mobx"; import { CSSProperties, Ref, RefCallback, useEffect } from "react"; import { CustomChartControllerHost } from "src/controllers/CustomChartControllerHost"; import { mergeRefs } from "src/utils/mergeRefs"; @@ -34,7 +33,8 @@ export function useCustomChart(props: CustomChartContainerProps): UseCustomChart const editorStore = useEditorStore({ dataLength: chartPropsController.data.length, - initState: initStateFromProps(chartPropsController.data) + initState: initStateFromProps(chartPropsController.data), + dataSourceKey: chartPropsController.data }); useEffect(() => { @@ -45,16 +45,6 @@ export function useCustomChart(props: CustomChartContainerProps): UseCustomChart editorStateGateProvider.setProps(editorStore.state); }); - useEffect(() => { - const dispose = reaction( - () => chartPropsController.data, - data => { - editorStore.reset(initStateFromProps(data)()); - } - ); - return dispose; - }, [chartPropsController, editorStore]); - const containerStyle: CSSProperties = { width: props.widthUnit === "percentage" ? `${props.width}%` : `${props.width}px` }; diff --git a/packages/shared/charts/src/helpers/useEditorStore.ts b/packages/shared/charts/src/helpers/useEditorStore.ts index 7610acf221..19641e999e 100644 --- a/packages/shared/charts/src/helpers/useEditorStore.ts +++ b/packages/shared/charts/src/helpers/useEditorStore.ts @@ -1,5 +1,5 @@ import { Data } from "plotly.js-dist-min"; -import { useEffect, useReducer, useState } from "react"; +import { useEffect, useReducer, useRef, useState } from "react"; import { fallback, pprint } from "../utils/json"; import { EditorStore, EditorStoreState } from "./EditorStore"; @@ -7,6 +7,7 @@ export type EditorStoreInitializer = () => EditorStoreState; type Params = { dataLength: number; + dataSourceKey?: Data[]; initState?: EditorStoreInitializer; }; @@ -23,6 +24,20 @@ export function useEditorStore(params: Params): EditorStore { return store; }); + const isInitialMount = useRef(true); + + useEffect(() => { + if (isInitialMount.current) { + isInitialMount.current = false; + return; + } + if (params.initState) { + const state = params.initState(); + store.reset(state); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [store, params.dataSourceKey]); + useEffect( () => () => { store.resetData(params.dataLength); From 652efe7d71469efadbde381689cfe3adb07e4d5b Mon Sep 17 00:00:00 2001 From: Rahman Date: Thu, 5 Feb 2026 15:24:48 +0100 Subject: [PATCH 4/4] fix(custom-chart-web): refactor resetData, assign freshState on data key change --- .../src/hooks/useCustomChart.ts | 1 - .../shared/charts/src/helpers/EditorStore.ts | 4 ++-- .../charts/src/helpers/useChartController.ts | 1 - .../charts/src/helpers/useEditorStore.ts | 21 ++++--------------- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts index 54264e3ab5..c384dea2d8 100644 --- a/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts +++ b/packages/pluggableWidgets/custom-chart-web/src/hooks/useCustomChart.ts @@ -32,7 +32,6 @@ export function useCustomChart(props: CustomChartContainerProps): UseCustomChart ); const editorStore = useEditorStore({ - dataLength: chartPropsController.data.length, initState: initStateFromProps(chartPropsController.data), dataSourceKey: chartPropsController.data }); diff --git a/packages/shared/charts/src/helpers/EditorStore.ts b/packages/shared/charts/src/helpers/EditorStore.ts index 43e23fad94..c0075080dc 100644 --- a/packages/shared/charts/src/helpers/EditorStore.ts +++ b/packages/shared/charts/src/helpers/EditorStore.ts @@ -35,8 +35,8 @@ export class EditorStore { return () => (this.listeners = this.listeners.filter(l => l !== listener)); } - resetData(length = 0): void { - this.state.data = Array(length).fill("{}"); + resetData(freshData: JSONString[]): void { + this.state = { ...this.state, data: [...freshData] }; this.emit(); } diff --git a/packages/shared/charts/src/helpers/useChartController.ts b/packages/shared/charts/src/helpers/useChartController.ts index 776ee29c9b..86db05df7f 100644 --- a/packages/shared/charts/src/helpers/useChartController.ts +++ b/packages/shared/charts/src/helpers/useChartController.ts @@ -12,7 +12,6 @@ type Params = { export function useChartController(props: ChartProps, params: Params): [ChartProps, PlaygroundData] { const { playgroundOn } = params; const store = useEditorStore({ - dataLength: props.data.length, initState: initStateFromProps(props) }); const playgroundContext = usePlaygroundDataFactory(props, store); diff --git a/packages/shared/charts/src/helpers/useEditorStore.ts b/packages/shared/charts/src/helpers/useEditorStore.ts index 19641e999e..1b5f4b843b 100644 --- a/packages/shared/charts/src/helpers/useEditorStore.ts +++ b/packages/shared/charts/src/helpers/useEditorStore.ts @@ -1,12 +1,11 @@ import { Data } from "plotly.js-dist-min"; -import { useEffect, useReducer, useRef, useState } from "react"; +import { useEffect, useReducer, useState } from "react"; import { fallback, pprint } from "../utils/json"; import { EditorStore, EditorStoreState } from "./EditorStore"; export type EditorStoreInitializer = () => EditorStoreState; type Params = { - dataLength: number; dataSourceKey?: Data[]; initState?: EditorStoreInitializer; }; @@ -24,27 +23,15 @@ export function useEditorStore(params: Params): EditorStore { return store; }); - const isInitialMount = useRef(true); - useEffect(() => { - if (isInitialMount.current) { - isInitialMount.current = false; - return; - } if (params.initState) { - const state = params.initState(); - store.reset(state); + // Reset only data, preserving layout/config customizations + const freshState = params.initState(); + store.resetData(freshState.data); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [store, params.dataSourceKey]); - useEffect( - () => () => { - store.resetData(params.dataLength); - }, - [store, params.dataLength] - ); - return store; }