Composables

Auto-imported composables available in your admin components and custom pages.

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

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.