用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/pimcore/skills --skill pimcore-studio-ui-tables-grids命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | pimcore-studio-ui-tables-grids |
| description | Using Grid component and TanStack Table in Pimcore Studio UI for data tables and grids |
| metadata | {"audience":"pimcore-developers","focus":"ui-components-tables"} |
How to use tables and grids in Pimcore Studio UI:
createColumnHelperUse this when:
BEFORE writing any import, read CRITICAL-IMPORT-PATHS.md.
All examples below use bundle imports (@pimcore/studio-ui-bundle/*). For core development (@sdk/*, @Pimcore/*), see the referenced file.
The Grid component is Pimcore's wrapper around TanStack Table with Studio UI styling and features.
import { Grid } from '@pimcore/studio-ui-bundle/components'
import { createColumnHelper } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
interface DataRow {
id: number
name: string
type: string
modified: string
}
export const MyDataGrid = () => {
const { t } = useTranslation()
const columnHelper = createColumnHelper<DataRow>()
const columns = [
columnHelper.accessor('name', {
header: t('columns.name'),
size: 200
}),
columnHelper.accessor('type', {
header: t('columns.type'),
size: 150
}),
columnHelper.accessor('modified', {
header: t('columns.modified'),
size: 180
})
]
const data: DataRow[] = [
{ id: 1, name: 'Item 1', type: 'Type A', modified: '2024-01-15' },
{ id: 2, name: 'Item 2', type: 'Type B', modified: '2024-01-16' }
]
return (
<Grid
columns={ columns }
data={ data }
/>
)
}
interface GridProps {
columns: ColumnDef<any>[] // Column definitions (required)
data: any[] // Row data (required)
// Selection
enableRowSelection?: boolean // Enable single row selection
enableMultipleRowSelection?: boolean // Enable multiple row selection
selectedRows?: Record<string, boolean> // Controlled selection state
onRowSelectionChange?: (selection: Record<string, boolean>) => void
// Sorting
enableSorting?: boolean // Enable column sorting
manualSorting?: boolean // Control sorting externally
sorting?: SortingState // Controlled sorting state
onSortingChange?: (sorting: SortingState) => void
// Loading & Empty States
isLoading?: boolean // Show loading skeleton
?: | |
?:
?:
?:
?:
?:
}
Use createColumnHelper to define type-safe columns.
import { createColumnHelper } from '@tanstack/react-table'
interface MyData {
id: number
name: string
status: string
count: number
}
const columnHelper = createColumnHelper<MyData>()
const columns = [
// Accessor column - directly access property
columnHelper.accessor('name', {
header: t('columns.name'),
size: 200
}),
// Accessor column with custom cell
columnHelper.accessor('status', {
header: t('columns.status'),
size: 120,
cell: (info) => {
const status = info.getValue()
return <Badge status={ status }>{status}</Badge>
}
}),
// Display column - computed value
columnHelper.display({
id: 'actions',
header: t(),
: ,
: (
)
})
]
{
// Identification
id?: string // Unique column ID
header: string | (() => JSX.Element) // Header content
// Sizing
size?: number // Default width in pixels
minSize?: number // Minimum width
maxSize?: number // Maximum width
// Cell Rendering
cell?: (info: CellContext) => JSX.Element // Custom cell renderer
// Sorting
enableSorting?: boolean // Enable sorting for this column
sortingFn?: string | SortingFn // Custom sort function
// Metadata
meta?: ColumnMetaType // Custom metadata (Pimcore-specific)
}
columnHelper.accessor('propertyName', {
header: t('header'),
size: 200
})
columnHelper.accessor((row) => row.firstName + ' ' + row.lastName, {
id: 'fullName',
header: t('full-name'),
size: 250
})
columnHelper.display({
id: 'actions',
header: t('actions'),
cell: (info) => (
<ButtonGroup items={ [
<IconButton
icon={ { value: 'edit' } }
key="edit"
onClick={ () => handleEdit(info.row.original.id) }
tooltip={ { title: t('edit') } }
/>,
<IconButton
icon={ { value: 'delete' } }
key="delete"
onClick={ () => handleDelete(info.row.original.id) }
tooltip={ { title: t('delete') } }
/>
] }/>
)
})
Enable row selection for interactive grids.
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({})
return (
<Grid
columns={ columns }
data={ data }
enableRowSelection
selectedRows={ selectedRows }
onRowSelectionChange={ setSelectedRows }
/>
)
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({})
return (
<Grid
columns={ columns }
data={ data }
enableMultipleRowSelection // Adds checkboxes
selectedRows={ selectedRows }
onRowSelectionChange={ setSelectedRows }
/>
)
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({})
const getSelectedData = () => {
return data.filter((row, index) => selectedRows[index])
}
const handleBulkAction = () => {
const selected = getSelectedData()
console.log('Selected items:', selected)
}
Enable column sorting functionality.
const [sorting, setSorting] = useState<SortingState>([])
return (
<Grid
columns={ columns }
data={ data }
enableSorting
sorting={ sorting }
onSortingChange={ setSorting }
/>
)
const [sorting, setSorting] = useState<SortingState>([])
// Fetch data when sorting changes
useEffect(() => {
if (sorting.length > 0) {
const { id, desc } = sorting[0]
fetchData({
sortBy: id,
sortOrder: desc ? 'DESC' : 'ASC'
})
}
}, [sorting])
return (
<Grid
columns={ columns }
data={ data }
enableSorting
manualSorting // Don't sort locally
sorting={ sorting }
onSortingChange={ setSorting }
/>
)
Show skeleton loading while data is fetching.
const { data, isLoading } = useQuery()
return (
<Grid
columns={ columns }
data={ data ?? [] }
isLoading={ isLoading } // Shows skeleton rows
/>
)
import { Grid, IconButton } from '@pimcore/studio-ui-bundle/components'
import { createColumnHelper } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
interface Metadata {
id: number
name: string
type: string
value: string
language?: string
}
export const MetadataTable = ({ metadata }: { metadata: Metadata[] }) => {
const { t } = useTranslation()
const columnHelper = createColumnHelper<Metadata>()
const columns = [
columnHelper.accessor('name', {
header: t('metadata.columns.name'),
size: 200
}),
columnHelper.accessor('type', {
header: t('metadata.columns.type'),
size: 150
}),
columnHelper.accessor('language', {
header: t(),
: ,
: info.() ||
}),
columnHelper.(, {
: (),
:
}),
columnHelper.({
: ,
: (),
: ,
: (
)
})
]
(
)
}
import { Grid, Button, IconButton } from '@pimcore/studio-ui-bundle/components'
import { createColumnHelper } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
interface Item {
id: number
name: string
status: 'active' | 'inactive'
modified: string
}
export const SelectableItemList = () => {
const { t } = useTranslation()
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({})
const columnHelper = createColumnHelper<Item>()
const { data, isLoading } = useGetItemsQuery()
const columns = [
columnHelper.accessor('name', {
header: t('columns.name'),
size: 250
}),
columnHelper.accessor('status', {
header: t('columns.status'),
: ,
: {
status = info.()
(
)
}
}),
columnHelper.(, {
: (),
:
}),
columnHelper.({
: ,
: (),
: ,
: (
)
})
]
selectedCount = .(selectedRows).().
= () => {
selectedItems = data?.( selectedRows[index])
}
(
)
}
const columnHelper = createColumnHelper<DataType>()
const columns = [
columnHelper.accessor('field1', {
header: t('field1'),
size: 200
}),
columnHelper.accessor('field2', {
header: t('field2'),
size: 150
})
]
return <Grid columns={ columns } data={ data } />
const columns = [
// ... data columns
columnHelper.display({
id: 'actions',
header: t('actions'),
size: 80,
cell: (info) => (
<IconButton
icon={ { value: 'edit' } }
onClick={ () => handleEdit(info.row.original.id) }
tooltip={ { title: t('edit') } }
/>
)
})
]
columnHelper.accessor('status', {
header: t('status'),
size: 120,
cell: (info) => {
const value = info.getValue()
return <Badge status={ value }>{t(`status.${value}`)}</Badge>
}
})
const [sorting, setSorting] = useState<SortingState>([])
return (
<Grid
columns={ columns }
data={ data }
enableSorting
sorting={ sorting }
onSortingChange={ setSorting }
/>
)
// DON'T - Hardcoded headers
columnHelper.accessor('name', {
header: 'Name'
})
// DO - Always translate
columnHelper.accessor('name', {
header: t('columns.name')
})
// DON'T - No ID
columnHelper.display({
cell: () => <button>Action</button>
})
// DO - Always provide ID
columnHelper.display({
id: 'actions',
cell: () => <button>Action</button>
})
// DON'T - No loading state
const { data } = useQuery()
return <Grid columns={ columns } data={ data } />
// DO - Handle loading
const { data, isLoading } = useQuery()
return <Grid columns={ columns } data={ data ?? [] } isLoading={ isLoading } />
// DON'T - No tooltip
<IconButton
icon={ { value: 'edit' } }
onClick={ handleEdit }
/>
// DO - Always include tooltip
<IconButton
icon={ { value: 'edit' } }
onClick={ handleEdit }
tooltip={ { title: t('edit') } }
/>
import { Grid } from '@pimcore/studio-ui-bundle/components'
import { createColumnHelper } from '@tanstack/react-table'
const columnHelper = createColumnHelper<DataType>()
const columns = [
columnHelper.accessor('field', {
header: t('header'),
size: 200
})
]
<Grid columns={ columns } data={ data } />
// Simple accessor
columnHelper.accessor('name', { header: t('name') })
// Custom cell
columnHelper.accessor('status', {
header: t('status'),
cell: (info) => <Badge>{info.getValue()}</Badge>
})
// Actions column
columnHelper.display({
id: 'actions',
cell: (info) => <IconButton icon={ { value: 'edit' } } />
})