Table structure contract
Shape of the load-table response and query-table payload
This is the contract between backend and frontend. When the UI looks wrong, compare your actual JSON against this page.
Who owns this contract?
Backend owns field names and allowed values. Frontend renders them. If a column is missing, fix $TBLColumns — not the React code.
Structure response (load-table)
{
"success": true,
"tableName": "users",
"columns": [],
"filters": [],
"advancedFilters": [],
"rowActions": {},
"bulkActions": [],
"sortables": ["id", "name"],
"defSortCol": "id",
"defSortDir": "desc"
}Top-level fields
| Field | Required | Junior explanation | Example |
|---|---|---|---|
tableName | Yes | ID used in all other endpoints | "users" |
columns | Yes | Table headers and cell types | See below |
filters | No | Filter form fields | [] if none |
advancedFilters | No | Extra filter panel | Often same as filters |
rowActions | No | Row button definitions | Includes show_details |
bulkActions | No | Toolbar actions | Includes export_excel |
sortables | No | Columns user may sort | ["id", "name"] |
defSortCol | No | Default sort column | "id" |
defSortDir | No | Default direction | "desc" |
Column object (columns[])
{
"label": "Name",
"data_src": "name",
"type": "text",
"sortable": true,
"showable": true,
"showInMobileApp": true,
"minWidth": 120
}| Field | Purpose |
|---|---|
label | Header text (translated) |
data_src | Key in each row object |
type | Renderer — Column types |
sortable | Show sort UI when true |
showable | false = hidden |
values_formating | Badges, boolean labels (type-specific) |
Link columns add: linkStyle, linkText, linkColor, showCopyBtn.
Action columns require per-row row.actions in query items.
Filter object (filters[])
{
"type": "text",
"filter_name": "name",
"label": "Name",
"loadIf": true,
"props": {
"operators": ["=", "like"]
}
}| Field | Maps to query payload |
|---|---|
filter_name | filters[].field |
props.operators | Allowed filters[].operator values |
props.select_options | Dropdown choices (select filters) |
Row actions (rowActions)
Two shapes the frontend accepts:
- Flat —
{ "archive": { ...action def } } - Nested —
{ "general_actions": { "archive": { ... } } }
Each action definition includes:
| Field | Purpose |
|---|---|
action_key | Identifier |
action_type | normal, modalOpen, toggle, etc. |
action.api | Full URL to POST |
method | Usually post |
button | Label, classes, icons |
need_confirmation | Confirm dialog |
onSuccess | Post-action refresh behavior |
applicableAsBulkAction | Allow multi-select |
Bulk actions (bulkActions[])
{
"action_key": "export_excel",
"label": "Export Excel",
"method": "post",
"action": { "api": "..." },
"need_confirmation": false,
"responseType": "instant"
}Query response (query-table)
{
"success": true,
"items": [
{
"id": 1,
"name": "Jane",
"email": "jane@example.com",
"row": { "actions": { "archive": { "applicable": true } } }
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 42,
"last_page": 2
},
"bindings": {}
}| Field | Purpose |
|---|---|
items | Current page rows |
pagination | Standard Laravel-style meta |
bindings | Dynamic filter options |
Validation workflow (backend + frontend)
- Backend dev: curl
load-table→ save JSON - Frontend dev: compare Redux
tableStructurewith saved JSON - Fix mismatches on the backend first