@buoy-gg/react-query 1.7.7 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/index.js +619 -24
- package/lib/commonjs/preset.js +1 -1
- package/lib/commonjs/react-query/components/ReactQueryDevToolsModal.js +12 -0
- package/lib/commonjs/react-query/components/modals/MutationBrowserModal.js +10 -1
- package/lib/commonjs/react-query/components/modals/QueryBrowserModal.js +17 -15
- package/lib/commonjs/react-query/components/modals/ReactQueryModalHeader.js +14 -1
- package/lib/commonjs/react-query/hooks/useAllMutations.js +65 -15
- package/lib/commonjs/react-query/hooks/useWifiState.js +3 -3
- package/lib/commonjs/react-query/index.js +11 -0
- package/lib/commonjs/react-query/stores/index.js +48 -0
- package/lib/commonjs/react-query/stores/reactQueryEventStore.js +311 -0
- package/lib/commonjs/react-query/utils/modalStorageOperations.js +2 -2
- package/lib/module/index.js +113 -8
- package/lib/module/preset.js +2 -2
- package/lib/module/react-query/components/ReactQueryDevToolsModal.js +13 -1
- package/lib/module/react-query/components/modals/MutationBrowserModal.js +10 -1
- package/lib/module/react-query/components/modals/QueryBrowserModal.js +18 -16
- package/lib/module/react-query/components/modals/ReactQueryModalHeader.js +15 -2
- package/lib/module/react-query/hooks/useAllMutations.js +66 -16
- package/lib/module/react-query/hooks/useWifiState.js +4 -4
- package/lib/module/react-query/index.js +2 -1
- package/lib/module/react-query/stores/index.js +3 -0
- package/lib/module/react-query/stores/reactQueryEventStore.js +302 -0
- package/lib/module/react-query/utils/modalStorageOperations.js +3 -3
- package/lib/typescript/index.d.ts +61 -5
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/react-query/components/ReactQueryDevToolsModal.d.ts.map +1 -1
- package/lib/typescript/react-query/components/modals/MutationBrowserModal.d.ts.map +1 -1
- package/lib/typescript/react-query/components/modals/QueryBrowserModal.d.ts.map +1 -1
- package/lib/typescript/react-query/components/modals/ReactQueryModalHeader.d.ts +2 -1
- package/lib/typescript/react-query/components/modals/ReactQueryModalHeader.d.ts.map +1 -1
- package/lib/typescript/react-query/hooks/useAllMutations.d.ts +2 -2
- package/lib/typescript/react-query/hooks/useAllMutations.d.ts.map +1 -1
- package/lib/typescript/react-query/hooks/useWifiState.d.ts +1 -1
- package/lib/typescript/react-query/hooks/useWifiState.d.ts.map +1 -1
- package/lib/typescript/react-query/index.d.ts +1 -0
- package/lib/typescript/react-query/index.d.ts.map +1 -1
- package/lib/typescript/react-query/stores/index.d.ts +2 -0
- package/lib/typescript/react-query/stores/index.d.ts.map +1 -0
- package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts +99 -0
- package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts.map +1 -0
- package/package.json +17 -3
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.subscribeToReactQueryEvents = exports.setQueryClient = exports.reactQueryEventStore = exports.isReactQueryConnected = exports.getReactQueryEvents = exports.disconnectQueryClient = exports.clearReactQueryEvents = void 0;
|
|
7
|
+
var _storageQueryUtils = require("../utils/storageQueryUtils");
|
|
8
|
+
/**
|
|
9
|
+
* React Query Event Store
|
|
10
|
+
*
|
|
11
|
+
* Bridges React Query's cache subscription system to a simple pub/sub pattern
|
|
12
|
+
* that can be consumed by the unified Events DevTools.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* 1. In your app, call setQueryClient(queryClient) to connect
|
|
16
|
+
* 2. The store will emit events for query/mutation state changes
|
|
17
|
+
* 3. The Events DevTools subscribes to these events
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* React Query event types for the unified timeline
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Unified React Query event for the timeline
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
let eventIdCounter = 0;
|
|
29
|
+
function generateEventId() {
|
|
30
|
+
return `rq-${Date.now()}-${++eventIdCounter}`;
|
|
31
|
+
}
|
|
32
|
+
class ReactQueryEventStore {
|
|
33
|
+
events = [];
|
|
34
|
+
listeners = new Set();
|
|
35
|
+
queryClient = null;
|
|
36
|
+
queryUnsubscribe = null;
|
|
37
|
+
mutationUnsubscribe = null;
|
|
38
|
+
maxEvents = 200;
|
|
39
|
+
|
|
40
|
+
// Track fetch start times for duration calculation
|
|
41
|
+
fetchStartTimes = new Map();
|
|
42
|
+
mutationStartTimes = new Map();
|
|
43
|
+
|
|
44
|
+
// Track last known states to detect transitions
|
|
45
|
+
lastQueryStates = new Map();
|
|
46
|
+
lastMutationStates = new Map();
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Connect a QueryClient to the store
|
|
50
|
+
* Call this in your app after creating the QueryClient
|
|
51
|
+
*/
|
|
52
|
+
setQueryClient(queryClient) {
|
|
53
|
+
// Cleanup previous connection
|
|
54
|
+
this.disconnect();
|
|
55
|
+
this.queryClient = queryClient;
|
|
56
|
+
|
|
57
|
+
// Subscribe to query cache
|
|
58
|
+
this.queryUnsubscribe = queryClient.getQueryCache().subscribe(event => {
|
|
59
|
+
if (event.type === "updated" && event.query) {
|
|
60
|
+
this.handleQueryUpdate(event.query);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Subscribe to mutation cache
|
|
65
|
+
this.mutationUnsubscribe = queryClient.getMutationCache().subscribe(event => {
|
|
66
|
+
if (event.type === "updated" && event.mutation) {
|
|
67
|
+
this.handleMutationUpdate(event.mutation);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Disconnect from the QueryClient
|
|
74
|
+
*/
|
|
75
|
+
disconnect() {
|
|
76
|
+
if (this.queryUnsubscribe) {
|
|
77
|
+
this.queryUnsubscribe();
|
|
78
|
+
this.queryUnsubscribe = null;
|
|
79
|
+
}
|
|
80
|
+
if (this.mutationUnsubscribe) {
|
|
81
|
+
this.mutationUnsubscribe();
|
|
82
|
+
this.mutationUnsubscribe = null;
|
|
83
|
+
}
|
|
84
|
+
this.queryClient = null;
|
|
85
|
+
this.lastQueryStates.clear();
|
|
86
|
+
this.lastMutationStates.clear();
|
|
87
|
+
this.fetchStartTimes.clear();
|
|
88
|
+
this.mutationStartTimes.clear();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handle query state updates and emit appropriate events
|
|
93
|
+
*/
|
|
94
|
+
handleQueryUpdate(query) {
|
|
95
|
+
// Skip storage queries (internal to the devtools)
|
|
96
|
+
if ((0, _storageQueryUtils.isStorageQuery)(query.queryKey)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const queryHash = query.queryHash;
|
|
100
|
+
const currentState = {
|
|
101
|
+
fetchStatus: query.state.fetchStatus,
|
|
102
|
+
status: query.state.status
|
|
103
|
+
};
|
|
104
|
+
const lastState = this.lastQueryStates.get(queryHash);
|
|
105
|
+
|
|
106
|
+
// Detect state transitions
|
|
107
|
+
if (!lastState) {
|
|
108
|
+
// New query - if it's fetching, emit fetch start
|
|
109
|
+
if (currentState.fetchStatus === "fetching") {
|
|
110
|
+
this.fetchStartTimes.set(queryHash, Date.now());
|
|
111
|
+
this.addEvent({
|
|
112
|
+
id: generateEventId(),
|
|
113
|
+
type: "query-fetch-start",
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
queryKey: query.queryKey,
|
|
116
|
+
queryHash,
|
|
117
|
+
query
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
// Existing query - check for transitions
|
|
122
|
+
const wasFetching = lastState.fetchStatus === "fetching";
|
|
123
|
+
const isFetching = currentState.fetchStatus === "fetching";
|
|
124
|
+
|
|
125
|
+
// Started fetching
|
|
126
|
+
if (!wasFetching && isFetching) {
|
|
127
|
+
this.fetchStartTimes.set(queryHash, Date.now());
|
|
128
|
+
this.addEvent({
|
|
129
|
+
id: generateEventId(),
|
|
130
|
+
type: "query-fetch-start",
|
|
131
|
+
timestamp: Date.now(),
|
|
132
|
+
queryKey: query.queryKey,
|
|
133
|
+
queryHash,
|
|
134
|
+
query
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Finished fetching
|
|
139
|
+
if (wasFetching && !isFetching) {
|
|
140
|
+
const startTime = this.fetchStartTimes.get(queryHash);
|
|
141
|
+
const duration = startTime ? Date.now() - startTime : undefined;
|
|
142
|
+
this.fetchStartTimes.delete(queryHash);
|
|
143
|
+
if (currentState.status === "error") {
|
|
144
|
+
this.addEvent({
|
|
145
|
+
id: generateEventId(),
|
|
146
|
+
type: "query-fetch-error",
|
|
147
|
+
timestamp: Date.now(),
|
|
148
|
+
queryKey: query.queryKey,
|
|
149
|
+
queryHash,
|
|
150
|
+
queryError: query.state.error,
|
|
151
|
+
duration,
|
|
152
|
+
query
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
this.addEvent({
|
|
156
|
+
id: generateEventId(),
|
|
157
|
+
type: "query-fetch-success",
|
|
158
|
+
timestamp: Date.now(),
|
|
159
|
+
queryKey: query.queryKey,
|
|
160
|
+
queryHash,
|
|
161
|
+
queryData: query.state.data,
|
|
162
|
+
duration,
|
|
163
|
+
query
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Query was invalidated
|
|
169
|
+
if (!lastState.status && query.state.isInvalidated) {
|
|
170
|
+
this.addEvent({
|
|
171
|
+
id: generateEventId(),
|
|
172
|
+
type: "query-invalidated",
|
|
173
|
+
timestamp: Date.now(),
|
|
174
|
+
queryKey: query.queryKey,
|
|
175
|
+
queryHash,
|
|
176
|
+
query
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Update last known state
|
|
182
|
+
this.lastQueryStates.set(queryHash, currentState);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Handle mutation state updates and emit appropriate events
|
|
187
|
+
*/
|
|
188
|
+
handleMutationUpdate(mutation) {
|
|
189
|
+
const mutationId = mutation.mutationId;
|
|
190
|
+
const currentStatus = mutation.state.status;
|
|
191
|
+
const lastStatus = this.lastMutationStates.get(mutationId);
|
|
192
|
+
if (lastStatus !== currentStatus) {
|
|
193
|
+
// Status changed
|
|
194
|
+
if (currentStatus === "pending" && lastStatus !== "pending") {
|
|
195
|
+
// Mutation started
|
|
196
|
+
this.mutationStartTimes.set(mutationId, Date.now());
|
|
197
|
+
this.addEvent({
|
|
198
|
+
id: generateEventId(),
|
|
199
|
+
type: "mutation-start",
|
|
200
|
+
timestamp: Date.now(),
|
|
201
|
+
mutationId,
|
|
202
|
+
mutationKey: mutation.options.mutationKey,
|
|
203
|
+
mutationVariables: mutation.state.variables,
|
|
204
|
+
mutation
|
|
205
|
+
});
|
|
206
|
+
} else if (currentStatus === "success" && lastStatus === "pending") {
|
|
207
|
+
// Mutation succeeded
|
|
208
|
+
const startTime = this.mutationStartTimes.get(mutationId);
|
|
209
|
+
const duration = startTime ? Date.now() - startTime : undefined;
|
|
210
|
+
this.mutationStartTimes.delete(mutationId);
|
|
211
|
+
this.addEvent({
|
|
212
|
+
id: generateEventId(),
|
|
213
|
+
type: "mutation-success",
|
|
214
|
+
timestamp: Date.now(),
|
|
215
|
+
mutationId,
|
|
216
|
+
mutationKey: mutation.options.mutationKey,
|
|
217
|
+
mutationVariables: mutation.state.variables,
|
|
218
|
+
mutationData: mutation.state.data,
|
|
219
|
+
duration,
|
|
220
|
+
mutation
|
|
221
|
+
});
|
|
222
|
+
} else if (currentStatus === "error" && lastStatus === "pending") {
|
|
223
|
+
// Mutation failed
|
|
224
|
+
const startTime = this.mutationStartTimes.get(mutationId);
|
|
225
|
+
const duration = startTime ? Date.now() - startTime : undefined;
|
|
226
|
+
this.mutationStartTimes.delete(mutationId);
|
|
227
|
+
this.addEvent({
|
|
228
|
+
id: generateEventId(),
|
|
229
|
+
type: "mutation-error",
|
|
230
|
+
timestamp: Date.now(),
|
|
231
|
+
mutationId,
|
|
232
|
+
mutationKey: mutation.options.mutationKey,
|
|
233
|
+
mutationVariables: mutation.state.variables,
|
|
234
|
+
mutationError: mutation.state.error,
|
|
235
|
+
duration,
|
|
236
|
+
mutation
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Update last known status
|
|
242
|
+
this.lastMutationStates.set(mutationId, currentStatus);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Add an event to the store
|
|
247
|
+
*/
|
|
248
|
+
addEvent(event) {
|
|
249
|
+
this.events = [event, ...this.events].slice(0, this.maxEvents);
|
|
250
|
+
this.notifyListeners();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get all events
|
|
255
|
+
*/
|
|
256
|
+
getEvents() {
|
|
257
|
+
return this.events;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Subscribe to event changes
|
|
262
|
+
*/
|
|
263
|
+
subscribe(listener) {
|
|
264
|
+
this.listeners.add(listener);
|
|
265
|
+
// Immediately call with current events
|
|
266
|
+
listener(this.events);
|
|
267
|
+
return () => {
|
|
268
|
+
this.listeners.delete(listener);
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Notify all listeners
|
|
274
|
+
*/
|
|
275
|
+
notifyListeners() {
|
|
276
|
+
const events = this.events;
|
|
277
|
+
this.listeners.forEach(listener => listener(events));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Clear all events
|
|
282
|
+
*/
|
|
283
|
+
clearEvents() {
|
|
284
|
+
this.events = [];
|
|
285
|
+
this.notifyListeners();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Check if connected to a QueryClient
|
|
290
|
+
*/
|
|
291
|
+
isConnected() {
|
|
292
|
+
return this.queryClient !== null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Singleton instance
|
|
297
|
+
const reactQueryEventStore = exports.reactQueryEventStore = new ReactQueryEventStore();
|
|
298
|
+
|
|
299
|
+
// Convenience exports
|
|
300
|
+
const setQueryClient = queryClient => reactQueryEventStore.setQueryClient(queryClient);
|
|
301
|
+
exports.setQueryClient = setQueryClient;
|
|
302
|
+
const disconnectQueryClient = () => reactQueryEventStore.disconnect();
|
|
303
|
+
exports.disconnectQueryClient = disconnectQueryClient;
|
|
304
|
+
const getReactQueryEvents = () => reactQueryEventStore.getEvents();
|
|
305
|
+
exports.getReactQueryEvents = getReactQueryEvents;
|
|
306
|
+
const subscribeToReactQueryEvents = listener => reactQueryEventStore.subscribe(listener);
|
|
307
|
+
exports.subscribeToReactQueryEvents = subscribeToReactQueryEvents;
|
|
308
|
+
const clearReactQueryEvents = () => reactQueryEventStore.clearEvents();
|
|
309
|
+
exports.clearReactQueryEvents = clearReactQueryEvents;
|
|
310
|
+
const isReactQueryConnected = () => reactQueryEventStore.isConnected();
|
|
311
|
+
exports.isReactQueryConnected = isReactQueryConnected;
|
|
@@ -7,10 +7,10 @@ exports.savePanelHeight = exports.savePanelDimensions = exports.saveModalVisibil
|
|
|
7
7
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
8
|
// Helper functions for persisting panel state using shared storage wrapper
|
|
9
9
|
const setItem = async (key, value) => {
|
|
10
|
-
await
|
|
10
|
+
await _sharedUi.persistentStorage.setItem(key, value);
|
|
11
11
|
};
|
|
12
12
|
const getItem = async key => {
|
|
13
|
-
return
|
|
13
|
+
return _sharedUi.persistentStorage.getItem(key);
|
|
14
14
|
};
|
|
15
15
|
// Storage operations
|
|
16
16
|
/**
|
package/lib/module/index.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @buoy-gg/react-query
|
|
5
|
+
*
|
|
6
|
+
* React Query DevTools for React Native.
|
|
7
|
+
*
|
|
8
|
+
* PUBLIC API - Only these exports are supported for external use.
|
|
9
|
+
* Internal stores and event subscription mechanisms are not exported
|
|
10
|
+
* to prevent bypassing the tool's intended usage patterns.
|
|
11
|
+
*/
|
|
12
|
+
|
|
3
13
|
// Check if @tanstack/react-query is installed
|
|
4
14
|
try {
|
|
5
15
|
require("@tanstack/react-query");
|
|
@@ -7,13 +17,108 @@ try {
|
|
|
7
17
|
throw new Error("\n\n[@buoy-gg/react-query] ERROR: Missing required peer dependency\n\n" + "This package requires @tanstack/react-query to be installed.\n\n" + "Install it with:\n" + " npm install @tanstack/react-query\n" + " or\n" + " pnpm add @tanstack/react-query\n" + " or\n" + " yarn add @tanstack/react-query\n\n" + "For more information, visit: https://tanstack.com/query/latest\n");
|
|
8
18
|
}
|
|
9
19
|
|
|
10
|
-
//
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// PRESET (Primary entry point for users)
|
|
22
|
+
// =============================================================================
|
|
11
23
|
export { reactQueryToolPreset, createReactQueryTool, wifiTogglePreset, createWifiToggleTool } from "./preset";
|
|
12
24
|
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// QUERY CLIENT CONNECTION (Required for users to connect their QueryClient)
|
|
27
|
+
// =============================================================================
|
|
28
|
+
export { setQueryClient, disconnectQueryClient } from "./react-query/stores/reactQueryEventStore";
|
|
29
|
+
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// COMPONENTS (For custom UI implementations)
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
// Main modals
|
|
35
|
+
export { ReactQueryModal } from "./react-query/components/modals/ReactQueryModal";
|
|
36
|
+
export { ReactQueryModalHeader } from "./react-query/components/modals/ReactQueryModalHeader";
|
|
37
|
+
export { QueryBrowserModal } from "./react-query/components/modals/QueryBrowserModal";
|
|
38
|
+
export { MutationBrowserModal } from "./react-query/components/modals/MutationBrowserModal";
|
|
39
|
+
export { MutationEditorModal } from "./react-query/components/modals/MutationEditorModal";
|
|
40
|
+
export { DataEditorModal } from "./react-query/components/modals/DataEditorModal";
|
|
41
|
+
export { QueryBrowserFooter } from "./react-query/components/modals/QueryBrowserFooter";
|
|
42
|
+
export { MutationBrowserFooter } from "./react-query/components/modals/MutationBrowserFooter";
|
|
43
|
+
export { SwipeIndicator } from "./react-query/components/modals/SwipeIndicator";
|
|
44
|
+
|
|
45
|
+
// Query browser components
|
|
46
|
+
export { Explorer, QueryBrowser, QueryDetails, QueryInformation, QueryActions, QueryRow, QueryStatus, QueryStatusCount, QueryDetailsChip, MutationsList, MutationDetails, MutationInformation, MutationButton, MutationStatusCount, MutationDetailsChips, ActionButton, ClearCacheButton, NetworkToggleButton, StorageStatusCount } from "./react-query/components/query-browser";
|
|
47
|
+
|
|
48
|
+
// Mode components
|
|
49
|
+
export { QueryBrowserMode } from "./react-query/components/QueryBrowserMode";
|
|
50
|
+
export { MutationBrowserMode } from "./react-query/components/MutationBrowserMode";
|
|
51
|
+
export { MutationEditorMode } from "./react-query/components/MutationEditorMode";
|
|
52
|
+
export { DataEditorMode } from "./react-query/components/DataEditorMode";
|
|
53
|
+
export { QuerySelector } from "./react-query/components/QuerySelector";
|
|
54
|
+
export { QueryDebugInfo } from "./react-query/components/QueryDebugInfo";
|
|
55
|
+
export { WifiToggle } from "./react-query/components/WifiToggle";
|
|
56
|
+
export { ReactQuerySection } from "./react-query/components/ReactQuerySection";
|
|
57
|
+
export { ReactQueryDevToolsModal } from "./react-query/components/ReactQueryDevToolsModal";
|
|
58
|
+
|
|
59
|
+
// Shared data viewer components
|
|
60
|
+
export { VirtualizedDataExplorer, DataViewer, TypeLegend } from "@buoy-gg/shared-ui/dataViewer";
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// HOOKS (For consuming React Query data)
|
|
64
|
+
// =============================================================================
|
|
65
|
+
export { default as useAllQueries } from "./react-query/hooks/useAllQueries";
|
|
66
|
+
export { default as useAllMutations } from "./react-query/hooks/useAllMutations";
|
|
67
|
+
export { useGetQueryByQueryKey, useGetQueryByQueryKeyWithVersion } from "./react-query/hooks/useSelectedQuery";
|
|
68
|
+
export { useGetMutationById } from "./react-query/hooks/useSelectedMutation";
|
|
69
|
+
export { default as useQueryStatusCounts } from "./react-query/hooks/useQueryStatusCounts";
|
|
70
|
+
export { useStorageQueryCounts } from "./react-query/hooks/useStorageQueryCounts";
|
|
71
|
+
export { useReactQueryState } from "./react-query/hooks/useReactQueryState";
|
|
72
|
+
export { useActionButtons } from "./react-query/hooks/useActionButtons";
|
|
73
|
+
export { useMutationActionButtons } from "./react-query/hooks/useMutationActionButtons";
|
|
74
|
+
export { useModalManager } from "./react-query/hooks/useModalManager";
|
|
75
|
+
export { useModalPersistence } from "./react-query/hooks/useModalPersistence";
|
|
76
|
+
export { useWifiState } from "./react-query/hooks/useWifiState";
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// UTILITIES (Public helpers only)
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
// Action utilities
|
|
83
|
+
export { default as invalidate } from "./react-query/utils/actions/invalidate";
|
|
84
|
+
export { default as refetch } from "./react-query/utils/actions/refetch";
|
|
85
|
+
export { default as reset } from "./react-query/utils/actions/reset";
|
|
86
|
+
export { default as remove } from "./react-query/utils/actions/remove";
|
|
87
|
+
export { default as deleteItem } from "./react-query/utils/actions/deleteItem";
|
|
88
|
+
export { default as triggerError } from "./react-query/utils/actions/triggerError";
|
|
89
|
+
export { default as triggerLoading } from "./react-query/utils/actions/triggerLoading";
|
|
90
|
+
|
|
91
|
+
// Query status utilities
|
|
92
|
+
export * from "./react-query/utils/getQueryStatusLabel";
|
|
93
|
+
export * from "./react-query/utils/getQueryStatusColor";
|
|
94
|
+
|
|
95
|
+
// Storage utilities
|
|
96
|
+
export * from "./react-query/utils/getStorageQueryCounts";
|
|
97
|
+
export * from "./react-query/utils/storageQueryUtils";
|
|
98
|
+
export * from "./react-query/utils/modalStorageOperations";
|
|
99
|
+
|
|
100
|
+
// Data manipulation utilities
|
|
101
|
+
export * from "./react-query/utils/updateNestedDataByPath";
|
|
102
|
+
export * from "./react-query/utils/deleteNestedDataByPath";
|
|
103
|
+
export { safeStringify, displayValue, parseDisplayValue } from "@buoy-gg/shared-ui";
|
|
104
|
+
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// TYPES
|
|
107
|
+
// =============================================================================
|
|
108
|
+
|
|
109
|
+
export { isPlainObject } from "./react-query/types/types";
|
|
110
|
+
|
|
111
|
+
// =============================================================================
|
|
112
|
+
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
113
|
+
// =============================================================================
|
|
114
|
+
/** @internal */
|
|
115
|
+
export { reactQueryEventStore } from "./react-query/stores/reactQueryEventStore";
|
|
116
|
+
|
|
117
|
+
// =============================================================================
|
|
118
|
+
// NOT EXPORTED (Internal controls)
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// The following are intentionally NOT exported to prevent bypassing:
|
|
121
|
+
// - getReactQueryEvents (internal store access)
|
|
122
|
+
// - subscribeToReactQueryEvents (internal subscription)
|
|
123
|
+
// - clearReactQueryEvents (internal store control)
|
|
124
|
+
// - isReactQueryConnected (internal state query)
|
package/lib/module/preset.js
CHANGED
|
@@ -21,7 +21,7 @@ import { QueryIcon } from "@buoy-gg/floating-tools-core";
|
|
|
21
21
|
import { Wifi } from "@buoy-gg/shared-ui";
|
|
22
22
|
import { ReactQueryDevToolsModal } from "./react-query/components/ReactQueryDevToolsModal";
|
|
23
23
|
import { onlineManager } from "@tanstack/react-query";
|
|
24
|
-
import { devToolsStorageKeys,
|
|
24
|
+
import { devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
|
|
25
25
|
|
|
26
26
|
// Empty component for toggle-only mode
|
|
27
27
|
const EmptyComponent = () => null;
|
|
@@ -29,7 +29,7 @@ const EmptyComponent = () => null;
|
|
|
29
29
|
// Save WiFi state to storage
|
|
30
30
|
const saveWifiState = async enabled => {
|
|
31
31
|
try {
|
|
32
|
-
await
|
|
32
|
+
await persistentStorage.setItem(devToolsStorageKeys.settings.wifiEnabled(), enabled.toString());
|
|
33
33
|
} catch (error) {
|
|
34
34
|
// Failed to save WiFi state
|
|
35
35
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useState } from "react";
|
|
3
|
+
import { useCallback, useState, useEffect } from "react";
|
|
4
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
4
5
|
import { ReactQueryModal } from "./modals/ReactQueryModal";
|
|
6
|
+
import { reactQueryEventStore } from "../stores/reactQueryEventStore";
|
|
5
7
|
|
|
6
8
|
/** Configuration options for the high-level React Query dev tools modal wrapper. */
|
|
7
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -15,6 +17,16 @@ export function ReactQueryDevToolsModal({
|
|
|
15
17
|
onMinimize,
|
|
16
18
|
enableSharedModalDimensions = true
|
|
17
19
|
}) {
|
|
20
|
+
// Get QueryClient and connect to event store for unified Events DevTools
|
|
21
|
+
const queryClient = useQueryClient();
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
// Connect the QueryClient to the event store so events flow to unified Events DevTools
|
|
24
|
+
// Only connect if not already connected (to preserve connection across modal open/close)
|
|
25
|
+
if (!reactQueryEventStore.isConnected()) {
|
|
26
|
+
reactQueryEventStore.setQueryClient(queryClient);
|
|
27
|
+
}
|
|
28
|
+
// Don't disconnect on unmount - keep the connection for unified Events DevTools
|
|
29
|
+
}, [queryClient]);
|
|
18
30
|
const [selectedQueryKey, setSelectedQueryKey] = useState(undefined);
|
|
19
31
|
const [selectedMutationId, setSelectedMutationId] = useState(undefined);
|
|
20
32
|
const [activeFilter, setActiveFilter] = useState(null);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
4
|
import { useCallback, useState, useRef } from "react";
|
|
4
5
|
import { useGetMutationById } from "../../hooks/useSelectedMutation";
|
|
5
6
|
import { MutationBrowserMode } from "../MutationBrowserMode";
|
|
@@ -27,11 +28,18 @@ export function MutationBrowserModal({
|
|
|
27
28
|
searchText = "",
|
|
28
29
|
onSearchChange
|
|
29
30
|
}) {
|
|
31
|
+
const queryClient = useQueryClient();
|
|
30
32
|
const selectedMutation = useGetMutationById(selectedMutationId);
|
|
31
33
|
const [internalActiveFilter, setInternalActiveFilter] = useState(null);
|
|
32
34
|
const activeFilter = externalActiveFilter ?? internalActiveFilter;
|
|
33
35
|
const setActiveFilter = externalOnFilterChange ?? setInternalActiveFilter;
|
|
34
36
|
|
|
37
|
+
// Clear mutation cache handler
|
|
38
|
+
const handleClearCache = useCallback(() => {
|
|
39
|
+
queryClient.getMutationCache().clear();
|
|
40
|
+
onMutationSelect(undefined);
|
|
41
|
+
}, [queryClient, onMutationSelect]);
|
|
42
|
+
|
|
35
43
|
// Track modal mode for conditional styling
|
|
36
44
|
// Initialize with bottomSheet but it will be updated from persisted state if available
|
|
37
45
|
const [modalMode, setModalMode] = useState("bottomSheet");
|
|
@@ -95,7 +103,8 @@ export function MutationBrowserModal({
|
|
|
95
103
|
onTabChange: onTabChange,
|
|
96
104
|
onBack: () => onMutationSelect(undefined),
|
|
97
105
|
searchText: searchText,
|
|
98
|
-
onSearchChange: onSearchChange
|
|
106
|
+
onSearchChange: onSearchChange,
|
|
107
|
+
onClearCache: handleClearCache
|
|
99
108
|
});
|
|
100
109
|
const footerNode = /*#__PURE__*/_jsx(MutationBrowserFooter, {
|
|
101
110
|
activeFilter: activeFilter,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
4
|
import { JsModal, ModalHeader, TabSelector } from "@buoy-gg/shared-ui";
|
|
4
5
|
import { useGetQueryByQueryKey } from "../../hooks/useSelectedQuery";
|
|
5
6
|
import { ReactQueryModalHeader } from "./ReactQueryModalHeader";
|
|
@@ -8,7 +9,7 @@ import { QueryBrowserFooter } from "./QueryBrowserFooter";
|
|
|
8
9
|
import { QueryFilterViewV3 } from "../QueryFilterViewV3";
|
|
9
10
|
import { useState, useCallback, useEffect } from "react";
|
|
10
11
|
import { View, StyleSheet } from "react-native";
|
|
11
|
-
import { devToolsStorageKeys,
|
|
12
|
+
import { devToolsStorageKeys, persistentStorage, buoyColors } from "@buoy-gg/shared-ui";
|
|
12
13
|
import useAllQueries from "../../hooks/useAllQueries";
|
|
13
14
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
15
|
/**
|
|
@@ -28,9 +29,15 @@ export function QueryBrowserModal({
|
|
|
28
29
|
searchText = "",
|
|
29
30
|
onSearchChange
|
|
30
31
|
}) {
|
|
32
|
+
const queryClient = useQueryClient();
|
|
31
33
|
const selectedQuery = useGetQueryByQueryKey(selectedQueryKey);
|
|
32
34
|
const allQueries = useAllQueries();
|
|
33
35
|
|
|
36
|
+
// Clear query cache handler
|
|
37
|
+
const handleClearCache = useCallback(() => {
|
|
38
|
+
queryClient.getQueryCache().clear();
|
|
39
|
+
}, [queryClient]);
|
|
40
|
+
|
|
34
41
|
// Use external filter state if provided (for persistence), otherwise use internal state
|
|
35
42
|
const [internalActiveFilter, setInternalActiveFilter] = useState(null);
|
|
36
43
|
const activeFilter = externalActiveFilter ?? internalActiveFilter;
|
|
@@ -41,17 +48,11 @@ export function QueryBrowserModal({
|
|
|
41
48
|
const [ignoredPatterns, setIgnoredPatterns] = useState(new Set());
|
|
42
49
|
const [includedPatterns, setIncludedPatterns] = useState(new Set());
|
|
43
50
|
|
|
44
|
-
// AsyncStorage for persisting ignored patterns
|
|
45
|
-
const {
|
|
46
|
-
getItem: safeGetItem,
|
|
47
|
-
setItem: safeSetItem
|
|
48
|
-
} = useSafeAsyncStorage();
|
|
49
|
-
|
|
50
51
|
// Load ignored patterns from storage on mount
|
|
51
52
|
useEffect(() => {
|
|
52
53
|
const loadFilters = async () => {
|
|
53
54
|
try {
|
|
54
|
-
const stored = await
|
|
55
|
+
const stored = await persistentStorage.getItem(devToolsStorageKeys.reactQuery.ignoredPatterns());
|
|
55
56
|
if (stored) {
|
|
56
57
|
const patterns = JSON.parse(stored);
|
|
57
58
|
if (Array.isArray(patterns)) {
|
|
@@ -63,13 +64,13 @@ export function QueryBrowserModal({
|
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
loadFilters();
|
|
66
|
-
}, [
|
|
67
|
+
}, []);
|
|
67
68
|
|
|
68
69
|
// Load included patterns from storage on mount
|
|
69
70
|
useEffect(() => {
|
|
70
71
|
const loadFilters = async () => {
|
|
71
72
|
try {
|
|
72
|
-
const stored = await
|
|
73
|
+
const stored = await persistentStorage.getItem(devToolsStorageKeys.reactQuery.includedPatterns());
|
|
73
74
|
if (stored) {
|
|
74
75
|
const patterns = JSON.parse(stored);
|
|
75
76
|
if (Array.isArray(patterns)) {
|
|
@@ -81,33 +82,33 @@ export function QueryBrowserModal({
|
|
|
81
82
|
}
|
|
82
83
|
};
|
|
83
84
|
loadFilters();
|
|
84
|
-
}, [
|
|
85
|
+
}, []);
|
|
85
86
|
|
|
86
87
|
// Save ignored patterns to storage when they change
|
|
87
88
|
useEffect(() => {
|
|
88
89
|
const saveFilters = async () => {
|
|
89
90
|
try {
|
|
90
91
|
const patterns = Array.from(ignoredPatterns);
|
|
91
|
-
await
|
|
92
|
+
await persistentStorage.setItem(devToolsStorageKeys.reactQuery.ignoredPatterns(), JSON.stringify(patterns));
|
|
92
93
|
} catch (error) {
|
|
93
94
|
console.error("Failed to save ignored patterns:", error);
|
|
94
95
|
}
|
|
95
96
|
};
|
|
96
97
|
saveFilters();
|
|
97
|
-
}, [ignoredPatterns
|
|
98
|
+
}, [ignoredPatterns]);
|
|
98
99
|
|
|
99
100
|
// Save included patterns to storage when they change
|
|
100
101
|
useEffect(() => {
|
|
101
102
|
const saveFilters = async () => {
|
|
102
103
|
try {
|
|
103
104
|
const patterns = Array.from(includedPatterns);
|
|
104
|
-
await
|
|
105
|
+
await persistentStorage.setItem(devToolsStorageKeys.reactQuery.includedPatterns(), JSON.stringify(patterns));
|
|
105
106
|
} catch (error) {
|
|
106
107
|
console.error("Failed to save included patterns:", error);
|
|
107
108
|
}
|
|
108
109
|
};
|
|
109
110
|
saveFilters();
|
|
110
|
-
}, [includedPatterns
|
|
111
|
+
}, [includedPatterns]);
|
|
111
112
|
|
|
112
113
|
// Toggle pattern in ignored set
|
|
113
114
|
const handlePatternToggle = useCallback(pattern => {
|
|
@@ -173,7 +174,8 @@ export function QueryBrowserModal({
|
|
|
173
174
|
searchText: searchText,
|
|
174
175
|
onSearchChange: onSearchChange,
|
|
175
176
|
onFilterPress: () => setShowFilterView(true),
|
|
176
|
-
hasActiveFilters: activeFilter !== null || ignoredPatterns.size > 0 || includedPatterns.size > 0
|
|
177
|
+
hasActiveFilters: activeFilter !== null || ignoredPatterns.size > 0 || includedPatterns.size > 0,
|
|
178
|
+
onClearCache: handleClearCache
|
|
177
179
|
});
|
|
178
180
|
};
|
|
179
181
|
const footerNode = /*#__PURE__*/_jsx(QueryBrowserFooter, {
|