Compare commits

...

1 Commits

Author SHA1 Message Date
Vinícius Lourenço
82e64bad90 fix(dashboards): variables can be undefined when create new dashboard 2026-04-30 13:21:40 -03:00
7 changed files with 44 additions and 29 deletions

View File

@@ -240,7 +240,7 @@ function DashboardsList(): JSX.Element {
isLocked: !!e.locked || false,
lastUpdatedBy: e.updatedBy,
image: e.data.image || Base64Icons[0],
variables: e.data.variables,
variables: e.data.variables ?? {},
widgets: e.data.widgets,
layout: e.data.layout,
panelMap: e.data.panelMap,

View File

@@ -71,7 +71,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
const orders = Object.values(result.data.variables).map((v) => v.order);
const orders = Object.values(result.data.variables!).map((v) => v.order);
expect(orders).toContain(0);
expect(orders).toContain(1);
});
@@ -84,7 +84,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.order).toBe(5);
expect(result.data.variables!.v1.order).toBe(5);
});
it('assigns unique orders across multiple variables that all lack an order', () => {
@@ -97,7 +97,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
const orders = Object.values(result.data.variables).map((v) => v.order);
const orders = Object.values(result.data.variables!).map((v) => v.order);
// All three newly assigned orders must be distinct
expect(new Set(orders).size).toBe(3);
});
@@ -112,7 +112,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.id).toMatch(
expect(result.data.variables!.v1.id).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
);
});
@@ -125,7 +125,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.id).toBe('keep-me');
expect(result.data.variables!.v1.id).toBe('keep-me');
});
});
@@ -145,7 +145,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.defaultValue).toBe('hello');
expect(result.data.variables!.v1.defaultValue).toBe('hello');
});
it('does not overwrite an existing defaultValue', () => {
@@ -163,7 +163,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.defaultValue).toBe('keep');
expect(result.data.variables!.v1.defaultValue).toBe('keep');
});
});
@@ -178,7 +178,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toBe('staging');
expect(result.data.variables!.v1.selectedValue).toBe('staging');
});
it('applies localStorage allSelected over DB value', () => {
@@ -196,7 +196,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.allSelected).toBe(true);
expect(result.data.variables!.v1.allSelected).toBe(true);
});
});
@@ -217,7 +217,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.allSelected).toBe(true);
expect(result.data.variables!.v1.allSelected).toBe(true);
});
it('sets selectedValue from URL and clears allSelected when showALLOption is true', () => {
@@ -237,8 +237,8 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toBe('dev');
expect(result.data.variables.v1.allSelected).toBe(false);
expect(result.data.variables!.v1.selectedValue).toBe('dev');
expect(result.data.variables!.v1.allSelected).toBe(false);
});
it('does not set allSelected=false when showALLOption is false', () => {
@@ -258,8 +258,8 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toBe('dev');
expect(result.data.variables.v1.allSelected).toBe(true);
expect(result.data.variables!.v1.selectedValue).toBe('dev');
expect(result.data.variables!.v1.allSelected).toBe(true);
});
it('normalizes array URL value to single value for single-select variable', () => {
@@ -277,7 +277,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toBe('prod');
expect(result.data.variables!.v1.selectedValue).toBe('prod');
});
it('wraps single URL value in array for multi-select variable', () => {
@@ -292,7 +292,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toStrictEqual(['prod']);
expect(result.data.variables!.v1.selectedValue).toStrictEqual(['prod']);
});
it('looks up URL variable by variable id when name is absent', () => {
@@ -306,7 +306,7 @@ describe('useTransformDashboardVariables', () => {
const result = transformDashboardVariables(dashboard);
expect(result.data.variables.v1.selectedValue).toBe('fallback');
expect(result.data.variables!.v1.selectedValue).toBe('fallback');
});
});
@@ -327,11 +327,11 @@ describe('useTransformDashboardVariables', () => {
const dashboard = makeDashboard({
v1: makeVariable({ id: 'id1', name: 'env', selectedValue: 'prod' }),
});
const originalValue = dashboard.data.variables.v1.selectedValue;
const originalValue = dashboard.data.variables!.v1.selectedValue;
transformDashboardVariables(dashboard);
expect(dashboard.data.variables.v1.selectedValue).toBe(originalValue);
expect(dashboard.data.variables!.v1.selectedValue).toBe(originalValue);
});
});
});

View File

@@ -22,11 +22,12 @@ export function useTransformDashboardVariables(dashboardId: string): Pick<
localStorageVariables: any,
): Dashboard => {
const updatedData = data;
if (data && localStorageVariables) {
const updatedVariables = data.data.variables;
const variables = data?.data?.variables;
if (data && localStorageVariables && variables) {
const updatedVariables = variables;
const variablesFromUrl = getUrlVariables();
Object.keys(data.data.variables).forEach((variable) => {
const variableData = data.data.variables[variable];
Object.keys(variables).forEach((variable) => {
const variableData = variables[variable];
// values from url
const urlVariable = variableData?.name
@@ -34,7 +35,7 @@ export function useTransformDashboardVariables(dashboardId: string): Pick<
: variablesFromUrl[variableData.id];
let updatedVariable = {
...data.data.variables[variable],
...variables[variable],
...localStorageVariables[variableData.name as any],
};

View File

@@ -85,7 +85,7 @@ function DashboardWidgetInternal({
setDashboardData(updatedDashboardData);
setDashboardVariablesStore({
dashboardId,
variables: updatedDashboardData.data.variables,
variables: updatedDashboardData.data.variables ?? {},
});
},
});

View File

@@ -41,6 +41,20 @@ describe('dashboardVariablesStoreUtils', () => {
expect(result).toStrictEqual([]);
});
it('should return empty array when variables is undefined', () => {
const result = buildSortedVariablesArray(
undefined as unknown as IDashboardVariables,
);
expect(result).toStrictEqual([]);
});
it('should return empty array when variables is null', () => {
const result = buildSortedVariablesArray(
null as unknown as IDashboardVariables,
);
expect(result).toStrictEqual([]);
});
it('should create copies of variables (not references)', () => {
const original = createVariable({ name: 'a', order: 0 });
const variables: IDashboardVariables = { a: original };

View File

@@ -17,11 +17,11 @@ import {
* Build a sorted array of variables by their order property
*/
export function buildSortedVariablesArray(
variables: IDashboardVariables,
variables?: IDashboardVariables,
): IDashboardVariable[] {
const sortedVariablesArray: IDashboardVariable[] = [];
Object.values(variables).forEach((value) => {
Object.values(variables ?? {}).forEach((value) => {
sortedVariablesArray.push({ ...value });
});

View File

@@ -95,7 +95,7 @@ export interface DashboardData {
title: string;
layout?: Layout[];
panelMap?: Record<string, { widgets: Layout[]; collapsed: boolean }>;
variables: Record<string, IDashboardVariable>;
variables?: Record<string, IDashboardVariable>;
version?: string;
image?: string;
}