AI Skill Report Card
Generating Table Index Files
Quick Start15 / 15
TypeScript// Variant A: Tab + Versioned + Non-Editable (External Form) export interface ForwardEquipeRefProps { addEquipe: () => void; } export default forwardRef<ForwardEquipeRefProps>((props: any, ref) => { const [form] = Form.useForm(); const [data, setData] = useState<DataType[]>([]); const [openForm, setOpenForm] = useState<boolean>(false); const [record, setRecord] = useState<Pessoal.Namespace.Equipe>(); const { selectedVersao } = useModel('global'); const { equipes, getEquipes } = useModel('pessoal.equipe.model'); const [queryStringParams, setQueryStringParams] = useState<Pessoal.Namespace.Equipe.EquipeQueryStringParams>(defaultQueryStringParams); const addEquipe = () => { setRecord(undefined); setOpenForm(true); }; useImperativeHandle(ref, () => ({ addEquipe })); return ( <> <SimpleTable loading={false} columns={mergedColumns} dataSource={data} ignoreColumnKeys={!selectedVersao?.id ? columns.map(c => c.key as string) : ['acoes']} onChange={(pagination, filters, sorter: any) => { // Standard pagination + filtering logic }} pagination={{ total: equipes?.count, current: queryStringParams.page, pageSize: queryStringParams.page_size, }} /> <FormEquipe open={openForm} setOpen={setOpenForm} record={record} /> </> ); });
Recommendation▾
Add a decision tree diagram or flowchart to make the variant selection process even faster
Workflow15 / 15
Step 1: Determine Pattern Variant
Decision Matrix:
- Variant A: Tab + Versioned + Non-Editable (External Form) -
forwardRef, usesselectedVersao, opens form dialog - Variant B: Standalone Page + Non-Editable - No
forwardRef, add button in ownPageContainer - Variant C: Tab + Versioned + Editable Inline -
forwardRef, usesselectedVersao,EditableCell+mergedColumns - Variant D: Tab + Non-Versioned + Editable Inline -
forwardRef, noselectedVersao,EditableCell+mergedColumns
Step 2: Set Up Core Structure
Progress:
- Import statements and interfaces
- State management and hooks
- Data fetching effects
- Column definitions
- SimpleTable configuration
- Form/modal components (if applicable)
Step 3: Configure Columns
Column type mapping:
type: 'boolean'for true/false fieldstype: 'date'withdatePropsfor date fieldstype: 'filter'withfiltersarray for enum valuestype: 'select'withcomponentfor relationship fieldstype: 'percent'|'money'|'number'for numeric fields- No type for basic text columns
Step 4: Implement ignoreColumnKeys Logic
TypeScript// Non-versioned standalone ignoreColumnKeys={['acoes']} // Versioned tab ignoreColumnKeys={!selectedVersao?.id ? columns.map(c => c.key as string) : ['acoes']} // Editable (versioned) ignoreColumnKeys={editingKey !== '' || !selectedVersao?.id ? columns.map(c => c.key as string) : ['acoes']} // Editable (non-versioned) ignoreColumnKeys={editingKey !== '' ? columns.map(c => c.key as string) : ['acoes']}
Step 5: Add Pagination and Filtering
All paginated tables use identical onChange structure with field mapping for __label columns back to API parameters.
Recommendation▾
Include more error handling patterns and common debugging scenarios in the examples
Examples18 / 20
Example 1 - Variant B (Standalone Page):
TypeScriptexport default () => { const [data, setData] = useState<VersaoType[]>([]); const [openForm, setOpenForm] = useState(false); const [record, setRecord] = useState<Planejamento.Versao.Versao>(); const { versoes, getVersoes, deleteVersao } = useModel('planejamento.versao.model'); const columns: SimpleTableColumnType<VersaoType>[] = [ { title: 'Nome', dataIndex: 'nome', key: 'nome', minWidth: 200, }, { title: 'Tipo', dataIndex: 'tipo__label', key: 'tipo__label', type: 'filter', filters: [ { text: 'Budget', value: 'Budget' }, { text: 'Forecast', value: 'Forecast' }, ], }, { title: 'Ações', dataIndex: 'acoes', key: 'acoes', render: (_, record) => ( <Space> <Button icon={<EditOutlined />} onClick={() => { setRecord(record); setOpenForm(true); }} /> <Popconfirm title="Confirma Deletar?" onConfirm={() => deleteVersao(record.id)}> <Button icon={<DeleteOutlined />} /> </Popconfirm> </Space> ), }, ]; return ( <PageContainer header={{ title: 'Versões' }} extra={<Button onClick={() => setOpenForm(true)}>Criar Versão</Button>} > <SimpleTable columns={columns} dataSource={data} ignoreColumnKeys={['acoes']} /> <FormEditCreate open={openForm} setOpen={setOpenForm} record={record} /> </PageContainer> ); };
Example 2 - Variant C (Editable Inline):
TypeScriptconst EditableCell: React.FC<EditableCellProps> = ({ editing, inputType, children, formName, ...restProps }) => { const inputNodeMap = { sindicato: <SelectSindicato />, data: <DatePicker.MonthPicker format="MMM/YYYY" />, percent: <InputPercent max={100} />, }; return ( <td {...restProps}> {editing ? ( <Form.Item name={formName} style={{ margin: 0 }}> {inputNodeMap[inputType]} </Form.Item> ) : children} </td> ); }; export default forwardRef<ForwardDissidioRefProps>((props, ref) => { const [form] = Form.useForm(); const [data, setData] = useState<DataType[]>([]); const [editingKey, setEditingKey] = useState(''); const isEditing = (record: DataType) => record.key === editingKey; const mergedColumns = columns.map(col => { if (!col.editable) return col; return { ...col, onCell: (record: DataType) => ({ record, inputType: col.dataIndex, formName: col.dataIndex, editing: isEditing(record), }), }; }); const addDissidio = () => { const key = Date.now().toString(); const record = { key, sindicato: undefined, data: undefined, percent: undefined }; setData(prev => [record, ...prev]); edit(record); }; useImperativeHandle(ref, () => ({ addDissidio })); return ( <Form form={form} component={false}> <SimpleTable components={{ body: { cell: EditableCell } }} columns={mergedColumns} dataSource={data} ignoreColumnKeys={editingKey !== '' || !selectedVersao?.id ? columns.map(c => c.key as string) : ['acoes']} /> </Form> ); });
Recommendation▾
Consider adding performance optimization tips for large datasets or complex column configurations
Best Practices
Data Mapping:
- Non-editable: Use spread pattern
{ key: c.id.toString(), ...c } - Editable: Explicit fields
{ key: c.id.toString(), id: c.id, nome: c.nome }
Column Keys:
- Use API field names exactly:
cargo__label,sindicato__nome,is_active - Actions column always uses
key: 'acoes',dataIndex: 'acoes'
Filter Mapping:
__labelcolumns need mapping inonChange:cargo__label→cargo- Static enum filters use full array:
classificacao: filters[curr] - Select filters use
.at(0):cargo: filters[curr]?.at(0)
Parent Containers:
- Root tabs:
PageContainer+Spin+SelectVersaowith add button inextra - Intermediate tabs: Just
Tabswith add button intabBarExtraContent - Standalone pages: Add button in own
PageContainerextra
Common Pitfalls
Don't:
- Mix spread and explicit field patterns in same codebase area
- Put add buttons inside tab components (they go in parent containers)
- Use
selectedVersaoin non-versioned variants - Forget to map
__labelcolumn keys to API parameters inonChange - Use
type: 'select'for static enum values (usetype: 'filter'instead)
Always:
- Match
dataIndexto API response field names exactly - Include
keyproperty matchingdataIndexfor all columns - Use
forwardRef+useImperativeHandlefor all tab components - Set
minWidthon columns to prevent layout issues - Include
fixed: 'right'on actions column