diff --git a/frontend/components/SpeczData.js b/frontend/components/SpeczData.js
index 24191cf..94b5a89 100644
--- a/frontend/components/SpeczData.js
+++ b/frontend/components/SpeczData.js
@@ -5,30 +5,57 @@ import PropTypes from 'prop-types'
import * as React from 'react'
import { useEffect } from 'react'
import { useQuery } from 'react-query'
-import { getAllProductsSpecz } from '../services/product'
+import { getProductsSpecz } from '../services/product'
const DataTableWrapper = ({
+ filters = {},
+ query = '',
onSelectionChange = () => {},
clearSelection = false
}) => {
+ const [page, setPage] = React.useState(0)
+ const [pageSize, setPageSize] = React.useState(25)
const [selectedRows, setSelectedRows] = React.useState([])
const { data, isLoading } = useQuery(
- ['productData'],
- () => getAllProductsSpecz(),
+ ['productData', { filters, query, page, pageSize }],
+ () =>
+ getProductsSpecz({
+ filters,
+ page,
+ page_size: pageSize,
+ sort: [{ field: 'created_at', sort: 'desc' }],
+ search: query
+ }),
{
+ keepPreviousData: true,
staleTime: Infinity,
refetchInterval: false,
retry: false
}
)
+ // Reset paginação quando a busca/filtros mudam.
+ // Serializa os filtros: como `filters` é um objeto recriado a cada render,
+ // usar ele direto como dependência dispararia o efeito em todo render,
+ // travando a paginação sempre na primeira página.
+ const filtersKey = JSON.stringify(filters)
+ useEffect(() => {
+ setPage(0)
+ }, [query, filtersKey])
+
const handleSelectionChange = selection => {
- const selectedProducts = selection.map(
- id => data?.results?.find(product => product.id === id) || {}
+ const currentPageProducts = data?.results || []
+ const previousSelection = selectedRows.filter(
+ row => !currentPageProducts.some(p => p.id === row.id)
)
- setSelectedRows(selectedProducts)
- onSelectionChange(selectedProducts)
+ const newSelectionFromPage = selection
+ .map(id => currentPageProducts.find(product => product.id === id))
+ .filter(Boolean)
+
+ const merged = [...previousSelection, ...newSelectionFromPage]
+ setSelectedRows(merged)
+ onSelectionChange(merged)
}
useEffect(() => {
@@ -67,7 +94,7 @@ const DataTableWrapper = ({
return (
row.id || row.unique_key}
rows={data?.results || []}
columns={columns}
loading={isLoading}
+ paginationMode="server"
+ page={page}
+ pageSize={pageSize}
+ rowCount={data?.count || 0}
+ onPageChange={newPage => setPage(newPage)}
+ onPageSizeChange={newPageSize => setPageSize(newPageSize)}
+ rowsPerPageOptions={[10, 25, 50]}
onSelectionModelChange={newSelection =>
handleSelectionChange(newSelection)
}
@@ -94,6 +129,8 @@ const DataTableWrapper = ({
}
DataTableWrapper.propTypes = {
+ filters: PropTypes.object,
+ query: PropTypes.string,
onSelectionChange: PropTypes.func,
clearSelection: PropTypes.bool
}
diff --git a/frontend/components/TsmData.js b/frontend/components/TsmData.js
index aff4ddc..4af5205 100644
--- a/frontend/components/TsmData.js
+++ b/frontend/components/TsmData.js
@@ -1,6 +1,6 @@
import Box from '@mui/material/Box'
import Radio from '@mui/material/Radio'
-import { DataGrid } from '@mui/x-data-grid'
+import { DataGrid, GridToolbarFilterButton } from '@mui/x-data-grid'
import moment from 'moment'
import PropTypes from 'prop-types'
import * as React from 'react'
@@ -14,13 +14,22 @@ const DataTableWrapper = ({
selectedProductId
}) => {
const [page, setPage] = React.useState(0)
- const [pageSize, setPageSize] = React.useState(10)
+ const [pageSize, setPageSize] = React.useState(25)
const [selectedRowId, setSelectedRowId] = React.useState(null)
React.useEffect(() => {
setSelectedRowId(selectedProductId)
}, [selectedProductId])
+ // Reset paginação quando a busca/filtros mudam.
+ // Serializa os filtros: como `filters` é um objeto recriado a cada render,
+ // usar ele direto como dependência dispararia o efeito em todo render,
+ // travando a paginação sempre na primeira página.
+ const filtersKey = JSON.stringify(filters)
+ React.useEffect(() => {
+ setPage(0)
+ }, [query, filtersKey])
+
const { data, isLoading } = useQuery(
['productData', { filters, query, page, pageSize }],
() =>
@@ -32,6 +41,7 @@ const DataTableWrapper = ({
search: query
}),
{
+ keepPreviousData: true,
staleTime: Infinity,
refetchInterval: false,
retry: false
@@ -96,12 +106,13 @@ const DataTableWrapper = ({
rowCount={data?.count || 0}
onPageChange={newPage => setPage(newPage)}
onPageSizeChange={newPageSize => setPageSize(newPageSize)}
- rowsPerPageOptions={[10]}
+ rowsPerPageOptions={[10, 25, 50]}
loading={isLoading}
localeText={{
noRowsLabel: isLoading ? 'Loading...' : 'No products found'
}}
onRowClick={params => handleRowSelection(params.row.id)}
+ components={{ Toolbar: GridToolbarFilterButton }}
/>
>
diff --git a/frontend/pages/specz_catalogs.js b/frontend/pages/specz_catalogs.js
index 7c7a669..a7f913a 100644
--- a/frontend/pages/specz_catalogs.js
+++ b/frontend/pages/specz_catalogs.js
@@ -22,6 +22,7 @@ import Typography from '@mui/material/Typography'
import { useTheme } from '@mui/system'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
+import SearchField from '../components/SearchField'
import SpeczData from '../components/SpeczData'
import { getPipelineByName } from '../services/pipeline'
import { submitProcess } from '../services/process'
@@ -48,6 +49,7 @@ function SpeczCatalogs() {
const [fieldErrors] = useState({})
const [selectedProducts, setSelectedProducts] = useState([])
const [outputFormat, setOutputFormat] = useState('parquet')
+ const [search, setSearch] = useState('')
useEffect(() => {
const fetchPipelineData = async () => {
@@ -264,13 +266,12 @@ function SpeczCatalogs() {
3. Select the Redshift Catalogs to include in your sample:
- {/* setSearch(query)} /> */}
+ setSearch(query)} />
diff --git a/frontend/services/product.js b/frontend/services/product.js
index 366d343..eaf691f 100644
--- a/frontend/services/product.js
+++ b/frontend/services/product.js
@@ -258,11 +258,6 @@ export const getProductConfigFiles = async productId => {
}
}
-export const getAllProductsSpecz = async () => {
- const res = await api.get('/api/products-specz/')
- return res.data
-}
-
export const getProductsSpecz = ({
filters = {},
search = '',