Composables
Composables
Auto-imported composables available in your admin components and custom pages.
Admin Composables
useAdminRegistry
Access all registered resources and their schemas.
const {
allResources, // Ref<ResourceSchema[]>
getResourcesByGroup, // Ref<Record<string, ResourceSchema[]>>
getResource, // (name: string) => ResourceSchema | undefined
isLoading, // Ref<boolean>
} = useAdminRegistry()
Example:
<script setup>
const { allResources, getResourcesByGroup } = useAdminRegistry()
// Get all resources
console.log(allResources.value)
// Get resources by group
const grouped = getResourcesByGroup.value
// { 'Content': [...], 'User Management': [...] }
// Get specific resource
const { getResource } = useAdminRegistry()
const usersResource = getResource('users')
</script>
useAdminResource
Get schema information for a specific resource.
const {
resource, // Ref<ResourceSchema | undefined>
isLoading, // Ref<boolean>
} = useAdminResource(resourceName)
Example:
<script setup>
const resourceName = ref('users')
const { resource } = useAdminResource(resourceName)
// Access schema
console.log(resource.value?.displayName) // 'Users'
console.log(resource.value?.icon) // 'i-heroicons-user-group'
console.log(resource.value?.columns) // Column metadata
console.log(resource.value?.formFields) // Form configuration
</script>
useAdminPermissions
Check permissions for a resource.
const {
canCreate, // Ref<boolean>
canRead, // Ref<boolean>
canUpdate, // Ref<boolean>
canDelete, // Ref<boolean>
hasAnyPermission, // Ref<boolean>
isLoading, // Ref<boolean>
getPermissionDeniedMessage, // (action: string) => string
} = useAdminPermissions(resourceName)
Example:
<template>
<div>
<UButton v-if="canCreate" @click="createNew">
Create New
</UButton>
<UButton v-if="canUpdate" :disabled="!canUpdate" @click="edit">
Edit
</UButton>
</div>
</template>
<script setup>
const { canCreate, canUpdate, canDelete } = useAdminPermissions('posts')
</script>
useAdminActions
Get common navigation and action functions for a resource.
const {
goToList, // () => void
goToDetail, // (id: string | number) => void
goToEdit, // (id: string | number) => void
goToCreate, // () => void
handleDelete, // (id: string | number, options?: { redirect?: boolean }) => Promise<void>
isDeleting, // Ref<boolean>
} = useAdminActions(resourceName)
Example:
<template>
<div>
<UButton @click="goToList">Back to List</UButton>
<UButton @click="goToEdit(user.id)">Edit</UButton>
<UButton
:loading="isDeleting"
@click="handleDelete(user.id, { redirect: true })"
>
Delete
</UButton>
</div>
</template>
<script setup>
const props = defineProps<{ user: any }>()
const { goToList, goToEdit, handleDelete, isDeleting } = useAdminActions('users')
</script>
useResourceForm
Generate form fields and initial data for a resource.
const {
fields, // Ref<FieldConfig[]>
initialData, // Ref<Record<string, any>>
isLoading, // Ref<boolean>
resource, // Ref<ResourceSchema | undefined>
} = useResourceForm(resourceName, mode) // mode: 'create' | 'edit'
Example:
<script setup>
const { fields, initialData } = useResourceForm('posts', 'create')
// Use in custom form
const formData = ref(initialData.value)
</script>
useAdminConfig
Access admin configuration.
const {
prefix, // string - Admin route prefix
branding, // { title, logo, favicon }
permissions, // { unauthorizedButtons, unauthorizedSidebarItems }
features, // { bulkActions, search, filters, ... }
} = useAdminConfig()
Example:
<script setup>
const { branding, permissions } = useAdminConfig()
console.log(branding.title) // 'My Admin Panel'
const showDisabledButtons = permissions.unauthorizedButtons === 'disable'
</script>
Auto-API Composables
These composables are from @websideproject/nuxt-auto-api and work in the admin panel:
useAutoApiList
Query a list of resources.
const {
data, // Ref<ListResponse<T> | undefined>
isLoading, // Ref<boolean>
error, // Ref<Error | null>
refetch, // () => Promise<void>
} = useAutoApiList(resource, params, options)
Example:
<script setup>
const params = reactive({
filter: { status: 'published' },
sort: '-createdAt',
page: 1,
limit: 20,
})
const { data, isLoading } = useAutoApiList('posts', params)
// Access results
const posts = computed(() => data.value?.data || [])
const total = computed(() => data.value?.meta?.total)
</script>
useAutoApiGet
Get a single resource by ID.
const {
data, // Ref<GetResponse<T> | undefined>
isLoading, // Ref<boolean>
error, // Ref<Error | null>
refetch, // () => Promise<void>
} = useAutoApiGet(resource, id, params, options)
Example:
<script setup>
const route = useRoute()
const id = computed(() => route.params.id as string)
const { data, isLoading } = useAutoApiGet('posts', id, {
include: 'author,comments'
})
// Access record
const post = computed(() => data.value?.data)
</script>
useAutoApiCreate
Create a new resource.
const {
mutate, // (data: T) => void
mutateAsync, // (data: T) => Promise<any>
isPending, // Ref<boolean>
isSuccess, // Ref<boolean>
error, // Ref<Error | null>
} = useAutoApiCreate(resource)
Example:
<script setup>
const { mutate: createPost, isPending } = useAutoApiCreate('posts')
function handleSubmit(formData) {
createPost(formData, {
onSuccess: (response) => {
console.log('Created:', response.data)
navigateTo(`/admin/posts/${response.data.id}`)
},
onError: (error) => {
console.error('Failed:', error)
},
})
}
</script>
useAutoApiUpdate
Update an existing resource.
const {
mutate, // ({ id, data }: { id: string | number, data: T }) => void
mutateAsync,
isPending,
isSuccess,
error,
} = useAutoApiUpdate(resource)
Example:
<script setup>
const { mutate: updatePost, isPending } = useAutoApiUpdate('posts')
function handleSubmit(formData) {
updatePost(
{ id: postId.value, data: formData },
{
onSuccess: () => {
toast.success('Post updated')
},
}
)
}
</script>
useAutoApiDelete
Delete a resource.
const {
mutate, // (id: string | number) => void
mutateAsync,
isPending,
isSuccess,
error,
} = useAutoApiDelete(resource)
Example:
<script setup>
const { mutate: deletePost, isPending: isDeleting } = useAutoApiDelete('posts')
function confirmDelete() {
deletePost(postId.value, {
onSuccess: () => {
toast.success('Post deleted')
navigateTo('/admin/posts')
},
})
}
</script>
usePermissions
Get permissions from auto-api (used internally by useAdminPermissions).
const {
permissions, // Ref<ResourcePermissions | undefined>
canCreate,
canRead,
canUpdate,
canDelete,
isLoading,
} = usePermissions(resource)
useAutoApiToast
Get toast notification functions.
const toast = useAutoApiToast()
toast.success('Operation successful')
toast.error('Operation failed', error)
toast.info('Information message')
toast.warning('Warning message')
Utility Functions
formatFieldLabel
Convert field names to human-readable labels.
import { formatFieldLabel } from '#@websideproject/nuxt-auto-admin/utils'
formatFieldLabel('firstName') // 'First Name'
formatFieldLabel('email') // 'Email'
formatFieldLabel('createdAt') // 'Created At'
formatDisplayValue
Format values for display based on column type.
import { formatDisplayValue } from '#@websideproject/nuxt-auto-admin/utils'
const column = { type: 'timestamp', name: 'createdAt' }
formatDisplayValue(new Date(), column) // '2024-01-15 14:30'
const boolColumn = { type: 'boolean', name: 'active' }
formatDisplayValue(true, boolColumn) // 'Yes'
Complete Custom Page Example
<!-- pages/admin/analytics.vue -->
<template>
<div class="space-y-4">
<h1 class="text-2xl font-semibold">Analytics Dashboard</h1>
<div v-if="isLoadingStats" class="text-center p-8">
<UIcon name="i-heroicons-arrow-path" class="animate-spin h-8 w-8" />
</div>
<div v-else class="grid grid-cols-1 md:grid-cols-3 gap-4">
<UCard>
<div class="text-center">
<div class="text-3xl font-bold">{{ stats.users }}</div>
<div class="text-sm text-gray-500">Total Users</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-3xl font-bold">{{ stats.posts }}</div>
<div class="text-sm text-gray-500">Total Posts</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-3xl font-bold">{{ stats.comments }}</div>
<div class="text-sm text-gray-500">Total Comments</div>
</div>
</UCard>
</div>
<UCard>
<h2 class="text-lg font-semibold mb-4">Recent Posts</h2>
<div v-if="isLoadingPosts" class="text-center p-4">Loading...</div>
<div v-else>
<div
v-for="post in recentPosts"
:key="post.id"
class="flex items-center justify-between p-3 border-b last:border-0"
>
<div>
<div class="font-medium">{{ post.title }}</div>
<div class="text-sm text-gray-500">
{{ formatDisplayValue(post.createdAt, { type: 'timestamp' }) }}
</div>
</div>
<UButton
size="xs"
variant="ghost"
@click="goToPostDetail(post.id)"
>
View
</UButton>
</div>
</div>
</UCard>
</div>
</template>
<script setup lang="ts">
import { formatDisplayValue } from '#@websideproject/nuxt-auto-admin/utils'
definePageMeta({
layout: 'admin',
})
// Check permissions
const { hasAnyPermission } = useAdminPermissions('posts')
// Get stats
const stats = ref({ users: 0, posts: 0, comments: 0 })
const isLoadingStats = ref(true)
onMounted(async () => {
const [users, posts, comments] = await Promise.all([
$fetch('/api/users', { query: { aggregate: 'count' } }),
$fetch('/api/posts', { query: { aggregate: 'count' } }),
$fetch('/api/comments', { query: { aggregate: 'count' } }),
])
stats.value = {
users: users.meta.aggregates.count,
posts: posts.meta.aggregates.count,
comments: comments.meta.aggregates.count,
}
isLoadingStats.value = false
})
// Get recent posts
const {
data: postsResponse,
isLoading: isLoadingPosts,
} = useAutoApiList('posts', {
sort: '-createdAt',
limit: 5,
})
const recentPosts = computed(() => postsResponse.value?.data || [])
// Navigation
const { goToDetail } = useAdminActions('posts')
const goToPostDetail = (id: number) => goToDetail(id)
</script>
Next Steps
- Custom Pages - Build custom admin pages
- Custom Actions - Add custom resource actions