From c4e26c1675a36459ee1fdb14c419b674139d3fcb Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 8 Oct 2024 11:09:20 +0530 Subject: [PATCH 1/3] upcoming: [DI-21322] - Use deep equal logic for bug fix --- .../CloudPulse/Utils/FilterBuilder.test.ts | 37 ++++++++++ .../CloudPulse/Utils/FilterBuilder.ts | 67 +++++++++++++++++++ .../CloudPulseDashboardFilterBuilder.tsx | 2 +- .../shared/CloudPulseResourcesSelect.tsx | 4 +- 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 1c4b5894d7d..6687ebbb561 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -2,6 +2,7 @@ import { dashboardFactory } from 'src/factories'; import { databaseQueries } from 'src/queries/databases/databases'; import { RESOURCES } from './constants'; +import { deepEqual } from './FilterBuilder'; import { buildXFilter, checkIfAllMandatoryFiltersAreSelected, @@ -264,3 +265,39 @@ it('test constructAdditionalRequestFilters method', () => { expect(result).toBeDefined(); expect(result.length).toEqual(0); }); + +it('returns true for identical primitive values', () => { + expect(deepEqual(1, 1)).toBe(true); + expect(deepEqual('test', 'test')).toBe(true); + expect(deepEqual(true, true)).toBe(true); +}); + +it('returns false for different primitive values', () => { + expect(deepEqual(1, 2)).toBe(false); + expect(deepEqual('test', 'other')).toBe(false); + expect(deepEqual(true, false)).toBe(false); +}); + +it('returns true for identical objects', () => { + const obj1 = { a: 1, b: { c: 2 } }; + const obj2 = { a: 1, b: { c: 2 } }; + expect(deepEqual(obj1, obj2)).toBe(true); +}); + +it('returns false for different objects', () => { + const obj1 = { a: 1, b: { c: 2 } }; + const obj2 = { a: 1, b: { c: 3 } }; + expect(deepEqual(obj1, obj2)).toBe(false); +}); + +it('returns true for identical arrays', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 3]; + expect(deepEqual(arr1, arr2)).toBe(true); +}); + +it('returns false for different arrays', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 4]; + expect(deepEqual(arr1, arr2)).toBe(false); +}); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 2a0ee2cd64a..7e415e6c756 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -373,3 +373,70 @@ const getDependentFiltersByFilterKey = ( : configuration.filterKey ); }; + + +/** + * @param obj1 The first object to be compared + * @param obj2 The second object to be compared + * @returns True if, both are equal else false + */ +export const deepEqual = (obj1: T, obj2: T): boolean => { + if (obj1 === obj2) { + return true; // Identical references or values + } + + // If either is null or undefined, or they are not of object type, return false + if ( + obj1 === null || + obj2 === null || + typeof obj1 !== 'object' || + typeof obj2 !== 'object' + ) { + return false; + } + + // Handle array comparison separately + if (Array.isArray(obj1) && Array.isArray(obj2)) { + return compareArrays(obj1, obj2); + } + + // Ensure both objects have the same number of keys + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) { + return false; + } + + // Recursively check each key + for (const key of keys1) { + if (!(key in obj2)) { + return false; + } + // Recursive deep equal check + if (!deepEqual((obj1 as any)[key], (obj2 as any)[key])) { + return false; + } + } + + return true; +}; + +/** + * @param arr1 Array for comparison + * @param arr2 Array for comparison + * @returns True if, both the arrays are equal, else false + */ +const compareArrays = (arr1: T[], arr2: T[]): boolean => { + if (arr1.length !== arr2.length) { + return false; + } + + for (let i = 0; i < arr1.length; i++) { + if (!deepEqual(arr1[i], arr2[i])) { + return false; + } + } + + return true; +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 73bb56016ad..c4818562563 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -330,6 +330,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index f3055326b98..e47338a09d1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -4,6 +4,8 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; +import { deepEqual } from '../Utils/FilterBuilder'; + import type { Filter, FilterValue } from '@linode/api-v4'; export interface CloudPulseResources { @@ -129,7 +131,7 @@ function compareProps( return false; } } - if (prevProps.xFilter !== nextProps.xFilter) { + if (!deepEqual(prevProps.xFilter, nextProps.xFilter)) { return false; } From b4712ea79fa9a49d394a3f1af7a49cb7317797c6 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 20:03:54 +0530 Subject: [PATCH 2/3] upcoming: [DI-21322] - PR comments --- .../.changeset/pr-11068-upcoming-features-1728916409850.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-11068-upcoming-features-1728916409850.md diff --git a/packages/manager/.changeset/pr-11068-upcoming-features-1728916409850.md b/packages/manager/.changeset/pr-11068-upcoming-features-1728916409850.md new file mode 100644 index 00000000000..dbe9182d101 --- /dev/null +++ b/packages/manager/.changeset/pr-11068-upcoming-features-1728916409850.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Retain resource selection while expand or collapse the filter button ([#11068](https://github.com/linode/manager/pull/11068)) From ba72ce3f09453929f4f9645359155d0a43fb0e8b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 21:42:05 +0530 Subject: [PATCH 3/3] upcoming: [DI-21322] - As per dev --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index c4818562563..73bb56016ad 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -330,6 +330,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); }