-
Notifications
You must be signed in to change notification settings - Fork 965
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
base: main
Are you sure you want to change the base?
fix: Introduce zustand state to FacetsPanel to improve maintainability #4769
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
…ity in Facet components
Codecov ReportAll modified and coverable lines are covered by tests ✅
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. 🚀 New features to boost your workflow:
|
…lters' of https://github.com/keephq/keep into 4560-Incidents-page-load-with-resolved-ones-ignoring-filters
There was a problem hiding this 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
tocheckedByDefaultOptionValues
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
const atLeastOneUnselected = | ||
allFacetOptions.length !== facetsState[facet.id].size; |
There was a problem hiding this comment.
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.
const atLeastOneUnselected = | |
allFacetOptions.length !== facetsState[facet.id].size; | |
const atLeastOneUnselected = | |
allFacetOptions.length !== facetsState[facet.id]?.size; |
// In case facetOptions are not loaded yet, we need to create placeholder wich will be | ||
// populated based on uncheckedByDefaultOptionValues | ||
// populated based on checkedByDefaultOptionValues |
There was a problem hiding this comment.
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'
// 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 |
const facetOptionsRef = useRef<any>(facetOptions); | ||
facetOptionsRef.current = facetOptions; |
There was a problem hiding this comment.
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
const facetOptionsRef = useRef<any>(facetOptions); | |
facetOptionsRef.current = facetOptions; | |
const facetOptionsRef = useRef<{ [key: string]: FacetOptionDto[] }>(facetOptions); | |
facetOptionsRef.current = facetOptions; |
facetOptionQueries && onReloadFacetOptionsRef.current?.(facetOptionQueries); | ||
}, [JSON.stringify(facetOptionQueries)]); |
There was a problem hiding this comment.
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
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; | ||
} |
There was a problem hiding this comment.
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.
useFacetsLoadingStateHandler(storeRef.current); | ||
useQueriesHandler(storeRef.current); |
There was a problem hiding this comment.
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]); |
There was a problem hiding this comment.
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
}, [debouncedFacetsState, setQueriesState]); | |
}, [debouncedFacetsState]); |
function buildFacetsCelState( | ||
facets: FacetDto[], | ||
allFacetOptions: Record<string, FacetOptionDto[]>, | ||
facetsState: Record<string, any> |
There was a problem hiding this comment.
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
There was a problem hiding this 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( |
There was a problem hiding this comment.
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?
For the context: let's merge when @skynetigor back from OOO |
Closes #4560
📑 Description
✅ Checks
ℹ Additional Information