Skip to content

Commit bd2d125

Browse files
author
John Rogers
committed
Adjusted memoization for response options and URLs to utilize server data fiields URLs and Response Options when available.
1 parent 9f9a81b commit bd2d125

1 file changed

Lines changed: 74 additions & 41 deletions

File tree

src/components/MatchedVariablesDataGrid.tsx

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ function MatchedVariablesDataGrid({
161161
const [isApiReady, setIsApiReady] = useState(false);
162162
const [totalVariableCount, setTotalVariableCount] = useState<number | null>(null);
163163
const [shouldHideTable, setShouldHideTable] = useState(false);
164+
const [currentSearchQuery, setCurrentSearchQuery] = useState<string>("");
165+
const [hasUrlsFromServer, setHasUrlsFromServer] = useState(false);
166+
const [hasResponseOptionsFromServer, setHasResponseOptionsFromServer] = useState(false);
164167

165168
// Debouncing for search queries
166169
const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null);
@@ -198,9 +201,9 @@ function MatchedVariablesDataGrid({
198201
return {
199202
getRows: async (params: any) => {
200203
// Extract search query from filterModel (QuickFilter sets this)
201-
// QuickFilter uses the "quickFilterValues" in filterModel
202-
const quickFilterValue = params.filterModel?.quickFilterValues?.[0] || "";
203-
const searchQuery = quickFilterValue;
204+
// QuickFilter splits by spaces, so we need to join all values back together
205+
const quickFilterValues = params.filterModel?.quickFilterValues || [];
206+
const searchQuery = quickFilterValues.join(" ").trim();
204207

205208
// Handle paginationModel (can be undefined in some cases)
206209
const paginationModel = params.paginationModel || { page: 0, pageSize: 50 };
@@ -257,6 +260,9 @@ function MatchedVariablesDataGrid({
257260
sortOrder = `${field}:${direction}`;
258261
}
259262

263+
// Update current search query for empty state display
264+
setCurrentSearchQuery(searchQuery || "");
265+
260266
// Build fetch options - only include query/search params if we have a query
261267
const fetchOptions: Parameters<typeof fetchVariables>[0] = {
262268
// Use ancestor_uuid for all cases (works for both top-level studies and child datasets)
@@ -283,43 +289,39 @@ function MatchedVariablesDataGrid({
283289
let response = await fetchVariables(fetchOptions);
284290
let results = response.results || [];
285291

286-
// If no results and we have a search query, try again without the query
287-
// Only do this on the first page (offset 0) to avoid retrying on every page
288-
if (results.length === 0 &&
289-
searchQuery &&
290-
searchQuery.trim() &&
291-
paginationModel.page === 0 &&
292-
paginationModel.pageSize > 0) {
293-
const retryOptions: Parameters<typeof fetchVariables>[0] = {
294-
...fetchOptions,
295-
query: undefined, // Remove query for retry
296-
};
297-
298-
response = await fetchVariables(retryOptions);
299-
results = response.results || [];
300-
301-
// If still no results, hide the table
302-
if (results.length === 0 && (response.num_hits === 0 || response.num_hits === undefined)) {
303-
setShouldHideTable(true);
304-
onShouldHideTable?.(true);
305-
} else {
292+
// Check for URLs and response options in the server response
293+
// Only check on first page to avoid unnecessary updates
294+
if (paginationModel.page === 0) {
295+
const hasUrls = results.some((r: any) =>
296+
r.urls && Array.isArray(r.urls) && r.urls.length > 0
297+
);
298+
const hasResponseOptions = results.some((r: any) => {
299+
const options = r.response_options || r.options;
300+
return options && Array.isArray(options) && options.length > 0;
301+
});
302+
setHasUrlsFromServer(hasUrls);
303+
setHasResponseOptionsFromServer(hasResponseOptions);
304+
}
305+
306+
// Check if we should hide the table on first page with no results
307+
// Only hide if there's no query - if there's a query, show empty state instead
308+
if (paginationModel.page === 0 &&
309+
results.length === 0 &&
310+
(response.num_hits === 0 || response.num_hits === undefined)) {
311+
// If there's a search query, show the table with empty state
312+
// Otherwise, hide the table (no variables at all)
313+
if (searchQuery && searchQuery.trim()) {
306314
setShouldHideTable(false);
307315
onShouldHideTable?.(false);
308-
}
309-
} else {
310-
// Check if we should hide the table on first page with no results
311-
// This applies whether or not there's a search query
312-
if (paginationModel.page === 0 &&
313-
results.length === 0 &&
314-
(response.num_hits === 0 || response.num_hits === undefined)) {
315-
// No results on first page - hide the table
316+
} else {
317+
// No results and no query - hide the table
316318
setShouldHideTable(true);
317319
onShouldHideTable?.(true);
318-
} else {
319-
// We have results or there are more results available - show the table
320-
setShouldHideTable(false);
321-
onShouldHideTable?.(false);
322320
}
321+
} else {
322+
// We have results or there are more results available - show the table
323+
setShouldHideTable(false);
324+
onShouldHideTable?.(false);
323325
}
324326

325327
// Create a Set of matched variable names for quick lookup
@@ -527,19 +529,31 @@ function MatchedVariablesDataGrid({
527529
}, []);
528530

529531
// Check if any variables have response options data
532+
// Use server data if available (server-side mode), otherwise check props variables (client-side mode)
530533
const hasResponseOptions = useMemo(() => {
534+
if (studyUuid) {
535+
// Server-side mode - use state from API response
536+
return hasResponseOptionsFromServer;
537+
}
538+
// Client-side mode - check props variables
531539
return variables.some((v) => {
532540
const responseOptions = v.response_options || v.options;
533541
return responseOptions && Array.isArray(responseOptions) && responseOptions.length > 0;
534542
});
535-
}, [variables]);
536-
543+
}, [studyUuid, hasResponseOptionsFromServer, variables]);
544+
537545
// Check if any variables have URLs
546+
// Use server data if available (server-side mode), otherwise check props variables (client-side mode)
538547
const hasUrls = useMemo(() => {
548+
if (studyUuid) {
549+
// Server-side mode - use state from API response
550+
return hasUrlsFromServer;
551+
}
552+
// Client-side mode - check props variables
539553
return variables.some((v) => {
540554
return v.urls && Array.isArray(v.urls) && v.urls.length > 0;
541555
});
542-
}, [variables]);
556+
}, [studyUuid, hasUrlsFromServer, variables]);
543557

544558
const columns: GridColDef[] = useMemo(() => {
545559
const baseColumns: GridColDef[] = [
@@ -590,11 +604,12 @@ function MatchedVariablesDataGrid({
590604
if (hasUrls) {
591605
baseColumns.push({
592606
field: "url",
593-
headerName: "",
594-
width: 60,
607+
headerName: "Learn more",
608+
width: 120,
595609
sortable: false,
596610
renderCell: (params: any) => {
597-
const variable = variables[params.row.originalIndex ?? 0];
611+
// Get variable data from row (works for both client-side and server-side)
612+
const variable = params.row;
598613
const firstUrl = variable?.urls && Array.isArray(variable.urls) && variable.urls.length > 0
599614
? variable.urls[0]
600615
: null;
@@ -895,6 +910,24 @@ function MatchedVariablesDataGrid({
895910
showToolbar
896911
initialState={initialState}
897912
slots={{
913+
noRowsOverlay: () => (
914+
<Box
915+
sx={{
916+
display: "flex",
917+
flexDirection: "column",
918+
alignItems: "center",
919+
justifyContent: "center",
920+
height: "100%",
921+
p: 4,
922+
}}
923+
>
924+
<Typography variant="body1" color="text.secondary">
925+
{currentSearchQuery && currentSearchQuery.trim()
926+
? "No variables match your query. Remove it to see them all."
927+
: "No variables found."}
928+
</Typography>
929+
</Box>
930+
),
898931
toolbar: () => (
899932
<Box
900933
sx={{

0 commit comments

Comments
 (0)