Skip to content

Commit 13ea965

Browse files
committed
Merge branch 'refs/heads/main' into yogesh-41-skeleton
# Conflicts: # chartlets.js/packages/lib/src/actions/handleHostStoreChange.ts # chartlets.js/packages/lib/src/store.ts # chartlets.js/packages/lib/src/types/state/store.ts
2 parents 49d60d5 + f6118e4 commit 13ea965

File tree

4 files changed

+143
-4
lines changed

4 files changed

+143
-4
lines changed

chartlets.js/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Add `multiple` property for `Select` component to enable the selection
44
of multiple elements. The `default` mode is supported at the moment.
55

6+
* Callbacks will now only be invoked when there’s an actual change in state,
7+
reducing unnecessary processing and improving performance. (#112)
68

79
## Version 0.1.4 (from 2025/03/06)
810

chartlets.js/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chartlets.js/packages/lib/src/actions/handleHostStoreChanges.test.tsx

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { describe, it, expect, beforeEach } from "vitest";
1+
import { beforeEach, describe, expect, it } from "vitest";
22
import { store } from "@/store";
3-
import { handleHostStoreChange } from "./handleHostStoreChange";
3+
import {
4+
getCallbackRequests,
5+
handleHostStoreChange,
6+
type PropertyRef,
7+
} from "./handleHostStoreChange";
8+
import type { ContribPoint } from "@/types/model/extension";
9+
import type { ContributionState } from "@/types/state/contribution";
410

511
describe("handleHostStoreChange", () => {
612
let listeners: (() => void)[] = [];
@@ -15,10 +21,12 @@ describe("handleHostStoreChange", () => {
1521
listeners.push(_l);
1622
},
1723
};
24+
let lastCallbackInputValues: Record<string, unknown[]> = {};
1825

1926
beforeEach(() => {
2027
listeners = [];
2128
hostState = {};
29+
lastCallbackInputValues = {};
2230
});
2331

2432
it("should do nothing without host store", () => {
@@ -78,8 +86,137 @@ describe("handleHostStoreChange", () => {
7886
},
7987
},
8088
},
89+
contributionsRecord: {
90+
panel: [
91+
{
92+
name: "p0",
93+
container: { title: "Panel A" },
94+
extension: "e0",
95+
componentResult: {},
96+
initialState: {},
97+
callbacks: [
98+
{
99+
function: {
100+
name: "callback",
101+
parameters: [],
102+
return: {},
103+
},
104+
inputs: [{ id: "@app", property: "variableName" }],
105+
outputs: [{ id: "select", property: "value" }],
106+
},
107+
],
108+
},
109+
],
110+
},
81111
});
82112
hostStore.set("variableName", "CHL");
83113
handleHostStoreChange();
114+
115+
// calling it second time for coverage. No state change changes the
116+
// control flow
117+
handleHostStoreChange();
118+
// TODO: Update this test to assert the generated callback request
119+
});
120+
121+
it("should memoize second call with same arguments", () => {
122+
const extensions = [{ name: "ext", version: "0", contributes: ["panels"] }];
123+
store.setState({
124+
configuration: { hostStore, logging: { enabled: false } },
125+
extensions,
126+
contributionsResult: {
127+
status: "ok",
128+
data: {
129+
extensions,
130+
contributions: {
131+
panels: [
132+
{
133+
name: "ext.p1",
134+
extension: "ext",
135+
layout: {
136+
function: {
137+
name: "layout",
138+
parameters: [],
139+
return: {},
140+
},
141+
inputs: [],
142+
outputs: [],
143+
},
144+
callbacks: [
145+
{
146+
function: {
147+
name: "callback",
148+
parameters: [],
149+
return: {},
150+
},
151+
inputs: [{ id: "@app", property: "variableName" }],
152+
},
153+
],
154+
initialState: {},
155+
},
156+
],
157+
},
158+
},
159+
},
160+
lastCallbackInputValues: lastCallbackInputValues,
161+
});
162+
const propertyRefs: PropertyRef[] = [
163+
{
164+
contribPoint: "panel",
165+
contribIndex: 0,
166+
callbackIndex: 0,
167+
property: "value",
168+
inputIndex: 0,
169+
},
170+
];
171+
const contributionsRecord: Record<ContribPoint, ContributionState[]> = {
172+
panel: [
173+
{
174+
name: "ext.p1",
175+
container: { title: "Panel A" },
176+
extension: "ext",
177+
componentResult: {},
178+
initialState: { title: "Panel A" },
179+
callbacks: [
180+
{
181+
function: {
182+
name: "callback",
183+
parameters: [{ name: "param1" }],
184+
return: {},
185+
},
186+
inputs: [{ id: "@app", property: "variableName" }],
187+
},
188+
],
189+
},
190+
],
191+
};
192+
193+
hostStore.set("variableName", "CHL");
194+
195+
// first call -> should create callback request
196+
let result = getCallbackRequests(
197+
propertyRefs,
198+
contributionsRecord,
199+
hostStore,
200+
);
201+
expect(result[0]).toEqual({
202+
...propertyRefs[0],
203+
inputValues: ["CHL"],
204+
});
205+
206+
// second call -> memoized -> should not create callback request
207+
result = getCallbackRequests(propertyRefs, contributionsRecord, hostStore);
208+
expect(result).toEqual([undefined]);
209+
210+
// Third call - change state -> should create callback request
211+
hostStore.set("variableName", "TMP");
212+
result = getCallbackRequests(propertyRefs, contributionsRecord, hostStore);
213+
expect(result[0]).toEqual({
214+
...propertyRefs[0],
215+
inputValues: ["TMP"],
216+
});
217+
218+
// fourth call -> memoized -> should not invoke callback
219+
result = getCallbackRequests(propertyRefs, contributionsRecord, hostStore);
220+
expect(result).toEqual([undefined]);
84221
});
85222
});

chartlets.js/packages/lib/src/actions/helpers/getInputValues.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function getInputValues(
2626

2727
const noValue = {};
2828

29-
export function getInputValue(
29+
function getInputValue(
3030
input: Input,
3131
contributionState: ContributionState,
3232
hostStore?: HostStore,

0 commit comments

Comments
 (0)