Skip to content

fix: Introduce zustand state to FacetsPanel to improve maintainability #4769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

skynetigor
Copy link
Contributor

@skynetigor skynetigor commented May 12, 2025

Closes #4560

📑 Description

✅ Checks

  • My pull request adheres to the code style of this project
  • My code requires changes to the documentation
  • I have updated the documentation as required
  • All the tests have passed

ℹ Additional Information

Copy link

vercel bot commented May 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
keep ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 14, 2025 3:34pm

Copy link

codecov bot commented May 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 30.81%. Comparing base (73a3a32) to head (7270d5e).
Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4769      +/-   ##
==========================================
- Coverage   30.97%   30.81%   -0.16%     
==========================================
  Files          93       93              
  Lines       10855    10948      +93     
==========================================
+ Hits         3362     3374      +12     
- Misses       7493     7574      +81     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@skynetigor skynetigor marked this pull request as ready for review May 14, 2025 07:34
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label May 14, 2025
@dosubot dosubot bot added the Bug Something isn't working label May 14, 2025
@Kiryous
Copy link
Contributor

Kiryous commented May 14, 2025

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR introduces Zustand state management to improve FacetsPanel maintainability and fixes an issue where resolved incidents were incorrectly displayed despite filters.

  • Switched from uncheckedByDefaultOptionValues to checkedByDefaultOptionValues in /keep-ui/features/filter/models.tsx to fix default filter behavior
  • Added new Zustand store in /keep-ui/features/filter/store/create-facets-store.ts for centralized facet state management
  • Implemented useFacetsConfig hook in /keep-ui/features/filter/store/use-facets-config.tsx for ID-based facet configuration
  • Added query handling logic in /keep-ui/features/filter/store/use-queries-handler.ts for building CEL expressions
  • Added E2E tests in /tests/e2e_tests/incidents_alerts_tests/test_filtering_sort_search_on_incidents.py to verify default filter behavior

17 file(s) reviewed, 20 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +35 to +36
const atLeastOneUnselected =
allFacetOptions.length !== facetsState[facet.id].size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: This logic assumes facetsState[facet.id] is always a Set. Need null check to prevent runtime errors.

Suggested change
const atLeastOneUnselected =
allFacetOptions.length !== facetsState[facet.id].size;
const atLeastOneUnselected =
allFacetOptions.length !== facetsState[facet.id]?.size;

Comment on lines 9 to +10
// In case facetOptions are not loaded yet, we need to create placeholder wich will be
// populated based on uncheckedByDefaultOptionValues
// populated based on checkedByDefaultOptionValues
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Typo in comment: 'wich' should be 'which'

Suggested change
// In case facetOptions are not loaded yet, we need to create placeholder wich will be
// populated based on uncheckedByDefaultOptionValues
// populated based on checkedByDefaultOptionValues
// In case facetOptions are not loaded yet, we need to create placeholder which will be
// populated based on checkedByDefaultOptionValues

Comment on lines 57 to 58
const facetOptionsRef = useRef<any>(facetOptions);
facetOptionsRef.current = facetOptions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: facetOptionsRef type should be explicitly defined as Record<string, FacetOptionDto[]> instead of any

Suggested change
const facetOptionsRef = useRef<any>(facetOptions);
facetOptionsRef.current = facetOptions;
const facetOptionsRef = useRef<{ [key: string]: FacetOptionDto[] }>(facetOptions);
facetOptionsRef.current = facetOptions;

Comment on lines +92 to 93
facetOptionQueries && onReloadFacetOptionsRef.current?.(facetOptionQueries);
}, [JSON.stringify(facetOptionQueries)]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: JSON.stringify in dependency array could cause unnecessary re-renders. Consider using a deep comparison utility or restructuring the state updates

Comment on lines +7 to +18
export function useNewFacetStore() {
const storeRef = useRef<ReturnType<typeof createFacetStore>>();

if (!storeRef.current) {
storeRef.current = createFacetStore(); // New store per provider
}

useFacetsLoadingStateHandler(storeRef.current);
useQueriesHandler(storeRef.current);

return storeRef.current;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Store instance persists across re-renders but not across multiple instances of useNewFacetStore. Could lead to memory leaks if component unmounts/remounts frequently.

Comment on lines +14 to +15
useFacetsLoadingStateHandler(storeRef.current);
useQueriesHandler(storeRef.current);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Handlers are recreated on every render. Consider moving these to useEffect or memoizing them.

allFacetOptionsRef.current || {},
debouncedFacetsState
);
}, [debouncedFacetsState, setQueriesState]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: setQueriesState in dependency array but not used in computation

Suggested change
}, [debouncedFacetsState, setQueriesState]);
}, [debouncedFacetsState]);

function buildFacetsCelState(
facets: FacetDto[],
allFacetOptions: Record<string, FacetOptionDto[]>,
facetsState: Record<string, any>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Record<string, any> loses type safety - consider using a more specific type

Copy link
Contributor

@Kiryous Kiryous left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great effort! Approving, but please consider adding type safety suggested by greptileai and removing useless useEffects, if possible


useEffect(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this effects to sync state? may we just store areFacetOptionsLoading in the store?

let's use this refactor opportunity to eliminate them?

@Kiryous
Copy link
Contributor

Kiryous commented May 15, 2025

For the context: let's merge when @skynetigor back from OOO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working size:XL This PR changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[🐛 Bug]: Incidents page load with resolved ones, ignoring filters
3 participants