Skip to main content

CrudHandler

CrudHandler is the primary React component for CRUD pages. It connects to a BaseCrudView endpoint and renders the list table, the Add form, and the detail view — all driven by the backend.

import { CrudHandler } from '@zango-core/crud/table';

Default CRUD Page

The simplest usage — pass the endpoint and an optional header title:

const Patients = () => (
<CrudHandler
api_endpoint="/patients/"
headerProps={{ title: "Patients" }}
/>
);

This renders a full list with search, sort, pagination, Add button, and a default detail drawer.


Custom Detail Drawer

Override the detail drawer with your own component while keeping the default table:

import { CrudHandler } from '@zango-core/crud/table';

const PatientDetail = ({ selectedRow, data, workflowDetails, open, onClose }) => {
if (!open) return null;
return (
<div>
<h2>{data?.title}</h2>
{Object.entries(data?.general_details?.fields || {}).map(([k, f]) => (
<div key={k}>
<strong>{f.display_name}:</strong> {f.value}
</div>
))}
<button onClick={onClose}>Close</button>
</div>
);
};

const Patients = () => (
<CrudHandler
api_endpoint="/patients/"
customDrawerDetail={PatientDetail}
/>
);

Detail Drawer Props

PropDescription
selectedRowThe raw row data from the table
dataFull detail response from the backend
data.titleRecord title
data.general_details.fieldsObject of { display_name, value } pairs
workflowDetailsWorkflow status and transitions (if workflow is enabled)
openWhether the drawer is open
onCloseCallback to close the drawer

Full-Page Detail View (Navigate on Row Click)

For primary entities where a drawer isn't enough — navigate to a full detail page on row click:

import { useNavigate } from 'react-router-dom';
import { CrudHandler, TableBody } from '@zango-core/crud/table';

// Pass a component ref — not JSX
const NavigateTableBody = () => <TableBody defaultDetailView="navigate" />;

const PatientDetail = ({ data, generalDetails, objectUuid }) => {
const navigate = useNavigate();
if (!data) return null;
return (
<div>
<button onClick={() => navigate(-1)}>← Back</button>
<h1>{data.title}</h1>
{Object.entries(generalDetails?.fields || {}).map(([k, f]) => (
<div key={k}>
<strong>{f.display_name}:</strong> {f.value}
</div>
))}
</div>
);
};

const Patients = () => (
<CrudHandler
api_endpoint="/patients/"
enableDetailViewRoute={true}
customMainDetail={PatientDetail}
customTableBody={NavigateTableBody}
/>
);

Full-Page Detail Props

PropDescription
dataFull detail response from the backend
generalDetailscamelCase alias for data.general_details
objectUuidUUID of the current record
workflowDetailsWorkflow status and transitions

Custom List Layout (Kanban, Calendar, Cards)

Swap the table body for a custom layout while keeping all the CRUD wiring:

import { CrudHandler, TableBody } from '@zango-core/crud/table';

const KanbanBody = () => (
<TableBody
customTableBody={({ rows }) => (
<div style={{ display: 'flex', gap: 16 }}>
{rows.map(row => (
<div key={row.id} className="kanban-card">{row.cells[0].value}</div>
))}
</div>
)}
/>
);

const Tasks = () => (
<CrudHandler
api_endpoint="/tasks/"
customTableBody={KanbanBody}
/>
);

Props Reference

PropTypeDescription
api_endpointstringThe URL of your BaseCrudView endpoint
headerPropsobject{ title: string } — page header
customDrawerDetailcomponentCustom drawer detail component
customMainDetailcomponentFull-page detail component (use with enableDetailViewRoute)
customTableBodycomponent refCustom table body component
enableDetailViewRoutebooleanEnable route-based navigation for detail view

AppBuilder Route Config

After creating your React component, register it in AppBuilder:

Default CRUD page (no React component needed):

{
"page_type": "crud",
"extra_params": { "api_endpoint": "/patients/" }
}

Custom component page:

{
"page_type": "custom",
"component": "Patients"
}

The component value must exactly match the export name in pages/index.js.