Skip to content

Commit

Permalink
Dashboard Scene: Fix snapshots not displaying variables values (grafa…
Browse files Browse the repository at this point in the history
…na#88967)

* Use new snapshot variables from scenes

* Add snapshotVariable implementation

* Refactor: Extract variables logic from transforSaveModelToScene file

---------

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
  • Loading branch information
axelavargas and dprokop authored Aug 20, 2024
1 parent 6f63def commit cd4b7ef
Show file tree
Hide file tree
Showing 15 changed files with 1,286 additions and 830 deletions.
5 changes: 3 additions & 2 deletions kinds/dashboard/dashboard_kind.cue
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ lineage: schemas: [{
// `textbox`: Display a free text input field with an optional default value.
// `custom`: Define the variable options manually using a comma-separated list.
// `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
#VariableType: "query" | "adhoc" | "groupby" | "constant" | "datasource" | "interval" | "textbox" | "custom" | "system" @cuetsy(kind="type") @grafanamaturity(NeedsExpertReview)
#VariableType: "query" | "adhoc" | "groupby" | "constant" | "datasource" | "interval" | "textbox" | "custom" |
"system" | "snapshot" @cuetsy(kind="type") @grafanamaturity(NeedsExpertReview)

// Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
// Continuous color interpolates a color using the percentage of a value relative to min and max.
Expand Down Expand Up @@ -594,7 +595,7 @@ lineage: schemas: [{
// Dynamically load the panel
libraryPanel?: #LibraryPanelRef

// Sets panel queries cache timeout.
// Sets panel queries cache timeout.
cacheTimeout?: string

// Overrides the data source configured time-to-live for a query cache item in milliseconds
Expand Down
1 change: 1 addition & 0 deletions packages/grafana-data/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ export {
type UserVariableModel,
type SystemVariable,
type BaseVariableModel,
type SnapshotVariableModel,
} from './types/templateVars';
export { type Threshold, ThresholdsMode, type ThresholdsConfig } from './types/thresholds';
export {
Expand Down
8 changes: 7 additions & 1 deletion packages/grafana-data/src/types/templateVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export type TypedVariableModel =
| CustomVariableModel
| UserVariableModel
| OrgVariableModel
| DashboardVariableModel;
| DashboardVariableModel
| SnapshotVariableModel;

export enum VariableRefresh {
never, // removed from the UI
Expand Down Expand Up @@ -178,3 +179,8 @@ export interface BaseVariableModel {
description: string | null;
usedInRepeat?: boolean;
}

export interface SnapshotVariableModel extends VariableWithOptions {
type: 'snapshot';
query: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export type DashboardLinkType = ('link' | 'dashboards');
* `custom`: Define the variable options manually using a comma-separated list.
* `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
*/
export type VariableType = ('query' | 'adhoc' | 'groupby' | 'constant' | 'datasource' | 'interval' | 'textbox' | 'custom' | 'system');
export type VariableType = ('query' | 'adhoc' | 'groupby' | 'constant' | 'datasource' | 'interval' | 'textbox' | 'custom' | 'system' | 'snapshot');

/**
* Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
Expand Down
1 change: 1 addition & 0 deletions pkg/kinds/dashboard/dashboard_spec_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { SnapshotVariable } from './SnapshotVariable';

describe('SnapshotVariable', () => {
describe('SnapshotVariable state', () => {
it('should create a new snapshotVariable when custom variable is passed', () => {
const { multiVariable } = setupScene();
const snapshot = new SnapshotVariable(multiVariable);
//expect snapshot to be defined
expect(snapshot).toBeDefined();
expect(snapshot.state).toBeDefined();
expect(snapshot.state.type).toBe('snapshot');
expect(snapshot.state.isReadOnly).toBe(true);
expect(snapshot.state.value).toBe(multiVariable.value);
expect(snapshot.state.text).toBe(multiVariable.text);
expect(snapshot.state.hide).toBe(multiVariable.hide);
});
});
});

function setupScene() {
// create custom variable type custom

const multiVariable = {
name: 'Multi',
description: 'Define variable values manually',
text: 'myMultiText',
value: 'myMultiValue',
multi: true,
hide: 0,
};

return { multiVariable };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Observable, map, of } from 'rxjs';

import {
MultiValueVariable,
MultiValueVariableState,
SceneComponentProps,
ValidateAndUpdateResult,
VariableDependencyConfig,
VariableValueOption,
renderSelectForVariable,
sceneGraph,
VariableGetOptionsArgs,
} from '@grafana/scenes';

export interface SnapshotVariableState extends MultiValueVariableState {
query?: string;
}

export class SnapshotVariable extends MultiValueVariable<SnapshotVariableState> {
protected _variableDependency = new VariableDependencyConfig(this, {
statePaths: [],
});

public constructor(initialState: Partial<SnapshotVariableState>) {
super({
name: '',
type: 'snapshot',
isReadOnly: true,
query: '',
value: '',
text: '',
options: [],
...initialState,
});
}

public getValueOptions(args: VariableGetOptionsArgs): Observable<VariableValueOption[]> {
const interpolated = sceneGraph.interpolate(this, this.state.query);
const match = interpolated.match(/(?:\\,|[^,])+/g) ?? [];

const options = match.map((text) => {
text = text.replace(/\\,/g, ',');
const textMatch = /^(.+)\s:\s(.+)$/g.exec(text) ?? [];
if (textMatch.length === 3) {
const [, key, value] = textMatch;
return { label: key.trim(), value: value.trim() };
} else {
return { label: text.trim(), value: text.trim() };
}
});

return of(options);
}

public validateAndUpdate(): Observable<ValidateAndUpdateResult> {
return this.getValueOptions({}).pipe(
map((options) => {
if (this.state.options !== options) {
this._updateValueGivenNewOptions(options);
}
return {};
})
);
}

public static Component = ({ model }: SceneComponentProps<MultiValueVariable<SnapshotVariableState>>) => {
return renderSelectForVariable(model);
};
// we will always preserve the current value and text for snapshots
private _updateValueGivenNewOptions(options: VariableValueOption[]) {
const { value: currentValue, text: currentText } = this.state;
const stateUpdate: Partial<MultiValueVariableState> = {
options,
loading: false,
value: currentValue ?? [],
text: currentText ?? [],
};

this.setState(stateUpdate);
}
}
Loading

0 comments on commit cd4b7ef

Please sign in to comment.