AgentSkillsCN

data-table-page

构建管理后台/CRUD 数据表页面,采用服务器端获取数据、SWR 缓存以及乐观更新机制。 当您需要创建数据表页面、实现 CRUD 操作、处理数据变更,或在分页、筛选与批量操作中进行开发时,可调用此技能。从 API 到 UI,完整覆盖相关模式。

SKILL.md
--- frontmatter
name: data-table-page
description: |
  Build admin/CRUD data table pages with server-side fetching, SWR caching, and optimistic mutations.
  Use when creating table pages, implementing CRUD operations, handling data mutations, or working with
  pagination, filters, and bulk operations. Covers the complete pattern from API to UI.
allowed-tools: Read, Write, Edit, Grep, Glob, Bash

Data Table Page Skill

Overview

This skill teaches how to build production-grade data table pages following the established patterns in this codebase. The architecture combines:

  • Server-side data fetching (Next.js Server Components)
  • Client-side caching (SWR with optimistic updates)
  • URL state management (nuqs for pagination/filters)
  • Context API (for CRUD actions propagation)
  • TanStack Table (for table rendering)

CRITICAL: Always follow existing patterns. Do not introduce new state management libraries or data fetching approaches.

When to Use This Skill

Activate when request involves:

  • Creating a new data table page
  • Adding CRUD operations to a table
  • Implementing server-side data fetching
  • Setting up SWR caching and mutations
  • Handling optimistic UI updates
  • Adding pagination, search, or filters
  • Creating column definitions
  • Implementing bulk operations
  • Building row action menus
  • Creating add/edit/view sheets/modals

Quick Reference

Page Structure (Reference: Users Page)

code
app/(pages)/{feature}/
├── page.tsx                    # Server component - data fetching
├── _components/
│   ├── table/
│   │   ├── {feature}-table.tsx        # SWR setup + context provider
│   │   ├── {feature}-table-body.tsx   # DataTable + toolbars
│   │   ├── {feature}-table-columns.tsx # Column definitions
│   │   ├── {feature}-table-header.tsx  # Search, export, print
│   │   └── {feature}-table-controller.tsx # Bulk actions
│   ├── actions/
│   │   ├── actions-menu.tsx           # Row action buttons
│   │   └── add-{item}-button.tsx      # Add button
│   ├── filters/                       # Filter components
│   ├── sidebar/
│   │   └── status-panel.tsx           # Summary + filters sidebar
│   └── modal/
│       ├── add-{item}-sheet.tsx       # Create form
│       ├── edit-{item}-sheet.tsx      # Update form
│       └── view-{item}-sheet.tsx      # Read-only view
└── context/
    └── {feature}-actions-context.tsx  # CRUD actions context

Shared Components

ComponentPathPurpose
DataTablecomponents/data-table/table/data-table.tsxTanStack Table wrapper
TableHeadercomponents/data-table/table/table-header.tsxSearch + export bar
TableControllercomponents/data-table/table/table-controller.tsxBulk actions bar
Paginationcomponents/data-table/table/pagination.tsxURL-synced pagination
SearchInputcomponents/data-table/controls/search-input.tsxDebounced search
ExportButtoncomponents/data-table/actions/export-button.tsxCSV/Excel export

API Layer Files

TypePath Pattern
Server Actionslib/actions/{feature}.actions.ts
Client APIlib/api/{feature}.ts
Typestypes/{feature}.ts

Core Data Flow

code
1. page.tsx (Server)
   ↓ Fetch initial data with server actions
   ↓ Pass to client component as initialData

2. {feature}-table.tsx (Client)
   ↓ SWR hook with fallbackData: initialData
   ↓ Define updateItems() for cache mutations
   ↓ Wrap children in ContextProvider

3. Column definitions
   ↓ Receive callbacks: updateItems, markUpdating, clearUpdating
   ↓ Call API → Update cache → Show toast

4. User interaction
   ↓ markUpdating([id]) → API call → updateItems([result]) → clearUpdating()

Key Patterns Summary

1. Server-Side Fetching (page.tsx)

typescript
export default async function Page({ searchParams }) {
  const data = await getData(limit, skip, filters);
  return <Table initialData={data} />;
}

2. SWR Setup (table.tsx)

typescript
const { data, mutate } = useSWR(apiUrl, fetcher, {
  fallbackData: initialData,
  keepPreviousData: true,
  revalidateOnMount: false,
});

3. Cache Update Function

typescript
const updateItems = async (updatedItems) => {
  await mutate((current) => ({
    ...current,
    items: current.items.map(item =>
      updatedMap.has(item.id) ? updatedMap.get(item.id) : item
    ),
  }), { revalidate: false });
};

4. Mutation Pattern

typescript
markUpdating([id]);
try {
  const result = await apiCall(id, data);
  await updateItems([result]);
  toast.success(message);
} finally {
  clearUpdating([id]);
}

For complete patterns, see PATTERNS.md.

Allowed Operations

DO:

  • Create new table pages following the users page structure
  • Add CRUD operations with optimistic updates
  • Extend shared components for feature-specific needs
  • Add new column definitions with callbacks
  • Create context providers for actions
  • Add server actions and client API functions

DON'T:

  • Bypass SWR for data fetching
  • Use useState for server data (use SWR)
  • Call APIs directly from column cells without proper error handling
  • Skip the context pattern for shared actions
  • Create new pagination components (use shared Pagination)

Validation Checklist

Before completing data table work:

  • Server component fetches initial data
  • SWR uses fallbackData from server
  • updateItems function updates cache correctly
  • Mutations follow markUpdating → API → updateItems → clearUpdating
  • Toast notifications on success/error
  • Loading states show during operations
  • URL state works for pagination/filters
  • Context provides actions to nested components
  • Types defined in types/{feature}.ts

Additional Resources

Trigger Phrases

  • "data table", "table page", "CRUD page"
  • "server-side fetching", "SWR", "useSWR"
  • "mutations", "updateUsers", "updateItems"
  • "optimistic update", "cache invalidation"
  • "column definitions", "createColumns"
  • "row actions", "bulk operations"
  • "pagination", "filters", "search"
  • "add sheet", "edit sheet", "view sheet"
  • "context provider", "actions context"