Skip to main content

ProTable Component

ProTable is a general-purpose remote table component in Page Designer. Use it to call an HTTP API directly and configure columns, query toolbars, pagination, and row actions on the page.

After reading this guide, you will be able to:

  • Connect a Custom URL to a paginated GET or POST endpoint
  • Pass current values from Input and other components through Query Context
  • Start a new search from the first page with a Search button
  • Keep the current search criteria when moving between pages
  • Configure response paths, columns, row keys, and display styles
  • Implement a ProTable-compatible backend endpoint with the Java example in this guide

This guide uses Spark's built-in product query sample. The endpoint contains 23 sample products and supports a case-insensitive partial match on product code and name through keyword.

1. When to use ProTable​

Use ProTable when:

  • The page needs to call a custom backend endpoint directly
  • Data comes from a third-party or aggregation service rather than one Business Object
  • The endpoint owns its pagination, filtering, sorting, or authorization logic
  • A button calls an endpoint and then writes the returned array to the table with setTableData

1.2 ProTable, DataList, and TaskList​

ComponentPrimary dataBest suited for
ProTableCustom URL or Model Data SourceGeneral HTTP APIs, aggregated data, and custom pagination contracts
DataListBusiness ObjectDQL, model fields, Object Actions, and model data permissions
TaskListSpark TasksTask filters, task statuses, task processing, and task context

ProTable also supports Model Data Source, whose model binding is similar to DataList. For Business Objects, DQL, and model filters, read the DataList Component guide. This guide focuses on ProTable's Custom URL data source.

2. Sample used in this guide​

Sample endpoint:

POST https://spark.hiforce.ai/spark/api/sample/protable/products

The sample page is configured with:

  • Data source: Custom URL
  • Request method: POST
  • Default page size: 10 records
  • Left Toolbar: one Key Word Input and one Search Button
  • Query Context: maps the Input value to the keyword request field
  • Search interaction: calls reloadTable on the current ProTable
  • Columns: code, name, category, price, and stock

After signing in to Spark with access to the application, open the runtime page used by this guide to verify the example.

3. Custom URL pagination contract​

3.1 POST request​

When ProTable loads the first page, it merges pagination fields and Query Context parameters into a JSON request body:

{
"current": 1,
"pageSize": 10,
"keyword": "Graphite"
}
FieldTypeDescription
currentnumberCurrent page number, starting at 1
pageSizenumberNumber of records per page
keywordstringBusiness query parameter added through Query Context in this example

ProTable manages current and pageSize automatically. Do not define them again in Query Context.

3.2 GET request​

With GET selected, the same parameters are converted to a URL query string:

/spark/api/sample/protable/products?current=1&pageSize=10&keyword=Graphite

GET requests omit undefined, null, and empty-string values. Array and object parameters are serialized as JSON strings, which the backend must parse as JSON.

3.3 Default response structure​

The sample returns Spark's standard ApiResult, with paginated data under data:

{
"success": true,
"code": 200,
"message": "Product data loaded successfully.",
"data": {
"total": 1,
"current": 1,
"pageSize": 10,
"requestContext": {
"environment": "DEV",
"renderMode": "RUNTIME"
},
"records": [
{
"id": 4,
"code": "DSP-2002",
"name": "Graphite Monitor 32",
"category": "DISPLAY",
"status": "ACTIVE",
"price": 699.00,
"stock": 21,
"updatedAt": "2026-07-25T16:40:00Z"
}
]
}
}

Configure the data source paths as follows:

Rows Path: data.records
Total Path: data.total
Current Page Path: data.current
Page Size Path: data.pageSize

Paths use dot notation for nested properties. If your endpoint returns records under result.items, set Rows Path to result.items.

A paginated endpoint must return the total number of filtered records, not the length of the current page array. Otherwise, ProTable cannot calculate the correct number of pages.

3.4 Page request context headers​

When ProTable sends a real HTTP request through Custom URL, it automatically includes two standard headers. The backend can use them to choose test data, restrict designer access, or record where a request originated:

HeaderValuesDescription
X-Spark-Page-EnvironmentDEV, TEST, PRODCurrent page environment; data previews in Page Designer use DEV
X-Spark-Page-Render-ModeDESIGN_PREVIEW, RUNTIMEPage Designer, Preview opened from the designer, and real-record previews use DESIGN_PREVIEW; normal runtime pages use RUNTIME

Environment and render mode are independent dimensions. For example, a runtime page in the development environment sends DEV + RUNTIME, while loading real records inside Page Designer sends DEV + DESIGN_PREVIEW. These values are stable enums; the backend must not infer the scenario from the page URL or Referer.

This is the shared contract for all Page Designer and Page Runtime backend requests, not only ProTable or Custom URL. Model Data Source, Data Form, Task components, uploads, row actions, and Send Request use the same headers. GET and POST behave identically. If a Custom URL targets a cross-origin service, its CORS configuration must allow both headers in Access-Control-Allow-Headers.

4. Add and configure ProTable​

4.1 Add the component​

  1. Open the target page in Page Designer.
  2. Expand Data in the component palette.
  3. Drag ProTable into a compatible container.
  4. Select ProTable and give it a stable, recognizable name such as productTable.

A stable name makes it easier to select the correct target in a Button's Component API interaction.

4.2 Configure Custom URL​

Select Custom URL under ProTable's Data Source and enter:

PropertyValue
URLhttps://spark.hiforce.ai/spark/api/sample/protable/products
Request MethodPOST
Rows Pathdata.records
Total Pathdata.total
Current Page Pathdata.current
Page Size Pathdata.pageSize

The URL supports three forms:

https://api.example.com/products
connection://erp/products
/products # Select a Connection Key as well
  • For same-origin Spark APIs, use a full URL or a site-relative path.
  • For external services, configure an External Connection in application settings and use its Connection Key.
  • Store secrets, tokens, and passwords in the connection configuration, never in the URL or Query Context.
  • The endpoint remains subject to authentication, data permissions, and backend authorization. Opening a protected endpoint directly in the browser may return 401.

Configure Response Fields​

Model Data Source can read Business Object field metadata directly. With Custom URL, maintain Response Fields in Data Source. Each item contains:

PropertyDescription
Field PathPath relative to one record, such as name or owner.name
LabelName shown in Columns and other field selectors
Data TypeTEXT, NUMBER, BOOLEAN, DATE, DATETIME, URL, OBJECT, or ARRAY

Add fields manually with the plus button, or click Test & Import to request up to 20 records and merge the discovered fields. Import follows these rules:

  • The backend is called only after an explicit click; opening the dialog never sends a request.
  • The request uses the current URL, Method, Query Context, and Rows Path.
  • Nested objects become dot paths; arrays register only the array field itself.
  • Existing Labels, Data Types, and ordering are preserved; only new paths are appended.
  • Sample values are not saved, and an empty or failed response never overwrites existing fields.

Test & Import uses the DEV + DESIGN_PREVIEW page request context. Data Source changes enter the page configuration only after Save; Cancel discards the current draft.

4.3 Configure Columns​

Add these entries to Columns in order:

LabelData Field
Codecode
Namename
Categorycategory
Priceprice
Stockstock

Data Field supports dot paths. For example, if a record contains owner.name, enter:

owner.name

Set column widths according to their content. A code column can be narrow, while a name column needs more room. Do not let long text expand the entire table.

4.4 Configure pagination and the row key​

Recommended settings:

Pagination / Page Size: 10
Row Unique Key: id

The Row Unique Key field must be stable and unique. Do not use names, statuses, or other values that may repeat or change.

At runtime, users can switch between 10, 20, and 50 records per page. When the page number or size changes, ProTable requests the endpoint again while keeping the current Query Context criteria.

5. Add a query control to Left Toolbar​

Select ProTable and add an Input to Left Toolbar:

Label: Key Word
Name: productKeywordInput
Allow Clear: true

The Input's internal ID on the sample page is field_bfd1e2b2. Do not copy this ID into your page. Select the Input you just added from the FX editor instead.

When Allow Clear is enabled, the clear icon appears while the Input contains text. Clearing the Input only changes its value; click Search again to reload the table without the keyword.

A common toolbar layout is:

  • Left Toolbar: Input, Date Picker, Select, Radio, and Search controls
  • Toolbar: Create, Import, Export, and other business actions

To keep the criteria and Search on the same horizontal line, place Search in Left Toolbar as shown in this example.

6. Bind keyword with Query Context​

Query Context maps runtime page values to HTTP request parameters. This example needs the following mapping:

Current Input value → productKeyword variable → keyword request field

6.1 Add a variable​

  1. Edit ProTable's Data Source.
  2. Click FX under Query Context.
  3. Click Add Variable.
  4. Enter productKeyword as Variable Name.
  5. Select Component Value as Source.
  6. Select the Key Word Input you just added as Component.

6.2 Add a request parameter​

Add this entry in the Query Context parameter area:

Parameter: keyword
Value: [[productKeyword]]

Before every request, the runtime reads the Input's current value again. If the user enters nothing, keyword is empty. The sample backend ignores a blank keyword and returns all records.

6.3 Common variable sources​

SourceUse case
Component ValueCurrent value of Input, Select, Radio, Date Picker, Uploader, or another component
URL ParameterQuery parameter from the browser URL
Page ContextPage context or a value written by an earlier interaction
Current RowA field from the current record in a row action
Static ValueA fixed string, number, or boolean

Target Value can reference one variable or combine several values:

[[productKeyword]]
prefix-[[productKeyword]]

When Target Value is exactly [[variableName]], the runtime preserves the original value type whenever possible. Arrays, objects, numbers, and booleans do not need to be converted to strings first.

7. Configure the Search button​

Add a Button to Left Toolbar:

Text: Search
Button Type: Primary

Then configure its click interaction:

  1. Select the Search Button and open Interaction editor.
  2. Add a Component API action.
  3. Select the current ProTable, such as productTable, as Target Component.
  4. Select reloadTable as Function.
  5. Save the interaction.

reloadTable starts a new query. It:

  1. Resets the current page to 1.
  2. Resolves current component values in Query Context again.
  3. Requests the endpoint with the new current, pageSize, and keyword.

This behavior prevents a common issue. Suppose a user is on page 2 and enters a keyword with only one matching record. Sending current: 2 would correctly return an empty array. Because Search calls reloadTable, the request sends current: 1 and displays the match.

Normal pagination is not a new search. When the user moves to another page, ProTable changes only current and keeps the current keyword:

Click Search: reset to page 1 + use the latest criteria
Click pagination: change the page + keep the current criteria

8. Java backend example​

The complete implementation in the Spark repository is located at:

spark-sample/src/main/java/hiforce/spark/sample/protable/

spark-console includes spark-sample, so the endpoint is published with Spark Console. The following sections show the core code required by a ProTable Custom URL.

8.1 Request DTO​

package hiforce.spark.sample.protable.model;

import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;

@Getter
@Setter
public class ProTableProductQueryRequest {

private Integer current = 1;
private Integer pageSize = 10;
private String keyword;
private String category;
private String status;
private BigDecimal minPrice;
private BigDecimal maxPrice;
}

In addition to keyword, the sample reserves category, status, and price range fields. The full repository implementation also includes generic conditions and a sortBy map.

8.2 Row DTO and page result​

package hiforce.spark.sample.protable.model;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;

@Getter
@AllArgsConstructor
public class ProTableProductDTO {
private final Long id;
private final String code;
private final String name;
private final String category;
private final String status;
private final BigDecimal price;
private final Integer stock;
private final Instant updatedAt;
}

@Getter
@AllArgsConstructor
public class ProTablePageResult<T> {
private final long total;
private final int current;
private final int pageSize;
private final List<T> records;
}

In an actual project, place the two public classes in separate files with matching names. They are combined here only to show the request and response contract together.

8.3 Controller​

package hiforce.spark.sample.protable.web;

import hiforce.spark.base.model.result.ApiResult;
import hiforce.spark.base.web.SparkApiResultHelper;
import hiforce.spark.sample.protable.model.ProTablePageResult;
import hiforce.spark.sample.protable.model.ProTableProductDTO;
import hiforce.spark.sample.protable.model.ProTableProductQueryRequest;
import hiforce.spark.sample.protable.service.ProTableProductService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Locale;

@RestController
@RequestMapping("/spark/api/sample/protable/products")
public class ProTableProductController {

private final ProTableProductService productService;

public ProTableProductController(ProTableProductService productService) {
this.productService = productService;
}

@PostMapping
public ApiResult<ProTablePageResult<ProTableProductDTO>> query(
@RequestBody(required = false) ProTableProductQueryRequest request,
@RequestHeader(value = "Accept-Language", required = false) String language) {
Locale locale = SparkApiResultHelper.resolveLocale(language);
return SparkApiResultHelper.success(
locale,
productService.query(request),
"SPARK-SAMPLE-PROTABLE-0001");
}
}

The Controller returns DTOs and a page result wrapped in ApiResult. The user-facing success message is localized through the Lattice Message Code SPARK-SAMPLE-PROTABLE-0001 instead of being hard-coded in the Controller.

8.4 Query, partial match, and pagination​

package hiforce.spark.sample.protable.service;

import hiforce.spark.sample.protable.model.ProTablePageResult;
import hiforce.spark.sample.protable.model.ProTableProductDTO;
import hiforce.spark.sample.protable.model.ProTableProductQueryRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

@Service
public class ProTableProductService {

private static final int MAX_PAGE_SIZE = 100;

private static final List<ProTableProductDTO> PRODUCTS = List.of(
product(1, "SPK-1001", "SparkBook Air", "COMPUTING", "ACTIVE", "999.00", 32,
"2026-07-27T14:20:00Z"),
product(2, "SPK-1002", "SparkBook Pro", "COMPUTING", "ACTIVE", "1599.00", 18,
"2026-07-28T09:10:00Z"),
product(3, "DSP-2001", "Aurora Monitor 27", "DISPLAY", "ACTIVE", "499.00", 45,
"2026-07-26T08:30:00Z"),
product(4, "DSP-2002", "Graphite Monitor 32", "DISPLAY", "ACTIVE", "699.00", 21,
"2026-07-25T16:40:00Z"),
product(5, "ACC-3001", "Pulse Mechanical Keyboard", "ACCESSORY", "ACTIVE", "129.00", 86,
"2026-07-24T11:00:00Z"),
product(6, "ACC-3002", "Flow Wireless Mouse", "ACCESSORY", "ACTIVE", "79.00", 120,
"2026-07-23T13:15:00Z"),
product(7, "ACC-3003", "Runtime Dock", "ACCESSORY", "ACTIVE", "219.00", 38,
"2026-07-22T09:45:00Z"),
product(8, "STO-4001", "Core SSD 1TB", "STORAGE", "ACTIVE", "149.00", 64,
"2026-07-21T15:20:00Z"),
product(9, "STO-4002", "Core SSD 2TB", "STORAGE", "ACTIVE", "269.00", 41,
"2026-07-20T10:05:00Z"),
product(10, "NET-5001", "Lattice Router", "NETWORK", "ACTIVE", "189.00", 27,
"2026-07-19T17:25:00Z"),
product(11, "NET-5002", "Mesh Access Point", "NETWORK", "ACTIVE", "139.00", 54,
"2026-07-18T12:35:00Z"),
product(12, "CMP-6001", "Build Station", "COMPUTING", "DRAFT", "2399.00", 7,
"2026-07-17T08:50:00Z"),
product(13, "DSP-2003", "Silk Portable Display", "DISPLAY", "ACTIVE", "329.00", 33,
"2026-07-16T14:10:00Z"),
product(14, "ACC-3004", "Spark AI Headset", "ACCESSORY", "ACTIVE", "199.00", 49,
"2026-07-15T10:45:00Z"),
product(15, "ACC-3005", "Console Camera", "ACCESSORY", "ACTIVE", "159.00", 72,
"2026-07-14T09:35:00Z"),
product(16, "STO-4003", "Archive Drive 8TB", "STORAGE", "ACTIVE", "289.00", 25,
"2026-07-13T18:20:00Z"),
product(17, "NET-5003", "Secure Gateway", "NETWORK", "DRAFT", "799.00", 5,
"2026-07-12T07:30:00Z"),
product(18, "CMP-6002", "Runtime Server", "COMPUTING", "ACTIVE", "3499.00", 4,
"2026-07-11T16:00:00Z"),
product(19, "ACC-3006", "USB-C Travel Hub", "ACCESSORY", "DISCONTINUED", "59.00", 0,
"2026-07-10T11:40:00Z"),
product(20, "DSP-2004", "Aurora Display Mini", "DISPLAY", "DRAFT", "279.00", 12,
"2026-07-09T13:05:00Z"),
product(21, "PRN-7001", "Flow Label Printer", "OFFICE", "ACTIVE", "249.00", 28,
"2026-07-08T08:25:00Z"),
product(22, "AUD-8001", "Aurora Conference Speaker", "AUDIO", "ACTIVE", "349.00", 16,
"2026-07-07T15:35:00Z"),
product(23, "PWR-9001", "Core Power Station", "POWER", "DRAFT", "899.00", 9,
"2026-07-06T10:15:00Z"));

public ProTablePageResult<ProTableProductDTO> query(ProTableProductQueryRequest request) {
ProTableProductQueryRequest query = request == null
? new ProTableProductQueryRequest()
: request;

int current = Math.max(query.getCurrent() == null ? 1 : query.getCurrent(), 1);
int pageSize = Math.min(
Math.max(query.getPageSize() == null ? 10 : query.getPageSize(), 1),
MAX_PAGE_SIZE);
String keyword = StringUtils.trimToNull(query.getKeyword());

List<ProTableProductDTO> filtered = PRODUCTS.stream()
.filter(product -> keyword == null
|| StringUtils.containsIgnoreCase(product.getCode(), keyword)
|| StringUtils.containsIgnoreCase(product.getName(), keyword))
.sorted(Comparator.comparing(ProTableProductDTO::getCode))
.toList();

long requestedOffset = (long) (current - 1) * pageSize;
int fromIndex = (int) Math.min(requestedOffset, filtered.size());
int toIndex = Math.min(fromIndex + pageSize, filtered.size());

return new ProTablePageResult<>(
filtered.size(),
current,
pageSize,
new ArrayList<>(filtered.subList(fromIndex, toIndex)));
}

private static ProTableProductDTO product(long id, String code, String name,
String category, String status, String price,
int stock, String updatedAt) {
return new ProTableProductDTO(
id, code, name, category, status,
new BigDecimal(price), stock, Instant.parse(updatedAt));
}
}

The sample has three important behaviors:

  1. StringUtils.trimToNull converts a blank keyword to null, which means no keyword filter.
  2. containsIgnoreCase matches both product code and name, so Graphite matches Graphite Monitor 32.
  3. The service filters and calculates total before slicing the current page with current and pageSize.

To keep the keyword flow focused, the Service above omits the full repository implementation's category, status, price, generic condition, and multi-field sorting logic. Its 23 products and pagination behavior match the actual sample.

8.5 GET endpoint extension​

To support GET as well, assemble the query parameters into the same Request DTO and reuse the POST query method:

@GetMapping
public ApiResult<ProTablePageResult<ProTableProductDTO>> queryByGet(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String keyword,
@RequestHeader(value = "Accept-Language", required = false) String language) {
ProTableProductQueryRequest request = new ProTableProductQueryRequest();
request.setCurrent(current);
request.setPageSize(pageSize);
request.setKeyword(keyword);
return query(request, language);
}

The actual sample endpoint also supports:

ParameterDescription
categoryCase-insensitive exact category match
statusCase-insensitive exact status match
minPrice / maxPricePrice range
conditionsGeneric condition array
sortByOrdered map from field names to asc or desc

With GET, conditions and sortBy are URL-encoded JSON strings. With POST, they are sent directly as a JSON array or object.

9. Advanced configuration​

9.1 Multiple criteria​

Add a Category Select, Status Radio, or Price Input to Left Toolbar and map each value in Query Context:

{
"keyword": "[[productKeyword]]",
"category": "[[productCategory]]",
"status": "[[productStatus]]",
"minPrice": "[[minimumPrice]]",
"maxPrice": "[[maximumPrice]]"
}

The backend defines whether an empty value means "do not filter." For optional strings, use trimToNull; for optional numbers, use null rather than a special string.

9.2 Row Actions​

Add View, Edit, Delete, or other operations under Row Actions. A row action receives the current record context, so FX can read fields such as id and code from that row.

After a successful modification, call reloadTable on the current ProTable to retrieve fresh server data. Add confirmation for destructive actions, and enforce authorization and business validation on the backend.

9.3 setTableData​

When a button has already called another endpoint and obtained a complete record array, it can call:

setTableData(data)

This replaces the table's local data with the supplied array and resets the page to 1. setTableData does not persist data and does not extract data.records from an outer response object automatically. The supplied value must be the record array itself.

For standard remote pagination, prefer reloadTable so that the backend continues to own the criteria, total, and paging behavior.

9.4 Display properties​

PropertyDescription
Enable Row NumberDisplays a continuous row number across pages in the first column
Table SizeSets large, middle, or small density
Show HeaderControls whether the column header row is visible
BorderedControls whether table borders are visible
Row Unique KeyUnique identifier field for each row; defaults to id

10. Verify the sample​

After saving the page, verify these steps in Preview and Runtime:

  1. Leave the keyword empty. The first load should show page 1 with 23 total records.
  2. Move to page 2. The table should show the next page of data.
  3. On page 2, enter Graphite and click Search.
  4. The request should use current: 1, and the result should contain only DSP-2002 / Graphite Monitor 32.
  5. Clear the Input and click Search. All 23 records should be available again, starting on page 1.
  6. Enter a keyword that matches multiple pages, click Search, and then paginate. Subsequent requests should keep the keyword.

In the browser developer tools, inspect the POST Request Payload:

{
"current": 1,
"pageSize": 10,
"keyword": "Graphite"
}

Confirm that data.total, data.current, data.pageSize, and data.records in the response match the request.

11. Troubleshooting​

11.1 Graphite is not found after searching from page 2​

The Search button may be configured as a regular request instead of calling ProTable's reloadTable. Verify:

Interaction: Component API
Target Component: current ProTable
Function: reloadTable

reloadTable resets the page to 1. Normal pagination still keeps the current criteria.

11.2 Data does not change after entering a keyword​

Check the following in order:

  1. Query Context contains a keyword parameter.
  2. The productKeyword variable reads Component Value from the correct Input.
  3. Target Value is [[productKeyword]].
  4. The backend request field is also named keyword.
  5. Search calls reloadTable on the current ProTable.

11.3 The Input has no clear icon​

Make sure Allow Clear is enabled and the runtime Input contains text. The clear icon is not shown for an empty Input. Click Search after clearing to reload the table.

11.4 The endpoint returns data but the table is empty​

Check Rows Path. The record array in this guide is located at:

data.records

If you configure an incorrect custom path, ProTable does not guess another custom path and displays an empty array.

11.5 The total or page number is incorrect​

Verify that:

  • Total Path points to the total number of filtered records
  • Current Page Path points to the current page returned by the server
  • Page Size Path points to the page size actually used by the server
  • Backend page numbering starts at 1

11.6 The endpoint returns 401, 403, or a CORS error​

  • 401: The session is invalid, or the endpoint requires authentication.
  • 403: The current user does not have endpoint or data permission.
  • CORS: The external service does not allow requests from the current Spark origin.

Prefer an External Connection or a controlled backend proxy for external systems. Never expose long-lived credentials in page configuration.

11.7 GET conditions cannot be parsed​

GET serializes objects and arrays as JSON strings. URL-decode them and use a JSON parser on the backend instead of splitting complex objects by commas. POST has no extra conversion, so prefer POST for complex criteria.

11.8 Custom URL Data Field has no options​

Open Data Source, configure Response Fields, and save. Add them manually or use Test & Import. Response Fields belong to the data source contract; loading one table preview record does not temporarily change the field catalog.

12. Configuration checklist​

  • ProTable has a stable and unique component name
  • Data Source is set to Custom URL
  • Response Fields have been added manually or imported with Test & Import and saved
  • URL, Request Method, and authentication are correct
  • Rows, Total, Current Page, and Page Size paths match the response
  • Column Data Fields match the record fields
  • Row Unique Key is stable and unique
  • Query Context parameter names match backend DTO fields
  • FX variables read from the correct Component Value
  • Search calls reloadTable on the current ProTable
  • A new search returns to page 1
  • Normal pagination keeps the current criteria
  • Empty, matching, and non-matching keywords have been tested
  • Toolbar, table, and pagination have been verified in both Preview and Runtime

After completing this configuration, ProTable can serve as a stable list surface for a custom HTTP API and coordinate query controls, server-side pagination, and page interactions correctly.