Skip to content

Commit

Permalink
AdHocFiltersVariable: provide updateFilters method to allow updating …
Browse files Browse the repository at this point in the history
…filters without emitting SceneVariableValueChangedEvent (#1004)
  • Loading branch information
gtk-grafana authored Dec 20, 2024
1 parent fc15e94 commit 0788102
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 0 deletions.
128 changes: 128 additions & 0 deletions packages/scenes/src/variables/adhoc/AdHocFiltersVariable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,134 @@ describe.each(['11.1.2', '11.1.1'])('AdHocFiltersVariable', (v) => {
expect(evtHandler).not.toHaveBeenCalled();
});

it('Should not overwrite filterExpression on setState', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
filterExpression: '',
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.setState({ filters: variable.state.filters.slice(0), filterExpression: 'hello filter expression!' });

expect(evtHandler).not.toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual('hello filter expression!');
});

it('Should overwrite filterExpression on updateFilters', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
filterExpression: 'hello filter expression!',
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters(variable.state.filters.slice(0));

expect(evtHandler).toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual('key1="val1"');
});

it('updateFilters should not publish event when expr did not change', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters(variable.state.filters.slice(0));

expect(evtHandler).not.toHaveBeenCalled();
});

it('updateFilters should publish event when expr did not change, but forcePublish is set', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters(variable.state.filters.slice(0), { forcePublish: true });

expect(evtHandler).toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual('key1="val1"');
});

it('updateFilters should publish event on when expr did change', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters([{ key: 'key2', operator: '=', value: 'val1' }]);

expect(evtHandler).toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual(`key2="val1"`);
});

it('updateFilters should not publish event when skip event is true', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
filterExpression: 'hello filter expression',
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters([{ key: 'key2', operator: '=', value: 'val1' }], { skipPublish: true });

expect(evtHandler).not.toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual(`key2="val1"`);
});

it('updateFilters should not publish event on when expr did change, if skipPublish is true', () => {
const variable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
applyMode: 'manual',
filters: [{ key: 'key1', operator: '=', value: 'val1' }],
});

variable.activate();

const evtHandler = jest.fn();
variable.subscribeToEvent(SceneVariableValueChangedEvent, evtHandler);

variable.updateFilters([{ key: 'key2', operator: '=', value: 'val1' }], { skipPublish: true });

expect(evtHandler).not.toHaveBeenCalled();
expect(variable.state.filterExpression).toEqual(`key2="val1"`);
});

it('Should create variable with applyMode as manual by default and it allows to override it', () => {
const defaultVariable = new AdHocFiltersVariable({
datasource: { uid: 'hello' },
Expand Down
30 changes: 30 additions & 0 deletions packages/scenes/src/variables/adhoc/AdHocFiltersVariable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,36 @@ export class AdHocFiltersVariable
}
}

/**
* Updates the variable's `filters` and `filterExpression` state.
* If `skipPublish` option is true, this will not emit the `SceneVariableValueChangedEvent`,
* allowing consumers to update the filters without triggering dependent data providers.
*/
public updateFilters(
filters: AdHocFilterWithLabels[],
options?: {
skipPublish?: boolean;
forcePublish?: boolean;
}
): void {
let filterExpressionChanged = false;
let filterExpression = undefined;

if (filters && filters !== this.state.filters) {
filterExpression = renderExpression(this.state.expressionBuilder, filters);
filterExpressionChanged = filterExpression !== this.state.filterExpression;
}

super.setState({
filters,
filterExpression,
});

if ((filterExpressionChanged && options?.skipPublish !== true) || options?.forcePublish) {
this.publishEvent(new SceneVariableValueChangedEvent(this), true);
}
}

public getValue(): VariableValue | undefined {
return this.state.filterExpression;
}
Expand Down

0 comments on commit 0788102

Please sign in to comment.