History

Prepare datamodel for multi-environment (#1765)

Julius Marminge committed 7 months ago

Commit b96308f1 parent 72b7f90121 files · +10206 −4969Browse files

Showing the changes to apps/web/src/threadSelectionStore.ts (1 of 121 files). Show all

Unified · Split

apps/web/src/threadSelectionStore.ts+51−53
@@ -4,121 +4,119 @@ · 3 unmodified lines
4 * Supports Cmd/Ctrl+Click (toggle individual), Shift+Click (range select),4 * Supports Cmd/Ctrl+Click (toggle individual), Shift+Click (range select),
5 * and bulk actions on the selected set.5 * and bulk actions on the selected set.
6 */6 */
7
8import type { ThreadId } from "@t3tools/contracts";
9import { create } from "zustand";7import { create } from "zustand";
10 8
11export interface ThreadSelectionState {9export interface ThreadSelectionState {
12 /** Currently selected thread IDs. */10 /** Currently selected scoped thread keys. */
13 selectedThreadIds: ReadonlySet<ThreadId>;11 selectedThreadKeys: ReadonlySet<string>;
14 /** The thread ID that anchors shift-click range selection. */12 /** The scoped thread key that anchors shift-click range selection. */
15 anchorThreadId: ThreadId | null;13 anchorThreadKey: string | null;
16}14}
17 15
18interface ThreadSelectionStore extends ThreadSelectionState {16interface ThreadSelectionStore extends ThreadSelectionState {
19 /** Toggle a single thread in the selection (Cmd/Ctrl+Click). */17 /** Toggle a single scoped thread key in the selection (Cmd/Ctrl+Click). */
20 toggleThread: (threadId: ThreadId) => void;18 toggleThread: (threadKey: string) => void;
21 /**19 /**
22 * Select a range of threads (Shift+Click).20 * Select a range of threads (Shift+Click).
23 * Requires the ordered list of thread IDs within the same project21 * Requires the ordered list of scoped thread keys within the same project
24 * so the store can compute which threads fall between anchor and target.22 * so the store can compute which threads fall between anchor and target.
25 */23 */
26 rangeSelectTo: (threadId: ThreadId, orderedThreadIds: readonly ThreadId[]) => void;24 rangeSelectTo: (threadKey: string, orderedThreadKeys: readonly string[]) => void;
27 /** Clear all selection state. */25 /** Clear all selection state. */
28 clearSelection: () => void;26 clearSelection: () => void;
29 /** Remove specific thread IDs from the selection (e.g. after deletion). */27 /** Remove specific scoped thread keys from the selection (e.g. after deletion). */
30 removeFromSelection: (threadIds: readonly ThreadId[]) => void;28 removeFromSelection: (threadKeys: readonly string[]) => void;
31 /** Set the anchor thread without adding it to the selection (e.g. on plain-click navigate). */29 /** Set the anchor thread without adding it to the selection (e.g. on plain-click navigate). */
32 setAnchor: (threadId: ThreadId) => void;30 setAnchor: (threadKey: string) => void;
33 /** Check if any threads are selected. */31 /** Check if any threads are selected. */
34 hasSelection: () => boolean;32 hasSelection: () => boolean;
35}33}
36 34
37const EMPTY_SET = new Set<ThreadId>();35const EMPTY_SET = new Set<string>();
38 36
39export const useThreadSelectionStore = create<ThreadSelectionStore>((set, get) => ({37export const useThreadSelectionStore = create<ThreadSelectionStore>((set, get) => ({
40 selectedThreadIds: EMPTY_SET,38 selectedThreadKeys: EMPTY_SET,
41 anchorThreadId: null,39 anchorThreadKey: null,
42 40
43 toggleThread: (threadId) => {41 toggleThread: (threadKey) => {
44 set((state) => {42 set((state) => {
45 const next = new Set(state.selectedThreadIds);43 const next = new Set(state.selectedThreadKeys);
46 if (next.has(threadId)) {44 if (next.has(threadKey)) {
47 next.delete(threadId);45 next.delete(threadKey);
48 } else {46 } else {
49 next.add(threadId);47 next.add(threadKey);
50 }48 }
51 return {49 return {
52 selectedThreadIds: next,50 selectedThreadKeys: next,
53 anchorThreadId: next.has(threadId) ? threadId : state.anchorThreadId,51 anchorThreadKey: next.has(threadKey) ? threadKey : state.anchorThreadKey,
54 };52 };
55 });53 });
56 },54 },
57 55
58 rangeSelectTo: (threadId, orderedThreadIds) => {56 rangeSelectTo: (threadKey, orderedThreadKeys) => {
59 set((state) => {57 set((state) => {
60 const anchor = state.anchorThreadId;58 const anchor = state.anchorThreadKey;
61 if (anchor === null) {59 if (anchor === null) {
62 // No anchor yet — treat as a single toggle60 // No anchor yet — treat as a single toggle
63 const next = new Set(state.selectedThreadIds);61 const next = new Set(state.selectedThreadKeys);
64 next.add(threadId);62 next.add(threadKey);
65 return { selectedThreadIds: next, anchorThreadId: threadId };63 return { selectedThreadKeys: next, anchorThreadKey: threadKey };
66 }64 }
67 65
68 const anchorIndex = orderedThreadIds.indexOf(anchor);66 const anchorIndex = orderedThreadKeys.indexOf(anchor);
69 const targetIndex = orderedThreadIds.indexOf(threadId);67 const targetIndex = orderedThreadKeys.indexOf(threadKey);
70 if (anchorIndex === -1 || targetIndex === -1) {68 if (anchorIndex === -1 || targetIndex === -1) {
71 // Anchor or target not in this list (different project?) — fallback to toggle69 // Anchor or target not in this list (different project?) — fallback to toggle
72 const next = new Set(state.selectedThreadIds);70 const next = new Set(state.selectedThreadKeys);
73 next.add(threadId);71 next.add(threadKey);
74 return { selectedThreadIds: next, anchorThreadId: threadId };72 return { selectedThreadKeys: next, anchorThreadKey: threadKey };
75 }73 }
76 74
77 const start = Math.min(anchorIndex, targetIndex);75 const start = Math.min(anchorIndex, targetIndex);
78 const end = Math.max(anchorIndex, targetIndex);76 const end = Math.max(anchorIndex, targetIndex);
79 const next = new Set(state.selectedThreadIds);77 const next = new Set(state.selectedThreadKeys);
80 for (let i = start; i <= end; i++) {78 for (let i = start; i <= end; i++) {
81 const id = orderedThreadIds[i];79 const key = orderedThreadKeys[i];
82 if (id !== undefined) {80 if (key !== undefined) {
83 next.add(id);81 next.add(key);
84 }82 }
85 }83 }
86 // Keep anchor stable so subsequent shift-clicks extend from the same point84 // Keep anchor stable so subsequent shift-clicks extend from the same point
87 return { selectedThreadIds: next, anchorThreadId: anchor };85 return { selectedThreadKeys: next, anchorThreadKey: anchor };
88 });86 });
89 },87 },
90 88
91 clearSelection: () => {89 clearSelection: () => {
92 const state = get();90 const state = get();
93 if (state.selectedThreadIds.size === 0 && state.anchorThreadId === null) return;91 if (state.selectedThreadKeys.size === 0 && state.anchorThreadKey === null) return;
94 set({ selectedThreadIds: EMPTY_SET, anchorThreadId: null });92 set({ selectedThreadKeys: EMPTY_SET, anchorThreadKey: null });
95 },93 },
96 94
97 setAnchor: (threadId) => {95 setAnchor: (threadKey) => {
98 if (get().anchorThreadId === threadId) return;96 if (get().anchorThreadKey === threadKey) return;
99 set({ anchorThreadId: threadId });97 set({ anchorThreadKey: threadKey });
100 },98 },
101 99
102 removeFromSelection: (threadIds) => {100 removeFromSelection: (threadKeys) => {
103 set((state) => {101 set((state) => {
104 const toRemove = new Set(threadIds);102 const toRemove = new Set(threadKeys);
105 let changed = false;103 let changed = false;
106 const next = new Set<ThreadId>();104 const next = new Set<string>();
107 for (const id of state.selectedThreadIds) {105 for (const key of state.selectedThreadKeys) {
108 if (toRemove.has(id)) {106 if (toRemove.has(key)) {
109 changed = true;107 changed = true;
110 } else {108 } else {
111 next.add(id);109 next.add(key);
112 }110 }
113 }111 }
114 if (!changed) return state;112 if (!changed) return state;
115 const newAnchor =113 const newAnchor =
116 state.anchorThreadId !== null && toRemove.has(state.anchorThreadId)114 state.anchorThreadKey !== null && toRemove.has(state.anchorThreadKey)
117 ? null115 ? null
118 : state.anchorThreadId;116 : state.anchorThreadKey;
119 return { selectedThreadIds: next, anchorThreadId: newAnchor };117 return { selectedThreadKeys: next, anchorThreadKey: newAnchor };
120 });118 });
121 },119 },
122 120
123 hasSelection: () => get().selectedThreadIds.size > 0,121 hasSelection: () => get().selectedThreadKeys.size > 0,
124}));122}));

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t