feat(bulk-edit): add bulkSelection store backed by SvelteSet
Module-singleton live accumulator: selection persists across pagination and route changes within /documents and /enrich. Cleared on successful bulk save or via Alles aufheben. Refs #225 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
53
frontend/src/lib/stores/bulkSelection.svelte.spec.ts
Normal file
53
frontend/src/lib/stores/bulkSelection.svelte.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { bulkSelectionStore } from './bulkSelection.svelte';
|
||||
|
||||
describe('bulkSelectionStore', () => {
|
||||
afterEach(() => bulkSelectionStore.clear());
|
||||
|
||||
it('starts empty', () => {
|
||||
expect(bulkSelectionStore.size).toBe(0);
|
||||
});
|
||||
|
||||
it('toggle adds an id when absent', () => {
|
||||
bulkSelectionStore.toggle('a');
|
||||
expect(bulkSelectionStore.has('a')).toBe(true);
|
||||
expect(bulkSelectionStore.size).toBe(1);
|
||||
});
|
||||
|
||||
it('toggle removes an id when present', () => {
|
||||
bulkSelectionStore.add('a');
|
||||
bulkSelectionStore.toggle('a');
|
||||
expect(bulkSelectionStore.has('a')).toBe(false);
|
||||
});
|
||||
|
||||
it('add and remove update size', () => {
|
||||
bulkSelectionStore.add('a');
|
||||
bulkSelectionStore.add('b');
|
||||
expect(bulkSelectionStore.size).toBe(2);
|
||||
bulkSelectionStore.remove('a');
|
||||
expect(bulkSelectionStore.size).toBe(1);
|
||||
expect(bulkSelectionStore.has('b')).toBe(true);
|
||||
});
|
||||
|
||||
it('add is idempotent', () => {
|
||||
bulkSelectionStore.add('a');
|
||||
bulkSelectionStore.add('a');
|
||||
expect(bulkSelectionStore.size).toBe(1);
|
||||
});
|
||||
|
||||
it('setAll replaces the selection', () => {
|
||||
bulkSelectionStore.add('a');
|
||||
bulkSelectionStore.add('b');
|
||||
bulkSelectionStore.setAll(['c', 'd', 'e']);
|
||||
expect(bulkSelectionStore.size).toBe(3);
|
||||
expect(bulkSelectionStore.has('a')).toBe(false);
|
||||
expect(bulkSelectionStore.has('c')).toBe(true);
|
||||
});
|
||||
|
||||
it('clear empties the selection', () => {
|
||||
bulkSelectionStore.add('a');
|
||||
bulkSelectionStore.add('b');
|
||||
bulkSelectionStore.clear();
|
||||
expect(bulkSelectionStore.size).toBe(0);
|
||||
});
|
||||
});
|
||||
36
frontend/src/lib/stores/bulkSelection.svelte.ts
Normal file
36
frontend/src/lib/stores/bulkSelection.svelte.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
// Live accumulator. Selection persists across pagination and route changes
|
||||
// within /documents and /enrich. Cleared on successful bulk save or via
|
||||
// "Alles aufheben". The store is module-singleton — there is only ever one
|
||||
// bulk-edit selection per browser session.
|
||||
const selectedIds = new SvelteSet<string>();
|
||||
|
||||
export const bulkSelectionStore = {
|
||||
get ids(): SvelteSet<string> {
|
||||
return selectedIds;
|
||||
},
|
||||
get size(): number {
|
||||
return selectedIds.size;
|
||||
},
|
||||
has(id: string): boolean {
|
||||
return selectedIds.has(id);
|
||||
},
|
||||
toggle(id: string): void {
|
||||
if (selectedIds.has(id)) selectedIds.delete(id);
|
||||
else selectedIds.add(id);
|
||||
},
|
||||
add(id: string): void {
|
||||
selectedIds.add(id);
|
||||
},
|
||||
remove(id: string): void {
|
||||
selectedIds.delete(id);
|
||||
},
|
||||
setAll(ids: Iterable<string>): void {
|
||||
selectedIds.clear();
|
||||
for (const id of ids) selectedIds.add(id);
|
||||
},
|
||||
clear(): void {
|
||||
selectedIds.clear();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user