fix(codebase audit): preserve cleanup without regressions

Fix codebase audit regressions while preserving UI/UX behavior and adding review-driven hardening.
This commit is contained in:
Tommaso Casaburi
2026-04-24 15:48:07 +07:00
committed by GitHub
parent 5df994b2c7
commit 5dc5408a15
70 changed files with 1478 additions and 518 deletions
@@ -87,7 +87,7 @@ describe('useCatalogFiltersStore', () => {
expect(persisted).not.toContain('"filteredCids"');
});
it('applies search and content filters, hides matching comments, and counts hidden cids only once per board', async () => {
it('applies search and content filters without mutating counts from the predicate', async () => {
const useCatalogFiltersStore = await loadStore();
useCatalogFiltersStore.getState().setFilterItems([createFilterItem('spam', { hide: true }), createFilterItem('highlight', { hide: false, top: true })] as never);
@@ -103,15 +103,13 @@ describe('useCatalogFiltersStore', () => {
expect(filter?.({ cid: 'cid-3', content: 'topic highlight', communityAddress: 'music.eth' } as never)).toBe(true);
expect(filter?.({ cid: 'cid-4', content: 'ordinary update', communityAddress: 'music.eth' } as never)).toBe(false);
vi.runAllTimers();
const state = useCatalogFiltersStore.getState();
expect(testState.commentMatchesPatternMock).toHaveBeenCalled();
expect(state.filterItems[0].count).toBe(1);
expect(state.filterItems[0].filteredCids).toEqual(new Set(['cid-1']));
expect(state.filterItems[0].communityCounts.get('music.eth')).toBe(1);
expect(state.filteredCount).toBe(1);
expect(state.getFilteredCountForCurrentCommunity()).toBe(1);
expect(state.filterItems[0].count).toBe(0);
expect(state.filterItems[0].filteredCids).toEqual(new Set());
expect(state.filterItems[0].communityCounts.get('music.eth')).toBe(0);
expect(state.filteredCount).toBe(0);
expect(state.getFilteredCountForCurrentCommunity()).toBe(0);
});
it('preserves counts for unchanged filters when saving and clears matched filters', async () => {
+23 -60
View File
@@ -1,7 +1,6 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { Comment } from '@bitsocial/bitsocial-react-hooks';
import { getCommentCommunityAddress } from '../lib/utils/comment-utils';
import { commentMatchesPattern } from '../lib/utils/pattern-utils';
interface FilterItem {
@@ -72,6 +71,25 @@ const normalizeFilterItem = (item: RawFilterItem): FilterItem => {
};
};
const createCatalogFilter = (get: () => CatalogFiltersStore) => (comment: Comment) => {
if (!comment?.cid) return true;
const state = get();
if (state.searchText.trim() !== '' && !commentMatchesPattern(comment, state.searchText)) {
return false;
}
let shouldHide = false;
for (const item of state.filterItems) {
if (item.enabled && item.text.trim() !== '' && item.hide && commentMatchesPattern(comment, item.text)) {
shouldHide = true;
break;
}
}
return !shouldHide;
};
const useCatalogFiltersStore = create(
persist<CatalogFiltersStore>(
(set, get) => ({
@@ -138,9 +156,7 @@ const useCatalogFiltersStore = create(
};
});
// Recalculate the filtered count for the current community
get().recalcFilteredCount();
get().updateFilter();
} else {
set({ currentCommunityAddress: address });
}
@@ -148,11 +164,9 @@ const useCatalogFiltersStore = create(
searchText: '',
setSearchFilter: (text: string) => {
set({ searchText: text });
get().updateFilter();
},
clearSearchFilter: () => {
set({ searchText: '' });
get().updateFilter();
},
setFilterItems: (items: FilterItem[]) => {
const nonEmptyItems = items.filter((item) => item.text.trim() !== '').map((item) => normalizeFilterItem(item));
@@ -200,57 +214,10 @@ const useCatalogFiltersStore = create(
});
get().recalcFilteredCount();
get().updateFilter();
},
filter: undefined,
updateFilter: () => {
set((state) => ({
filter: (comment: Comment) => {
if (!comment?.cid) return true;
const currentCommunityAddress = state.currentCommunityAddress;
// Apply search filter
if (state.searchText.trim() !== '') {
if (!commentMatchesPattern(comment, state.searchText)) {
return false;
}
}
// Apply content filters
const { filterItems } = state;
let shouldHide = false;
const commentCommunityAddress = getCommentCommunityAddress(comment);
for (let i = 0; i < filterItems.length; i++) {
const item = filterItems[i];
if (item.enabled && item.text.trim() !== '') {
if (commentMatchesPattern(comment, item.text)) {
// If we have a current community and this is a match, increment the count
if (currentCommunityAddress && commentCommunityAddress && commentCommunityAddress === currentCommunityAddress) {
// We need to use a timeout to avoid modifying state during a state update
setTimeout(() => {
const filterIndex = filterItems.findIndex((f) => f.text === item.text && f.enabled);
if (filterIndex !== -1) {
get().incrementFilterCount(filterIndex, comment.cid, commentCommunityAddress);
}
}, 0);
}
if (item.hide) {
shouldHide = true;
}
}
}
}
return !shouldHide;
},
}));
},
initializeFilter: () => {
get().updateFilter();
},
filter: createCatalogFilter(get),
updateFilter: () => undefined,
initializeFilter: () => undefined,
incrementFilterCount: (filterIndex: number, cid: string, communityAddress: string) => {
set((state) => {
const newFilterItems = [...state.filterItems];
@@ -351,9 +318,6 @@ const useCatalogFiltersStore = create(
filteredCount: 0,
};
});
// Trigger filter reapplication to start counting again
get().updateFilter();
},
}),
{
@@ -365,6 +329,7 @@ const useCatalogFiltersStore = create(
enabled: item.enabled,
hide: item.hide,
top: item.top,
color: item.color,
})),
} as any;
},
@@ -395,6 +360,4 @@ const useCatalogFiltersStore = create(
),
);
useCatalogFiltersStore.getState().updateFilter();
export default useCatalogFiltersStore;
+8
View File
@@ -108,6 +108,14 @@ const useModQueueStore = create<ModQueueState>()(
};
return current as ModQueueState;
},
partialize: (state): PersistedModQueueData => ({
alertThresholdValue: state.alertThresholdValue,
alertThresholdUnit: state.alertThresholdUnit,
dismissedCommentCids: state.dismissedCommentCids,
queuedCommentHistory: state.queuedCommentHistory,
selectedBoardFilter: state.selectedBoardFilter,
viewMode: state.viewMode,
}),
},
),
);