Table export (PWA)
Client-side CSV, Excel, and PDF export for paginated grids in frontend-pwa.
Architecture
| Layer | Location | Responsibility |
|---|---|---|
| Pure utilities | apps/frontend-pwa/src/lib/table-export/ | Fetch all pages, build rows, write files |
| Hook | apps/frontend-pwa/src/hooks/useTableExport.ts | Orchestration, toasts, loading state |
| UI | apps/frontend-pwa/src/components/ui/TableExportMenu.tsx | Export dropdown |
| Integration | *List.tsx / *Search.tsx | Column definitions + filtered fetch |
| Services | apps/frontend-pwa/src/services/*Service.ts | getAll*Filtered using same API params as grid |
TablePagination accepts an optional exportActions slot (rendered before Refresh / Print).
Integration checklist
- Add
getAll<Entity>Filteredin*Service.tsviacreateOffsetExportFetcherorgetAllSearchFilteredfor search-only catalogs. - Create
<entity>ExportColumns.tswith explicitExportColumn[](omit action columns). - Wire
useTableExport+TableExportMenuin the list/search component. - Pass
totalRecordsCountto pagination and export hook. - Apply the same client sort used in the grid after fetching all rows.
- Build a
filterSummarystring for PDF headers.
Products reference
- Columns:
apps/frontend-pwa/src/components/forms/product/productExportColumns.ts - Fetch:
getAllProductsFilteredinproductService.ts - UI:
ProductList.tsx→TablePagination.exportActions
Search-only catalogs
For grids with a single search query param, use getAllSearchFiltered from lib/table-export/get-all-search-filtered.ts and buildSearchFilterSummary for PDF headers.
| Screen | Columns file | Service | List |
|---|---|---|---|
| Customers | customerExportColumns.ts | getAllCustomersFiltered | CustomerList.tsx |
| Suppliers | supplierExportColumns.ts | getAllSuppliersFiltered | SupplierList.tsx |
| Brands | brandExportColumns.ts | getAllBrandsFiltered | BrandList.tsx |
| Categories | categoryExportColumns.ts | getAllCategoriesFiltered | CategoryList.tsx |
| Colors | colorExportColumns.ts | getAllColorsFiltered | ColorList.tsx |
| Sizes | sizeExportColumns.ts | getAllSizesFiltered | SizeList.tsx |
| Units of measure | unitOfMeasureExportColumns.ts | getAllUnitsOfMeasureFiltered | UnitOfMeasureList.tsx |
| Locations | locationExportColumns.ts | getAllLocationsFiltered | LocationList.tsx |
| Employees | employeeExportColumns.ts | getAllEmployeesFiltered | EmployeeList.tsx |
| Styles | styleExportColumns.ts | getAllStylesFiltered | StyleList.tsx |
| Models | modelExportColumns.ts | getAllModelsFiltered | ModelList.tsx |
| Attributes | attributeExportColumns.ts | getAllAttributesFiltered | AttributeList.tsx |
| Currencies | currencyExportColumns.ts | getAllCurrenciesFiltered | CurrencyList.tsx |
| Payment methods | paymentMethodExportColumns.ts | getAllPaymentMethodsFiltered | PaymentMethodList.tsx |
| Service types | serviceTypeExportColumns.ts | getAllServiceTypesFiltered | ServiceTypeList.tsx |
| Addresses | addressExportColumns.ts | getAllAddressesFiltered | AddressList.tsx |
| Forms | formExportColumns.ts | getAllFormsFiltered | FormList.tsx |
| Document templates | templateExportColumns.ts | getAllTemplatesFiltered | TemplateManagementPage.tsx |
| Inventory | inventoryExportColumns.ts | getAllInventoriesFiltered | InventoryList.tsx |
| Services | serviceExportColumns.ts | getAllServicesFiltered | ServiceList.tsx |
| Exchange rates | exchangeRateExportColumns.ts | getAllExchangeRatesFiltered | ExchangeRateList.tsx |
| Inventory batch details | inventoryDetailExportColumns.ts | getAllInventoryDetailsFiltered | InventoryDetailBatchList.tsx |
| Inventory serial details | inventoryDetailExportColumns.ts | getAllInventoryDetailsFiltered | InventoryDetailSerialList.tsx |
Pagination empty state
TablePagination normalizes empty grids: when totalPages is 0, navigation buttons are disabled and the label shows Page 1 of 1 instead of Page 1 of 0.
Limits
MAX_EXPORT_ROWS: 10,000EXPORT_WARN_ROWS: 2,000 (warning toast)EXPORT_PAGE_SIZE: 500 per API request (sequential pages)
Out of scope
- Activity Log (async backend CSV export)
- Editable POS line-item tables
- Metabase embeds