Skip to content

Commit fbb2594

Browse files
authored
Merge pull request #48 from grafana/scene-variable-set-detect-changes
SceneVariableSet: Detect state changes and init new variables
2 parents 44d607d + 4af2e7a commit fbb2594

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

packages/scenes/src/variables/sets/SceneVariableSet.test.tsx

+35
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,41 @@ describe('SceneVariableList', () => {
384384
expect(nestedSceneObject.state.variableValueChanged).toBe(1);
385385
});
386386
});
387+
388+
describe('When variables array changes', () => {
389+
it('Should start update process', async () => {
390+
const A = new TestVariable({ name: 'A', query: 'A.*', value: '', text: '', options: [] });
391+
const B = new TestVariable({ name: 'B', query: 'A.*', value: '', text: '', options: [] });
392+
const nestedObj = new TestSceneObect({ title: '$B', variableValueChanged: 0 });
393+
const set = new SceneVariableSet({ variables: [A] });
394+
395+
const scene = new TestScene({
396+
$variables: set,
397+
nested: nestedObj,
398+
});
399+
400+
scene.activate();
401+
nestedObj.activate();
402+
403+
A.signalUpdateCompleted();
404+
405+
// No variable value changed for B yet as it is not part of scene yet
406+
expect(nestedObj.state.variableValueChanged).toBe(0);
407+
408+
// Update state with a new variable
409+
set.setState({ variables: [A, B] });
410+
411+
// Should not start loading A again, it has options already
412+
expect(A.state.loading).toBe(false);
413+
// Should start B
414+
expect(B.state.loading).toBe(true);
415+
416+
B.signalUpdateCompleted();
417+
418+
// Depenedent scene object notified of change
419+
expect(nestedObj.state.variableValueChanged).toBe(1);
420+
});
421+
});
387422
});
388423

389424
interface TestSceneObjectState extends SceneLayoutChildState {

packages/scenes/src/variables/sets/SceneVariableSet.ts

+36
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export class SceneVariableSet extends SceneObjectBase<SceneVariableSetState> imp
3939
this.subscribeToEvent(SceneVariableValueChangedEvent, (event) => this.handleVariableValueChanged(event.payload))
4040
);
4141

42+
// Subscribe to state changes
43+
this._subs.add(this.subscribeToState(this.handleStateChanged));
44+
4245
this.checkForVariablesThatChangedWhileInactive();
4346

4447
// Add all variables that need updating to queue
@@ -74,6 +77,39 @@ export class SceneVariableSet extends SceneObjectBase<SceneVariableSetState> imp
7477
this._updating.clear();
7578
};
7679

80+
/**
81+
* Look for new variables that need to be initialized
82+
*/
83+
private handleStateChanged = (newState: SceneVariableSetState, oldState: SceneVariableSetState) => {
84+
const variablesToUpdateCountStart = this._variablesToUpdate.size;
85+
86+
// Check for removed variables
87+
for (const variable of oldState.variables) {
88+
if (!newState.variables.includes(variable)) {
89+
const updating = this._updating.get(variable);
90+
if (updating?.subscription) {
91+
updating.subscription.unsubscribe();
92+
}
93+
this._updating.delete(variable);
94+
this._variablesToUpdate.delete(variable);
95+
}
96+
}
97+
98+
// Check for new variables
99+
for (const variable of newState.variables) {
100+
if (!oldState.variables.includes(variable)) {
101+
if (this.variableNeedsUpdate(variable)) {
102+
this._variablesToUpdate.add(variable);
103+
}
104+
}
105+
}
106+
107+
// Only start a new batch if there was no batch already running
108+
if (variablesToUpdateCountStart === 0 && this._variablesToUpdate.size > 0) {
109+
this.updateNextBatch();
110+
}
111+
};
112+
77113
/**
78114
* If variables changed while in in-active state we don't get any change events, so we need to check for that here.
79115
*/

0 commit comments

Comments
 (0)