Skip to content

Kern table improvements #77

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

Merged
merged 4 commits into from
Jul 17, 2025
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
15 changes: 5 additions & 10 deletions src/components/models-download/ModelsDownload.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { selectModelsDownloaded, setModelsDownloaded } from "@/src/reduxStore/states/pages/models-downloaded";
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { openModal, setModalStates } from "@/src/reduxStore/states/modal";
import { ModalEnum } from "@/src/types/shared/modal";
Expand All @@ -23,20 +23,15 @@ export default function ModelsDownload() {
const isAdmin = useSelector(selectIsAdmin);
const modelsDownloaded = useSelector(selectModelsDownloaded);

const [preparedValues, setPreparedValues] = useState([]);

useEffect(() => {
refetchModels();
}, []);

useEffect(() => {
if (!modelsDownloaded) return;
setPreparedValues(prepareTableBodyModelsDownload(modelsDownloaded, openDeleteModal, isAdmin));
}, [modelsDownloaded]);

function openDeleteModal(model) {
const openDeleteModal = useCallback((model) => {
dispatch(setModalStates(ModalEnum.DELETE_MODEL_DOWNLOAD, { modelName: model.name, open: true }));
}
}, []);

const preparedValues = useMemo(() => prepareTableBodyModelsDownload(modelsDownloaded, openDeleteModal, isAdmin), [modelsDownloaded, isAdmin]);

function refetchModels() {
getModelProviderInfo((res) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
import { selectHeuristic } from "@/src/reduxStore/states/pages/heuristics"
import { HEURISTICS_STATISTICS_TABLE_COLUMNS, prepareTableBodyHeuristicStatistics } from "@/src/util/table-preparations/heuristic-statistics";
import KernTable from "@/submodules/react-components/components/kern-table/KernTable";
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux"

export default function HeuristicStatistics() {
const currentHeuristic = useSelector(selectHeuristic);

const [preparedValues, setPreparedValues] = useState([]);

useEffect(() => {
setPreparedValues(prepareTableBodyHeuristicStatistics(currentHeuristic.stats));
}, [currentHeuristic]);
const preparedValues = useMemo(() => {
if (!currentHeuristic) return [];
return prepareTableBodyHeuristicStatistics(currentHeuristic.stats);
}, [currentHeuristic?.sourceStatistics]);

return (
<div className="mt-8">
<div className="text-sm leading-5 font-medium text-gray-700 inline-block">Statistics</div>
<div className="mt-1 flex flex-col">
<div className="overflow-x-auto">
<div className="inline-block min-w-full py-2 align-middle">
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<KernTable
headers={HEURISTICS_STATISTICS_TABLE_COLUMNS}
values={preparedValues}
/>
</div>
<div className="inline-block min-w-full py-2 align-middle">
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<KernTable
headers={HEURISTICS_STATISTICS_TABLE_COLUMNS}
values={preparedValues}
/>
</div>
</div >
</div>
</div>
</div>
)
Expand Down
81 changes: 33 additions & 48 deletions src/components/projects/projectId/playground/EvaluationGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import CreateEvaluationGroupModal from "./CreateEvaluationGroupModal";
import { ModalEnum } from "@/src/types/shared/modal";
import { useDispatch, useSelector } from "react-redux";
import { selectProjectId } from "@/src/reduxStore/states/project";
import { useEffect, useState, useRef, useLayoutEffect, useCallback, useMemo } from "react";
import { useEffect, useState, useRef, useCallback, useMemo } from "react";
import { getEvaluationGroups, getEvaluationSetsByGroupId } from "@/src/services/base/playground";
import ViewEvaluationGroupModal from "./ViewEvaluationGroupModal";
import KernTable from "@/submodules/react-components/components/kern-table/KernTable";
Expand All @@ -20,72 +20,57 @@ export function EvaluationGroups() {
const users = useSelector(selectAllUsers);

const [evaluationGroups, setEvaluationGroups] = useState(null);
const [preparedValues, setPreparedValues] = useState(null);
const [preparedHeaders, setPreparedHeaders] = useState(EVALUATION_GROUPS_TABLE_HEADER);
const [selectedEvaluationGroups, setSelectedEvaluationGroups] = useState(new Set<string>());
const isFetchingEvalGroups = useRef(false);
const [checked, setChecked] = useState(false);
const [indeterminate, setIndeterminate] = useState(false);
const checkbox = useRef<any>(null);

const usersDict = useMemo(() => arrayToDict(users, 'id'), [users]);

const projectIdRef = useRef(projectId);
useEffect(() => {
if (!projectId) return;
if (!projectIdRef.current) return;
if (isFetchingEvalGroups.current) return;
isFetchingEvalGroups.current = true
getEvaluationGroups(projectId, (res) => {
getEvaluationGroups(projectIdRef.current, (res) => {
setEvaluationGroups(res);
isFetchingEvalGroups.current = false
});
}, [projectId]);
}, []);

useLayoutEffect(() => {
if (!selectedEvaluationGroups || !evaluationGroups) return;
const isIndeterminate = selectedEvaluationGroups.size > 0 && selectedEvaluationGroups.size < evaluationGroups.length;
setChecked(selectedEvaluationGroups.size > 0 && selectedEvaluationGroups.size === evaluationGroups.length);
setIndeterminate(isIndeterminate);

if (checkbox.current !== null) {
checkbox.current.indeterminate = isIndeterminate;
}
}, [selectedEvaluationGroups, evaluationGroups]);
const refetchEvaluationGroups = useCallback(() => {
getEvaluationGroups(projectIdRef.current, (res) => {
setEvaluationGroups(res);
setSelectedEvaluationGroups(new Set<string>());
});
}, []);

useEffect(() => {
if (!evaluationGroups) return;
setPreparedValues(prepareTableBodyEvaluationGroups(evaluationGroups, selectedEvaluationGroups, setSelectedEvaluationGroups, usersDict, viewSetsModal));
}, [evaluationGroups, selectedEvaluationGroups, setSelectedEvaluationGroups]);
const toggleAll = useCallback(() => {
if (!evaluationGroups || evaluationGroups.length === 0) return;
if (checked) setSelectedEvaluationGroups(new Set<string>());
else setSelectedEvaluationGroups(new Set<string>(evaluationGroups.map(x => x.id)));
setChecked(!checked);
}, [checked, evaluationGroups]);

function viewSetsModal(groupId: string) {
const viewSetsModal = useCallback((groupId: string) => {
let setsArr = [];
getEvaluationSetsByGroupId(projectId, groupId, (res) => {
getEvaluationSetsByGroupId(projectIdRef.current, groupId, (res) => {
setsArr = res;
dispatch(setModalStates(ModalEnum.VIEW_EVALUATION_GROUP, { open: true, sets: setsArr }));
dispatch(setModalStates(ModalEnum.VIEW_EVALUATION_GROUP, { open: true, sets: res }));
});
}
}, []);

useEffect(() => {
setPreparedHeaders(preparedHeaders.map((header) => {
if (header.id === "checkboxes") {
return { ...header, hasCheckboxes: true, checked: checked, onChange: toggleAll };
}
return header;
}))
}, [checked, evaluationGroups, selectedEvaluationGroups])
const preparedValues = useMemo(() => {
if (!evaluationGroups) return null;
return prepareTableBodyEvaluationGroups(evaluationGroups, selectedEvaluationGroups, setSelectedEvaluationGroups, usersDict, viewSetsModal);
}, [evaluationGroups, selectedEvaluationGroups, setSelectedEvaluationGroups, usersDict, viewSetsModal]);

const refetchEvaluationGroups = useCallback(() => {
getEvaluationGroups(projectId, (res) => {
setEvaluationGroups(res);
setSelectedEvaluationGroups(new Set<string>());
const finalHeaders = useMemo(() => {
if (!evaluationGroups || !selectedEvaluationGroups) return null;
return EVALUATION_GROUPS_TABLE_HEADER.map((group) => {
if (group.id === "checkboxes") return { ...group, checked: selectedEvaluationGroups.size === evaluationGroups.length, onChange: toggleAll };
return group;
});
}, [projectId]);

function toggleAll() {
if (checked || indeterminate) setSelectedEvaluationGroups(new Set<string>());
else setSelectedEvaluationGroups(new Set<string>(evaluationGroups.map(x => x.id)));
setChecked(!checked && !indeterminate)
setIndeterminate(false)
}
}, [evaluationGroups, selectedEvaluationGroups, toggleAll]);

return <>
{projectId != null && <div className="p-4 bg-gray-100 h-full flex-1 flex flex-col overflow-y-auto">
Expand Down Expand Up @@ -114,9 +99,9 @@ export function EvaluationGroups() {
</div>
}
</div>
{preparedHeaders && preparedValues && (evaluationGroups.length > 0 ?
{finalHeaders && preparedValues && (evaluationGroups.length > 0 ?
<KernTable
headers={preparedHeaders}
headers={finalHeaders}
values={preparedValues}
config={EVALUATION_GROUPS_TABLE_CONFIG}
/>
Expand Down
65 changes: 25 additions & 40 deletions src/components/projects/projectId/playground/EvaluationRuns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from "react-redux";
import { selectProjectId } from "@/src/reduxStore/states/project";
import KernTable from "@/submodules/react-components/components/kern-table/KernTable";
import { EVALUATION_RUN_TABLE_CONFIG, EVALUATION_RUN_TABLE_HEADER, prepareTableBodyEvaluationRun } from "@/src/util/table-preparations/evaluation-runs";
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { getEvaluationGroups, getEvaluationRuns } from "@/src/services/base/playground";
import { selectAllUsers } from "@/src/reduxStore/states/general";
import { arrayToDict } from "@/submodules/javascript-functions/general";
Expand All @@ -23,17 +23,13 @@ export default function EvaluationRuns() {
const usersDict = arrayToDict(users, 'id');
const onAttributeEmbeddings = useSelector(selectOnAttributeEmbeddings);

const [preparedValues, setPreparedValues] = useState(null);
const [evaluationRuns, setEvaluationRuns] = useState(null);
const [evaluationGroups, setEvaluationGroups] = useState([]);
const [evaluationDict, setEvaluationDict] = useState(null);
const [embeddingsDict, setEmbeddingsDict] = useState(null);
const [refetchTrigger, setRefetchTrigger] = useState(false)
const [preparedHeaders, setPreparedHeaders] = useState(EVALUATION_RUN_TABLE_HEADER);
const [selectedEvaluationRuns, setSelectedEvaluationRuns] = useState(new Set<string>());
const [checked, setChecked] = useState(false);
const [indeterminate, setIndeterminate] = useState(false);
const checkbox = useRef<any>(null);

useEffect(() => {
if (!projectId) return;
Expand All @@ -51,48 +47,37 @@ export default function EvaluationRuns() {
setEmbeddingsDict(arrayToDict(onAttributeEmbeddings, 'id'));
}, [onAttributeEmbeddings]);

useLayoutEffect(() => {
if (!selectedEvaluationRuns || !evaluationRuns) return;
const isIndeterminate = selectedEvaluationRuns.size > 0 && selectedEvaluationRuns.size < evaluationRuns.length;
setChecked(selectedEvaluationRuns.size > 0 && selectedEvaluationRuns.size === evaluationRuns.length);
setIndeterminate(isIndeterminate);

if (checkbox.current !== null) {
checkbox.current.indeterminate = isIndeterminate;
}
}, [selectedEvaluationRuns, evaluationRuns]);

useEffect(() => {
if (!evaluationRuns || !evaluationDict || !embeddingsDict) return;
setPreparedValues(prepareTableBodyEvaluationRun(evaluationRuns, usersDict, embeddingsDict, evaluationDict, navigateToDetails, selectedEvaluationRuns, setSelectedEvaluationRuns));
}, [evaluationRuns, evaluationDict, embeddingsDict, selectedEvaluationRuns, setSelectedEvaluationRuns]);

useEffect(() => {
setPreparedHeaders(preparedHeaders.map((header) => {
if (header.id === "checkboxes") {
return { ...header, hasCheckboxes: true, checked: checked, onChange: toggleAll };
}
return header;
}))
}, [checked, evaluationGroups, selectedEvaluationRuns])

const refetchEvaluationRuns = useCallback(() => {
getEvaluationRuns(projectId, (res) => {
setEvaluationRuns(res);
setSelectedEvaluationRuns(new Set<string>());
});
}, [projectId]);

function toggleAll() {
if (checked || indeterminate) setSelectedEvaluationRuns(new Set<string>());
const navigateToDetails = useCallback((evaluationRunId: string) => {
router.push(`/projects/${projectId}/playground/${evaluationRunId}`);
}, [projectId]);

const toggleAll = useCallback(() => {
if (!evaluationRuns || evaluationRuns.length === 0) return;
if (checked) setSelectedEvaluationRuns(new Set<string>());
else setSelectedEvaluationRuns(new Set<string>(evaluationRuns.map(x => x.id)));
setChecked(!checked && !indeterminate)
setIndeterminate(false)
}
setChecked(!checked);
}, [checked, evaluationRuns]);

function navigateToDetails(evaluationRunId: string) {
router.push(`/projects/${projectId}/playground/${evaluationRunId}`);
}

const preparedValues = useMemo(() => {
if (!evaluationRuns) return null;
return prepareTableBodyEvaluationRun(evaluationRuns, usersDict, embeddingsDict, evaluationDict, navigateToDetails, selectedEvaluationRuns, setSelectedEvaluationRuns);
}, [evaluationRuns, usersDict, embeddingsDict, evaluationDict, selectedEvaluationRuns, setSelectedEvaluationRuns, navigateToDetails]);

const finalHeaders = useMemo(() => {
if (!evaluationRuns || !selectedEvaluationRuns) return null;
return EVALUATION_RUN_TABLE_HEADER.map((run) => {
if (run.id === "checkboxes") return { ...run, checked: selectedEvaluationRuns.size === evaluationRuns.length, onChange: toggleAll };
return run;
})
}, [selectedEvaluationRuns, evaluationRuns, toggleAll]);

return <>
{projectId != null && <div className="p-4 bg-gray-100 h-full flex-1 flex flex-col overflow-y-auto">
Expand Down Expand Up @@ -121,9 +106,9 @@ export default function EvaluationRuns() {
</div>
}
</div >
{preparedHeaders && preparedValues && (evaluationRuns.length > 0 ?
{finalHeaders && preparedValues && (evaluationRuns.length > 0 ?
<KernTable
headers={preparedHeaders}
headers={finalHeaders}
values={preparedValues}
config={EVALUATION_RUN_TABLE_CONFIG}
/> :
Expand Down
Loading