@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,276 @@
1
+ <script setup>
2
+ import { h, reactive, ref, resolveComponent } from "vue";
3
+ import useMongocampAdmin from "../composables/useMongocampAdmin";
4
+ const props = defineProps({
5
+ roleName: { type: String, required: true }
6
+ });
7
+ const { listRoles, updateRole, listCollections } = useMongocampAdmin();
8
+ const grants = ref([]);
9
+ const allCollections = ref([]);
10
+ const isAdmin = ref(false);
11
+ const loading = ref(false);
12
+ const isAddModalOpen = ref(false);
13
+ const isEditModalOpen = ref(false);
14
+ const errorMessage = ref("");
15
+ const editIndex = ref(-1);
16
+ const editGrantName = ref("");
17
+ const newGrant = ref({ collectionName: "", read: false, write: false, administrate: false });
18
+ const editGrant = ref({ read: false, write: false, administrate: false });
19
+ const addGrantSchema = reactive([
20
+ {
21
+ $formkit: "nuxtUISelectMenu",
22
+ name: "collectionName",
23
+ label: "Collection",
24
+ class: "w-full",
25
+ options: [],
26
+ validation: "required"
27
+ },
28
+ {
29
+ $formkit: "nuxtUISwitch",
30
+ name: "read",
31
+ label: "Read"
32
+ },
33
+ {
34
+ $formkit: "nuxtUISwitch",
35
+ name: "write",
36
+ label: "Write"
37
+ },
38
+ {
39
+ $formkit: "nuxtUISwitch",
40
+ name: "administrate",
41
+ label: "Administrate"
42
+ }
43
+ ]);
44
+ const editGrantSchema = reactive([
45
+ {
46
+ $formkit: "nuxtUISwitch",
47
+ name: "read",
48
+ label: "Read"
49
+ },
50
+ {
51
+ $formkit: "nuxtUISwitch",
52
+ name: "write",
53
+ label: "Write"
54
+ },
55
+ {
56
+ $formkit: "nuxtUISwitch",
57
+ name: "administrate",
58
+ label: "Administrate"
59
+ }
60
+ ]);
61
+ async function fetchRole() {
62
+ loading.value = true;
63
+ try {
64
+ const roles = await listRoles();
65
+ const role = roles.find((r) => r.name === props.roleName);
66
+ if (role) {
67
+ isAdmin.value = role.isAdmin;
68
+ grants.value = (role.collectionGrants ?? []).map((g) => ({ ...g }));
69
+ }
70
+ } finally {
71
+ loading.value = false;
72
+ }
73
+ }
74
+ async function fetchCollections() {
75
+ allCollections.value = await listCollections();
76
+ }
77
+ async function saveGrants() {
78
+ errorMessage.value = "";
79
+ try {
80
+ await updateRole(props.roleName, isAdmin.value, grants.value);
81
+ await fetchRole();
82
+ } catch (e) {
83
+ errorMessage.value = e instanceof Error ? e.message : "Failed to save grants";
84
+ }
85
+ }
86
+ async function handleAddGrant() {
87
+ const raw = newGrant.value.collectionName;
88
+ const collectionName = typeof newGrant.value.collectionName === "object" ? raw.value ?? raw.label ?? "" : newGrant.value.collectionName;
89
+ grants.value.push({
90
+ name: collectionName,
91
+ read: newGrant.value.read,
92
+ write: newGrant.value.write,
93
+ administrate: newGrant.value.administrate,
94
+ grantType: "COLLECTION"
95
+ });
96
+ await saveGrants();
97
+ isAddModalOpen.value = false;
98
+ }
99
+ function openEdit(index) {
100
+ const grant = grants.value[index];
101
+ editIndex.value = index;
102
+ editGrantName.value = grant.name;
103
+ editGrant.value = { read: grant.read, write: grant.write, administrate: grant.administrate };
104
+ isEditModalOpen.value = true;
105
+ }
106
+ async function handleEditGrant() {
107
+ const grant = grants.value[editIndex.value];
108
+ grants.value[editIndex.value] = {
109
+ ...grant,
110
+ read: editGrant.value.read,
111
+ write: editGrant.value.write,
112
+ administrate: editGrant.value.administrate
113
+ };
114
+ await saveGrants();
115
+ isEditModalOpen.value = false;
116
+ }
117
+ async function removeGrant(index) {
118
+ grants.value.splice(index, 1);
119
+ await saveGrants();
120
+ }
121
+ function openAdd() {
122
+ const grantedNames = new Set(grants.value.map((g) => g.name));
123
+ addGrantSchema[0].options = allCollections.value.filter((c) => !grantedNames.has(c));
124
+ newGrant.value = { collectionName: "", read: false, write: false, administrate: false };
125
+ isAddModalOpen.value = true;
126
+ }
127
+ const UBadge = resolveComponent("UBadge");
128
+ const UButton = resolveComponent("UButton");
129
+ const UTooltip = resolveComponent("UTooltip");
130
+ function withTooltip(text, node) {
131
+ return h(UTooltip, { text }, { default: () => node });
132
+ }
133
+ const columns = [
134
+ {
135
+ accessorKey: "name",
136
+ header: "Collection"
137
+ },
138
+ {
139
+ accessorKey: "grantType",
140
+ header: "Type",
141
+ cell: ({ row }) => h(UBadge, {
142
+ label: row.original.grantType,
143
+ color: "neutral",
144
+ variant: "subtle"
145
+ })
146
+ },
147
+ {
148
+ accessorKey: "read",
149
+ header: "Read",
150
+ cell: ({ row }) => h(UBadge, {
151
+ label: row.original.read ? "Yes" : "No",
152
+ color: row.original.read ? "success" : "neutral",
153
+ variant: "subtle"
154
+ })
155
+ },
156
+ {
157
+ accessorKey: "write",
158
+ header: "Write",
159
+ cell: ({ row }) => h(UBadge, {
160
+ label: row.original.write ? "Yes" : "No",
161
+ color: row.original.write ? "success" : "neutral",
162
+ variant: "subtle"
163
+ })
164
+ },
165
+ {
166
+ accessorKey: "administrate",
167
+ header: "Admin",
168
+ cell: ({ row }) => h(UBadge, {
169
+ label: row.original.administrate ? "Yes" : "No",
170
+ color: row.original.administrate ? "error" : "neutral",
171
+ variant: "subtle"
172
+ })
173
+ },
174
+ {
175
+ id: "actions",
176
+ header: "",
177
+ cell: ({ row }) => h("div", { class: "flex gap-1 justify-end" }, [
178
+ withTooltip("Edit grant", h(UButton, {
179
+ "icon": "i-lucide-pencil",
180
+ "color": "neutral",
181
+ "variant": "ghost",
182
+ "size": "sm",
183
+ "aria-label": "Edit grant",
184
+ "onClick": () => openEdit(row.index)
185
+ })),
186
+ withTooltip("Remove grant", h(UButton, {
187
+ "icon": "i-lucide-trash-2",
188
+ "color": "error",
189
+ "variant": "ghost",
190
+ "size": "sm",
191
+ "aria-label": "Remove grant",
192
+ "onClick": () => removeGrant(row.index)
193
+ }))
194
+ ])
195
+ }
196
+ ];
197
+ fetchRole();
198
+ fetchCollections();
199
+ </script>
200
+
201
+ <template>
202
+ <div class="flex flex-col gap-4">
203
+ <div class="flex items-center justify-between">
204
+ <h2 class="text-xl font-semibold">
205
+ Grants: {{ roleName }}
206
+ </h2>
207
+ <div class="flex gap-2">
208
+ <UTooltip text="Refresh">
209
+ <UButton
210
+ icon="i-lucide-refresh-cw"
211
+ color="neutral"
212
+ variant="ghost"
213
+ :loading="loading"
214
+ aria-label="Refresh"
215
+ @click="fetchRole"
216
+ />
217
+ </UTooltip>
218
+ <UButton
219
+ icon="i-lucide-plus"
220
+ label="Add Grant"
221
+ @click="openAdd"
222
+ />
223
+ </div>
224
+ </div>
225
+
226
+ <UTable
227
+ :data="grants"
228
+ :columns="columns"
229
+ :loading="loading"
230
+ />
231
+
232
+ <!-- Add Grant Modal -->
233
+ <UModal
234
+ v-model:open="isAddModalOpen"
235
+ title="Add Grant"
236
+ >
237
+ <template #body>
238
+ <FUDataEdit
239
+ :data="newGrant"
240
+ :schema="addGrantSchema"
241
+ submit-label="Add Grant"
242
+ submit-icon="i-lucide-plus"
243
+ @data-saved="handleAddGrant"
244
+ />
245
+ <p
246
+ v-if="errorMessage"
247
+ class="mt-2 text-sm text-error-500"
248
+ >
249
+ {{ errorMessage }}
250
+ </p>
251
+ </template>
252
+ </UModal>
253
+
254
+ <!-- Edit Grant Modal -->
255
+ <UModal
256
+ v-model:open="isEditModalOpen"
257
+ :title="`Edit Grant: ${editGrantName}`"
258
+ >
259
+ <template #body>
260
+ <FUDataEdit
261
+ :data="editGrant"
262
+ :schema="editGrantSchema"
263
+ submit-label="Save Changes"
264
+ submit-icon="i-lucide-save"
265
+ @data-saved="handleEditGrant"
266
+ />
267
+ <p
268
+ v-if="errorMessage"
269
+ class="mt-2 text-sm text-error-500"
270
+ >
271
+ {{ errorMessage }}
272
+ </p>
273
+ </template>
274
+ </UModal>
275
+ </div>
276
+ </template>
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ roleName: 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,6 @@
1
+ type __VLS_Props = {
2
+ grantsPath?: 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,272 @@
1
+ <script setup>
2
+ import { h, reactive, ref, resolveComponent } from "vue";
3
+ import useMongocampAdmin from "../composables/useMongocampAdmin";
4
+ const props = defineProps({
5
+ grantsPath: { type: String, required: false }
6
+ });
7
+ const { listRoles, addRole, updateRole, deleteRole } = useMongocampAdmin();
8
+ const roles = ref([]);
9
+ const loading = ref(false);
10
+ const filterText = ref("");
11
+ const sorting = ref([]);
12
+ let filterTimer;
13
+ const isAddModalOpen = ref(false);
14
+ const isEditModalOpen = ref(false);
15
+ const isDeleteModalOpen = ref(false);
16
+ const roleToDelete = ref("");
17
+ const errorMessage = ref("");
18
+ const newRole = ref({ name: "", isAdmin: false });
19
+ const editRole = ref({ roleName: "", isAdmin: false });
20
+ const editGrants = ref([]);
21
+ const addRoleSchema = reactive([
22
+ {
23
+ $formkit: "nuxtUIInput",
24
+ name: "name",
25
+ label: "Role Name",
26
+ validation: "required|length:2"
27
+ },
28
+ {
29
+ $formkit: "nuxtUISwitch",
30
+ name: "isAdmin",
31
+ label: "Admin Role"
32
+ }
33
+ ]);
34
+ const editRoleSchema = reactive([
35
+ {
36
+ $formkit: "nuxtUISwitch",
37
+ name: "isAdmin",
38
+ label: "Admin Role"
39
+ }
40
+ ]);
41
+ async function fetchRoles() {
42
+ loading.value = true;
43
+ try {
44
+ roles.value = await listRoles(filterText.value);
45
+ } finally {
46
+ loading.value = false;
47
+ }
48
+ }
49
+ function onFilterInput() {
50
+ clearTimeout(filterTimer);
51
+ filterTimer = setTimeout(() => fetchRoles(), 300);
52
+ }
53
+ async function handleAddRole() {
54
+ errorMessage.value = "";
55
+ try {
56
+ await addRole(newRole.value.name, newRole.value.isAdmin);
57
+ isAddModalOpen.value = false;
58
+ newRole.value = { name: "", isAdmin: false };
59
+ await fetchRoles();
60
+ } catch (e) {
61
+ errorMessage.value = e instanceof Error ? e.message : "Failed to add role";
62
+ }
63
+ }
64
+ function openEdit(role) {
65
+ editRole.value = { roleName: role.name, isAdmin: role.isAdmin };
66
+ editGrants.value = (role.collectionGrants ?? []).map((g) => ({ ...g }));
67
+ isEditModalOpen.value = true;
68
+ }
69
+ async function handleEditRole() {
70
+ errorMessage.value = "";
71
+ try {
72
+ await updateRole(editRole.value.roleName, editRole.value.isAdmin, editGrants.value);
73
+ isEditModalOpen.value = false;
74
+ await fetchRoles();
75
+ } catch (e) {
76
+ errorMessage.value = e instanceof Error ? e.message : "Failed to update role";
77
+ }
78
+ }
79
+ function confirmDelete(roleName) {
80
+ roleToDelete.value = roleName;
81
+ isDeleteModalOpen.value = true;
82
+ }
83
+ async function handleDeleteRole() {
84
+ await deleteRole(roleToDelete.value);
85
+ isDeleteModalOpen.value = false;
86
+ await fetchRoles();
87
+ }
88
+ const UBadge = resolveComponent("UBadge");
89
+ const UButton = resolveComponent("UButton");
90
+ const UTooltip = resolveComponent("UTooltip");
91
+ function withTooltip(text, node) {
92
+ return h(UTooltip, { text }, { default: () => node });
93
+ }
94
+ function sortHeader(column, label) {
95
+ const isSorted = column.getIsSorted();
96
+ return h(UButton, {
97
+ color: "neutral",
98
+ variant: "ghost",
99
+ label,
100
+ icon: isSorted === "asc" ? "i-lucide-arrow-up-narrow-wide" : isSorted === "desc" ? "i-lucide-arrow-down-wide-narrow" : "i-lucide-arrow-up-down",
101
+ class: "-mx-2.5",
102
+ onClick: () => column.toggleSorting(isSorted === "asc")
103
+ });
104
+ }
105
+ const columns = [
106
+ {
107
+ accessorKey: "name",
108
+ header: ({ column }) => sortHeader(column, "Role")
109
+ },
110
+ {
111
+ accessorKey: "isAdmin",
112
+ header: "Admin",
113
+ cell: ({ row }) => h(UBadge, {
114
+ label: row.original.isAdmin ? "Admin" : "Standard",
115
+ color: row.original.isAdmin ? "error" : "neutral",
116
+ variant: "subtle"
117
+ })
118
+ },
119
+ {
120
+ accessorKey: "collectionGrants",
121
+ header: "Grants",
122
+ cell: ({ row }) => {
123
+ const count = row.original.collectionGrants?.length ?? 0;
124
+ return count ? h(UBadge, { label: String(count), color: "primary", variant: "subtle" }) : h("span", { class: "text-dimmed" }, "\u2014");
125
+ }
126
+ },
127
+ {
128
+ id: "actions",
129
+ header: "",
130
+ cell: ({ row }) => h("div", { class: "flex gap-1 justify-end" }, [
131
+ withTooltip("Manage grants", h(UButton, {
132
+ "icon": "i-lucide-key",
133
+ "color": "neutral",
134
+ "variant": "ghost",
135
+ "size": "sm",
136
+ "aria-label": "Manage grants",
137
+ "to": props.grantsPath ? `${props.grantsPath}/${row.original.name}` : `/secured/admin/roles/${row.original.name}`
138
+ })),
139
+ withTooltip("Edit role", h(UButton, {
140
+ "icon": "i-lucide-pencil",
141
+ "color": "neutral",
142
+ "variant": "ghost",
143
+ "size": "sm",
144
+ "aria-label": "Edit role",
145
+ "onClick": () => openEdit(row.original)
146
+ })),
147
+ withTooltip("Delete role", h(UButton, {
148
+ "icon": "i-lucide-trash-2",
149
+ "color": "error",
150
+ "variant": "ghost",
151
+ "size": "sm",
152
+ "aria-label": "Delete role",
153
+ "onClick": () => confirmDelete(row.original.name)
154
+ }))
155
+ ])
156
+ }
157
+ ];
158
+ fetchRoles();
159
+ </script>
160
+
161
+ <template>
162
+ <div class="flex flex-col gap-4">
163
+ <div class="flex items-center justify-between gap-4">
164
+ <h2 class="text-xl font-semibold">
165
+ Roles
166
+ </h2>
167
+ <div class="flex flex-1 items-center gap-2">
168
+ <UInput
169
+ v-model="filterText"
170
+ icon="i-lucide-search"
171
+ placeholder="Search roles..."
172
+ size="sm"
173
+ class="flex-1 max-w-xs"
174
+ @input="onFilterInput"
175
+ />
176
+ <UTooltip text="Refresh">
177
+ <UButton
178
+ icon="i-lucide-refresh-cw"
179
+ color="neutral"
180
+ variant="ghost"
181
+ :loading="loading"
182
+ aria-label="Refresh"
183
+ @click="fetchRoles"
184
+ />
185
+ </UTooltip>
186
+ <UButton
187
+ icon="i-lucide-plus"
188
+ label="Add Role"
189
+ @click="isAddModalOpen = true"
190
+ />
191
+ </div>
192
+ </div>
193
+
194
+ <UTable
195
+ v-model:sorting="sorting"
196
+ :data="roles"
197
+ :columns="columns"
198
+ :loading="loading"
199
+ />
200
+
201
+ <!-- Add Role Modal -->
202
+ <UModal
203
+ v-model:open="isAddModalOpen"
204
+ title="Add Role"
205
+ >
206
+ <template #body>
207
+ <FUDataEdit
208
+ :data="newRole"
209
+ :schema="addRoleSchema"
210
+ submit-label="Add Role"
211
+ submit-icon="i-lucide-plus"
212
+ @data-saved="handleAddRole"
213
+ />
214
+ <p
215
+ v-if="errorMessage"
216
+ class="mt-2 text-sm text-error-500"
217
+ >
218
+ {{ errorMessage }}
219
+ </p>
220
+ </template>
221
+ </UModal>
222
+
223
+ <!-- Edit Role Modal -->
224
+ <UModal
225
+ v-model:open="isEditModalOpen"
226
+ :title="`Edit Role: ${editRole.roleName}`"
227
+ >
228
+ <template #body>
229
+ <FUDataEdit
230
+ :data="editRole"
231
+ :schema="editRoleSchema"
232
+ submit-label="Save Changes"
233
+ submit-icon="i-lucide-save"
234
+ @data-saved="handleEditRole"
235
+ />
236
+ <p
237
+ v-if="errorMessage"
238
+ class="mt-2 text-sm text-error-500"
239
+ >
240
+ {{ errorMessage }}
241
+ </p>
242
+ </template>
243
+ </UModal>
244
+
245
+ <!-- Delete Confirmation Modal -->
246
+ <UModal
247
+ v-model:open="isDeleteModalOpen"
248
+ title="Delete Role"
249
+ :ui="{ footer: 'justify-end' }"
250
+ >
251
+ <template #body>
252
+ <p>
253
+ Are you sure you want to delete role <strong>{{ roleToDelete }}</strong>?
254
+ This action cannot be undone.
255
+ </p>
256
+ </template>
257
+ <template #footer>
258
+ <UButton
259
+ label="Cancel"
260
+ color="neutral"
261
+ variant="ghost"
262
+ @click="isDeleteModalOpen = false"
263
+ />
264
+ <UButton
265
+ label="Delete"
266
+ color="error"
267
+ @click="handleDeleteRole"
268
+ />
269
+ </template>
270
+ </UModal>
271
+ </div>
272
+ </template>
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ grantsPath?: 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,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;