From b5651803e01498e6b5f48f5ffe4f4fb7ad8adb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 9 Nov 2022 10:27:20 +0100 Subject: [PATCH] Scene: ObjectVariable for supporting the built in system variables and object scoped variables (__data for example) (#58291) * Scene: Adds ObjectVariable to support the built-in/system variables * fixed lint issue --- .betterer.results | 4 +++ .../sceneTemplateInterpolator.test.ts | 18 +++++++++++ .../variables/variants/ObjectVariable.test.ts | 18 +++++++++++ .../variables/variants/ObjectVariable.ts | 32 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 public/app/features/scenes/variables/variants/ObjectVariable.test.ts create mode 100644 public/app/features/scenes/variables/variants/ObjectVariable.ts diff --git a/.betterer.results b/.betterer.results index e0890b5e1b6..f2403794aff 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4671,6 +4671,10 @@ exports[`better eslint`] = { "public/app/features/scenes/variables/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/features/scenes/variables/variants/ObjectVariable.ts:5381": [ + [0, 0, 0, "Unexpected any. Specify a different type.", "0"], + [0, 0, 0, "Unexpected any. Specify a different type.", "1"] + ], "public/app/features/search/components/SearchCard.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], diff --git a/public/app/features/scenes/variables/sceneTemplateInterpolator.test.ts b/public/app/features/scenes/variables/sceneTemplateInterpolator.test.ts index f79aa4a3f2e..22214be1c5f 100644 --- a/public/app/features/scenes/variables/sceneTemplateInterpolator.test.ts +++ b/public/app/features/scenes/variables/sceneTemplateInterpolator.test.ts @@ -4,6 +4,7 @@ import { SceneObjectStatePlain } from '../core/types'; import { sceneTemplateInterpolator } from './sceneTemplateInterpolator'; import { SceneVariableSet } from './sets/SceneVariableSet'; import { ConstantVariable } from './variants/ConstantVariable'; +import { ObjectVariable } from './variants/ObjectVariable'; interface TestSceneState extends SceneObjectStatePlain { nested?: TestScene; @@ -42,4 +43,21 @@ describe('sceneTemplateInterpolator', () => { expect(sceneTemplateInterpolator('${test}', scene.state.nested!)).toBe('nestedValue'); expect(sceneTemplateInterpolator('${atRootOnly}', scene.state.nested!)).toBe('RootValue'); }); + + describe('Given an expression with fieldPath', () => { + it('Should interpolate correctly', () => { + const scene = new TestScene({ + $variables: new SceneVariableSet({ + variables: [ + new ObjectVariable({ + name: 'test', + value: { prop1: 'prop1Value' }, + }), + ], + }), + }); + + expect(sceneTemplateInterpolator('${test.prop1}', scene)).toBe('prop1Value'); + }); + }); }); diff --git a/public/app/features/scenes/variables/variants/ObjectVariable.test.ts b/public/app/features/scenes/variables/variants/ObjectVariable.test.ts new file mode 100644 index 00000000000..cec60fe49d5 --- /dev/null +++ b/public/app/features/scenes/variables/variants/ObjectVariable.test.ts @@ -0,0 +1,18 @@ +import { ObjectVariable } from './ObjectVariable'; + +describe('ObjectVariable', () => { + describe('getValue', () => { + it('it should return value according to fieldPath', () => { + const variable = new ObjectVariable({ + name: 'test', + value: { + field1: 'value1', + array: ['value1', 'value2', 'value3'], + }, + }); + + expect(variable.getValue('field1')).toBe('value1'); + expect(variable.getValue('array[1]')).toBe('value2'); + }); + }); +}); diff --git a/public/app/features/scenes/variables/variants/ObjectVariable.ts b/public/app/features/scenes/variables/variants/ObjectVariable.ts new file mode 100644 index 00000000000..fd1d12b701c --- /dev/null +++ b/public/app/features/scenes/variables/variants/ObjectVariable.ts @@ -0,0 +1,32 @@ +import { property } from 'lodash'; + +import { SceneObjectBase } from '../../core/SceneObjectBase'; +import { SceneVariable, SceneVariableState, VariableValue } from '../types'; + +export interface ObjectVariableState extends SceneVariableState { + value: T; +} + +export class ObjectVariable + extends SceneObjectBase> + implements SceneVariable> +{ + private static fieldAccessorCache: FieldAccessorCache = {}; + + public getValue(fieldPath: string): VariableValue { + return this.getFieldAccessor(fieldPath)(this.state.value); + } + + private getFieldAccessor(fieldPath: string) { + const accessor = ObjectVariable.fieldAccessorCache[fieldPath]; + if (accessor) { + return accessor; + } + + return (ObjectVariable.fieldAccessorCache[fieldPath] = property(fieldPath)); + } +} + +interface FieldAccessorCache { + [key: string]: (obj: any) => any; +}