Create Your First Page
Learn to Create Admin Pages with SmartCrudPage in 15 Minutes
๐ Overview
This tutorial will guide you through creating a complete CRUD admin page using the SmartCrudPage template.
What You'll Learn
- โ How to design Prisma data models
- โ How to create Server Actions
- โ How to configure SmartCrudPage
- โ How to add admin menu items
Final Result
Create an "Announcement Management" page with:
- ๐ Data List (pagination, sorting, search)
- โ Create Announcement
- โ๏ธ Edit Announcement
- ๐๏ธ Delete Announcement
- ๐๏ธ View Details
๐ง Preparation
1. Design Data Model
Add the announcement model to prisma/schema.prisma:
model Announcement {
id String @id @default(cuid())
title String // Announcement Title
content String @db.Text // Announcement Content
type String @default("info") // Type: info/warning/success
enable Boolean @default(true) // Enabled
sort Int @default(0) // Sort Order
remark String? // Remarks
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime? // Soft Delete
}2. Execute Database Migration
npx prisma migrate dev --name add_announcement๐ Creation Steps
Step 1: Create Server Actions
Create file app/(admin)/actions/content/crud-action.announcement.js:
'use server'
import { createCrudActions } from '@/lib/core/crud-helper'
/**
* Announcement Management - Server Actions
*
* Naming Conventions:
* - sys prefix: Requires admin permission
* - auth prefix: Requires login
* - pub prefix: Public access
*/
// Resource Configuration
const announcementConfig = {
// Basic Configuration
modelName: 'announcement',
primaryKey: 'id',
softDelete: true,
// Field Configuration
fields: {
creatable: ['title', 'content', 'type', 'enable', 'sort', 'remark'],
updatable: ['title', 'content', 'type', 'enable', 'sort', 'remark'],
searchable: ['title', 'content', 'type'],
},
// Query Configuration
query: {
defaultSort: { sort: 'asc', createdAt: 'desc' },
defaultPageSize: 20,
},
// Validation Rules
validation: {
title: {
required: true,
maxLength: 100,
message: 'Title is required, max 100 characters'
},
content: {
required: true,
message: 'Content is required'
},
type: {
enum: ['info', 'warning', 'success'],
message: 'Type must be info/warning/success'
}
}
}
// Export CRUD Actions
export const {
getList: getAnnouncementListAction,
getDetail: getAnnouncementDetailAction,
create: createAnnouncementAction,
update: updateAnnouncementAction,
delete: deleteAnnouncementAction,
} = createCrudActions(announcementConfig)Step 2: Create Frontend Page
Create file app/(admin)/admin/content/announcements/page.js:
'use client'
import SmartCrudPage from '@/components/admin/smart-crud-page'
import * as announcementActions from '@/app/(admin)/actions/content/crud-action.announcement'
/**
* Announcement Management Page
*/
export default function AnnouncementsPage() {
// Fields Configuration - Core configuration that drives the entire page
const fieldsConfig = [
{
key: 'id',
title: 'ID',
type: 'text',
table: { width: 80, copyable: true },
form: { hidden: true },
},
{
key: 'title',
title: 'Announcement Title',
type: 'text',
table: { width: 200, ellipsis: true },
form: { required: true, placeholder: 'Enter announcement title' },
search: { enabled: true, mode: 'like' },
},
{
key: 'content',
title: 'Announcement Content',
type: 'textarea',
table: { width: 300, ellipsis: true },
form: { required: true, rows: 4 },
},
{
key: 'type',
title: 'Type',
type: 'select',
options: [
{ label: '๐ข Notice', value: 'info' },
{ label: 'โ ๏ธ Warning', value: 'warning' },
{ label: 'โ
Success', value: 'success' },
],
table: { width: 100 },
form: { required: true },
search: { enabled: true, mode: 'exact' },
},
{
key: 'enable',
title: 'Status',
type: 'switch',
table: {
width: 80,
render: (value) => value ? 'โ
Enabled' : 'โ Disabled'
},
form: { defaultValue: true },
search: { enabled: true, mode: 'exact' },
},
{
key: 'sort',
title: 'Sort',
type: 'number',
table: { width: 80, sorter: true },
form: { defaultValue: 0, min: 0 },
},
{
key: 'remark',
title: 'Remarks',
type: 'textarea',
table: { hidden: true },
form: { rows: 2 },
},
{
key: 'createdAt',
title: 'Created At',
type: 'datetime',
table: { width: 180, sorter: true },
form: { hidden: true },
search: { enabled: true, mode: 'range' },
},
]
// Actions Configuration
const actions = {
getList: announcementActions.getAnnouncementListAction,
getDetail: announcementActions.getAnnouncementDetailAction,
create: announcementActions.createAnnouncementAction,
update: announcementActions.updateAnnouncementAction,
delete: announcementActions.deleteAnnouncementAction,
}
return (
<SmartCrudPage
title="Announcement Management"
fieldsConfig={fieldsConfig}
actions={actions}
enableCreate={true}
enableEdit={true}
enableDelete={true}
enableDetail={true}
/>
)
}Step 3: Add Menu (Optional)
Add a new menu item in the admin panel's "Menu Management" page:
| Field | Value |
|---|---|
| Name | Announcement Management |
| URL | /admin/content/announcements |
| Icon | BellOutlined |
| Parent Menu | Content Management (if exists) |
| Sort | 10 |
โ Verification
1. Start Development Server
2. Access Page
Open browser and visit: http://localhost:3000/admin/content/announcements
3. Functionality Testing
- List displays correctly
- Click "New" opens form
- Can save after filling form
- Click "Edit" can modify data
- Click "Delete" can delete data
- Search functionality works
- Pagination works correctly
๐จ Advanced Configuration
Add Custom Row Actions
const customRowActions = [
{
key: 'publish',
label: 'Publish',
onClick: async (record) => {
// Custom action logic
console.log('Publish announcement:', record.id)
},
showCondition: (record) => !record.enable,
},
]
<SmartCrudPage
// ...other configurations
customRowActions={customRowActions}
/>Add Toolbar Buttons
const toolbarExtra = (
<Button onClick={() => console.log('Export')}>
Export Data
</Button>
)
<SmartCrudPage
// ...other configurations
toolbarExtra={toolbarExtra}
/>Use Hooks for Business Logic
Add to crud-action.announcement.js:
const announcementConfig = {
// ...other configurations
hooks: {
beforeCreate: async (data) => {
// Pre-create processing
console.log('About to create announcement:', data.title)
return data
},
afterCreate: async (record) => {
// Post-create processing
console.log('Announcement created successfully:', record.id)
},
beforeUpdate: async (id, data) => {
// Pre-update processing
return data
},
beforeDelete: async (id) => {
// Pre-delete check
// If returns false or throws error, deletion will be prevented
return true
},
}
}๐ Related Documentation
SmartCrudPage Complete Guide
View all options and examples for table/form configuration
fieldsConfig Configuration
Complete reference for field configuration options
Server Actions Development
Best practices for encapsulation, authentication, and logging
Complete Example: Coupon Management
End-to-end more complex CRUD example