From be59a6113b9c789725e5f69fed987f1447ade66c Mon Sep 17 00:00:00 2001 From: Brendan O'Handley Date: Tue, 19 Nov 2024 21:13:57 -0600 Subject: [PATCH] Explore metrics: Default for OTel to select deployment environment like prod (#96585) * default to select deployment environment like prod * add tests * return null if options are empty to prevent error, fix test --- public/app/features/trails/DataTrail.tsx | 11 ++++- public/app/features/trails/otel/util.ts | 15 ++++++ public/app/features/trails/otel/utils.test.ts | 48 ++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/public/app/features/trails/DataTrail.tsx b/public/app/features/trails/DataTrail.tsx index dcae58bb515..69412411454 100644 --- a/public/app/features/trails/DataTrail.tsx +++ b/public/app/features/trails/DataTrail.tsx @@ -49,7 +49,13 @@ import { MetricDatasourceHelper } from './helpers/MetricDatasourceHelper'; import { reportChangeInLabelFilters } from './interactions'; import { getDeploymentEnvironments, TARGET_INFO_FILTER, totalOtelResources } from './otel/api'; import { OtelResourcesObject, OtelTargetType } from './otel/types'; -import { sortResources, getOtelJoinQuery, getOtelResourcesObject, updateOtelJoinWithGroupLeft } from './otel/util'; +import { + sortResources, + getOtelJoinQuery, + getOtelResourcesObject, + updateOtelJoinWithGroupLeft, + getProdOrDefaultOption, +} from './otel/util'; import { getOtelExperienceToggleState } from './services/store'; import { getVariablesWithOtelJoinQueryConstant, @@ -357,7 +363,8 @@ export class DataTrail extends SceneObjectBase { // We have to have a default value because custom variable requires it // we choose one default value to help filter metrics // The work flow for OTel begins with users selecting a deployment environment - const defaultDepEnv = options[0].value; // usually production + // default to production + let defaultDepEnv = getProdOrDefaultOption(options) ?? ''; // On starting the explore metrics workflow, the custom variable has no value // Even if there is state, the value is always '' // The only reference to state values are in the text diff --git a/public/app/features/trails/otel/util.ts b/public/app/features/trails/otel/util.ts index dc76fbeb623..ef935bc9017 100644 --- a/public/app/features/trails/otel/util.ts +++ b/public/app/features/trails/otel/util.ts @@ -284,3 +284,18 @@ export async function updateOtelJoinWithGroupLeft(trail: DataTrail, metric: stri otelJoinQueryVariable.setState({ value: otelJoinQuery }); } } + +/** + * Returns the option value that is like 'prod'. + * If there are no options, returns null. + * + * @param options + * @returns + */ +export function getProdOrDefaultOption(options: Array<{ value: string; label: string }>): string | null { + if (options.length === 0) { + return null; + } + + return options.find((option) => option.value.toLowerCase().indexOf('prod') > -1)?.value ?? options[0].value; +} diff --git a/public/app/features/trails/otel/utils.test.ts b/public/app/features/trails/otel/utils.test.ts index d8f72ecf587..b6edb714bbf 100644 --- a/public/app/features/trails/otel/utils.test.ts +++ b/public/app/features/trails/otel/utils.test.ts @@ -8,7 +8,14 @@ import { activateFullSceneTree } from 'app/features/dashboard-scene/utils/test-u import { DataTrail } from '../DataTrail'; import { VAR_OTEL_DEPLOYMENT_ENV, VAR_OTEL_GROUP_LEFT, VAR_OTEL_JOIN_QUERY, VAR_OTEL_RESOURCES } from '../shared'; -import { sortResources, getOtelJoinQuery, blessedList, limitOtelMatchTerms, updateOtelJoinWithGroupLeft } from './util'; +import { + sortResources, + getOtelJoinQuery, + blessedList, + limitOtelMatchTerms, + updateOtelJoinWithGroupLeft, + getProdOrDefaultOption, +} from './util'; jest.mock('./api', () => ({ totalOtelResources: jest.fn(() => ({ job: 'oteldemo', instance: 'instance' })), @@ -270,3 +277,42 @@ describe('updateOtelJoinWithGroupLeft', () => { expect(otelJoinQueryVar.getValue()).toBe(''); }); }); + +describe('getProdOrDefaultOption', () => { + it('should return the value of the option containing "prod"', () => { + const options = [ + { value: 'test1', label: 'Test 1' }, + { value: 'prod2', label: 'Prod 2' }, + { value: 'test3', label: 'Test 3' }, + ]; + expect(getProdOrDefaultOption(options)).toBe('prod2'); + }); + + it('should return the first option value if no option contains "prod"', () => { + const options = [ + { value: 'test1', label: 'Test 1' }, + { value: 'test2', label: 'Test 2' }, + { value: 'test3', label: 'Test 3' }, + ]; + expect(getProdOrDefaultOption(options)).toBe('test1'); + }); + + it('should handle case insensitivity', () => { + const options = [ + { value: 'test1', label: 'Test 1' }, + { value: 'PROD2', label: 'Prod 2' }, + { value: 'test3', label: 'Test 3' }, + ]; + expect(getProdOrDefaultOption(options)).toBe('PROD2'); + }); + + it('should return null if the options array is empty', () => { + const options: Array<{ value: string; label: string }> = []; + expect(getProdOrDefaultOption(options)).toBeNull(); + }); + + it('should return the first option value if the options array has one element', () => { + const options = [{ value: 'test1', label: 'Test 1' }]; + expect(getProdOrDefaultOption(options)).toBe('test1'); + }); +});