@sfxcode/nuxt-ui-mongocamp 1.1.0

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/module.d.mts +8 -0
  4. package/dist/module.json +12 -0
  5. package/dist/module.mjs +35 -0
  6. package/dist/runtime/components/MongocampAccount.d.vue.ts +3 -0
  7. package/dist/runtime/components/MongocampAccount.vue +197 -0
  8. package/dist/runtime/components/MongocampAccount.vue.d.ts +3 -0
  9. package/dist/runtime/components/MongocampCollectionData.d.vue.ts +6 -0
  10. package/dist/runtime/components/MongocampCollectionData.vue +511 -0
  11. package/dist/runtime/components/MongocampCollectionData.vue.d.ts +6 -0
  12. package/dist/runtime/components/MongocampCollectionInfos.d.vue.ts +9 -0
  13. package/dist/runtime/components/MongocampCollectionInfos.vue +393 -0
  14. package/dist/runtime/components/MongocampCollectionInfos.vue.d.ts +9 -0
  15. package/dist/runtime/components/MongocampCollections.d.vue.ts +7 -0
  16. package/dist/runtime/components/MongocampCollections.vue +231 -0
  17. package/dist/runtime/components/MongocampCollections.vue.d.ts +7 -0
  18. package/dist/runtime/components/MongocampDatabases.d.vue.ts +3 -0
  19. package/dist/runtime/components/MongocampDatabases.vue +112 -0
  20. package/dist/runtime/components/MongocampDatabases.vue.d.ts +3 -0
  21. package/dist/runtime/components/MongocampJobs.d.vue.ts +3 -0
  22. package/dist/runtime/components/MongocampJobs.vue +354 -0
  23. package/dist/runtime/components/MongocampJobs.vue.d.ts +3 -0
  24. package/dist/runtime/components/MongocampLogin.d.vue.ts +3 -0
  25. package/dist/runtime/components/MongocampLogin.vue +63 -0
  26. package/dist/runtime/components/MongocampLogin.vue.d.ts +3 -0
  27. package/dist/runtime/components/MongocampRoleGrants.d.vue.ts +6 -0
  28. package/dist/runtime/components/MongocampRoleGrants.vue +276 -0
  29. package/dist/runtime/components/MongocampRoleGrants.vue.d.ts +6 -0
  30. package/dist/runtime/components/MongocampRoles.d.vue.ts +6 -0
  31. package/dist/runtime/components/MongocampRoles.vue +272 -0
  32. package/dist/runtime/components/MongocampRoles.vue.d.ts +6 -0
  33. package/dist/runtime/components/MongocampUsers.d.vue.ts +3 -0
  34. package/dist/runtime/components/MongocampUsers.vue +320 -0
  35. package/dist/runtime/components/MongocampUsers.vue.d.ts +3 -0
  36. package/dist/runtime/components/MongocampVersion.d.vue.ts +3 -0
  37. package/dist/runtime/components/MongocampVersion.vue +25 -0
  38. package/dist/runtime/components/MongocampVersion.vue.d.ts +3 -0
  39. package/dist/runtime/composables/useMongocampAccount.d.ts +7 -0
  40. package/dist/runtime/composables/useMongocampAccount.js +28 -0
  41. package/dist/runtime/composables/useMongocampAdmin.d.ts +14 -0
  42. package/dist/runtime/composables/useMongocampAdmin.js +48 -0
  43. package/dist/runtime/composables/useMongocampBucket.d.ts +15 -0
  44. package/dist/runtime/composables/useMongocampBucket.js +109 -0
  45. package/dist/runtime/composables/useMongocampCollection.d.ts +17 -0
  46. package/dist/runtime/composables/useMongocampCollection.js +12 -0
  47. package/dist/runtime/composables/useMongocampDocument.d.ts +13 -0
  48. package/dist/runtime/composables/useMongocampDocument.js +18 -0
  49. package/dist/runtime/composables/useMongocampDynamicForm.d.ts +14 -0
  50. package/dist/runtime/composables/useMongocampDynamicForm.js +231 -0
  51. package/dist/runtime/composables/useMongocampIndex.d.ts +9 -0
  52. package/dist/runtime/composables/useMongocampIndex.js +23 -0
  53. package/dist/runtime/composables/useMongocampJobs.d.ts +9 -0
  54. package/dist/runtime/composables/useMongocampJobs.js +25 -0
  55. package/dist/runtime/composables/useMongocampQuery.d.ts +99 -0
  56. package/dist/runtime/composables/useMongocampQuery.js +108 -0
  57. package/dist/runtime/composables/useMongocampQueryBuilder.d.ts +30 -0
  58. package/dist/runtime/composables/useMongocampQueryBuilder.js +112 -0
  59. package/dist/runtime/composables/useMongocampSchema.d.ts +14 -0
  60. package/dist/runtime/composables/useMongocampSchema.js +142 -0
  61. package/dist/runtime/composables/useMongocampSystem.d.ts +12 -0
  62. package/dist/runtime/composables/useMongocampSystem.js +21 -0
  63. package/dist/runtime/plugin.d.ts +6 -0
  64. package/dist/runtime/plugin.js +23 -0
  65. package/dist/runtime/server/tsconfig.json +3 -0
  66. package/dist/types.d.mts +3 -0
  67. package/package.json +99 -0
@@ -0,0 +1,511 @@
1
+ <script setup>
2
+ import { h, ref, resolveComponent, watch } from "vue";
3
+ import { useMongocampApi } from "#imports";
4
+ import useMongocampCollection from "../composables/useMongocampCollection";
5
+ import { useMongocampBucket } from "../composables/useMongocampBucket";
6
+ import { useMongocampSchema } from "../composables/useMongocampSchema";
7
+ import { columnsToFormKitSchema, documentToFormData, formDataToDocument } from "../composables/useMongocampDynamicForm";
8
+ import useMongocampDocument from "../composables/useMongocampDocument";
9
+ import { useMongocampQuery } from "../composables/useMongocampQuery";
10
+ const props = defineProps({
11
+ collectionName: { type: String, required: true }
12
+ });
13
+ const { documentApi } = useMongocampApi();
14
+ const { pagination, total } = useMongocampCollection();
15
+ const { isBucketCollection, fileIdForRow, downloadingFileIds, uploading, downloadFile, uploadFile } = useMongocampBucket();
16
+ const { schemaFromSamples } = useMongocampSchema();
17
+ const { ensureMetaData } = useMongocampDocument();
18
+ const { like, or } = useMongocampQuery();
19
+ const fileInputRef = ref(null);
20
+ function openFilePicker() {
21
+ fileInputRef.value?.click();
22
+ }
23
+ async function handleFileSelected(event) {
24
+ const input = event.target;
25
+ const file = input.files?.[0];
26
+ input.value = "";
27
+ if (!file) return;
28
+ const success = await uploadFile(props.collectionName, file);
29
+ if (success) await fetchDocuments();
30
+ }
31
+ const UButton = resolveComponent("UButton");
32
+ const UTooltip = resolveComponent("UTooltip");
33
+ function withTooltip(text, node) {
34
+ return h(UTooltip, { text }, { default: () => node });
35
+ }
36
+ const isEditModalOpen = ref(false);
37
+ const isDeleteModalOpen = ref(false);
38
+ const editMode = ref("insert");
39
+ const editDocId = ref(void 0);
40
+ const editJson = ref("{}");
41
+ const editError = ref("");
42
+ const docToDelete = ref(void 0);
43
+ const deleteError = ref("");
44
+ const editColumns = ref([]);
45
+ const editSchema = ref([]);
46
+ const editFormData = ref({});
47
+ const originalRow = ref(void 0);
48
+ function getDocId(row) {
49
+ const id = row._id;
50
+ if (typeof id === "string") return id;
51
+ if (typeof id === "object" && id !== null && "$oid" in id)
52
+ return String(id.$oid);
53
+ return void 0;
54
+ }
55
+ function openInsert() {
56
+ editMode.value = "insert";
57
+ editDocId.value = void 0;
58
+ editError.value = "";
59
+ originalRow.value = void 0;
60
+ editColumns.value = schemaFromSamples(documents.value);
61
+ if (editColumns.value.length > 0) {
62
+ editSchema.value = columnsToFormKitSchema(editColumns.value);
63
+ editFormData.value = {};
64
+ } else {
65
+ editJson.value = "{}";
66
+ }
67
+ isEditModalOpen.value = true;
68
+ }
69
+ function openEdit(row) {
70
+ editMode.value = "update";
71
+ editDocId.value = getDocId(row);
72
+ editError.value = "";
73
+ originalRow.value = row;
74
+ editColumns.value = schemaFromSamples(documents.value);
75
+ if (editColumns.value.length > 0) {
76
+ editSchema.value = columnsToFormKitSchema(editColumns.value);
77
+ editFormData.value = documentToFormData(row, editColumns.value);
78
+ } else {
79
+ editJson.value = JSON.stringify(row, null, 2);
80
+ }
81
+ isEditModalOpen.value = true;
82
+ }
83
+ function confirmDelete(row) {
84
+ docToDelete.value = getDocId(row);
85
+ deleteError.value = "";
86
+ isDeleteModalOpen.value = true;
87
+ }
88
+ async function handleSave() {
89
+ editError.value = "";
90
+ let payload;
91
+ if (editColumns.value.length > 0) {
92
+ payload = formDataToDocument(editFormData.value, editColumns.value, editMode.value === "update" ? originalRow.value : void 0);
93
+ } else {
94
+ try {
95
+ payload = JSON.parse(editJson.value);
96
+ } catch {
97
+ editError.value = "Invalid JSON";
98
+ return;
99
+ }
100
+ }
101
+ ensureMetaData(payload);
102
+ try {
103
+ if (editMode.value === "insert") {
104
+ await documentApi.insert({ collectionName: props.collectionName, requestBody: payload });
105
+ } else {
106
+ if (!editDocId.value) return;
107
+ const body = { ...payload };
108
+ delete body._id;
109
+ await documentApi.update({ collectionName: props.collectionName, documentId: editDocId.value, requestBody: body });
110
+ }
111
+ isEditModalOpen.value = false;
112
+ await fetchDocuments();
113
+ } catch (e) {
114
+ editError.value = e instanceof Error ? e.message : "Error saving document";
115
+ }
116
+ }
117
+ async function handleDelete() {
118
+ deleteError.value = "";
119
+ if (!docToDelete.value) return;
120
+ try {
121
+ await documentApi._delete({ collectionName: props.collectionName, documentId: docToDelete.value });
122
+ isDeleteModalOpen.value = false;
123
+ await fetchDocuments();
124
+ } catch (e) {
125
+ deleteError.value = e instanceof Error ? e.message : "Error deleting document";
126
+ }
127
+ }
128
+ function makeActionsColumn() {
129
+ return {
130
+ id: "actions",
131
+ header: "",
132
+ cell: ({ row }) => {
133
+ const buttons = [];
134
+ if (isBucketCollection(props.collectionName)) {
135
+ const fileId = fileIdForRow(props.collectionName, row.original);
136
+ if (fileId) {
137
+ buttons.push(withTooltip("Download file", h(UButton, {
138
+ "icon": "i-lucide-download",
139
+ "color": "neutral",
140
+ "variant": "ghost",
141
+ "size": "sm",
142
+ "aria-label": "Download file",
143
+ "loading": downloadingFileIds.value.has(fileId),
144
+ "onClick": () => downloadFile(props.collectionName, fileId)
145
+ })));
146
+ }
147
+ }
148
+ buttons.push(
149
+ withTooltip("Edit document", h(UButton, {
150
+ "icon": "i-lucide-pencil",
151
+ "color": "neutral",
152
+ "variant": "ghost",
153
+ "size": "sm",
154
+ "aria-label": "Edit document",
155
+ "onClick": () => openEdit(row.original)
156
+ })),
157
+ withTooltip("Delete document", h(UButton, {
158
+ "icon": "i-lucide-trash-2",
159
+ "color": "error",
160
+ "variant": "ghost",
161
+ "size": "sm",
162
+ "aria-label": "Delete document",
163
+ "onClick": () => confirmDelete(row.original)
164
+ }))
165
+ );
166
+ return h("div", { class: "flex gap-1 justify-end" }, buttons);
167
+ }
168
+ };
169
+ }
170
+ function sortHeader(column, label) {
171
+ const isSorted = column.getIsSorted();
172
+ return h(UButton, {
173
+ color: "neutral",
174
+ variant: "ghost",
175
+ label,
176
+ icon: isSorted === "asc" ? "i-lucide-arrow-up-narrow-wide" : isSorted === "desc" ? "i-lucide-arrow-down-wide-narrow" : "i-lucide-arrow-up-down",
177
+ class: "-mx-2.5",
178
+ onClick: () => column.toggleSorting(isSorted === "asc")
179
+ });
180
+ }
181
+ const columns = ref([]);
182
+ const documents = ref([]);
183
+ const loading = ref(false);
184
+ const filterText = ref("");
185
+ const filterableColumns = ref([]);
186
+ const sorting = ref([]);
187
+ const isInitializing = ref(false);
188
+ const detailOpen = ref(false);
189
+ const detailContent = ref("");
190
+ let filterTimer;
191
+ function openDetail(value) {
192
+ detailContent.value = JSON.stringify(value, null, 2);
193
+ detailOpen.value = true;
194
+ }
195
+ function buildLuceneFilter(term) {
196
+ const t = term.trim();
197
+ if (!t || filterableColumns.value.length === 0) return void 0;
198
+ return or(...filterableColumns.value.map((col) => like(col, t))) || void 0;
199
+ }
200
+ function onFilterInput() {
201
+ clearTimeout(filterTimer);
202
+ filterTimer = setTimeout(() => {
203
+ pagination.value.pageIndex = 1;
204
+ fetchDocuments();
205
+ }, 300);
206
+ }
207
+ function sortingToMongoSort(s) {
208
+ return s.map((col) => col.desc ? `-${col.id}` : col.id);
209
+ }
210
+ watch(sorting, () => {
211
+ if (isInitializing.value) return;
212
+ pagination.value.pageIndex = 1;
213
+ fetchDocuments();
214
+ });
215
+ function toIso(value) {
216
+ if (!value) return "";
217
+ try {
218
+ if (value instanceof Date) return value.toISOString();
219
+ if (typeof value === "string" || typeof value === "number") return new Date(value).toISOString();
220
+ if (typeof value === "object") {
221
+ const obj = value;
222
+ if ("$date" in obj) {
223
+ const d = obj.$date;
224
+ if (typeof d === "string" || typeof d === "number") return new Date(d).toISOString();
225
+ if (typeof d === "object" && d !== null && "$numberLong" in d) {
226
+ return new Date(Number(d.$numberLong)).toISOString();
227
+ }
228
+ }
229
+ }
230
+ return String(value);
231
+ } catch {
232
+ return String(value);
233
+ }
234
+ }
235
+ function toDateDisplay(value) {
236
+ const iso = toIso(value);
237
+ if (!iso) return "";
238
+ try {
239
+ return new Date(iso).toLocaleString();
240
+ } catch {
241
+ return iso;
242
+ }
243
+ }
244
+ function isMetaData(value) {
245
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
246
+ const obj = value;
247
+ return "created" in obj || "updated" in obj;
248
+ }
249
+ const CELL_TEXT_MAX_LENGTH = 60;
250
+ function truncateText(value, maxLength = CELL_TEXT_MAX_LENGTH) {
251
+ return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
252
+ }
253
+ function makeCell(key, type) {
254
+ return ({ row }) => {
255
+ const raw = row.original[key];
256
+ if (type === "date-time" && raw) {
257
+ return h("span", toDateDisplay(raw));
258
+ }
259
+ if (raw === null || raw === void 0) {
260
+ return h("span", "");
261
+ }
262
+ if (typeof raw === "object") {
263
+ if (!Array.isArray(raw)) {
264
+ const obj = raw;
265
+ if ("$oid" in obj) return h("span", { class: "font-mono text-xs" }, String(obj.$oid));
266
+ if ("$date" in obj) return h("span", toDateDisplay(obj));
267
+ if (isMetaData(obj)) {
268
+ const rows = [];
269
+ if (obj.created) {
270
+ rows.push(h("div", [
271
+ h("span", { class: "text-dimmed" }, "created: "),
272
+ h("span", toDateDisplay(obj.created))
273
+ ]));
274
+ }
275
+ if (obj.updated && obj.updated !== obj.created) {
276
+ rows.push(h("div", [
277
+ h("span", { class: "text-dimmed" }, "updated: "),
278
+ h("span", toDateDisplay(obj.updated))
279
+ ]));
280
+ }
281
+ if (obj.createdBy) {
282
+ rows.push(h("div", [
283
+ h("span", { class: "text-dimmed" }, "by: "),
284
+ h("span", String(obj.createdBy))
285
+ ]));
286
+ }
287
+ return h("div", { class: "flex flex-col gap-0.5 text-xs py-1" }, rows);
288
+ }
289
+ }
290
+ const viewLabel = Array.isArray(raw) ? "View array" : "View object";
291
+ return withTooltip(viewLabel, h(UButton, {
292
+ "icon": Array.isArray(raw) ? "i-lucide-list" : "i-lucide-braces",
293
+ "color": "neutral",
294
+ "variant": "ghost",
295
+ "size": "xs",
296
+ "aria-label": viewLabel,
297
+ "onClick": () => openDetail(raw)
298
+ }));
299
+ }
300
+ const text = String(raw);
301
+ const truncated = truncateText(text);
302
+ return h("span", { title: truncated !== text ? text : void 0 }, truncated);
303
+ };
304
+ }
305
+ async function fetchDocuments() {
306
+ loading.value = true;
307
+ try {
308
+ const res = await documentApi.listDocumentsRaw({
309
+ collectionName: props.collectionName,
310
+ rowsPerPage: pagination.value.pageSize,
311
+ page: pagination.value.pageIndex,
312
+ sort: sorting.value.length ? sortingToMongoSort(sorting.value) : void 0,
313
+ filter: buildLuceneFilter(filterText.value)
314
+ });
315
+ total.value = +(res.raw.headers.get("x-pagination-count-rows") ?? 0);
316
+ const rows = await res.value();
317
+ documents.value = rows;
318
+ const firstRow = rows[0];
319
+ if (columns.value.length === 0 && firstRow) {
320
+ const keys = Object.keys(firstRow);
321
+ const orderedKeys = [
322
+ ...keys.filter((k) => k === "_id"),
323
+ ...keys.filter((k) => k !== "_id" && k !== "metaData").sort(),
324
+ ...keys.filter((k) => k === "metaData")
325
+ ];
326
+ columns.value = orderedKeys.map((key) => ({
327
+ accessorKey: key,
328
+ header: ({ column }) => sortHeader(column, key),
329
+ cell: makeCell(key, "string")
330
+ }));
331
+ filterableColumns.value = orderedKeys.filter((k) => k !== "_id" && k !== "metaData" && typeof firstRow[k] === "string");
332
+ columns.value.push(makeActionsColumn());
333
+ }
334
+ } finally {
335
+ loading.value = false;
336
+ }
337
+ }
338
+ async function init() {
339
+ isInitializing.value = true;
340
+ sorting.value = [];
341
+ pagination.value.pageIndex = 1;
342
+ filterText.value = "";
343
+ filterableColumns.value = [];
344
+ columns.value = [];
345
+ documents.value = [];
346
+ await fetchDocuments();
347
+ isInitializing.value = false;
348
+ }
349
+ watch(() => props.collectionName, init, { immediate: true });
350
+ </script>
351
+
352
+ <template>
353
+ <div class="flex flex-col gap-4">
354
+ <div class="flex items-center justify-between gap-4">
355
+ <UInput
356
+ v-model="filterText"
357
+ icon="i-lucide-search"
358
+ placeholder="Filter rows..."
359
+ size="sm"
360
+ class="flex-1 max-w-xs"
361
+ :disabled="filterableColumns.length === 0"
362
+ @input="onFilterInput"
363
+ />
364
+ <div class="flex items-center gap-2">
365
+ <span class="text-sm text-gray-500 dark:text-gray-400 shrink-0">
366
+ {{ total }} documents
367
+ </span>
368
+ <UTooltip
369
+ v-if="isBucketCollection(collectionName)"
370
+ text="Upload file"
371
+ >
372
+ <UButton
373
+ icon="i-lucide-upload"
374
+ color="primary"
375
+ variant="ghost"
376
+ size="sm"
377
+ :loading="uploading"
378
+ aria-label="Upload file"
379
+ @click="openFilePicker"
380
+ />
381
+ </UTooltip>
382
+ <UTooltip
383
+ v-else
384
+ text="Insert document"
385
+ >
386
+ <UButton
387
+ icon="i-lucide-plus"
388
+ color="primary"
389
+ variant="ghost"
390
+ size="sm"
391
+ aria-label="Insert document"
392
+ @click="openInsert"
393
+ />
394
+ </UTooltip>
395
+ <input
396
+ ref="fileInputRef"
397
+ type="file"
398
+ class="hidden"
399
+ @change="handleFileSelected"
400
+ >
401
+ <UTooltip text="Reload">
402
+ <UButton
403
+ icon="i-lucide-refresh-cw"
404
+ color="neutral"
405
+ variant="ghost"
406
+ :loading="loading"
407
+ aria-label="Reload"
408
+ @click="init"
409
+ />
410
+ </UTooltip>
411
+ <UPagination
412
+ v-model:page="pagination.pageIndex"
413
+ :total="total"
414
+ :items-per-page="pagination.pageSize"
415
+ @update:page="fetchDocuments"
416
+ />
417
+ </div>
418
+ </div>
419
+ <UTable
420
+ v-model:sorting="sorting"
421
+ :sorting-options="{ manualSorting: true }"
422
+ :data="documents"
423
+ :columns="columns"
424
+ :loading="loading"
425
+ />
426
+
427
+ <UModal
428
+ v-model:open="detailOpen"
429
+ title="Details"
430
+ >
431
+ <template #body>
432
+ <pre class="text-xs overflow-auto max-h-[60vh] whitespace-pre-wrap break-all">{{ detailContent }}</pre>
433
+ </template>
434
+ </UModal>
435
+
436
+ <UModal
437
+ v-model:open="isEditModalOpen"
438
+ :title="editMode === 'insert' ? 'Insert Document' : 'Edit Document'"
439
+ :ui="{ footer: 'justify-end' }"
440
+ >
441
+ <template #body>
442
+ <FUDataEdit
443
+ v-if="editColumns.length > 0"
444
+ :data="editFormData"
445
+ :schema="editSchema"
446
+ :submit-label="editMode === 'insert' ? 'Insert' : 'Save'"
447
+ :submit-icon="editMode === 'insert' ? 'i-lucide-plus' : 'i-lucide-save'"
448
+ @data-saved="handleSave"
449
+ />
450
+ <textarea
451
+ v-else
452
+ v-model="editJson"
453
+ class="w-full h-80 font-mono text-xs p-2 border rounded bg-gray-50 dark:bg-gray-900 border-gray-200 dark:border-gray-700 focus:outline-none resize-y"
454
+ spellcheck="false"
455
+ />
456
+ <p
457
+ v-if="editError"
458
+ class="mt-2 text-sm text-error-500"
459
+ >
460
+ {{ editError }}
461
+ </p>
462
+ </template>
463
+ <template
464
+ v-if="editColumns.length === 0"
465
+ #footer
466
+ >
467
+ <UButton
468
+ label="Cancel"
469
+ color="neutral"
470
+ variant="ghost"
471
+ @click="isEditModalOpen = false"
472
+ />
473
+ <UButton
474
+ :label="editMode === 'insert' ? 'Insert' : 'Save'"
475
+ :icon="editMode === 'insert' ? 'i-lucide-plus' : 'i-lucide-save'"
476
+ @click="handleSave"
477
+ />
478
+ </template>
479
+ </UModal>
480
+
481
+ <UModal
482
+ v-model:open="isDeleteModalOpen"
483
+ title="Delete Document"
484
+ :ui="{ footer: 'justify-end' }"
485
+ >
486
+ <template #body>
487
+ <p>Are you sure you want to delete this document? This action cannot be undone.</p>
488
+ <p
489
+ v-if="deleteError"
490
+ class="mt-2 text-sm text-error-500"
491
+ >
492
+ {{ deleteError }}
493
+ </p>
494
+ </template>
495
+ <template #footer>
496
+ <UButton
497
+ label="Cancel"
498
+ color="neutral"
499
+ variant="ghost"
500
+ @click="isDeleteModalOpen = false"
501
+ />
502
+ <UButton
503
+ label="Delete"
504
+ color="error"
505
+ icon="i-lucide-trash-2"
506
+ @click="handleDelete"
507
+ />
508
+ </template>
509
+ </UModal>
510
+ </div>
511
+ </template>
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ collectionName: string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
@@ -0,0 +1,9 @@
1
+ type __VLS_Props = {
2
+ collectionName: string;
3
+ sampleSize?: number;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
6
+ sampleSize: number;
7
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;