@syncular/console 0.0.6-159 → 0.0.6-168
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/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useConsoleApi.d.ts +113 -97
- package/dist/hooks/useConsoleApi.d.ts.map +1 -1
- package/dist/hooks/useConsoleApi.js +368 -520
- package/dist/hooks/useConsoleApi.js.map +1 -1
- package/dist/hooks/useLiveEvents.d.ts.map +1 -1
- package/dist/hooks/useLiveEvents.js +2 -94
- package/dist/hooks/useLiveEvents.js.map +1 -1
- package/dist/lib/topology.d.ts +2 -2
- package/dist/lib/topology.d.ts.map +1 -1
- package/dist/lib/topology.js.map +1 -1
- package/dist/lib/types.d.ts +58 -170
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +1 -1
- package/dist/pages/Config.d.ts.map +1 -1
- package/dist/pages/Config.js +2 -1
- package/dist/pages/Config.js.map +1 -1
- package/package.json +4 -4
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useConsoleApi.ts +552 -756
- package/src/hooks/useLiveEvents.ts +2 -115
- package/src/lib/topology.ts +3 -3
- package/src/lib/types.ts +104 -187
- package/src/pages/Config.tsx +3 -1
- package/web-dist/assets/index-DYjezUNM.js +86 -0
- package/web-dist/index.html +1 -1
- package/dist/hooks/useRequestEvents.d.ts +0 -7
- package/dist/hooks/useRequestEvents.d.ts.map +0 -1
- package/dist/hooks/useRequestEvents.js +0 -33
- package/dist/hooks/useRequestEvents.js.map +0 -1
- package/src/hooks/useRequestEvents.ts +0 -35
- package/web-dist/assets/index-DWD8MzCy.js +0 -86
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* React Query hooks for Console API
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { unwrap } from '@syncular/transport-http';
|
|
6
5
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
6
|
+
import type { ConnectionConfig } from '../lib/api';
|
|
7
7
|
import type {
|
|
8
|
+
ApiKeyType,
|
|
8
9
|
ConsoleApiKey,
|
|
9
10
|
ConsoleApiKeyBulkRevokeResponse,
|
|
10
11
|
ConsoleBlobListResponse,
|
|
@@ -25,57 +26,89 @@ import type {
|
|
|
25
26
|
TimeseriesRange,
|
|
26
27
|
TimeseriesStatsResponse,
|
|
27
28
|
} from '../lib/types';
|
|
28
|
-
import {
|
|
29
|
+
import { useConnection } from './ConnectionContext';
|
|
29
30
|
import { useInstanceContext } from './useInstanceContext';
|
|
30
31
|
|
|
32
|
+
type StatsParams = {
|
|
33
|
+
partitionId?: string;
|
|
34
|
+
instanceId?: string;
|
|
35
|
+
};
|
|
36
|
+
type TimeseriesParams = {
|
|
37
|
+
interval?: TimeseriesInterval;
|
|
38
|
+
range?: TimeseriesRange;
|
|
39
|
+
partitionId?: string;
|
|
40
|
+
instanceId?: string;
|
|
41
|
+
};
|
|
42
|
+
type LatencyParams = {
|
|
43
|
+
range?: TimeseriesRange;
|
|
44
|
+
partitionId?: string;
|
|
45
|
+
instanceId?: string;
|
|
46
|
+
};
|
|
47
|
+
type ListParams = {
|
|
48
|
+
limit?: number;
|
|
49
|
+
offset?: number;
|
|
50
|
+
partitionId?: string;
|
|
51
|
+
instanceId?: string;
|
|
52
|
+
};
|
|
53
|
+
type TimelineParams = ListParams & {
|
|
54
|
+
view?: 'all' | 'commits' | 'events';
|
|
55
|
+
eventType?: 'push' | 'pull';
|
|
56
|
+
actorId?: string;
|
|
57
|
+
clientId?: string;
|
|
58
|
+
requestId?: string;
|
|
59
|
+
traceId?: string;
|
|
60
|
+
table?: string;
|
|
61
|
+
outcome?: string;
|
|
62
|
+
search?: string;
|
|
63
|
+
from?: string;
|
|
64
|
+
to?: string;
|
|
65
|
+
};
|
|
66
|
+
type EntityLookupOptions = {
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
partitionId?: string;
|
|
69
|
+
instanceId?: string;
|
|
70
|
+
};
|
|
71
|
+
type RefetchableQueryOptions = {
|
|
72
|
+
refetchIntervalMs?: number;
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
};
|
|
75
|
+
type PrunePreviewOptions = {
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
instanceId?: string;
|
|
78
|
+
};
|
|
79
|
+
type OperationEventsParams = ListParams & {
|
|
80
|
+
operationType?: ConsoleOperationType;
|
|
81
|
+
};
|
|
82
|
+
type ApiKeysParams = {
|
|
83
|
+
limit?: number;
|
|
84
|
+
offset?: number;
|
|
85
|
+
type?: 'relay' | 'proxy' | 'admin';
|
|
86
|
+
status?: 'active' | 'revoked' | 'expiring';
|
|
87
|
+
expiresWithinDays?: number;
|
|
88
|
+
instanceId?: string;
|
|
89
|
+
};
|
|
90
|
+
type BlobsOptions = {
|
|
91
|
+
prefix?: string;
|
|
92
|
+
cursor?: string;
|
|
93
|
+
limit?: number;
|
|
94
|
+
refetchIntervalMs?: number;
|
|
95
|
+
};
|
|
96
|
+
|
|
31
97
|
const queryKeys = {
|
|
32
|
-
stats: (params?:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
instanceId?: string;
|
|
39
|
-
}) => ['console', 'stats', 'timeseries', params] as const,
|
|
40
|
-
latency: (params?: {
|
|
41
|
-
range?: TimeseriesRange;
|
|
42
|
-
partitionId?: string;
|
|
43
|
-
instanceId?: string;
|
|
44
|
-
}) => ['console', 'stats', 'latency', params] as const,
|
|
45
|
-
commits: (params?: {
|
|
46
|
-
limit?: number;
|
|
47
|
-
offset?: number;
|
|
48
|
-
partitionId?: string;
|
|
49
|
-
instanceId?: string;
|
|
50
|
-
}) => ['console', 'commits', params] as const,
|
|
98
|
+
stats: (params?: StatsParams) => ['console', 'stats', params] as const,
|
|
99
|
+
timeseries: (params?: TimeseriesParams) =>
|
|
100
|
+
['console', 'stats', 'timeseries', params] as const,
|
|
101
|
+
latency: (params?: LatencyParams) =>
|
|
102
|
+
['console', 'stats', 'latency', params] as const,
|
|
103
|
+
commits: (params?: ListParams) => ['console', 'commits', params] as const,
|
|
51
104
|
commitDetail: (
|
|
52
105
|
seq?: string | number,
|
|
53
106
|
partitionId?: string,
|
|
54
107
|
instanceId?: string
|
|
55
108
|
) => ['console', 'commit-detail', seq, partitionId, instanceId] as const,
|
|
56
|
-
timeline: (params?:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
partitionId?: string;
|
|
60
|
-
instanceId?: string;
|
|
61
|
-
view?: 'all' | 'commits' | 'events';
|
|
62
|
-
eventType?: 'push' | 'pull';
|
|
63
|
-
actorId?: string;
|
|
64
|
-
clientId?: string;
|
|
65
|
-
requestId?: string;
|
|
66
|
-
traceId?: string;
|
|
67
|
-
table?: string;
|
|
68
|
-
outcome?: string;
|
|
69
|
-
search?: string;
|
|
70
|
-
from?: string;
|
|
71
|
-
to?: string;
|
|
72
|
-
}) => ['console', 'timeline', params] as const,
|
|
73
|
-
clients: (params?: {
|
|
74
|
-
limit?: number;
|
|
75
|
-
offset?: number;
|
|
76
|
-
partitionId?: string;
|
|
77
|
-
instanceId?: string;
|
|
78
|
-
}) => ['console', 'clients', params] as const,
|
|
109
|
+
timeline: (params?: TimelineParams) =>
|
|
110
|
+
['console', 'timeline', params] as const,
|
|
111
|
+
clients: (params?: ListParams) => ['console', 'clients', params] as const,
|
|
79
112
|
eventDetail: (
|
|
80
113
|
id?: string | number,
|
|
81
114
|
partitionId?: string,
|
|
@@ -90,21 +123,9 @@ const queryKeys = {
|
|
|
90
123
|
['console', 'handlers', instanceId] as const,
|
|
91
124
|
prunePreview: (instanceId?: string) =>
|
|
92
125
|
['console', 'prune', 'preview', instanceId] as const,
|
|
93
|
-
operations: (params?:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
operationType?: ConsoleOperationType;
|
|
97
|
-
partitionId?: string;
|
|
98
|
-
instanceId?: string;
|
|
99
|
-
}) => ['console', 'operations', params] as const,
|
|
100
|
-
apiKeys: (params?: {
|
|
101
|
-
limit?: number;
|
|
102
|
-
offset?: number;
|
|
103
|
-
type?: 'relay' | 'proxy' | 'admin';
|
|
104
|
-
status?: 'active' | 'revoked' | 'expiring';
|
|
105
|
-
expiresWithinDays?: number;
|
|
106
|
-
instanceId?: string;
|
|
107
|
-
}) => ['console', 'api-keys', params] as const,
|
|
126
|
+
operations: (params?: OperationEventsParams) =>
|
|
127
|
+
['console', 'operations', params] as const,
|
|
128
|
+
apiKeys: (params?: ApiKeysParams) => ['console', 'api-keys', params] as const,
|
|
108
129
|
storage: (params?: Record<string, unknown>) =>
|
|
109
130
|
['console', 'storage', params] as const,
|
|
110
131
|
};
|
|
@@ -117,220 +138,305 @@ function resolveRefetchInterval(
|
|
|
117
138
|
return refreshIntervalMs ?? defaultValueMs;
|
|
118
139
|
}
|
|
119
140
|
|
|
120
|
-
|
|
141
|
+
type ConsoleQueryValue = string | number | boolean | null | undefined;
|
|
142
|
+
type QueryKey = readonly unknown[];
|
|
143
|
+
type EvictClientRequest = {
|
|
144
|
+
clientId: string;
|
|
145
|
+
partitionId?: string;
|
|
121
146
|
instanceId?: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
instanceId
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
};
|
|
148
|
+
type NotifyDataChangeRequest = {
|
|
149
|
+
tables: string[];
|
|
150
|
+
partitionId?: string;
|
|
151
|
+
instanceId?: string;
|
|
152
|
+
};
|
|
153
|
+
type CreateApiKeyRequest = {
|
|
154
|
+
name: string;
|
|
155
|
+
keyType: ApiKeyType;
|
|
156
|
+
scopeKeys?: string[];
|
|
157
|
+
actorId?: string;
|
|
158
|
+
expiresInDays?: number;
|
|
159
|
+
};
|
|
160
|
+
type ApiKeySecretResponse = { key: ConsoleApiKey; secretKey: string };
|
|
161
|
+
|
|
162
|
+
function buildQueryString(
|
|
163
|
+
query: Record<string, ConsoleQueryValue> | undefined
|
|
164
|
+
): URLSearchParams {
|
|
165
|
+
const params = new URLSearchParams();
|
|
166
|
+
if (!query) return params;
|
|
167
|
+
for (const [key, value] of Object.entries(query)) {
|
|
168
|
+
if (value === undefined || value === null) continue;
|
|
169
|
+
params.set(key, String(value));
|
|
170
|
+
}
|
|
171
|
+
return params;
|
|
134
172
|
}
|
|
135
173
|
|
|
136
174
|
function buildConsoleUrl(
|
|
137
175
|
serverUrl: string,
|
|
138
176
|
path: string,
|
|
139
|
-
|
|
177
|
+
query?: Record<string, ConsoleQueryValue>
|
|
140
178
|
): string {
|
|
141
179
|
const baseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl;
|
|
180
|
+
const queryString = buildQueryString(query);
|
|
142
181
|
const suffix = queryString?.toString();
|
|
143
182
|
return `${baseUrl}${path}${suffix ? `?${suffix}` : ''}`;
|
|
144
183
|
}
|
|
145
184
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
185
|
+
function requireConnection(
|
|
186
|
+
connectionConfig: ConnectionConfig | null,
|
|
187
|
+
isConnected: boolean
|
|
188
|
+
): ConnectionConfig {
|
|
189
|
+
if (!isConnected || !connectionConfig) throw new Error('Not connected');
|
|
190
|
+
return connectionConfig;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function fetchConsoleJson<T>(args: {
|
|
194
|
+
connectionConfig: ConnectionConfig;
|
|
195
|
+
path: string;
|
|
196
|
+
query?: Record<string, ConsoleQueryValue>;
|
|
197
|
+
method?: 'GET' | 'POST' | 'DELETE';
|
|
198
|
+
body?: unknown;
|
|
199
|
+
errorMessage: string;
|
|
200
|
+
}): Promise<T> {
|
|
201
|
+
const headers: Record<string, string> = {
|
|
202
|
+
Authorization: `Bearer ${args.connectionConfig.token}`,
|
|
203
|
+
};
|
|
204
|
+
if (args.body !== undefined) {
|
|
205
|
+
headers['Content-Type'] = 'application/json';
|
|
206
|
+
}
|
|
207
|
+
const response = await fetch(
|
|
208
|
+
buildConsoleUrl(args.connectionConfig.serverUrl, args.path, args.query),
|
|
209
|
+
{
|
|
210
|
+
method: args.method ?? 'GET',
|
|
211
|
+
headers,
|
|
212
|
+
body: args.body === undefined ? undefined : JSON.stringify(args.body),
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
if (!response.ok) throw new Error(args.errorMessage);
|
|
216
|
+
return response.json();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function fetchConsoleBlob(args: {
|
|
220
|
+
connectionConfig: ConnectionConfig;
|
|
221
|
+
path: string;
|
|
222
|
+
query?: Record<string, ConsoleQueryValue>;
|
|
223
|
+
errorMessage: string;
|
|
224
|
+
}): Promise<Blob> {
|
|
225
|
+
const response = await fetch(
|
|
226
|
+
buildConsoleUrl(args.connectionConfig.serverUrl, args.path, args.query),
|
|
227
|
+
{
|
|
228
|
+
method: 'GET',
|
|
229
|
+
headers: { Authorization: `Bearer ${args.connectionConfig.token}` },
|
|
230
|
+
}
|
|
159
231
|
);
|
|
232
|
+
if (!response.ok) throw new Error(args.errorMessage);
|
|
233
|
+
return response.blob();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function useConsoleJsonQuery<T>(options: {
|
|
237
|
+
queryKey: QueryKey;
|
|
238
|
+
path: string;
|
|
239
|
+
query?: Record<string, ConsoleQueryValue>;
|
|
240
|
+
method?: 'GET' | 'POST' | 'DELETE';
|
|
241
|
+
errorMessage: string;
|
|
242
|
+
enabled?: boolean;
|
|
243
|
+
refetchInterval?: number | false;
|
|
244
|
+
}) {
|
|
245
|
+
const { config: connectionConfig, isConnected } = useConnection();
|
|
246
|
+
|
|
247
|
+
return useQuery<T>({
|
|
248
|
+
queryKey: options.queryKey,
|
|
249
|
+
queryFn: () =>
|
|
250
|
+
fetchConsoleJson<T>({
|
|
251
|
+
connectionConfig: requireConnection(connectionConfig, isConnected),
|
|
252
|
+
path: options.path,
|
|
253
|
+
query: options.query,
|
|
254
|
+
method: options.method,
|
|
255
|
+
errorMessage: options.errorMessage,
|
|
256
|
+
}),
|
|
257
|
+
enabled: (options.enabled ?? true) && isConnected && !!connectionConfig,
|
|
258
|
+
refetchInterval: options.refetchInterval,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function useConsoleEntityQuery<T>(options: {
|
|
263
|
+
queryKey: QueryKey;
|
|
264
|
+
id: string | number | undefined;
|
|
265
|
+
requiredMessage: string;
|
|
266
|
+
path: (id: string | number) => string;
|
|
267
|
+
query?: Record<string, ConsoleQueryValue>;
|
|
268
|
+
errorMessage: string;
|
|
269
|
+
enabled?: boolean;
|
|
270
|
+
}) {
|
|
271
|
+
const { config: connectionConfig, isConnected } = useConnection();
|
|
272
|
+
|
|
273
|
+
return useQuery<T>({
|
|
274
|
+
queryKey: options.queryKey,
|
|
275
|
+
queryFn: () => {
|
|
276
|
+
if (options.id === undefined) throw new Error(options.requiredMessage);
|
|
277
|
+
return fetchConsoleJson<T>({
|
|
278
|
+
connectionConfig: requireConnection(connectionConfig, isConnected),
|
|
279
|
+
path: options.path(options.id),
|
|
280
|
+
query: options.query,
|
|
281
|
+
errorMessage: options.errorMessage,
|
|
282
|
+
});
|
|
283
|
+
},
|
|
284
|
+
enabled:
|
|
285
|
+
(options.enabled ?? true) &&
|
|
286
|
+
options.id !== undefined &&
|
|
287
|
+
isConnected &&
|
|
288
|
+
!!connectionConfig,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function invalidateConsoleQueries(
|
|
293
|
+
queryClient: ReturnType<typeof useQueryClient>,
|
|
294
|
+
queryKeysToInvalidate: ReadonlyArray<QueryKey>
|
|
295
|
+
): void {
|
|
296
|
+
for (const queryKey of queryKeysToInvalidate) {
|
|
297
|
+
queryClient.invalidateQueries({ queryKey });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
160
300
|
|
|
161
|
-
|
|
162
|
-
|
|
301
|
+
function useEffectiveInstanceId(instanceId?: string): string | undefined {
|
|
302
|
+
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
303
|
+
return instanceId ?? selectedInstanceId;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function useConsoleJsonMutation<TResult, TVariables>(options: {
|
|
307
|
+
mutationFn: (args: {
|
|
308
|
+
connectionConfig: ConnectionConfig;
|
|
309
|
+
variables: TVariables;
|
|
310
|
+
selectedInstanceId?: string;
|
|
311
|
+
}) => Promise<TResult>;
|
|
312
|
+
invalidateQueryKeys?: ReadonlyArray<QueryKey>;
|
|
313
|
+
}) {
|
|
314
|
+
const { config: connectionConfig, isConnected } = useConnection();
|
|
315
|
+
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
316
|
+
const queryClient = useQueryClient();
|
|
317
|
+
|
|
318
|
+
return useMutation<TResult, Error, TVariables>({
|
|
319
|
+
mutationFn: (variables) =>
|
|
320
|
+
options.mutationFn({
|
|
321
|
+
connectionConfig: requireConnection(connectionConfig, isConnected),
|
|
322
|
+
variables,
|
|
323
|
+
selectedInstanceId,
|
|
324
|
+
}),
|
|
325
|
+
onSuccess: () => {
|
|
326
|
+
if (!options.invalidateQueryKeys) return;
|
|
327
|
+
invalidateConsoleQueries(queryClient, options.invalidateQueryKeys);
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function useStats(
|
|
333
|
+
options: StatsParams & { refetchIntervalMs?: number } = {}
|
|
334
|
+
) {
|
|
335
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
336
|
+
return useConsoleJsonQuery<SyncStats>({
|
|
337
|
+
queryKey: queryKeys.stats({ partitionId: options.partitionId, instanceId }),
|
|
338
|
+
path: '/console/stats',
|
|
339
|
+
query: {
|
|
163
340
|
partitionId: options.partitionId,
|
|
164
341
|
instanceId,
|
|
165
|
-
}),
|
|
166
|
-
queryFn: () => {
|
|
167
|
-
if (!client) throw new Error('Not connected');
|
|
168
|
-
return unwrap(client.GET('/console/stats', { params: { query } }));
|
|
169
342
|
},
|
|
170
|
-
|
|
343
|
+
errorMessage: 'Failed to fetch stats',
|
|
171
344
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 5000),
|
|
172
345
|
});
|
|
173
346
|
}
|
|
174
347
|
|
|
175
348
|
export function useTimeseriesStats(
|
|
176
|
-
params: {
|
|
177
|
-
|
|
178
|
-
range?: TimeseriesRange;
|
|
179
|
-
partitionId?: string;
|
|
180
|
-
instanceId?: string;
|
|
181
|
-
} = {},
|
|
182
|
-
options: { refetchIntervalMs?: number; enabled?: boolean } = {}
|
|
349
|
+
params: TimeseriesParams = {},
|
|
350
|
+
options: RefetchableQueryOptions = {}
|
|
183
351
|
) {
|
|
184
|
-
const
|
|
185
|
-
const { config: connectionConfig } = useConnection();
|
|
186
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
187
|
-
const instanceId = params.instanceId ?? selectedInstanceId;
|
|
352
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
188
353
|
|
|
189
|
-
return
|
|
354
|
+
return useConsoleJsonQuery<TimeseriesStatsResponse>({
|
|
190
355
|
queryKey: queryKeys.timeseries({ ...params, instanceId }),
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (params.partitionId)
|
|
198
|
-
queryString.set('partitionId', params.partitionId);
|
|
199
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
200
|
-
const response = await fetch(
|
|
201
|
-
`${connectionConfig.serverUrl}/console/stats/timeseries?${queryString}`,
|
|
202
|
-
{ headers: { Authorization: `Bearer ${connectionConfig.token}` } }
|
|
203
|
-
);
|
|
204
|
-
if (!response.ok) throw new Error('Failed to fetch timeseries stats');
|
|
205
|
-
return response.json();
|
|
356
|
+
path: '/console/stats/timeseries',
|
|
357
|
+
query: {
|
|
358
|
+
interval: params.interval,
|
|
359
|
+
range: params.range,
|
|
360
|
+
partitionId: params.partitionId,
|
|
361
|
+
instanceId,
|
|
206
362
|
},
|
|
207
|
-
|
|
363
|
+
errorMessage: 'Failed to fetch timeseries stats',
|
|
364
|
+
enabled: options.enabled,
|
|
208
365
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 30000),
|
|
209
366
|
});
|
|
210
367
|
}
|
|
211
368
|
|
|
212
369
|
export function useLatencyStats(
|
|
213
|
-
params: {
|
|
214
|
-
|
|
215
|
-
partitionId?: string;
|
|
216
|
-
instanceId?: string;
|
|
217
|
-
} = {},
|
|
218
|
-
options: { refetchIntervalMs?: number; enabled?: boolean } = {}
|
|
370
|
+
params: LatencyParams = {},
|
|
371
|
+
options: RefetchableQueryOptions = {}
|
|
219
372
|
) {
|
|
220
|
-
const
|
|
221
|
-
const { config: connectionConfig } = useConnection();
|
|
222
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
223
|
-
const instanceId = params.instanceId ?? selectedInstanceId;
|
|
373
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
224
374
|
|
|
225
|
-
return
|
|
375
|
+
return useConsoleJsonQuery<LatencyStatsResponse>({
|
|
226
376
|
queryKey: queryKeys.latency({ ...params, instanceId }),
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (params.partitionId)
|
|
233
|
-
queryString.set('partitionId', params.partitionId);
|
|
234
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
235
|
-
const response = await fetch(
|
|
236
|
-
`${connectionConfig.serverUrl}/console/stats/latency?${queryString}`,
|
|
237
|
-
{ headers: { Authorization: `Bearer ${connectionConfig.token}` } }
|
|
238
|
-
);
|
|
239
|
-
if (!response.ok) throw new Error('Failed to fetch latency stats');
|
|
240
|
-
return response.json();
|
|
377
|
+
path: '/console/stats/latency',
|
|
378
|
+
query: {
|
|
379
|
+
range: params.range,
|
|
380
|
+
partitionId: params.partitionId,
|
|
381
|
+
instanceId,
|
|
241
382
|
},
|
|
242
|
-
|
|
383
|
+
errorMessage: 'Failed to fetch latency stats',
|
|
384
|
+
enabled: options.enabled,
|
|
243
385
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 30000),
|
|
244
386
|
});
|
|
245
387
|
}
|
|
246
388
|
|
|
247
389
|
export function useCommits(
|
|
248
|
-
params: {
|
|
249
|
-
|
|
250
|
-
offset?: number;
|
|
251
|
-
partitionId?: string;
|
|
252
|
-
instanceId?: string;
|
|
253
|
-
} = {},
|
|
254
|
-
options: { refetchIntervalMs?: number; enabled?: boolean } = {}
|
|
390
|
+
params: ListParams = {},
|
|
391
|
+
options: RefetchableQueryOptions = {}
|
|
255
392
|
) {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
393
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
394
|
+
|
|
395
|
+
return useConsoleJsonQuery<PaginatedResponse<ConsoleCommitListItem>>({
|
|
396
|
+
queryKey: queryKeys.commits({ ...params, instanceId }),
|
|
397
|
+
path: '/console/commits',
|
|
398
|
+
query: {
|
|
261
399
|
limit: params.limit,
|
|
262
400
|
offset: params.offset,
|
|
263
401
|
partitionId: params.partitionId,
|
|
402
|
+
instanceId,
|
|
264
403
|
},
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return useQuery<PaginatedResponse<ConsoleCommitListItem>>({
|
|
269
|
-
queryKey: queryKeys.commits({ ...params, instanceId }),
|
|
270
|
-
queryFn: () => {
|
|
271
|
-
if (!client) throw new Error('Not connected');
|
|
272
|
-
return unwrap(client.GET('/console/commits', { params: { query } }));
|
|
273
|
-
},
|
|
274
|
-
enabled: (options.enabled ?? true) && !!client,
|
|
404
|
+
errorMessage: 'Failed to fetch commits',
|
|
405
|
+
enabled: options.enabled,
|
|
275
406
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 10000),
|
|
276
407
|
});
|
|
277
408
|
}
|
|
278
409
|
|
|
279
410
|
export function useCommitDetail(
|
|
280
411
|
seq: string | number | undefined,
|
|
281
|
-
options:
|
|
412
|
+
options: EntityLookupOptions = {}
|
|
282
413
|
) {
|
|
283
|
-
const
|
|
284
|
-
const { config: connectionConfig } = useConnection();
|
|
285
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
286
|
-
const instanceId = options.instanceId ?? selectedInstanceId;
|
|
414
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
287
415
|
|
|
288
|
-
return
|
|
416
|
+
return useConsoleEntityQuery<ConsoleCommitDetail>({
|
|
289
417
|
queryKey: queryKeys.commitDetail(seq, options.partitionId, instanceId),
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
297
|
-
const suffix = queryString.toString();
|
|
298
|
-
const response = await fetch(
|
|
299
|
-
`${connectionConfig.serverUrl}/console/commits/${serializePathSegment(seq)}${suffix ? `?${suffix}` : ''}`,
|
|
300
|
-
{ headers: { Authorization: `Bearer ${connectionConfig.token}` } }
|
|
301
|
-
);
|
|
302
|
-
if (!response.ok) throw new Error('Failed to fetch commit detail');
|
|
303
|
-
return response.json();
|
|
418
|
+
id: seq,
|
|
419
|
+
requiredMessage: 'Commit sequence is required',
|
|
420
|
+
path: (value) => `/console/commits/${encodeURIComponent(String(value))}`,
|
|
421
|
+
query: {
|
|
422
|
+
partitionId: options.partitionId,
|
|
423
|
+
instanceId,
|
|
304
424
|
},
|
|
305
|
-
|
|
425
|
+
errorMessage: 'Failed to fetch commit detail',
|
|
426
|
+
enabled: options.enabled,
|
|
306
427
|
});
|
|
307
428
|
}
|
|
308
429
|
|
|
309
430
|
export function useTimeline(
|
|
310
|
-
params: {
|
|
311
|
-
|
|
312
|
-
offset?: number;
|
|
313
|
-
partitionId?: string;
|
|
314
|
-
instanceId?: string;
|
|
315
|
-
view?: 'all' | 'commits' | 'events';
|
|
316
|
-
eventType?: 'push' | 'pull';
|
|
317
|
-
actorId?: string;
|
|
318
|
-
clientId?: string;
|
|
319
|
-
requestId?: string;
|
|
320
|
-
traceId?: string;
|
|
321
|
-
table?: string;
|
|
322
|
-
outcome?: string;
|
|
323
|
-
search?: string;
|
|
324
|
-
from?: string;
|
|
325
|
-
to?: string;
|
|
326
|
-
} = {},
|
|
327
|
-
options: { refetchIntervalMs?: number; enabled?: boolean } = {}
|
|
431
|
+
params: TimelineParams = {},
|
|
432
|
+
options: RefetchableQueryOptions = {}
|
|
328
433
|
) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
434
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
435
|
+
|
|
436
|
+
return useConsoleJsonQuery<PaginatedResponse<ConsoleTimelineItem>>({
|
|
437
|
+
queryKey: queryKeys.timeline({ ...params, instanceId }),
|
|
438
|
+
path: '/console/timeline',
|
|
439
|
+
query: {
|
|
334
440
|
limit: params.limit,
|
|
335
441
|
offset: params.offset,
|
|
336
442
|
partitionId: params.partitionId,
|
|
@@ -345,586 +451,322 @@ export function useTimeline(
|
|
|
345
451
|
search: params.search,
|
|
346
452
|
from: params.from,
|
|
347
453
|
to: params.to,
|
|
454
|
+
instanceId,
|
|
348
455
|
},
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
return useQuery<PaginatedResponse<ConsoleTimelineItem>>({
|
|
353
|
-
queryKey: queryKeys.timeline({ ...params, instanceId }),
|
|
354
|
-
queryFn: () => {
|
|
355
|
-
if (!client) throw new Error('Not connected');
|
|
356
|
-
return unwrap(client.GET('/console/timeline', { params: { query } }));
|
|
357
|
-
},
|
|
358
|
-
enabled: (options.enabled ?? true) && !!client,
|
|
456
|
+
errorMessage: 'Failed to fetch timeline',
|
|
457
|
+
enabled: options.enabled,
|
|
359
458
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 10000),
|
|
360
459
|
});
|
|
361
460
|
}
|
|
362
461
|
|
|
363
462
|
export function useClients(
|
|
364
|
-
params: {
|
|
365
|
-
|
|
366
|
-
offset?: number;
|
|
367
|
-
partitionId?: string;
|
|
368
|
-
instanceId?: string;
|
|
369
|
-
} = {},
|
|
370
|
-
options: { refetchIntervalMs?: number; enabled?: boolean } = {}
|
|
463
|
+
params: ListParams = {},
|
|
464
|
+
options: RefetchableQueryOptions = {}
|
|
371
465
|
) {
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
466
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
467
|
+
|
|
468
|
+
return useConsoleJsonQuery<PaginatedResponse<ConsoleClient>>({
|
|
469
|
+
queryKey: queryKeys.clients({ ...params, instanceId }),
|
|
470
|
+
path: '/console/clients',
|
|
471
|
+
query: {
|
|
377
472
|
limit: params.limit,
|
|
378
473
|
offset: params.offset,
|
|
379
474
|
partitionId: params.partitionId,
|
|
475
|
+
instanceId,
|
|
380
476
|
},
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
return useQuery<PaginatedResponse<ConsoleClient>>({
|
|
385
|
-
queryKey: queryKeys.clients({ ...params, instanceId }),
|
|
386
|
-
queryFn: () => {
|
|
387
|
-
if (!client) throw new Error('Not connected');
|
|
388
|
-
return unwrap(client.GET('/console/clients', { params: { query } }));
|
|
389
|
-
},
|
|
390
|
-
enabled: (options.enabled ?? true) && !!client,
|
|
477
|
+
errorMessage: 'Failed to fetch clients',
|
|
478
|
+
enabled: options.enabled,
|
|
391
479
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 10000),
|
|
392
480
|
});
|
|
393
481
|
}
|
|
394
482
|
|
|
395
483
|
export function useRequestEventDetail(
|
|
396
484
|
id: string | number | undefined,
|
|
397
|
-
options:
|
|
485
|
+
options: EntityLookupOptions = {}
|
|
398
486
|
) {
|
|
399
|
-
const
|
|
400
|
-
const { config: connectionConfig } = useConnection();
|
|
401
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
402
|
-
const instanceId = options.instanceId ?? selectedInstanceId;
|
|
487
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
403
488
|
|
|
404
|
-
return
|
|
489
|
+
return useConsoleEntityQuery<ConsoleRequestEvent>({
|
|
405
490
|
queryKey: queryKeys.eventDetail(id, options.partitionId, instanceId),
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
413
|
-
const suffix = queryString.toString();
|
|
414
|
-
const response = await fetch(
|
|
415
|
-
`${connectionConfig.serverUrl}/console/events/${serializePathSegment(id)}${suffix ? `?${suffix}` : ''}`,
|
|
416
|
-
{ headers: { Authorization: `Bearer ${connectionConfig.token}` } }
|
|
417
|
-
);
|
|
418
|
-
if (!response.ok) throw new Error('Failed to fetch event detail');
|
|
419
|
-
return response.json();
|
|
491
|
+
id,
|
|
492
|
+
requiredMessage: 'Event id is required',
|
|
493
|
+
path: (value) => `/console/events/${encodeURIComponent(String(value))}`,
|
|
494
|
+
query: {
|
|
495
|
+
partitionId: options.partitionId,
|
|
496
|
+
instanceId,
|
|
420
497
|
},
|
|
421
|
-
|
|
498
|
+
errorMessage: 'Failed to fetch event detail',
|
|
499
|
+
enabled: options.enabled,
|
|
422
500
|
});
|
|
423
501
|
}
|
|
424
502
|
|
|
425
503
|
export function useRequestEventPayload(
|
|
426
504
|
id: string | number | undefined,
|
|
427
|
-
options:
|
|
505
|
+
options: EntityLookupOptions = {}
|
|
428
506
|
) {
|
|
429
|
-
const
|
|
430
|
-
const { config: connectionConfig } = useConnection();
|
|
431
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
432
|
-
const instanceId = options.instanceId ?? selectedInstanceId;
|
|
507
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
433
508
|
|
|
434
|
-
return
|
|
509
|
+
return useConsoleEntityQuery<ConsoleRequestPayload>({
|
|
435
510
|
queryKey: queryKeys.eventPayload(id, options.partitionId, instanceId),
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const suffix = queryString.toString();
|
|
444
|
-
const response = await fetch(
|
|
445
|
-
`${connectionConfig.serverUrl}/console/events/${serializePathSegment(id)}/payload${suffix ? `?${suffix}` : ''}`,
|
|
446
|
-
{ headers: { Authorization: `Bearer ${connectionConfig.token}` } }
|
|
447
|
-
);
|
|
448
|
-
if (!response.ok) throw new Error('Failed to fetch event payload');
|
|
449
|
-
return response.json();
|
|
511
|
+
id,
|
|
512
|
+
requiredMessage: 'Event id is required',
|
|
513
|
+
path: (value) =>
|
|
514
|
+
`/console/events/${encodeURIComponent(String(value))}/payload`,
|
|
515
|
+
query: {
|
|
516
|
+
partitionId: options.partitionId,
|
|
517
|
+
instanceId,
|
|
450
518
|
},
|
|
451
|
-
|
|
519
|
+
errorMessage: 'Failed to fetch event payload',
|
|
520
|
+
enabled: options.enabled,
|
|
452
521
|
});
|
|
453
522
|
}
|
|
454
523
|
|
|
455
524
|
export function useHandlers(options: { instanceId?: string } = {}) {
|
|
456
|
-
const
|
|
457
|
-
const { config: connectionConfig } = useConnection();
|
|
458
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
459
|
-
const instanceId = options.instanceId ?? selectedInstanceId;
|
|
525
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
460
526
|
|
|
461
|
-
return
|
|
527
|
+
return useConsoleJsonQuery<{ items: ConsoleHandler[] }>({
|
|
462
528
|
queryKey: queryKeys.handlers(instanceId),
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
467
|
-
const response = await fetch(
|
|
468
|
-
buildConsoleUrl(
|
|
469
|
-
connectionConfig.serverUrl,
|
|
470
|
-
'/console/handlers',
|
|
471
|
-
queryString
|
|
472
|
-
),
|
|
473
|
-
{
|
|
474
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
475
|
-
}
|
|
476
|
-
);
|
|
477
|
-
if (!response.ok) throw new Error('Failed to fetch handlers');
|
|
478
|
-
return response.json();
|
|
479
|
-
},
|
|
480
|
-
enabled: !!client && !!connectionConfig,
|
|
529
|
+
path: '/console/handlers',
|
|
530
|
+
query: { instanceId },
|
|
531
|
+
errorMessage: 'Failed to fetch handlers',
|
|
481
532
|
});
|
|
482
533
|
}
|
|
483
534
|
|
|
484
|
-
export function usePrunePreview(
|
|
485
|
-
|
|
486
|
-
) {
|
|
487
|
-
const client = useApiClient();
|
|
488
|
-
const { config: connectionConfig } = useConnection();
|
|
489
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
490
|
-
const instanceId = options.instanceId ?? selectedInstanceId;
|
|
535
|
+
export function usePrunePreview(options: PrunePreviewOptions = {}) {
|
|
536
|
+
const instanceId = useEffectiveInstanceId(options.instanceId);
|
|
491
537
|
|
|
492
|
-
return
|
|
538
|
+
return useConsoleJsonQuery<{
|
|
539
|
+
watermarkCommitSeq: number;
|
|
540
|
+
commitsToDelete: number;
|
|
541
|
+
}>({
|
|
493
542
|
queryKey: queryKeys.prunePreview(instanceId),
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
buildConsoleUrl(
|
|
500
|
-
connectionConfig.serverUrl,
|
|
501
|
-
'/console/prune/preview',
|
|
502
|
-
queryString
|
|
503
|
-
),
|
|
504
|
-
{
|
|
505
|
-
method: 'POST',
|
|
506
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
507
|
-
}
|
|
508
|
-
);
|
|
509
|
-
if (!response.ok) throw new Error('Failed to fetch prune preview');
|
|
510
|
-
return response.json();
|
|
511
|
-
},
|
|
512
|
-
enabled: !!client && !!connectionConfig && (options.enabled ?? true),
|
|
543
|
+
path: '/console/prune/preview',
|
|
544
|
+
query: { instanceId },
|
|
545
|
+
method: 'POST',
|
|
546
|
+
errorMessage: 'Failed to fetch prune preview',
|
|
547
|
+
enabled: options.enabled,
|
|
513
548
|
});
|
|
514
549
|
}
|
|
515
550
|
|
|
516
551
|
export function useOperationEvents(
|
|
517
|
-
params: {
|
|
518
|
-
|
|
519
|
-
offset?: number;
|
|
520
|
-
operationType?: ConsoleOperationType;
|
|
521
|
-
partitionId?: string;
|
|
522
|
-
instanceId?: string;
|
|
523
|
-
} = {},
|
|
524
|
-
options: { enabled?: boolean; refetchIntervalMs?: number } = {}
|
|
552
|
+
params: OperationEventsParams = {},
|
|
553
|
+
options: RefetchableQueryOptions = {}
|
|
525
554
|
) {
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
555
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
556
|
+
|
|
557
|
+
return useConsoleJsonQuery<PaginatedResponse<ConsoleOperationEvent>>({
|
|
558
|
+
queryKey: queryKeys.operations({ ...params, instanceId }),
|
|
559
|
+
path: '/console/operations',
|
|
560
|
+
query: {
|
|
531
561
|
limit: params.limit,
|
|
532
562
|
offset: params.offset,
|
|
533
563
|
operationType: params.operationType,
|
|
534
564
|
partitionId: params.partitionId,
|
|
565
|
+
instanceId,
|
|
535
566
|
},
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return useQuery<PaginatedResponse<ConsoleOperationEvent>>({
|
|
540
|
-
queryKey: queryKeys.operations({ ...params, instanceId }),
|
|
541
|
-
queryFn: () => {
|
|
542
|
-
if (!client) throw new Error('Not connected');
|
|
543
|
-
return unwrap(client.GET('/console/operations', { params: { query } }));
|
|
544
|
-
},
|
|
545
|
-
enabled: (options.enabled ?? true) && !!client,
|
|
567
|
+
errorMessage: 'Failed to fetch operations',
|
|
568
|
+
enabled: options.enabled,
|
|
546
569
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 10000),
|
|
547
570
|
});
|
|
548
571
|
}
|
|
549
572
|
|
|
550
|
-
export function
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
573
|
+
export function useClearEventsMutation() {
|
|
574
|
+
return useConsoleJsonMutation<{ deletedCount: number }, void>({
|
|
575
|
+
mutationFn: async ({ connectionConfig, selectedInstanceId }) =>
|
|
576
|
+
fetchConsoleJson<{ deletedCount: number }>({
|
|
577
|
+
connectionConfig,
|
|
578
|
+
path: '/console/events',
|
|
579
|
+
query: { instanceId: selectedInstanceId },
|
|
580
|
+
method: 'DELETE',
|
|
581
|
+
errorMessage: 'Failed to clear events',
|
|
582
|
+
}),
|
|
583
|
+
invalidateQueryKeys: [['console', 'events']],
|
|
584
|
+
});
|
|
585
|
+
}
|
|
555
586
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
connectionConfig.serverUrl,
|
|
571
|
-
`/console/clients/${serializePathSegment(clientId)}`,
|
|
572
|
-
queryString
|
|
573
|
-
),
|
|
574
|
-
{
|
|
575
|
-
method: 'DELETE',
|
|
576
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
577
|
-
}
|
|
578
|
-
);
|
|
579
|
-
if (!response.ok) throw new Error('Failed to evict client');
|
|
580
|
-
return response.json();
|
|
581
|
-
},
|
|
582
|
-
onSuccess: () => {
|
|
583
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'clients'] });
|
|
584
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'stats'] });
|
|
585
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'operations'] });
|
|
587
|
+
export function useEvictClientMutation() {
|
|
588
|
+
return useConsoleJsonMutation<{ evicted: boolean }, EvictClientRequest>({
|
|
589
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
590
|
+
const effectiveInstanceId = variables.instanceId ?? selectedInstanceId;
|
|
591
|
+
return fetchConsoleJson<{ evicted: boolean }>({
|
|
592
|
+
connectionConfig,
|
|
593
|
+
path: `/console/clients/${encodeURIComponent(variables.clientId)}`,
|
|
594
|
+
query: {
|
|
595
|
+
partitionId: variables.partitionId,
|
|
596
|
+
instanceId: effectiveInstanceId,
|
|
597
|
+
},
|
|
598
|
+
method: 'DELETE',
|
|
599
|
+
errorMessage: 'Failed to evict client',
|
|
600
|
+
});
|
|
586
601
|
},
|
|
602
|
+
invalidateQueryKeys: [
|
|
603
|
+
['console', 'clients'],
|
|
604
|
+
['console', 'stats'],
|
|
605
|
+
['console', 'operations'],
|
|
606
|
+
],
|
|
587
607
|
});
|
|
588
608
|
}
|
|
589
609
|
|
|
590
610
|
export function usePruneMutation() {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
{
|
|
608
|
-
method: 'POST',
|
|
609
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
610
|
-
}
|
|
611
|
-
);
|
|
612
|
-
if (!response.ok) throw new Error('Failed to prune');
|
|
613
|
-
return response.json();
|
|
614
|
-
},
|
|
615
|
-
onSuccess: () => {
|
|
616
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'stats'] });
|
|
617
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'commits'] });
|
|
618
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'timeline'] });
|
|
619
|
-
queryClient.invalidateQueries({
|
|
620
|
-
queryKey: ['console', 'prune', 'preview'],
|
|
621
|
-
});
|
|
622
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'operations'] });
|
|
623
|
-
},
|
|
611
|
+
return useConsoleJsonMutation<{ deletedCommits: number }, void>({
|
|
612
|
+
mutationFn: async ({ connectionConfig, selectedInstanceId }) =>
|
|
613
|
+
fetchConsoleJson<{ deletedCommits: number }>({
|
|
614
|
+
connectionConfig,
|
|
615
|
+
path: '/console/prune',
|
|
616
|
+
query: { instanceId: selectedInstanceId },
|
|
617
|
+
method: 'POST',
|
|
618
|
+
errorMessage: 'Failed to prune',
|
|
619
|
+
}),
|
|
620
|
+
invalidateQueryKeys: [
|
|
621
|
+
['console', 'stats'],
|
|
622
|
+
['console', 'commits'],
|
|
623
|
+
['console', 'timeline'],
|
|
624
|
+
['console', 'prune', 'preview'],
|
|
625
|
+
['console', 'operations'],
|
|
626
|
+
],
|
|
624
627
|
});
|
|
625
628
|
}
|
|
626
629
|
|
|
627
630
|
export function useCompactMutation() {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
'/console/compact',
|
|
642
|
-
queryString
|
|
643
|
-
),
|
|
644
|
-
{
|
|
645
|
-
method: 'POST',
|
|
646
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
647
|
-
}
|
|
648
|
-
);
|
|
649
|
-
if (!response.ok) throw new Error('Failed to compact');
|
|
650
|
-
return response.json();
|
|
651
|
-
},
|
|
652
|
-
onSuccess: () => {
|
|
653
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'stats'] });
|
|
654
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'operations'] });
|
|
655
|
-
},
|
|
631
|
+
return useConsoleJsonMutation<{ deletedChanges: number }, void>({
|
|
632
|
+
mutationFn: async ({ connectionConfig, selectedInstanceId }) =>
|
|
633
|
+
fetchConsoleJson<{ deletedChanges: number }>({
|
|
634
|
+
connectionConfig,
|
|
635
|
+
path: '/console/compact',
|
|
636
|
+
query: { instanceId: selectedInstanceId },
|
|
637
|
+
method: 'POST',
|
|
638
|
+
errorMessage: 'Failed to compact',
|
|
639
|
+
}),
|
|
640
|
+
invalidateQueryKeys: [
|
|
641
|
+
['console', 'stats'],
|
|
642
|
+
['console', 'operations'],
|
|
643
|
+
],
|
|
656
644
|
});
|
|
657
645
|
}
|
|
658
646
|
|
|
659
647
|
export function useNotifyDataChangeMutation() {
|
|
660
|
-
|
|
661
|
-
const { config: connectionConfig } = useConnection();
|
|
662
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
663
|
-
const queryClient = useQueryClient();
|
|
664
|
-
|
|
665
|
-
return useMutation<
|
|
648
|
+
return useConsoleJsonMutation<
|
|
666
649
|
ConsoleNotifyDataChangeResponse,
|
|
667
|
-
|
|
668
|
-
{ tables: string[]; partitionId?: string; instanceId?: string }
|
|
650
|
+
NotifyDataChangeRequest
|
|
669
651
|
>({
|
|
670
|
-
mutationFn: async (
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
method: 'POST',
|
|
684
|
-
headers: {
|
|
685
|
-
Authorization: `Bearer ${connectionConfig.token}`,
|
|
686
|
-
'Content-Type': 'application/json',
|
|
687
|
-
},
|
|
688
|
-
body: JSON.stringify({
|
|
689
|
-
tables: request.tables,
|
|
690
|
-
partitionId: request.partitionId,
|
|
691
|
-
}),
|
|
692
|
-
}
|
|
693
|
-
);
|
|
694
|
-
if (!response.ok) throw new Error('Failed to notify data change');
|
|
695
|
-
return response.json();
|
|
696
|
-
},
|
|
697
|
-
onSuccess: () => {
|
|
698
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'stats'] });
|
|
699
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'commits'] });
|
|
700
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'timeline'] });
|
|
701
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'operations'] });
|
|
652
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
653
|
+
const effectiveInstanceId = variables.instanceId ?? selectedInstanceId;
|
|
654
|
+
return fetchConsoleJson<ConsoleNotifyDataChangeResponse>({
|
|
655
|
+
connectionConfig,
|
|
656
|
+
path: '/console/notify-data-change',
|
|
657
|
+
query: { instanceId: effectiveInstanceId },
|
|
658
|
+
method: 'POST',
|
|
659
|
+
body: {
|
|
660
|
+
tables: variables.tables,
|
|
661
|
+
partitionId: variables.partitionId,
|
|
662
|
+
},
|
|
663
|
+
errorMessage: 'Failed to notify data change',
|
|
664
|
+
});
|
|
702
665
|
},
|
|
666
|
+
invalidateQueryKeys: [
|
|
667
|
+
['console', 'stats'],
|
|
668
|
+
['console', 'commits'],
|
|
669
|
+
['console', 'timeline'],
|
|
670
|
+
['console', 'operations'],
|
|
671
|
+
],
|
|
703
672
|
});
|
|
704
673
|
}
|
|
705
674
|
|
|
706
|
-
export function useApiKeys(
|
|
707
|
-
params
|
|
708
|
-
limit?: number;
|
|
709
|
-
offset?: number;
|
|
710
|
-
type?: 'relay' | 'proxy' | 'admin';
|
|
711
|
-
status?: 'active' | 'revoked' | 'expiring';
|
|
712
|
-
expiresWithinDays?: number;
|
|
713
|
-
instanceId?: string;
|
|
714
|
-
} = {}
|
|
715
|
-
) {
|
|
716
|
-
const client = useApiClient();
|
|
717
|
-
const { config: connectionConfig } = useConnection();
|
|
718
|
-
const { instanceId: selectedInstanceId } = useInstanceContext();
|
|
719
|
-
const instanceId = params.instanceId ?? selectedInstanceId;
|
|
675
|
+
export function useApiKeys(params: ApiKeysParams = {}) {
|
|
676
|
+
const instanceId = useEffectiveInstanceId(params.instanceId);
|
|
720
677
|
|
|
721
|
-
return
|
|
678
|
+
return useConsoleJsonQuery<PaginatedResponse<ConsoleApiKey>>({
|
|
722
679
|
queryKey: queryKeys.apiKeys({ ...params, instanceId }),
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (params.status) queryString.set('status', params.status);
|
|
732
|
-
if (params.expiresWithinDays !== undefined) {
|
|
733
|
-
queryString.set('expiresWithinDays', String(params.expiresWithinDays));
|
|
734
|
-
}
|
|
735
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
736
|
-
|
|
737
|
-
const response = await fetch(
|
|
738
|
-
buildConsoleUrl(
|
|
739
|
-
connectionConfig.serverUrl,
|
|
740
|
-
'/console/api-keys',
|
|
741
|
-
queryString
|
|
742
|
-
),
|
|
743
|
-
{
|
|
744
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
745
|
-
}
|
|
746
|
-
);
|
|
747
|
-
if (!response.ok) throw new Error('Failed to fetch API keys');
|
|
748
|
-
return response.json();
|
|
680
|
+
path: '/console/api-keys',
|
|
681
|
+
query: {
|
|
682
|
+
limit: params.limit,
|
|
683
|
+
offset: params.offset,
|
|
684
|
+
type: params.type,
|
|
685
|
+
status: params.status,
|
|
686
|
+
expiresWithinDays: params.expiresWithinDays,
|
|
687
|
+
instanceId,
|
|
749
688
|
},
|
|
750
|
-
|
|
689
|
+
errorMessage: 'Failed to fetch API keys',
|
|
751
690
|
});
|
|
752
691
|
}
|
|
753
692
|
|
|
754
693
|
export function useCreateApiKeyMutation() {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
keyType: 'relay' | 'proxy' | 'admin';
|
|
766
|
-
scopeKeys?: string[];
|
|
767
|
-
actorId?: string;
|
|
768
|
-
expiresInDays?: number;
|
|
769
|
-
}
|
|
770
|
-
>({
|
|
771
|
-
mutationFn: async (request) => {
|
|
772
|
-
if (!client || !connectionConfig) throw new Error('Not connected');
|
|
773
|
-
const queryString = new URLSearchParams();
|
|
774
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
775
|
-
const response = await fetch(
|
|
776
|
-
buildConsoleUrl(
|
|
777
|
-
connectionConfig.serverUrl,
|
|
778
|
-
'/console/api-keys',
|
|
779
|
-
queryString
|
|
780
|
-
),
|
|
781
|
-
{
|
|
782
|
-
method: 'POST',
|
|
783
|
-
headers: {
|
|
784
|
-
Authorization: `Bearer ${connectionConfig.token}`,
|
|
785
|
-
'Content-Type': 'application/json',
|
|
786
|
-
},
|
|
787
|
-
body: JSON.stringify(request),
|
|
788
|
-
}
|
|
789
|
-
);
|
|
790
|
-
if (!response.ok) throw new Error('Failed to create API key');
|
|
791
|
-
return response.json();
|
|
792
|
-
},
|
|
793
|
-
onSuccess: () => {
|
|
794
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'api-keys'] });
|
|
694
|
+
return useConsoleJsonMutation<ApiKeySecretResponse, CreateApiKeyRequest>({
|
|
695
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
696
|
+
return fetchConsoleJson<ApiKeySecretResponse>({
|
|
697
|
+
connectionConfig,
|
|
698
|
+
path: '/console/api-keys',
|
|
699
|
+
query: { instanceId: selectedInstanceId },
|
|
700
|
+
method: 'POST',
|
|
701
|
+
body: variables,
|
|
702
|
+
errorMessage: 'Failed to create API key',
|
|
703
|
+
});
|
|
795
704
|
},
|
|
705
|
+
invalidateQueryKeys: [['console', 'api-keys']],
|
|
796
706
|
});
|
|
797
707
|
}
|
|
798
708
|
|
|
799
709
|
export function useRevokeApiKeyMutation() {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
810
|
-
const response = await fetch(
|
|
811
|
-
buildConsoleUrl(
|
|
812
|
-
connectionConfig.serverUrl,
|
|
813
|
-
`/console/api-keys/${serializePathSegment(keyId)}`,
|
|
814
|
-
queryString
|
|
815
|
-
),
|
|
816
|
-
{
|
|
817
|
-
method: 'DELETE',
|
|
818
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
819
|
-
}
|
|
820
|
-
);
|
|
821
|
-
if (!response.ok) throw new Error('Failed to revoke API key');
|
|
822
|
-
return response.json();
|
|
823
|
-
},
|
|
824
|
-
onSuccess: () => {
|
|
825
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'api-keys'] });
|
|
710
|
+
return useConsoleJsonMutation<{ revoked: boolean }, string>({
|
|
711
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
712
|
+
return fetchConsoleJson<{ revoked: boolean }>({
|
|
713
|
+
connectionConfig,
|
|
714
|
+
path: `/console/api-keys/${encodeURIComponent(variables)}`,
|
|
715
|
+
query: { instanceId: selectedInstanceId },
|
|
716
|
+
method: 'DELETE',
|
|
717
|
+
errorMessage: 'Failed to revoke API key',
|
|
718
|
+
});
|
|
826
719
|
},
|
|
720
|
+
invalidateQueryKeys: [['console', 'api-keys']],
|
|
827
721
|
});
|
|
828
722
|
}
|
|
829
723
|
|
|
830
724
|
export function useBulkRevokeApiKeysMutation() {
|
|
831
|
-
|
|
832
|
-
const { config: connectionConfig } = useConnection();
|
|
833
|
-
const { instanceId } = useInstanceContext();
|
|
834
|
-
const queryClient = useQueryClient();
|
|
835
|
-
|
|
836
|
-
return useMutation<
|
|
725
|
+
return useConsoleJsonMutation<
|
|
837
726
|
ConsoleApiKeyBulkRevokeResponse,
|
|
838
|
-
Error,
|
|
839
727
|
{ keyIds: string[] }
|
|
840
728
|
>({
|
|
841
|
-
mutationFn: async (
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
),
|
|
851
|
-
{
|
|
852
|
-
method: 'POST',
|
|
853
|
-
headers: {
|
|
854
|
-
Authorization: `Bearer ${connectionConfig.token}`,
|
|
855
|
-
'Content-Type': 'application/json',
|
|
856
|
-
},
|
|
857
|
-
body: JSON.stringify(request),
|
|
858
|
-
}
|
|
859
|
-
);
|
|
860
|
-
if (!response.ok) throw new Error('Failed to bulk revoke API keys');
|
|
861
|
-
return response.json();
|
|
862
|
-
},
|
|
863
|
-
onSuccess: () => {
|
|
864
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'api-keys'] });
|
|
729
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
730
|
+
return fetchConsoleJson<ConsoleApiKeyBulkRevokeResponse>({
|
|
731
|
+
connectionConfig,
|
|
732
|
+
path: '/console/api-keys/bulk-revoke',
|
|
733
|
+
query: { instanceId: selectedInstanceId },
|
|
734
|
+
method: 'POST',
|
|
735
|
+
body: variables,
|
|
736
|
+
errorMessage: 'Failed to bulk revoke API keys',
|
|
737
|
+
});
|
|
865
738
|
},
|
|
739
|
+
invalidateQueryKeys: [['console', 'api-keys']],
|
|
866
740
|
});
|
|
867
741
|
}
|
|
868
742
|
|
|
869
743
|
export function useRotateApiKeyMutation() {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
880
|
-
const response = await fetch(
|
|
881
|
-
buildConsoleUrl(
|
|
882
|
-
connectionConfig.serverUrl,
|
|
883
|
-
`/console/api-keys/${serializePathSegment(keyId)}/rotate`,
|
|
884
|
-
queryString
|
|
885
|
-
),
|
|
886
|
-
{
|
|
887
|
-
method: 'POST',
|
|
888
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
889
|
-
}
|
|
890
|
-
);
|
|
891
|
-
if (!response.ok) throw new Error('Failed to rotate API key');
|
|
892
|
-
return response.json();
|
|
893
|
-
},
|
|
894
|
-
onSuccess: () => {
|
|
895
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'api-keys'] });
|
|
744
|
+
return useConsoleJsonMutation<ApiKeySecretResponse, string>({
|
|
745
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
746
|
+
return fetchConsoleJson<ApiKeySecretResponse>({
|
|
747
|
+
connectionConfig,
|
|
748
|
+
path: `/console/api-keys/${encodeURIComponent(variables)}/rotate`,
|
|
749
|
+
query: { instanceId: selectedInstanceId },
|
|
750
|
+
method: 'POST',
|
|
751
|
+
errorMessage: 'Failed to rotate API key',
|
|
752
|
+
});
|
|
896
753
|
},
|
|
754
|
+
invalidateQueryKeys: [['console', 'api-keys']],
|
|
897
755
|
});
|
|
898
756
|
}
|
|
899
757
|
|
|
900
758
|
export function useStageRotateApiKeyMutation() {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
if (instanceId) queryString.set('instanceId', instanceId);
|
|
911
|
-
const response = await fetch(
|
|
912
|
-
buildConsoleUrl(
|
|
913
|
-
connectionConfig.serverUrl,
|
|
914
|
-
`/console/api-keys/${serializePathSegment(keyId)}/rotate/stage`,
|
|
915
|
-
queryString
|
|
916
|
-
),
|
|
917
|
-
{
|
|
918
|
-
method: 'POST',
|
|
919
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
920
|
-
}
|
|
921
|
-
);
|
|
922
|
-
if (!response.ok) throw new Error('Failed to stage-rotate API key');
|
|
923
|
-
return response.json();
|
|
924
|
-
},
|
|
925
|
-
onSuccess: () => {
|
|
926
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'api-keys'] });
|
|
759
|
+
return useConsoleJsonMutation<ApiKeySecretResponse, string>({
|
|
760
|
+
mutationFn: async ({ connectionConfig, variables, selectedInstanceId }) => {
|
|
761
|
+
return fetchConsoleJson<ApiKeySecretResponse>({
|
|
762
|
+
connectionConfig,
|
|
763
|
+
path: `/console/api-keys/${encodeURIComponent(variables)}/rotate/stage`,
|
|
764
|
+
query: { instanceId: selectedInstanceId },
|
|
765
|
+
method: 'POST',
|
|
766
|
+
errorMessage: 'Failed to stage-rotate API key',
|
|
767
|
+
});
|
|
927
768
|
},
|
|
769
|
+
invalidateQueryKeys: [['console', 'api-keys']],
|
|
928
770
|
});
|
|
929
771
|
}
|
|
930
772
|
|
|
@@ -932,91 +774,45 @@ export function useStageRotateApiKeyMutation() {
|
|
|
932
774
|
// Blob storage hooks
|
|
933
775
|
// ---------------------------------------------------------------------------
|
|
934
776
|
|
|
935
|
-
export function useBlobs(
|
|
936
|
-
|
|
937
|
-
prefix?: string;
|
|
938
|
-
cursor?: string;
|
|
939
|
-
limit?: number;
|
|
940
|
-
refetchIntervalMs?: number;
|
|
941
|
-
} = {}
|
|
942
|
-
) {
|
|
943
|
-
const { config: connectionConfig } = useConnection();
|
|
944
|
-
return useQuery<ConsoleBlobListResponse>({
|
|
777
|
+
export function useBlobs(options: BlobsOptions = {}) {
|
|
778
|
+
return useConsoleJsonQuery<ConsoleBlobListResponse>({
|
|
945
779
|
queryKey: queryKeys.storage({
|
|
946
780
|
prefix: options.prefix,
|
|
947
781
|
cursor: options.cursor,
|
|
948
782
|
limit: options.limit,
|
|
949
783
|
}),
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (options.limit) queryString.set('limit', String(options.limit));
|
|
956
|
-
const response = await fetch(
|
|
957
|
-
buildConsoleUrl(
|
|
958
|
-
connectionConfig.serverUrl,
|
|
959
|
-
'/console/storage',
|
|
960
|
-
queryString
|
|
961
|
-
),
|
|
962
|
-
{
|
|
963
|
-
method: 'GET',
|
|
964
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
965
|
-
}
|
|
966
|
-
);
|
|
967
|
-
if (!response.ok) throw new Error('Failed to list blobs');
|
|
968
|
-
return response.json();
|
|
784
|
+
path: '/console/storage',
|
|
785
|
+
query: {
|
|
786
|
+
prefix: options.prefix,
|
|
787
|
+
cursor: options.cursor,
|
|
788
|
+
limit: options.limit,
|
|
969
789
|
},
|
|
970
|
-
|
|
790
|
+
errorMessage: 'Failed to list blobs',
|
|
971
791
|
refetchInterval: resolveRefetchInterval(options.refetchIntervalMs, 30000),
|
|
972
792
|
});
|
|
973
793
|
}
|
|
974
794
|
|
|
975
795
|
export function useDeleteBlobMutation() {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
`/console/storage/${encodedKey}`,
|
|
986
|
-
new URLSearchParams()
|
|
987
|
-
),
|
|
988
|
-
{
|
|
989
|
-
method: 'DELETE',
|
|
990
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
991
|
-
}
|
|
992
|
-
);
|
|
993
|
-
if (!response.ok) throw new Error('Failed to delete blob');
|
|
994
|
-
return response.json();
|
|
995
|
-
},
|
|
996
|
-
onSuccess: () => {
|
|
997
|
-
queryClient.invalidateQueries({ queryKey: ['console', 'storage'] });
|
|
998
|
-
},
|
|
796
|
+
return useConsoleJsonMutation<{ deleted: boolean }, string>({
|
|
797
|
+
mutationFn: async ({ connectionConfig, variables }) =>
|
|
798
|
+
fetchConsoleJson<{ deleted: boolean }>({
|
|
799
|
+
connectionConfig,
|
|
800
|
+
path: `/console/storage/${encodeURIComponent(variables)}`,
|
|
801
|
+
method: 'DELETE',
|
|
802
|
+
errorMessage: 'Failed to delete blob',
|
|
803
|
+
}),
|
|
804
|
+
invalidateQueryKeys: [['console', 'storage']],
|
|
999
805
|
});
|
|
1000
806
|
}
|
|
1001
807
|
|
|
1002
808
|
export function useBlobDownload() {
|
|
1003
|
-
const { config: connectionConfig } = useConnection();
|
|
809
|
+
const { config: connectionConfig, isConnected } = useConnection();
|
|
1004
810
|
return async (key: string) => {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
`/console/storage/${encodedKey}/download`,
|
|
1011
|
-
new URLSearchParams()
|
|
1012
|
-
),
|
|
1013
|
-
{
|
|
1014
|
-
method: 'GET',
|
|
1015
|
-
headers: { Authorization: `Bearer ${connectionConfig.token}` },
|
|
1016
|
-
}
|
|
1017
|
-
);
|
|
1018
|
-
if (!response.ok) throw new Error('Failed to download blob');
|
|
1019
|
-
const blob = await response.blob();
|
|
811
|
+
const blob = await fetchConsoleBlob({
|
|
812
|
+
connectionConfig: requireConnection(connectionConfig, isConnected),
|
|
813
|
+
path: `/console/storage/${encodeURIComponent(key)}/download`,
|
|
814
|
+
errorMessage: 'Failed to download blob',
|
|
815
|
+
});
|
|
1020
816
|
const url = URL.createObjectURL(blob);
|
|
1021
817
|
const a = document.createElement('a');
|
|
1022
818
|
a.href = url;
|