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 = '',