@powersync/nuxt 0.0.0-dev-20260128023420
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/LICENSE +201 -0
- package/README +374 -0
- package/dist/module.d.mts +39 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +160 -0
- package/dist/runtime/assets/powersync-icon.svg +14 -0
- package/dist/runtime/components/BucketsInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/BucketsInspectorTab.vue +646 -0
- package/dist/runtime/components/BucketsInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/ConfigInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/ConfigInspectorTab.vue +121 -0
- package/dist/runtime/components/ConfigInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/DataInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/DataInspectorTab.vue +678 -0
- package/dist/runtime/components/DataInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/LoadingSpinner.d.vue.ts +3 -0
- package/dist/runtime/components/LoadingSpinner.vue +12 -0
- package/dist/runtime/components/LoadingSpinner.vue.d.ts +3 -0
- package/dist/runtime/components/LogsTab.d.vue.ts +3 -0
- package/dist/runtime/components/LogsTab.vue +325 -0
- package/dist/runtime/components/LogsTab.vue.d.ts +3 -0
- package/dist/runtime/components/PowerSyncInstanceTab.d.vue.ts +3 -0
- package/dist/runtime/components/PowerSyncInstanceTab.vue +9 -0
- package/dist/runtime/components/PowerSyncInstanceTab.vue.d.ts +3 -0
- package/dist/runtime/components/SyncStatusTab.d.vue.ts +3 -0
- package/dist/runtime/components/SyncStatusTab.vue +272 -0
- package/dist/runtime/components/SyncStatusTab.vue.d.ts +3 -0
- package/dist/runtime/composables/useDiagnosticsLogger.d.ts +27 -0
- package/dist/runtime/composables/useDiagnosticsLogger.js +41 -0
- package/dist/runtime/composables/usePowerSyncInspector.d.ts +42 -0
- package/dist/runtime/composables/usePowerSyncInspector.js +19 -0
- package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.d.ts +153 -0
- package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.js +254 -0
- package/dist/runtime/composables/usePowerSyncKysely.d.ts +23 -0
- package/dist/runtime/composables/usePowerSyncKysely.js +7 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/layouts/powersync-inspector-layout.d.vue.ts +13 -0
- package/dist/runtime/layouts/powersync-inspector-layout.vue +90 -0
- package/dist/runtime/layouts/powersync-inspector-layout.vue.d.ts +13 -0
- package/dist/runtime/pages/__powersync-inspector.d.vue.ts +3 -0
- package/dist/runtime/pages/__powersync-inspector.vue +153 -0
- package/dist/runtime/pages/__powersync-inspector.vue.d.ts +3 -0
- package/dist/runtime/plugin.client.d.ts +2 -0
- package/dist/runtime/plugin.client.js +11 -0
- package/dist/runtime/utils/AppSchema.d.ts +27 -0
- package/dist/runtime/utils/AppSchema.js +23 -0
- package/dist/runtime/utils/DynamicSchemaManager.d.ts +15 -0
- package/dist/runtime/utils/DynamicSchemaManager.js +91 -0
- package/dist/runtime/utils/JsSchemaGenerator.d.ts +8 -0
- package/dist/runtime/utils/JsSchemaGenerator.js +28 -0
- package/dist/runtime/utils/NuxtPowerSyncDatabase.d.ts +40 -0
- package/dist/runtime/utils/NuxtPowerSyncDatabase.js +117 -0
- package/dist/runtime/utils/RecordingStorageAdapter.d.ts +13 -0
- package/dist/runtime/utils/RecordingStorageAdapter.js +76 -0
- package/dist/runtime/utils/RustClientInterceptor.d.ts +24 -0
- package/dist/runtime/utils/RustClientInterceptor.js +102 -0
- package/dist/runtime/utils/TokenConnector.d.ts +14 -0
- package/dist/runtime/utils/TokenConnector.js +62 -0
- package/dist/runtime/utils/addImportsFrom.d.ts +1 -0
- package/dist/runtime/utils/addImportsFrom.js +4 -0
- package/dist/runtime/utils/index.d.ts +1 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/types.d.mts +9 -0
- package/package.json +90 -0
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TooltipProvider :delay-duration="100">
|
|
3
|
+
<div
|
|
4
|
+
border="t"
|
|
5
|
+
border-color="gray-100"
|
|
6
|
+
relative
|
|
7
|
+
n-bg="base"
|
|
8
|
+
flex="~ col"
|
|
9
|
+
h="screen"
|
|
10
|
+
overflow="hidden"
|
|
11
|
+
>
|
|
12
|
+
<SplitterGroup
|
|
13
|
+
id="buckets-splitter-group"
|
|
14
|
+
class="h-full"
|
|
15
|
+
direction="horizontal"
|
|
16
|
+
>
|
|
17
|
+
<!-- Buckets List Panel -->
|
|
18
|
+
<SplitterPanel
|
|
19
|
+
id="buckets-list-panel"
|
|
20
|
+
:min-size="30"
|
|
21
|
+
:default-size="40"
|
|
22
|
+
class="border-r border-gray-200 flex flex-col overflow-hidden"
|
|
23
|
+
>
|
|
24
|
+
<div class="flex-1 flex flex-col overflow-hidden">
|
|
25
|
+
<!-- Header -->
|
|
26
|
+
<div class="p-3 border-b border-gray-200 dark:border-neutral-700">
|
|
27
|
+
<div class="flex items-center justify-between mb-2">
|
|
28
|
+
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
|
|
29
|
+
Buckets
|
|
30
|
+
</h2>
|
|
31
|
+
<NBadge n="slate xs">
|
|
32
|
+
{{ filteredBuckets.length }}
|
|
33
|
+
</NBadge>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- Search Bar -->
|
|
37
|
+
<NTextInput
|
|
38
|
+
v-model="searchQuery"
|
|
39
|
+
n="xs"
|
|
40
|
+
class="w-full"
|
|
41
|
+
placeholder="Search buckets..."
|
|
42
|
+
icon="carbon:search"
|
|
43
|
+
@input="onSearchInput"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Buckets List -->
|
|
48
|
+
<div class="flex-1 overflow-y-auto">
|
|
49
|
+
<div
|
|
50
|
+
v-if="filteredBuckets.length === 0 && !isLoading"
|
|
51
|
+
class="flex-1 flex items-center justify-center text-gray-500 dark:text-gray-400 text-sm mt-3"
|
|
52
|
+
>
|
|
53
|
+
<div class="text-center">
|
|
54
|
+
<NIcon
|
|
55
|
+
icon="carbon:data-error"
|
|
56
|
+
class="text-2xl mb-2"
|
|
57
|
+
/>
|
|
58
|
+
<div>No buckets found</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div
|
|
63
|
+
v-else-if="isLoading"
|
|
64
|
+
class="flex-1 flex items-center justify-center"
|
|
65
|
+
>
|
|
66
|
+
<NLoading />
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div
|
|
70
|
+
v-else
|
|
71
|
+
class="p-2 space-y-1"
|
|
72
|
+
>
|
|
73
|
+
<div
|
|
74
|
+
v-for="bucket in filteredBuckets"
|
|
75
|
+
:key="bucket.name"
|
|
76
|
+
class="bucket-item p-3 rounded-lg border border-gray-200 dark:border-neutral-700 cursor-pointer transition-all hover:bg-gray-50 dark:hover:bg-neutral-800"
|
|
77
|
+
:class="{
|
|
78
|
+
'bg-gray-100 dark:bg-neutral-400/20 border-gray-300 dark:border-blue-700': selectedBucket?.name === bucket.name
|
|
79
|
+
}"
|
|
80
|
+
@click="selectBucket(bucket)"
|
|
81
|
+
>
|
|
82
|
+
<div class="flex items-start justify-between">
|
|
83
|
+
<div class="flex-1 min-w-0 flex flex-col gap-1">
|
|
84
|
+
<div class="flex items-center gap-2 mb-1">
|
|
85
|
+
<NIcon
|
|
86
|
+
icon="carbon:db2-database"
|
|
87
|
+
class="text-blue-500 flex-shrink-0"
|
|
88
|
+
/>
|
|
89
|
+
<span class="font-medium text-gray-900 dark:text-gray-100 truncate">
|
|
90
|
+
{{ bucket.name }}
|
|
91
|
+
</span>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<!-- Bucket Details - Two Lines -->
|
|
95
|
+
<div class="grid grid-cols-4 gap-2 text-xs text-gray-600 dark:text-gray-400">
|
|
96
|
+
<!-- Data Size -->
|
|
97
|
+
<TooltipRoot>
|
|
98
|
+
<TooltipTrigger as-child>
|
|
99
|
+
<div class="flex items-center gap-1">
|
|
100
|
+
<NIcon
|
|
101
|
+
icon="carbon:data-volume"
|
|
102
|
+
class="text-xs"
|
|
103
|
+
/>
|
|
104
|
+
<span>{{ formatBytes(bucket.data_size || 0) }}</span>
|
|
105
|
+
</div>
|
|
106
|
+
</TooltipTrigger>
|
|
107
|
+
<TooltipContent
|
|
108
|
+
side="bottom"
|
|
109
|
+
class="text-xs bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-md p-2"
|
|
110
|
+
>
|
|
111
|
+
Data Size: {{ formatBytes(bucket.data_size || 0) }}
|
|
112
|
+
</TooltipContent>
|
|
113
|
+
</TooltipRoot>
|
|
114
|
+
|
|
115
|
+
<!-- Row Count -->
|
|
116
|
+
<TooltipRoot>
|
|
117
|
+
<TooltipTrigger as-child>
|
|
118
|
+
<div class="flex items-center gap-1">
|
|
119
|
+
<NIcon
|
|
120
|
+
icon="carbon:data-2"
|
|
121
|
+
class="text-xs"
|
|
122
|
+
/>
|
|
123
|
+
<span>{{ bucket.row_count || 0 }} rows</span>
|
|
124
|
+
</div>
|
|
125
|
+
</TooltipTrigger>
|
|
126
|
+
<TooltipContent
|
|
127
|
+
side="bottom"
|
|
128
|
+
class="text-xs bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-md p-2"
|
|
129
|
+
>
|
|
130
|
+
Row Count: {{ bucket.row_count || 0 }} rows
|
|
131
|
+
</TooltipContent>
|
|
132
|
+
</TooltipRoot>
|
|
133
|
+
|
|
134
|
+
<!-- Metadata Size -->
|
|
135
|
+
<TooltipRoot>
|
|
136
|
+
<TooltipTrigger as-child>
|
|
137
|
+
<div class="flex items-center gap-1">
|
|
138
|
+
<NIcon
|
|
139
|
+
icon="carbon:array-objects"
|
|
140
|
+
class="text-xs"
|
|
141
|
+
/>
|
|
142
|
+
<span>{{ formatBytes(bucket.metadata_size || 0) }}</span>
|
|
143
|
+
</div>
|
|
144
|
+
</TooltipTrigger>
|
|
145
|
+
<TooltipContent
|
|
146
|
+
side="bottom"
|
|
147
|
+
class="text-xs bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-md p-2"
|
|
148
|
+
>
|
|
149
|
+
Metadata Size: {{ formatBytes(bucket.metadata_size || 0) }}
|
|
150
|
+
</TooltipContent>
|
|
151
|
+
</TooltipRoot>
|
|
152
|
+
|
|
153
|
+
<!-- Download Size -->
|
|
154
|
+
<TooltipRoot>
|
|
155
|
+
<TooltipTrigger as-child>
|
|
156
|
+
<div class="flex items-center gap-1">
|
|
157
|
+
<NIcon
|
|
158
|
+
icon="carbon:download"
|
|
159
|
+
class="text-xs"
|
|
160
|
+
/>
|
|
161
|
+
<span>{{ formatBytes(bucket.download_size || 0) }}</span>
|
|
162
|
+
</div>
|
|
163
|
+
</TooltipTrigger>
|
|
164
|
+
<TooltipContent
|
|
165
|
+
side="bottom"
|
|
166
|
+
class="text-xs bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-md p-2"
|
|
167
|
+
>
|
|
168
|
+
Download Size: {{ formatBytes(bucket.download_size || 0) }}
|
|
169
|
+
</TooltipContent>
|
|
170
|
+
</TooltipRoot>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<!-- Status Line -->
|
|
174
|
+
<div class="flex items-center justify-between mt-1">
|
|
175
|
+
<div class="flex items-center gap-1 flex-wrap">
|
|
176
|
+
<span class="text-xs text-gray-500 dark:text-gray-400">Tables:</span>
|
|
177
|
+
<template v-if="JSON.parse(bucket.tables) && JSON.parse(bucket.tables).length > 0">
|
|
178
|
+
<template
|
|
179
|
+
v-for="tableName in JSON.parse(bucket.tables).slice(0, 3)"
|
|
180
|
+
:key="tableName"
|
|
181
|
+
>
|
|
182
|
+
<NBadge
|
|
183
|
+
n="gray xs"
|
|
184
|
+
class="text-xs"
|
|
185
|
+
>
|
|
186
|
+
{{ tableName }}
|
|
187
|
+
</NBadge>
|
|
188
|
+
</template>
|
|
189
|
+
<TooltipRoot v-if="JSON.parse(bucket.tables).length > 3">
|
|
190
|
+
<TooltipTrigger as-child>
|
|
191
|
+
<NBadge
|
|
192
|
+
n="gray xs"
|
|
193
|
+
class="text-xs"
|
|
194
|
+
>
|
|
195
|
+
+{{ JSON.parse(bucket.tables).length - 3 }}
|
|
196
|
+
</NBadge>
|
|
197
|
+
</TooltipTrigger>
|
|
198
|
+
<TooltipContent
|
|
199
|
+
side="bottom"
|
|
200
|
+
class="text-xs bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-md p-2"
|
|
201
|
+
>
|
|
202
|
+
All tables: {{ JSON.parse(bucket.tables).join(", ") }}
|
|
203
|
+
</TooltipContent>
|
|
204
|
+
</TooltipRoot>
|
|
205
|
+
</template>
|
|
206
|
+
<span
|
|
207
|
+
v-else
|
|
208
|
+
class="text-xs text-gray-500 dark:text-gray-400"
|
|
209
|
+
>
|
|
210
|
+
No tables
|
|
211
|
+
</span>
|
|
212
|
+
</div>
|
|
213
|
+
<NBadge
|
|
214
|
+
:n="bucket.downloading ? 'blue' : 'gray'"
|
|
215
|
+
:icon="bucket.downloading ? 'carbon:arrow-down' : 'carbon:pause'"
|
|
216
|
+
class="text-xs"
|
|
217
|
+
>
|
|
218
|
+
{{ bucket.downloading ? "Downloading" : "Idle" }}
|
|
219
|
+
</NBadge>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</SplitterPanel>
|
|
228
|
+
|
|
229
|
+
<SplitterResizeHandle
|
|
230
|
+
id="buckets-resize-handle"
|
|
231
|
+
class="w-[2px] bg-gray-200 hover:bg-indigo-300 dark:hover:bg-indigo-700"
|
|
232
|
+
/>
|
|
233
|
+
|
|
234
|
+
<!-- Bucket Content Panel -->
|
|
235
|
+
<SplitterPanel
|
|
236
|
+
id="bucket-content-panel"
|
|
237
|
+
:min-size="30"
|
|
238
|
+
class="flex flex-col overflow-hidden"
|
|
239
|
+
>
|
|
240
|
+
<div
|
|
241
|
+
v-if="!selectedBucket"
|
|
242
|
+
class="flex w-full h-full justify-center items-center"
|
|
243
|
+
>
|
|
244
|
+
<div
|
|
245
|
+
text="sm gray-500"
|
|
246
|
+
flex="~ gap-2 items-center"
|
|
247
|
+
>
|
|
248
|
+
<NIcon icon="carbon:data-base" />
|
|
249
|
+
<span>Select a bucket to view its content</span>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div
|
|
254
|
+
v-else
|
|
255
|
+
class="flex-1 flex flex-col overflow-hidden"
|
|
256
|
+
>
|
|
257
|
+
<!-- Bucket Header -->
|
|
258
|
+
<div class="p-3 border-b border-gray-200 dark:border-neutral-700 bg-gray-50 dark:bg-neutral-800">
|
|
259
|
+
<div class="flex items-center justify-between">
|
|
260
|
+
<div class="flex items-center gap-2">
|
|
261
|
+
<NIcon
|
|
262
|
+
icon="carbon:data-base"
|
|
263
|
+
class="text-blue-500"
|
|
264
|
+
/>
|
|
265
|
+
<h3 class="font-semibold text-gray-900 dark:text-gray-100">
|
|
266
|
+
{{ selectedBucket.name }}
|
|
267
|
+
</h3>
|
|
268
|
+
<NBadge n="blue xs">
|
|
269
|
+
{{ bucketContentRows?.length || 0 }} items
|
|
270
|
+
</NBadge>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<div class="flex items-center gap-2">
|
|
274
|
+
<NButton
|
|
275
|
+
n="xs"
|
|
276
|
+
icon="carbon:refresh"
|
|
277
|
+
@click="refreshBucketContent"
|
|
278
|
+
>
|
|
279
|
+
Refresh
|
|
280
|
+
</NButton>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<!-- Bucket Content Table -->
|
|
286
|
+
<div class="flex-1 overflow-hidden">
|
|
287
|
+
<div
|
|
288
|
+
v-if="isLoadingContent"
|
|
289
|
+
class="flex justify-center items-center h-full"
|
|
290
|
+
>
|
|
291
|
+
<NLoading />
|
|
292
|
+
</div>
|
|
293
|
+
|
|
294
|
+
<div
|
|
295
|
+
v-else-if="bucketContentError"
|
|
296
|
+
class="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded m-4"
|
|
297
|
+
>
|
|
298
|
+
<div class="text-red-800 dark:text-red-200 font-medium">
|
|
299
|
+
Error loading bucket content:
|
|
300
|
+
</div>
|
|
301
|
+
<div class="text-red-700 dark:text-red-300 text-sm mt-1">
|
|
302
|
+
{{ bucketContentError }}
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
<div
|
|
307
|
+
v-else-if="bucketContentRows && bucketContentRows.length > 0"
|
|
308
|
+
class="flex-1 flex flex-col overflow-hidden"
|
|
309
|
+
>
|
|
310
|
+
<!-- Table Controls -->
|
|
311
|
+
<div class="px-3 py-2 flex justify-between items-center bg-gray-50 dark:bg-neutral-800 border-b border-gray-200 dark:border-neutral-700 flex-shrink-0">
|
|
312
|
+
<div class="flex items-center gap-3">
|
|
313
|
+
<div class="text-xs text-gray-600 dark:text-gray-400">
|
|
314
|
+
{{ bucketContentRows.length }} row{{
|
|
315
|
+
bucketContentRows.length !== 1 ? "s" : ""
|
|
316
|
+
}}
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<div class="flex items-center gap-1">
|
|
321
|
+
<NButton
|
|
322
|
+
n="xs"
|
|
323
|
+
icon="carbon:chevron-left"
|
|
324
|
+
:disabled="!table.getCanPreviousPage()"
|
|
325
|
+
@click="table.previousPage()"
|
|
326
|
+
/>
|
|
327
|
+
|
|
328
|
+
<!-- Page Jump Input -->
|
|
329
|
+
<div class="flex items-center gap-1">
|
|
330
|
+
<span class="text-xs text-gray-600 dark:text-gray-400">Page</span>
|
|
331
|
+
<NTextInput
|
|
332
|
+
v-model="currentPageInput"
|
|
333
|
+
n="xs"
|
|
334
|
+
class="w-12 text-center"
|
|
335
|
+
type="number"
|
|
336
|
+
min="1"
|
|
337
|
+
:max="table.getPageCount()"
|
|
338
|
+
@blur="jumpToPage"
|
|
339
|
+
@keydown.enter="jumpToPage"
|
|
340
|
+
/>
|
|
341
|
+
<span class="text-xs text-gray-600 dark:text-gray-400">of {{ table.getPageCount() }}</span>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<NButton
|
|
345
|
+
n="xs"
|
|
346
|
+
icon="carbon:chevron-right"
|
|
347
|
+
:disabled="!table.getCanNextPage()"
|
|
348
|
+
@click="table.nextPage()"
|
|
349
|
+
/>
|
|
350
|
+
</div>
|
|
351
|
+
|
|
352
|
+
<!-- Page Size Control -->
|
|
353
|
+
<div class="flex items-center gap-1">
|
|
354
|
+
<span class="text-xs text-gray-600 dark:text-gray-400">Show:</span>
|
|
355
|
+
<NTextInput
|
|
356
|
+
v-model="pageSizeInput"
|
|
357
|
+
n="xs"
|
|
358
|
+
class="w-16"
|
|
359
|
+
type="number"
|
|
360
|
+
min="1"
|
|
361
|
+
max="1000"
|
|
362
|
+
@blur="updatePageSize"
|
|
363
|
+
@keydown.enter="updatePageSize"
|
|
364
|
+
/>
|
|
365
|
+
<span class="text-xs text-gray-600 dark:text-gray-400">per page</span>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<!-- Data Table -->
|
|
370
|
+
<div class="flex-1 border border-gray-200 dark:border-neutral-700 rounded-b-lg overflow-auto">
|
|
371
|
+
<table class="w-full min-w-max">
|
|
372
|
+
<thead class="bg-gray-50 dark:bg-neutral-800 sticky top-0">
|
|
373
|
+
<tr>
|
|
374
|
+
<th
|
|
375
|
+
v-for="header in table.getFlatHeaders()"
|
|
376
|
+
:key="header.id"
|
|
377
|
+
class="px-2 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 tracking-wider border-r border-gray-200 dark:border-neutral-700 last:border-r-0 relative overflow-hidden"
|
|
378
|
+
:class="
|
|
379
|
+
header.column.getCanSort() ? 'cursor-pointer hover:bg-gray-100 dark:hover:bg-neutral-700' : ''
|
|
380
|
+
"
|
|
381
|
+
:style="{
|
|
382
|
+
width: `${header.getSize()}px`,
|
|
383
|
+
maxWidth: `${header.getSize()}px`,
|
|
384
|
+
minWidth: `${header.getSize()}px`
|
|
385
|
+
}"
|
|
386
|
+
@click="
|
|
387
|
+
header.column.getToggleSortingHandler()?.($event)
|
|
388
|
+
"
|
|
389
|
+
>
|
|
390
|
+
<div class="flex items-center gap-1 min-w-0">
|
|
391
|
+
<div class="truncate flex-1 min-w-0">
|
|
392
|
+
<FlexRender
|
|
393
|
+
:render="header.column.columnDef.header"
|
|
394
|
+
:props="header.getContext()"
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
397
|
+
<span
|
|
398
|
+
v-if="header.column.getIsSorted()"
|
|
399
|
+
class="text-xs flex-shrink-0"
|
|
400
|
+
>
|
|
401
|
+
{{
|
|
402
|
+
header.column.getIsSorted() === "asc" ? "\u25B2" : "\u25BC"
|
|
403
|
+
}}
|
|
404
|
+
</span>
|
|
405
|
+
</div>
|
|
406
|
+
<!-- Column Resize Handle -->
|
|
407
|
+
<div
|
|
408
|
+
v-if="header.column.getCanResize()"
|
|
409
|
+
class="absolute top-0 right-0 h-full w-1 cursor-col-resize bg-transparent hover:bg-gray-500 hover:bg-opacity-50 group"
|
|
410
|
+
@mousedown="header.getResizeHandler()?.($event)"
|
|
411
|
+
@touchstart="header.getResizeHandler()?.($event)"
|
|
412
|
+
@click.stop
|
|
413
|
+
>
|
|
414
|
+
<div
|
|
415
|
+
class="w-full h-full group-hover:bg-gray-500 transition-colors duration-150"
|
|
416
|
+
/>
|
|
417
|
+
</div>
|
|
418
|
+
</th>
|
|
419
|
+
</tr>
|
|
420
|
+
</thead>
|
|
421
|
+
<tbody
|
|
422
|
+
class="bg-white dark:bg-neutral-900 border-t border-gray-200 dark:border-neutral-700"
|
|
423
|
+
>
|
|
424
|
+
<tr
|
|
425
|
+
v-for="row in table.getRowModel().rows"
|
|
426
|
+
:key="row.id"
|
|
427
|
+
class="hover:bg-gray-50 dark:hover:bg-neutral-800 border-b border-gray-200 dark:border-neutral-700"
|
|
428
|
+
>
|
|
429
|
+
<td
|
|
430
|
+
v-for="cell in row.getVisibleCells()"
|
|
431
|
+
:key="cell.id"
|
|
432
|
+
class="px-2 py-3 text-sm text-gray-900 dark:text-gray-100 border-r border-gray-200 dark:border-neutral-700 last:border-r-0 overflow-hidden"
|
|
433
|
+
:style="{
|
|
434
|
+
width: `${cell.column.getSize()}px`,
|
|
435
|
+
maxWidth: `${cell.column.getSize()}px`,
|
|
436
|
+
minWidth: `${cell.column.getSize()}px`
|
|
437
|
+
}"
|
|
438
|
+
>
|
|
439
|
+
<div
|
|
440
|
+
class="truncate w-full"
|
|
441
|
+
:title="String(cell.getValue())"
|
|
442
|
+
>
|
|
443
|
+
<FlexRender
|
|
444
|
+
:render="cell.column.columnDef.cell"
|
|
445
|
+
:props="cell.getContext()"
|
|
446
|
+
/>
|
|
447
|
+
</div>
|
|
448
|
+
</td>
|
|
449
|
+
</tr>
|
|
450
|
+
</tbody>
|
|
451
|
+
</table>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
<div
|
|
456
|
+
v-else
|
|
457
|
+
class="text-center py-8"
|
|
458
|
+
>
|
|
459
|
+
<div class="text-gray-500 dark:text-gray-400">
|
|
460
|
+
No content found in this bucket
|
|
461
|
+
</div>
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
</div>
|
|
465
|
+
</SplitterPanel>
|
|
466
|
+
</SplitterGroup>
|
|
467
|
+
</div>
|
|
468
|
+
</TooltipProvider>
|
|
469
|
+
</template>
|
|
470
|
+
|
|
471
|
+
<script setup>
|
|
472
|
+
import { ref, computed, watch, onMounted } from "vue";
|
|
473
|
+
import { usePowerSyncInspectorDiagnostics } from "#imports";
|
|
474
|
+
import {
|
|
475
|
+
SplitterGroup,
|
|
476
|
+
SplitterPanel,
|
|
477
|
+
SplitterResizeHandle,
|
|
478
|
+
TooltipContent,
|
|
479
|
+
TooltipProvider,
|
|
480
|
+
TooltipRoot,
|
|
481
|
+
TooltipTrigger
|
|
482
|
+
} from "reka-ui";
|
|
483
|
+
import {
|
|
484
|
+
FlexRender,
|
|
485
|
+
getCoreRowModel,
|
|
486
|
+
useVueTable,
|
|
487
|
+
getSortedRowModel,
|
|
488
|
+
getPaginationRowModel
|
|
489
|
+
} from "@tanstack/vue-table";
|
|
490
|
+
import Fuse from "fuse.js";
|
|
491
|
+
const { db, bucketRows, formatBytes } = usePowerSyncInspectorDiagnostics();
|
|
492
|
+
const searchQuery = ref("");
|
|
493
|
+
const selectedBucket = ref(null);
|
|
494
|
+
const isLoading = ref(false);
|
|
495
|
+
const fuse = ref();
|
|
496
|
+
const bucketContentRows = ref(null);
|
|
497
|
+
const isLoadingContent = ref(false);
|
|
498
|
+
const bucketContentError = ref(null);
|
|
499
|
+
const currentPageInput = ref("1");
|
|
500
|
+
const pageSizeInput = ref("50");
|
|
501
|
+
const initializeFuse = () => {
|
|
502
|
+
if (!bucketRows.value) return;
|
|
503
|
+
const fuseOptions = {
|
|
504
|
+
keys: ["name"],
|
|
505
|
+
threshold: 0.3,
|
|
506
|
+
includeScore: true,
|
|
507
|
+
includeMatches: true
|
|
508
|
+
};
|
|
509
|
+
fuse.value = new Fuse(bucketRows.value, fuseOptions);
|
|
510
|
+
};
|
|
511
|
+
const filteredBuckets = computed(() => {
|
|
512
|
+
if (!bucketRows.value) return [];
|
|
513
|
+
if (!searchQuery.value || !fuse.value) {
|
|
514
|
+
return bucketRows.value;
|
|
515
|
+
}
|
|
516
|
+
const searchResults = fuse.value.search(searchQuery.value);
|
|
517
|
+
return searchResults.map((result) => result.item);
|
|
518
|
+
});
|
|
519
|
+
const onSearchInput = () => {
|
|
520
|
+
};
|
|
521
|
+
const selectBucket = async (bucket) => {
|
|
522
|
+
selectedBucket.value = bucket;
|
|
523
|
+
await loadBucketContent(bucket);
|
|
524
|
+
};
|
|
525
|
+
const loadBucketContent = async (bucket) => {
|
|
526
|
+
if (!db.value) return;
|
|
527
|
+
isLoadingContent.value = true;
|
|
528
|
+
bucketContentError.value = null;
|
|
529
|
+
try {
|
|
530
|
+
const query = `
|
|
531
|
+
SELECT * FROM ps_oplog WHERE bucket = ?
|
|
532
|
+
ORDER BY op_id DESC
|
|
533
|
+
`;
|
|
534
|
+
const result = await db.value.getAll(query, [bucket.id]);
|
|
535
|
+
bucketContentRows.value = result;
|
|
536
|
+
} catch (error) {
|
|
537
|
+
bucketContentError.value = error instanceof Error ? error.message : "Unknown error occurred";
|
|
538
|
+
bucketContentRows.value = null;
|
|
539
|
+
} finally {
|
|
540
|
+
isLoadingContent.value = false;
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
const refreshBucketContent = async () => {
|
|
544
|
+
if (selectedBucket.value) {
|
|
545
|
+
await loadBucketContent(selectedBucket.value);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
const columns = computed(() => {
|
|
549
|
+
if (!bucketContentRows.value || bucketContentRows.value.length === 0) return [];
|
|
550
|
+
const firstRow = bucketContentRows.value[0];
|
|
551
|
+
const dataColumns = Object.keys(firstRow);
|
|
552
|
+
const columnsArray = [
|
|
553
|
+
// Row number column
|
|
554
|
+
{
|
|
555
|
+
id: "rowNumber",
|
|
556
|
+
header: "",
|
|
557
|
+
cell: ({ row }) => row.index + 1,
|
|
558
|
+
size: 60,
|
|
559
|
+
enableSorting: false,
|
|
560
|
+
enableResizing: false
|
|
561
|
+
},
|
|
562
|
+
// Data columns
|
|
563
|
+
...dataColumns.map((key) => ({
|
|
564
|
+
accessorKey: key,
|
|
565
|
+
header: key,
|
|
566
|
+
size: 150,
|
|
567
|
+
minSize: 20,
|
|
568
|
+
maxSize: 800,
|
|
569
|
+
enableResizing: true,
|
|
570
|
+
cell: ({ getValue }) => {
|
|
571
|
+
const value = getValue();
|
|
572
|
+
if (value === null) return "NULL";
|
|
573
|
+
if (value === void 0) return "UNDEFINED";
|
|
574
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
575
|
+
return String(value);
|
|
576
|
+
}
|
|
577
|
+
}))
|
|
578
|
+
];
|
|
579
|
+
return columnsArray;
|
|
580
|
+
});
|
|
581
|
+
const table = useVueTable({
|
|
582
|
+
get data() {
|
|
583
|
+
return bucketContentRows.value || [];
|
|
584
|
+
},
|
|
585
|
+
get columns() {
|
|
586
|
+
return columns.value;
|
|
587
|
+
},
|
|
588
|
+
getCoreRowModel: getCoreRowModel(),
|
|
589
|
+
getSortedRowModel: getSortedRowModel(),
|
|
590
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
591
|
+
enableColumnResizing: true,
|
|
592
|
+
columnResizeMode: "onChange",
|
|
593
|
+
defaultColumn: {
|
|
594
|
+
size: 150,
|
|
595
|
+
minSize: 20,
|
|
596
|
+
maxSize: 800
|
|
597
|
+
},
|
|
598
|
+
initialState: {
|
|
599
|
+
pagination: {
|
|
600
|
+
pageSize: 50
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
const jumpToPage = () => {
|
|
605
|
+
const pageNumber = Number.parseInt(currentPageInput.value, 10);
|
|
606
|
+
if (pageNumber >= 1 && pageNumber <= table.getPageCount()) {
|
|
607
|
+
table.setPageIndex(pageNumber - 1);
|
|
608
|
+
} else {
|
|
609
|
+
currentPageInput.value = String(table.getState().pagination.pageIndex + 1);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
const updatePageSize = () => {
|
|
613
|
+
const pageSize = Number.parseInt(pageSizeInput.value, 10);
|
|
614
|
+
if (pageSize >= 1 && pageSize <= 1e3) {
|
|
615
|
+
table.setPageSize(pageSize);
|
|
616
|
+
} else {
|
|
617
|
+
pageSizeInput.value = String(table.getState().pagination.pageSize);
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
watch(
|
|
621
|
+
() => table.getState().pagination.pageIndex,
|
|
622
|
+
(newPageIndex) => {
|
|
623
|
+
currentPageInput.value = String(newPageIndex + 1);
|
|
624
|
+
}
|
|
625
|
+
);
|
|
626
|
+
watch(
|
|
627
|
+
() => table.getState().pagination.pageSize,
|
|
628
|
+
(newPageSize) => {
|
|
629
|
+
pageSizeInput.value = String(newPageSize);
|
|
630
|
+
}
|
|
631
|
+
);
|
|
632
|
+
watch(bucketRows, () => {
|
|
633
|
+
if (bucketRows.value) {
|
|
634
|
+
initializeFuse();
|
|
635
|
+
}
|
|
636
|
+
}, { immediate: true });
|
|
637
|
+
onMounted(async () => {
|
|
638
|
+
if (bucketRows.value) {
|
|
639
|
+
initializeFuse();
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
</script>
|
|
643
|
+
|
|
644
|
+
<style scoped>
|
|
645
|
+
.bucket-item{transition:all .2s ease}.bucket-item:hover{box-shadow:0 2px 4px rgba(0,0,0,.1);transform:translateY(-1px)}
|
|
646
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|