@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.
- package/LICENSE +21 -0
- package/README.md +308 -0
- package/dist/module.d.mts +8 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +35 -0
- package/dist/runtime/components/MongocampAccount.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampAccount.vue +197 -0
- package/dist/runtime/components/MongocampAccount.vue.d.ts +3 -0
- package/dist/runtime/components/MongocampCollectionData.d.vue.ts +6 -0
- package/dist/runtime/components/MongocampCollectionData.vue +511 -0
- package/dist/runtime/components/MongocampCollectionData.vue.d.ts +6 -0
- package/dist/runtime/components/MongocampCollectionInfos.d.vue.ts +9 -0
- package/dist/runtime/components/MongocampCollectionInfos.vue +393 -0
- package/dist/runtime/components/MongocampCollectionInfos.vue.d.ts +9 -0
- package/dist/runtime/components/MongocampCollections.d.vue.ts +7 -0
- package/dist/runtime/components/MongocampCollections.vue +231 -0
- package/dist/runtime/components/MongocampCollections.vue.d.ts +7 -0
- package/dist/runtime/components/MongocampDatabases.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampDatabases.vue +112 -0
- package/dist/runtime/components/MongocampDatabases.vue.d.ts +3 -0
- package/dist/runtime/components/MongocampJobs.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampJobs.vue +354 -0
- package/dist/runtime/components/MongocampJobs.vue.d.ts +3 -0
- package/dist/runtime/components/MongocampLogin.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampLogin.vue +63 -0
- package/dist/runtime/components/MongocampLogin.vue.d.ts +3 -0
- package/dist/runtime/components/MongocampRoleGrants.d.vue.ts +6 -0
- package/dist/runtime/components/MongocampRoleGrants.vue +276 -0
- package/dist/runtime/components/MongocampRoleGrants.vue.d.ts +6 -0
- package/dist/runtime/components/MongocampRoles.d.vue.ts +6 -0
- package/dist/runtime/components/MongocampRoles.vue +272 -0
- package/dist/runtime/components/MongocampRoles.vue.d.ts +6 -0
- package/dist/runtime/components/MongocampUsers.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampUsers.vue +320 -0
- package/dist/runtime/components/MongocampUsers.vue.d.ts +3 -0
- package/dist/runtime/components/MongocampVersion.d.vue.ts +3 -0
- package/dist/runtime/components/MongocampVersion.vue +25 -0
- package/dist/runtime/components/MongocampVersion.vue.d.ts +3 -0
- package/dist/runtime/composables/useMongocampAccount.d.ts +7 -0
- package/dist/runtime/composables/useMongocampAccount.js +28 -0
- package/dist/runtime/composables/useMongocampAdmin.d.ts +14 -0
- package/dist/runtime/composables/useMongocampAdmin.js +48 -0
- package/dist/runtime/composables/useMongocampBucket.d.ts +15 -0
- package/dist/runtime/composables/useMongocampBucket.js +109 -0
- package/dist/runtime/composables/useMongocampCollection.d.ts +17 -0
- package/dist/runtime/composables/useMongocampCollection.js +12 -0
- package/dist/runtime/composables/useMongocampDocument.d.ts +13 -0
- package/dist/runtime/composables/useMongocampDocument.js +18 -0
- package/dist/runtime/composables/useMongocampDynamicForm.d.ts +14 -0
- package/dist/runtime/composables/useMongocampDynamicForm.js +231 -0
- package/dist/runtime/composables/useMongocampIndex.d.ts +9 -0
- package/dist/runtime/composables/useMongocampIndex.js +23 -0
- package/dist/runtime/composables/useMongocampJobs.d.ts +9 -0
- package/dist/runtime/composables/useMongocampJobs.js +25 -0
- package/dist/runtime/composables/useMongocampQuery.d.ts +99 -0
- package/dist/runtime/composables/useMongocampQuery.js +108 -0
- package/dist/runtime/composables/useMongocampQueryBuilder.d.ts +30 -0
- package/dist/runtime/composables/useMongocampQueryBuilder.js +112 -0
- package/dist/runtime/composables/useMongocampSchema.d.ts +14 -0
- package/dist/runtime/composables/useMongocampSchema.js +142 -0
- package/dist/runtime/composables/useMongocampSystem.d.ts +12 -0
- package/dist/runtime/composables/useMongocampSystem.js +21 -0
- package/dist/runtime/plugin.d.ts +6 -0
- package/dist/runtime/plugin.js +23 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/types.d.mts +3 -0
- 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;
|