@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sfxcode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # nuxt-ui-mongocamp
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+ [![Nuxt][nuxt-src]][nuxt-href]
7
+ [![Docs][docs-src]][docs-href]
8
+
9
+ A Nuxt module that wraps [`@sfxcode/nuxt-mongocamp-server`](https://www.npmjs.com/package/@sfxcode/nuxt-mongocamp-server) with ready-made UI components, composables, and a runtime plugin. Add the module to your Nuxt app and get MongoCamp authentication, user/role management, and collection access out of the box — built on [Nuxt UI](https://ui.nuxt.com) and [FormKit](https://formkit.com).
10
+
11
+ - [✨ Release Notes](/CHANGELOG.md)
12
+
13
+ ## Features
14
+
15
+ - **Auth middleware** — global route guard that protects `/secured/**` (login required) and `/admin/**` (admin role required)
16
+ - **Ready-made components** — login form, user/role management tables, collection browser with stats and paginated data table, server version badge
17
+ - **FormKit-powered forms** — schema-driven forms via `@sfxcode/nuxt-ui-formkit` with `nuxtUIInput`, `nuxtUISwitch`, `nuxtUIListbox`, and `nuxtUISelectMenu` inputs
18
+ - **Composables** — `useMongocampAdmin`, `useMongocampCollection`, `useMongocampDocument`, `useMongocampSchema` auto-imported into your app
19
+ - **Zero extra config** — peer modules (`@nuxt/ui`, `@formkit/nuxt`, `unocss-nuxt-ui`) are declared as `moduleDependencies` and configured automatically
20
+
21
+ ## Module Dependencies
22
+
23
+ These modules are declared as `moduleDependencies` and are automatically set up — you do not need to add them manually to your `nuxt.config.ts`:
24
+
25
+ | Module | Purpose |
26
+ |---|---|
27
+ | [`@nuxt/ui`](https://ui.nuxt.com) | Component library (UTable, UModal, UBadge, UPageCard, …) |
28
+ | [`unocss-nuxt-ui`](https://www.npmjs.com/package/unocss-nuxt-ui) | UnoCSS preset that matches Nuxt UI's design tokens |
29
+ | [`@formkit/nuxt`](https://formkit.com/getting-started/installation#with-nuxt) | FormKit core integration for Nuxt |
30
+ | [`@sfxcode/nuxt-ui-formkit`](https://www.npmjs.com/package/@sfxcode/nuxt-ui-formkit) | Nuxt UI input types for FormKit (`nuxtUIInput`, `nuxtUISwitch`, `nuxtUIListbox`, `nuxtUISelectMenu`) |
31
+ | [`@sfxcode/nuxt-mongocamp-server`](https://www.npmjs.com/package/@sfxcode/nuxt-mongocamp-server) | MongoCamp REST API client, auth state, and `useMongocampApi()` / `useMongocampAuth()` composables |
32
+
33
+ ## Quick Setup
34
+
35
+ ```bash
36
+ npm install nuxt-ui-mongocamp
37
+ ```
38
+
39
+ Add the module to `nuxt.config.ts`:
40
+
41
+ ```ts
42
+ export default defineNuxtConfig({
43
+ modules: ['nuxt-ui-mongocamp'],
44
+
45
+ mongocamp: {
46
+ url: process.env.MONGOCAMP_URL,
47
+ },
48
+ })
49
+ ```
50
+
51
+ The `mongocamp` key is forwarded to `@sfxcode/nuxt-mongocamp-server`. Set `MONGOCAMP_URL` (and optionally `MONGOCAMP_ADMIN_USER` / `MONGOCAMP_ADMIN_PASSWORD`) in your `.env` file.
52
+
53
+ ## Components
54
+
55
+ All components are auto-imported.
56
+
57
+ ### `<MongocampLogin />`
58
+
59
+ FormKit schema-driven login form. Persists the last user ID in a cookie (`mongocamp_login`) and redirects to `/secured` on success.
60
+
61
+ ```vue
62
+ <template>
63
+ <MongocampLogin />
64
+ </template>
65
+ ```
66
+
67
+ ### `<MongocampUsers />`
68
+
69
+ Full CRUD table for managing users — create, edit (roles via transfer listbox, password change), and delete, all via modal dialogs. Includes a server-side debounced search input and sortable column headers.
70
+
71
+ ```vue
72
+ <template>
73
+ <MongocampUsers />
74
+ </template>
75
+ ```
76
+
77
+ ### `<MongocampRoles />`
78
+
79
+ Full CRUD table for managing roles — create, edit (admin flag, collection grants), and delete. Includes a server-side debounced search input and sortable column headers.
80
+
81
+ ```vue
82
+ <template>
83
+ <MongocampRoles />
84
+ </template>
85
+ ```
86
+
87
+ ### `<MongocampRoleGrants />`
88
+
89
+ Per-role collection grant management — lists grants for a named role, with add/edit/delete. Filters the collection picker to exclude already-granted collections.
90
+
91
+ ```vue
92
+ <template>
93
+ <MongocampRoleGrants role-name="myRole" />
94
+ </template>
95
+ ```
96
+
97
+ ### `<MongocampCollections />`
98
+
99
+ Table of all collections with document count, storage size, and index count. Each row links to the collection info and data pages. Includes a client-side filter input and sortable column headers.
100
+
101
+ | Prop | Type | Default | Description |
102
+ |---|---|---|---|
103
+ | `infoPath` | `string` | `/secured/admin/collections` | Base path for the info page link |
104
+ | `dataPath` | `string` | `/secured/admin/collections` | Base path for the data page link (`<dataPath>/<name>/data`) |
105
+
106
+ ```vue
107
+ <template>
108
+ <MongocampCollections />
109
+ </template>
110
+ ```
111
+
112
+ ### `<MongocampCollectionInfos />`
113
+
114
+ Stat-card grid for a single collection — document count, data size, storage size, avg doc size, index count, total index size, and a per-index size table.
115
+
116
+ ```vue
117
+ <template>
118
+ <MongocampCollectionInfos collection-name="myCollection" />
119
+ </template>
120
+ ```
121
+
122
+ ### `<MongocampCollectionData />`
123
+
124
+ Schema-driven paginated data table for a collection.
125
+
126
+ - **Columns** derived from the collection's JSON schema; falls back to first-row key derivation when no schema properties exist. Column order: `_id` first, `metaData` last, all others sorted A–Z.
127
+ - **Sorting** — clickable column headers trigger server-side sort via the MongoCamp API (`field` / `-field`).
128
+ - **Filtering** — debounced search input sends a Lucene query (`col1: *term* OR col2: *term*`) across all string-typed columns to the API; disabled until the schema is loaded.
129
+ - **Cell rendering**:
130
+ - `date-time` columns and MongoDB `$date` extended JSON → locale-formatted date string
131
+ - MongoDB `$oid` → monospaced ID string
132
+ - `metaData` objects (with `created`/`updated` fields) → structured `created / updated / by` rows
133
+ - All other objects and arrays → icon button (`{}` / list); click opens a modal with pretty-printed JSON in a `<pre>` tag
134
+ - Includes a reload button and paginated footer.
135
+
136
+ ```vue
137
+ <template>
138
+ <MongocampCollectionData collection-name="myCollection" />
139
+ </template>
140
+ ```
141
+
142
+ ### `<MongocampVersion />`
143
+
144
+ Displays the connected MongoCamp server name and version as a `UBadge`. Shows a neutral "unavailable" badge when the server cannot be reached.
145
+
146
+ ```vue
147
+ <template>
148
+ <MongocampVersion />
149
+ </template>
150
+ ```
151
+
152
+ ## Composables
153
+
154
+ All composables are auto-imported.
155
+
156
+ ### `useMongocampAdmin()`
157
+
158
+ Wraps the `adminApi` and `collectionApi` for user and role management.
159
+
160
+ ```ts
161
+ const {
162
+ listUsers, // (filter?: string) => Promise<UserProfile[]>
163
+ addUser, // (userId, password, apiKey?, roles?) => Promise<UserProfile>
164
+ deleteUser, // (userId) => Promise<void>
165
+ updateUserRoles, // (userId, roles) => Promise<UserProfile>
166
+ updateUserPassword, // (userId, password) => Promise<void>
167
+ listRoles, // (filter?: string) => Promise<Role[]>
168
+ addRole, // (name, isAdmin?, collectionGrants?) => Promise<Role>
169
+ updateRole, // (roleName, isAdmin, collectionGrants?) => Promise<Role>
170
+ deleteRole, // (roleName) => Promise<void>
171
+ listCollections, // () => Promise<string[]>
172
+ } = useMongocampAdmin()
173
+ ```
174
+
175
+ ### `useMongocampCollection()`
176
+
177
+ Reactive state for paginated collection queries.
178
+
179
+ ```ts
180
+ const {
181
+ filter, // Ref<string | undefined> — MongoDB filter expression
182
+ sort, // Ref<string[] | undefined> — sort fields
183
+ projection, // Ref<string[] | undefined> — field projection
184
+ pagination, // Ref<{ pageIndex: number, pageSize: number }>
185
+ total, // Ref<number> — total document count
186
+ } = useMongocampCollection()
187
+ ```
188
+
189
+ ### `useMongocampDocument()`
190
+
191
+ Helpers for document-level operations.
192
+
193
+ ```ts
194
+ const {
195
+ ensureMetaData, // <T>(data: T) => T — stamps createdBy/updatedBy/timestamps from logged-in user
196
+ updateFromPartial, // <T>(obj: T, updates: Partial<T>) => T
197
+ } = useMongocampDocument()
198
+ ```
199
+
200
+ ### `useMongocampSchema()`
201
+
202
+ Converts a `JsonSchemaDefinition` to typed table column definitions. Used internally by `MongocampCollectionData`.
203
+
204
+ ```ts
205
+ const { schemaToColumnDefinition } = useMongocampSchema()
206
+
207
+ // schemaToColumnDefinition(definition, fields) => ColumnDefinition[]
208
+ // ColumnDefinition: { columnName, columnKey, columnType }
209
+ // columnType: 'string' | 'number' | 'date-time'
210
+ ```
211
+
212
+ Fields are sorted with `_id` first, `metaData` last, and all other fields alphabetically.
213
+
214
+ ## Route Protection
215
+
216
+ The module registers a global route middleware at startup:
217
+
218
+ | Path pattern | Requirement |
219
+ |---|---|
220
+ | `/secured/**` | User must be logged in; redirects to `/` otherwise |
221
+ | `/admin/**` or `/secured/admin/**` | User must be logged in **and** have the admin role; redirects to `/secured` otherwise |
222
+ | `/logout` | Calls `logout()` and redirects to `/` |
223
+
224
+ ## Runtime Plugin
225
+
226
+ The plugin provides `$mongocampVersion` (a `Ref` to the server's version info) via `useNuxtApp()`:
227
+
228
+ ```ts
229
+ const { $mongocampVersion } = useNuxtApp()
230
+ // $mongocampVersion.value?.name
231
+ // $mongocampVersion.value?.version
232
+ ```
233
+
234
+ ## Configuration
235
+
236
+ The module's own config key is `nuxtUiMongocamp` (currently no options). The MongoCamp server is configured under the `mongocamp` key (provided by `@sfxcode/nuxt-mongocamp-server`):
237
+
238
+ ```ts
239
+ mongocamp: {
240
+ url: 'https://your-mongocamp-server',
241
+ paginationSize: 500, // default: 500
242
+ refreshToken: true, // default: true
243
+ tokenRefreshIntervall: 5000, // ms, default: 5000
244
+ }
245
+ ```
246
+
247
+ ## Contribution
248
+
249
+ ```bash
250
+ # Install dependencies
251
+ pnpm install
252
+
253
+ # Build stubs + prepare the playground (run once after clone)
254
+ pnpm run dev:prepare
255
+
256
+ # Start playground dev server
257
+ pnpm run dev
258
+
259
+ # Lint
260
+ pnpm run lint
261
+
262
+ # Run tests (Vitest + @nuxt/test-utils e2e)
263
+ pnpm run test
264
+ pnpm run test:watch
265
+
266
+ # Type-check
267
+ pnpm run test:types
268
+
269
+ # Build for publishing
270
+ pnpm run prepack
271
+ ```
272
+
273
+ The playground reads `playground/.env` for `MONGOCAMP_URL`, `MONGOCAMP_ADMIN_USER`, and `MONGOCAMP_ADMIN_PASSWORD`.
274
+
275
+ ## Documentation
276
+
277
+ Full documentation (guides, components, composables) lives in `docs/` and is built with [VitePress](https://vitepress.dev):
278
+
279
+ ```bash
280
+ # Start the docs dev server
281
+ pnpm run docs:dev
282
+
283
+ # Build the static site
284
+ pnpm run docs:build
285
+
286
+ # Preview the built site
287
+ pnpm run docs:preview
288
+ ```
289
+
290
+ ## License
291
+
292
+ [MIT](./LICENSE)
293
+
294
+ <!-- Badges -->
295
+ [npm-version-src]: https://img.shields.io/npm/v/nuxt-ui-mongocamp/latest.svg?style=flat&colorA=020420&colorB=00DC82
296
+ [npm-version-href]: https://npmjs.com/package/nuxt-ui-mongocamp
297
+
298
+ [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-ui-mongocamp.svg?style=flat&colorA=020420&colorB=00DC82
299
+ [npm-downloads-href]: https://npm.chart.dev/nuxt-ui-mongocamp
300
+
301
+ [license-src]: https://img.shields.io/npm/l/nuxt-ui-mongocamp.svg?style=flat&colorA=020420&colorB=00DC82
302
+ [license-href]: https://npmjs.com/package/nuxt-ui-mongocamp
303
+
304
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
305
+ [nuxt-href]: https://nuxt.com
306
+
307
+ [docs-src]: https://img.shields.io/badge/docs-vitepress-020420.svg?style=flat&colorA=020420&colorB=00DC82
308
+ [docs-href]: https://sfxcode.github.io/nuxt-ui-mongocamp/
@@ -0,0 +1,8 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ interface ModuleOptions {
4
+ }
5
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
6
+
7
+ export { _default as default };
8
+ export type { ModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "nuxt-ui-mongocamp",
3
+ "configKey": "nuxtUiMongocamp",
4
+ "compatibility": {
5
+ "nuxt": ">=3.16.0"
6
+ },
7
+ "version": "1.1.0",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.2",
10
+ "unbuild": "3.6.1"
11
+ }
12
+ }
@@ -0,0 +1,35 @@
1
+ import { defineNuxtModule, createResolver, addPlugin, addComponentsDir, addImportsDir } from '@nuxt/kit';
2
+
3
+ const module$1 = defineNuxtModule({
4
+ meta: {
5
+ name: "nuxt-ui-mongocamp",
6
+ configKey: "nuxtUiMongocamp",
7
+ compatibility: {
8
+ nuxt: ">=3.16.0"
9
+ }
10
+ },
11
+ // Default configuration options of the Nuxt module
12
+ defaults: {},
13
+ moduleDependencies: {
14
+ "@nuxt/ui": {},
15
+ "unocss-nuxt-ui": {},
16
+ "@formkit/nuxt": {},
17
+ "@sfxcode/nuxt-ui-formkit": {},
18
+ "@sfxcode/nuxt-mongocamp-server": {
19
+ defaults: {
20
+ paginationSize: 500,
21
+ refreshToken: true,
22
+ tokenRefreshIntervall: 5e3
23
+ }
24
+ }
25
+ },
26
+ setup(_options, _nuxt) {
27
+ const { resolve } = createResolver(import.meta.url);
28
+ const runtimeDir = resolve("./runtime");
29
+ addPlugin(resolve(runtimeDir, "plugin"));
30
+ addComponentsDir({ path: resolve(runtimeDir, "components") });
31
+ addImportsDir(resolve(runtimeDir, "composables"));
32
+ }
33
+ });
34
+
35
+ export { module$1 as 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;
@@ -0,0 +1,197 @@
1
+ <script setup>
2
+ import { reactive, ref, resolveComponent } from "vue";
3
+ import { useMongocampAccount, useToast } from "#imports";
4
+ const { fetchProfile, changePassword, regenerateApiKey } = useMongocampAccount();
5
+ const toast = useToast();
6
+ const UBadge = resolveComponent("UBadge");
7
+ const profile = ref(null);
8
+ const loading = ref(false);
9
+ async function loadProfile() {
10
+ loading.value = true;
11
+ try {
12
+ profile.value = await fetchProfile();
13
+ } finally {
14
+ loading.value = false;
15
+ }
16
+ }
17
+ const passwordData = ref({ password: "" });
18
+ const passwordSchema = reactive([
19
+ {
20
+ $formkit: "nuxtUIInput",
21
+ name: "password",
22
+ label: "New Password",
23
+ inputType: "password",
24
+ validation: "required|length:3"
25
+ }
26
+ ]);
27
+ async function handleChangePassword() {
28
+ const success = await changePassword(passwordData.value.password);
29
+ if (success) {
30
+ passwordData.value = { password: "" };
31
+ }
32
+ }
33
+ const isRegenerateModalOpen = ref(false);
34
+ const newApiKey = ref(null);
35
+ function openRegenerateModal() {
36
+ isRegenerateModalOpen.value = true;
37
+ }
38
+ function closeRegenerateModal() {
39
+ isRegenerateModalOpen.value = false;
40
+ }
41
+ async function handleRegenerateApiKey() {
42
+ newApiKey.value = await regenerateApiKey();
43
+ isRegenerateModalOpen.value = false;
44
+ }
45
+ async function copyApiKey() {
46
+ if (!newApiKey.value) return;
47
+ await navigator.clipboard.writeText(newApiKey.value);
48
+ toast.add({ title: "Copied to clipboard", description: "API key copied.", color: "success" });
49
+ }
50
+ function dismissApiKey() {
51
+ newApiKey.value = null;
52
+ }
53
+ loadProfile();
54
+ </script>
55
+
56
+ <template>
57
+ <div class="flex flex-col gap-4">
58
+ <USkeleton
59
+ v-if="loading"
60
+ class="h-32 w-full"
61
+ />
62
+
63
+ <UCard v-else-if="profile">
64
+ <template #header>
65
+ <span class="font-semibold">Account</span>
66
+ </template>
67
+ <div class="flex flex-col gap-3">
68
+ <div>
69
+ <div class="text-sm text-gray-500 dark:text-gray-400">
70
+ User
71
+ </div>
72
+ <div class="text-lg font-medium">
73
+ {{ profile.user }}
74
+ </div>
75
+ </div>
76
+ <div>
77
+ <div class="text-sm text-gray-500 dark:text-gray-400 mb-1">
78
+ Role
79
+ </div>
80
+ <UBadge
81
+ :label="profile.isAdmin ? 'Admin' : 'Standard'"
82
+ :color="profile.isAdmin ? 'error' : 'neutral'"
83
+ variant="subtle"
84
+ />
85
+ </div>
86
+ <div>
87
+ <div class="text-sm text-gray-500 dark:text-gray-400 mb-1">
88
+ Roles
89
+ </div>
90
+ <div
91
+ v-if="profile.roles?.length"
92
+ class="flex flex-wrap gap-1"
93
+ >
94
+ <UBadge
95
+ v-for="role in profile.roles"
96
+ :key="role"
97
+ :label="role"
98
+ color="primary"
99
+ variant="subtle"
100
+ />
101
+ </div>
102
+ <span
103
+ v-else
104
+ class="text-dimmed"
105
+ >—</span>
106
+ </div>
107
+ </div>
108
+ </UCard>
109
+
110
+ <UCard>
111
+ <template #header>
112
+ <span class="font-semibold">Change Password</span>
113
+ </template>
114
+ <FUDataEdit
115
+ :data="passwordData"
116
+ :schema="passwordSchema"
117
+ submit-label="Change Password"
118
+ submit-icon="i-lucide-save"
119
+ @data-saved="handleChangePassword"
120
+ />
121
+ </UCard>
122
+
123
+ <UCard>
124
+ <template #header>
125
+ <span class="font-semibold">API Key</span>
126
+ </template>
127
+ <div
128
+ v-if="newApiKey"
129
+ class="flex flex-col gap-2"
130
+ >
131
+ <p class="text-sm text-warning-500">
132
+ This key is shown only once. Copy it now — it cannot be retrieved again.
133
+ </p>
134
+ <div class="flex items-center gap-2">
135
+ <UInput
136
+ :model-value="newApiKey"
137
+ readonly
138
+ class="flex-1 font-mono text-xs"
139
+ />
140
+ <UButton
141
+ icon="i-lucide-copy"
142
+ label="Copy"
143
+ color="neutral"
144
+ variant="subtle"
145
+ @click="copyApiKey"
146
+ />
147
+ </div>
148
+ <UButton
149
+ label="Dismiss"
150
+ color="neutral"
151
+ variant="ghost"
152
+ class="self-start"
153
+ @click="dismissApiKey"
154
+ />
155
+ </div>
156
+ <div
157
+ v-else
158
+ class="flex items-center justify-between gap-4"
159
+ >
160
+ <p class="text-sm text-gray-500 dark:text-gray-400">
161
+ Regenerating your API key immediately invalidates the current one.
162
+ </p>
163
+ <UButton
164
+ label="Regenerate API Key"
165
+ color="error"
166
+ variant="subtle"
167
+ icon="i-lucide-key-round"
168
+ @click="openRegenerateModal"
169
+ />
170
+ </div>
171
+ </UCard>
172
+
173
+ <UModal
174
+ v-model:open="isRegenerateModalOpen"
175
+ title="Regenerate API Key"
176
+ :ui="{ footer: 'justify-end' }"
177
+ >
178
+ <template #body>
179
+ <p>Are you sure you want to regenerate your API key? Your current key will stop working immediately.</p>
180
+ </template>
181
+ <template #footer>
182
+ <UButton
183
+ label="Cancel"
184
+ color="neutral"
185
+ variant="ghost"
186
+ @click="closeRegenerateModal"
187
+ />
188
+ <UButton
189
+ label="Regenerate"
190
+ color="error"
191
+ icon="i-lucide-key-round"
192
+ @click="handleRegenerateApiKey"
193
+ />
194
+ </template>
195
+ </UModal>
196
+ </div>
197
+ </template>
@@ -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,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;