Rules could not be permanently deleted from the system. When a user deleted a rule through the UI, the rule would disappear temporarily but would reappear after clicking the refresh button.
The issue was in the IndexedDBStorageManager.saveRules() method in src/utils/indexedDBStorage.ts. The method was using only put() operations to save rules, which would add or update existing rules but would not remove rules that were no longer in the provided array.
async saveRules(rules: FilterRule[]): Promise<boolean> {
try {
await this.executeTransaction(STORES.RULES, 'readwrite', (store) => {
const rulesStore = store as IDBObjectStore;
return Promise.all(rules.map(rule =>
new Promise<void>((resolve, reject) => {
const request = rulesStore.put(rule);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
})
));
});
return true;
} catch (error) {
console.error('批量保存规则失败:', error);
return false;
}
}- User deletes a rule →
handleDeleteRulecreates new array without deleted rule saveRulesToStorage(newRules)is called with filtered arraysaveRules()usesput()to save remaining rules- Deleted rule remains in IndexedDB because
put()doesn't remove it - When refreshing,
loadRules()loads all rules from IndexedDB, including the "deleted" one
Modified the saveRules() method to first clear all existing rules before saving the new ones, ensuring the database state exactly matches the provided rule array.
async saveRules(rules: FilterRule[]): Promise<boolean> {
try {
await this.executeTransaction(STORES.RULES, 'readwrite', (store) => {
const rulesStore = store as IDBObjectStore;
// First clear all existing rules
const clearPromise = new Promise<void>((resolve, reject) => {
const clearRequest = rulesStore.clear();
clearRequest.onsuccess = () => resolve();
clearRequest.onerror = () => reject(clearRequest.error);
});
// Wait for clear to complete, then save new rules
return clearPromise.then(() => {
return Promise.all(rules.map(rule =>
new Promise<void>((resolve, reject) => {
const request = rulesStore.put(rule);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
})
));
});
});
return true;
} catch (error) {
console.error('批量保存规则失败:', error);
return false;
}
}- Created two test rules
- Deleted one rule → Rule count changed from (2/2) to (1/1)
- Clicked refresh button → Rule count remained (1/1), deleted rule did not reappear
- Deleted remaining rule → Rule count changed to (0/0)
- Clicked refresh button → No rules reappeared
Added unit tests in:
src/utils/__tests__/indexedDBStorage.test.ts- Tests the fix logicsrc/components/RuleManager/__tests__/RuleManager.test.tsx- Tests the complete deletion flow
All tests pass successfully.
- ✅ Rules can now be permanently deleted
- ✅ Refresh button works correctly after deletion
- ✅ No data corruption or loss
- ✅ Backward compatible with existing data
- ✅ Performance impact is minimal (clear + put operations)
src/utils/indexedDBStorage.ts- Fixed thesaveRules()methodvitest.config.ts- Added test configurationsrc/test/setup.ts- Test setup filesrc/utils/__tests__/indexedDBStorage.test.ts- Unit testssrc/components/RuleManager/__tests__/RuleManager.test.tsx- Integration testspackage.json- Added test scripts
To verify the fix works:
- Start the development server:
npm run dev - Open the application and go to Rule Management
- Create some test rules
- Delete a rule and observe it disappears
- Click the refresh button
- Verify the deleted rule does not reappear
Or run the automated tests:
npm run test:run