Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui-results): resolve data misalignment in matrix column filtering #2269

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ interface Props {
studyId: string;
path: string;
colHeaders: string[][];
onColHeadersChange: (colHeaders: string[][]) => void;
onColHeadersChange: (colHeaders: string[][], indices: number[]) => void;
}

function ResultFilters({
Expand Down Expand Up @@ -104,48 +104,61 @@ function ResultFilters({
);
}, [colHeaders]);

useEffect(() => {
const filteredHeaders = parsedHeaders.filter((header) => {
// Apply search filters
if (filters.search) {
const matchesVariable = matchesSearchTerm(
header.variable,
filters.search,
);
// Process headers while keeping track of their original positions
// This ensures we can properly filter the data matrix later
// Example: if we filter out column 1, we need to know that column 2
// becomes column 1 in the filtered view but maps to index 2 in the data
const filteredHeaders = useMemo(() => {
return parsedHeaders
.map((header, index) => ({ ...header, index }))
.filter((header) => {
// Apply search filter
if (filters.search) {
const matchesVariable = matchesSearchTerm(
header.variable,
filters.search,
);

const matchesUnit = matchesSearchTerm(header.unit, filters.search);
const matchesUnit = matchesSearchTerm(header.unit, filters.search);

if (!matchesVariable && !matchesUnit) {
return false;
if (!matchesVariable && !matchesUnit) {
return false;
}
}
}

// Apply stat filters
if (header.stat) {
const stat = header.stat.toLowerCase();
// Apply statistical filters
if (header.stat) {
const stat = header.stat.toLowerCase();

if (!filters.exp && stat.includes("exp")) {
return false;
}
if (!filters.min && stat.includes("min")) {
return false;
}
if (!filters.max && stat.includes("max")) {
return false;
}
if (!filters.std && stat.includes("std")) {
return false;
if (!filters.exp && stat.includes("exp")) {
return false;
}
if (!filters.min && stat.includes("min")) {
return false;
}
if (!filters.max && stat.includes("max")) {
return false;
}
if (!filters.std && stat.includes("std")) {
return false;
}
if (!filters.values && stat.includes("values")) {
return false;
}
}
if (!filters.values && stat.includes("values")) {
return false;
}
}

return true;
});
return true;
});
}, [filters, parsedHeaders]);

onColHeadersChange(filteredHeaders.map((h) => h.original));
}, [filters, parsedHeaders, onColHeadersChange]);
// Notify parent of both filtered headers and their original indices
// This allows the parent to correctly map the filtered view back to the original data
useEffect(() => {
onColHeadersChange(
filteredHeaders.map((h) => h.original),
filteredHeaders.map((h) => h.index),
);
}, [filteredHeaders, onColHeadersChange]);

////////////////////////////////////////////////////////////////
// Event handlers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ import { getStudyMatrixIndex } from "../../../../../../services/api/matrix.ts";
import { MatrixGridSynthesis } from "@/components/common/Matrix/components/MatrixGridSynthesis";
import { ResultMatrixDTO } from "@/components/common/Matrix/shared/types.ts";

type SetResultColHeaders = (headers: string[][], indices: number[]) => void;

function ResultDetails() {
const { study } = useOutletContext<{ study: StudyMetadata }>();
const { outputId } = useParams();
Expand All @@ -84,7 +86,11 @@ function ResultDetails() {
const [itemType, setItemType] = useState(OutputItemType.Areas);
const [selectedItemId, setSelectedItemId] = useState("");
const [searchValue, setSearchValue] = useState("");
// Store filtered headers and their original indices separately
// This allows us to correctly map the data rows to their corresponding headers
// when some columns are filtered out
const [resultColHeaders, setResultColHeaders] = useState<string[][]>([]);
const [headerIndices, setHeaderIndices] = useState<number[]>([]);
const isSynthesis = itemType === OutputItemType.Synthesis;
const { t } = useTranslation();
const navigate = useNavigate();
Expand Down Expand Up @@ -143,16 +149,24 @@ function ResultDetails() {
}

const res = await getStudyData(study.id, path);
// TODO add backend parse

if (typeof res === "string") {
const fixed = res
.replace(/NaN/g, '"NaN"')
.replace(/Infinity/g, '"Infinity"');

return JSON.parse(fixed);
const parsed = JSON.parse(fixed);

return {
...parsed,
indices: Array.from({ length: parsed.columns.length }, (_, i) => i),
};
}

return res;
return {
...res,
indices: Array.from({ length: res.columns.length }, (_, i) => i),
};
},
{
resetDataOnReload: true,
Expand All @@ -161,6 +175,19 @@ function ResultDetails() {
},
);

// Transform the matrix data by keeping only the columns that match our filters
// headerIndices contains the original positions of our kept columns, ensuring
// the data stays aligned with its corresponding headers
const filteredData = useMemo(() => {
if (!matrixRes.data) {
return [];
}

return matrixRes.data.data.map((row) => {
return headerIndices.map((index) => row[index]);
});
}, [matrixRes.data, headerIndices]);

const synthesisRes = usePromise(
() => {
if (outputId && selectedItem && isSynthesis) {
Expand Down Expand Up @@ -213,6 +240,11 @@ function ResultDetails() {
}
};

const handleColHeadersChange: SetResultColHeaders = (headers, indices) => {
setResultColHeaders(headers);
setHeaderIndices(indices);
};

////////////////////////////////////////////////////////////////
// JSX
////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -295,7 +327,7 @@ function ResultDetails() {
studyId={study.id}
path={path}
colHeaders={matrixRes.data?.columns || []}
onColHeadersChange={setResultColHeaders}
onColHeadersChange={handleColHeadersChange}
/>
<UsePromiseCond
response={mergeResponses(outputRes, matrixRes)}
Expand All @@ -313,8 +345,8 @@ function ResultDetails() {
) : (
<MatrixGrid
key={`grid-${resultColHeaders.length}`}
data={matrix.data}
rows={matrix.data.length}
data={filteredData}
rows={filteredData.length}
columns={resultColumns}
dateTime={dateTime}
readOnly
Expand Down
Loading