Skip to content

Commit

Permalink
fix: variable flickers when changing value from right sidebar panel
Browse files Browse the repository at this point in the history
  • Loading branch information
adityasingh-anyline committed Dec 3, 2024
1 parent 5456858 commit d503939
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 24 deletions.
9 changes: 5 additions & 4 deletions src/components/debouncedVariableCheck.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { getTemplateSrv } from '@grafana/runtime';
import { isValidVariable } from './utils/isValidVariable';

export const debouncedVariableCheck = (
variableName: string,
onSuccess: (variableValue: string) => void,
onError: () => void,
interval = 1000,
maxDuration = 5000
maxDuration = 3000
) => {
let elapsed = 0;

const checkVariable = () => {
const variable = getTemplateSrv()
.getVariables()
.find((v) => v.name === variableName && (v as any).current?.value);
.find((v) => v.name === variableName);

if (variable && 'current' in variable) {
onSuccess(variable.current.value as string);
if (isValidVariable(variable)) {
onSuccess(variable.current.value);
} else {
elapsed += interval;
if (elapsed < maxDuration) {
Expand Down
32 changes: 32 additions & 0 deletions src/components/utils/extractRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
interface ExtractedRange {
minValue: string;
delimiter: string;
maxValue: string;
}

const extractRange = (value: string): ExtractedRange | null => {
const numberRegex = /(-?\d+)/;
const firstNumberMatch = numberRegex.exec(value);

if (!firstNumberMatch) {
return null;
}

const firstNumber = firstNumberMatch[1];
const restOfString = value.slice(firstNumberMatch.index + firstNumber.length);

const delimiterRegex = /(.+?)(-?\d+)([^\d]*)$/;
const delimiterMatch = delimiterRegex.exec(restOfString);

if (!delimiterMatch || delimiterMatch.length < 3) {
return null;
}

return {
minValue: firstNumber,
delimiter: delimiterMatch[1].trim(),
maxValue: delimiterMatch[2],
};
};

export default extractRange;
1 change: 0 additions & 1 deletion src/components/utils/findMinAndMaxValues.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ describe('findMinAndMaxValues', () => {
});

it('should throw an error when no min and max values are found', () => {
expect(() => findMinAndMaxValues('no numbers here')).toThrow('Could not find any number');
expect(() => findMinAndMaxValues('[10]')).toThrow('Could not find min and max values');
expect(() => findMinAndMaxValues('[10-to]')).toThrow('Could not find min and max values');
});
Expand Down
25 changes: 6 additions & 19 deletions src/components/utils/findMinAndMaxValues.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
export default function findMinAndMaxValues(variableValue: string) {
const numberRegex = /(-?\d+)/;
const firstNumberMatch = numberRegex.exec(variableValue);

if (!firstNumberMatch) {
throw new Error('Could not find any number');
}
import extractRange from './extractRange';

const firstNumber = firstNumberMatch[1];
const restOfString = variableValue.slice(firstNumberMatch.index + firstNumber.length);

const delimiterRegex = /(.+?)(-?\d+)([^\d]*)$/;
const delimiterMatch = delimiterRegex.exec(restOfString);
export default function findMinAndMaxValues(variableValue: string) {
const extracted = extractRange(variableValue);

if (delimiterMatch && delimiterMatch.length >= 3) {
return {
minValue: firstNumber,
delimiter: delimiterMatch[1].trim(),
maxValue: delimiterMatch[2],
};
} else {
if (!extracted) {
throw new Error('Could not find min and max values');
}

return extracted;
}
35 changes: 35 additions & 0 deletions src/components/utils/isValidVariable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { isValidVariable } from './isValidVariable';

describe('isValidVariable', () => {
it('should return true for valid RangeVariable with valid range format', () => {
const validVariable = { current: { value: '10-90' } };
expect(isValidVariable(validVariable)).toBe(true);
});

it('should return false for RangeVariable with invalid range format', () => {
const invalidVariable = { current: { value: 'invalid range' } };
expect(isValidVariable(invalidVariable)).toBe(false);
});

it('should return false for RangeVariable with no value property', () => {
const invalidVariable = { current: {} };
expect(isValidVariable(invalidVariable)).toBe(false);
});

it('should return false for non-object input', () => {
expect(isValidVariable(null)).toBe(false);
expect(isValidVariable(undefined)).toBe(false);
expect(isValidVariable('not an object')).toBe(false);
expect(isValidVariable(123)).toBe(false);
});

it('should return false for RangeVariable where current is null', () => {
const invalidVariable = { current: null };
expect(isValidVariable(invalidVariable)).toBe(false);
});

it('should return false for RangeVariable where value is not a string', () => {
const invalidVariable = { current: { value: 123 } };
expect(isValidVariable(invalidVariable)).toBe(false);
});
});
31 changes: 31 additions & 0 deletions src/components/utils/isValidVariable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import extractRange from './extractRange';

const isValidRangeFormat = (value: string): boolean => {
try {
return !!extractRange(value);
} catch {
return false;
}
};

export interface RangeVariable {
current: {
value: string;
};
}

export const isValidVariable = (v: any): v is RangeVariable => {
if (v === null || v === undefined) {
return false;
}

if (!v.current || v.current === null) {
return false;
}

if (typeof v.current.value !== 'string') {
return false;
}

return isValidRangeFormat(v.current.value);
};

0 comments on commit d503939

Please sign in to comment.