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

[OPIK-350] [Prompts Library][FE] Prompts details: Experiments tab #621

Merged
merged 1 commit into from
Nov 13, 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
3 changes: 3 additions & 0 deletions apps/opik-frontend/src/api/datasets/useDatasetsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Dataset } from "@/types/datasets";
type UseDatasetsListParams = {
workspaceName: string;
withExperimentsOnly?: boolean;
promptId?: string;
search?: string;
page: number;
size: number;
Expand All @@ -21,6 +22,7 @@ const getDatasetsList = async (
{
workspaceName,
withExperimentsOnly,
promptId,
search,
size,
page,
Expand All @@ -34,6 +36,7 @@ const getDatasetsList = async (
with_experiments_only: withExperimentsOnly,
}),
...(search && { name: search }),
...(promptId && { prompt_id: promptId }),
size,
page,
},
Expand Down
3 changes: 3 additions & 0 deletions apps/opik-frontend/src/api/datasets/useExperimentsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Experiment } from "@/types/datasets";
export type UseExperimentsListParams = {
workspaceName: string;
datasetId?: string;
promptId?: string;
datasetDeleted?: boolean;
search?: string;
page: number;
Expand All @@ -22,6 +23,7 @@ export const getExperimentsList = async (
{
workspaceName,
datasetId,
promptId,
datasetDeleted,
search,
size,
Expand All @@ -35,6 +37,7 @@ export const getExperimentsList = async (
...(isBoolean(datasetDeleted) && { dataset_deleted: datasetDeleted }),
...(search && { name: search }),
...(datasetId && { datasetId }),
...(promptId && { prompt_id: promptId }),
size,
page,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import React, { useCallback, useMemo, useRef, useState } from "react";
import { Info } from "lucide-react";
import { useNavigate } from "@tanstack/react-router";
import useLocalStorageState from "use-local-storage-state";
import {
ExpandedState,
GroupingState,
RowSelectionState,
Row,
} from "@tanstack/react-table";
import { RowSelectionState } from "@tanstack/react-table";

import DataTable from "@/components/shared/DataTable/DataTable";
import DataTablePagination from "@/components/shared/DataTablePagination/DataTablePagination";
Expand All @@ -29,32 +18,32 @@ import { COLUMN_TYPE, ColumnData } from "@/types/shared";
import { convertColumnDataToColumn } from "@/lib/table";
import ColumnsButton from "@/components/shared/ColumnsButton/ColumnsButton";
import AddExperimentDialog from "@/components/pages/ExperimentsPage/AddExperimentDialog";
import ExperimentsActionsPanel from "@/components/pages/ExperimentsPage/ExperimentsActionsPanel";
import ExperimentsFiltersButton from "@/components/pages/ExperimentsPage/ExperimentsFiltersButton";
import ExperimentsActionsPanel from "@/components/pages/ExperimentsShared/ExperimentsActionsPanel";
import ExperimentsFiltersButton from "@/components/pages/ExperimentsShared/ExperimentsFiltersButton";
import ExperimentRowActionsCell from "@/components/pages/ExperimentsPage/ExperimentRowActionsCell";
import ExperimentsChartsWrapper from "@/components/pages/ExperimentsPage/charts/ExperimentsChartsWrapper";
import SearchInput from "@/components/shared/SearchInput/SearchInput";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import useGroupedExperimentsList, {
checkIsMoreRowId,
DEFAULT_EXPERIMENTS_PER_GROUP,
GroupedExperiment,
GROUPING_COLUMN,
} from "@/hooks/useGroupedExperimentsList";
import {
generateExperimentNameColumDef,
generateGroupedCellDef,
} from "@/components/pages/ExperimentsPage/table";
getIsMoreRow,
getRowId,
GROUPING_CONFIG,
} from "@/components/pages/ExperimentsShared/table";
import { useExpandingConfig } from "@/components/pages/ExperimentsShared/useExpandingConfig";
import { useGroupLimitsConfig } from "@/components/pages/ExperimentsShared/useGroupLimitsConfig";

const SELECTED_COLUMNS_KEY = "experiments-selected-columns";
const COLUMNS_WIDTH_KEY = "experiments-columns-width";
const COLUMNS_ORDER_KEY = "experiments-columns-order";

const getRowId = (e: GroupedExperiment) => e.id;
const getIsMoreRow = (row: Row<GroupedExperiment>) =>
checkIsMoreRowId(row?.original?.id || "");

export const DEFAULT_COLUMNS: ColumnData<GroupedExperiment>[] = [
{
id: "id",
Expand Down Expand Up @@ -89,8 +78,6 @@ export const DEFAULT_SELECTED_COLUMNS: string[] = [
const ExperimentsPage: React.FunctionComponent = () => {
const navigate = useNavigate();
const workspaceName = useAppStore((state) => state.activeWorkspaceName);

const openGroupsRef = useRef<Record<string, boolean>>({});
const resetDialogKeyRef = useRef(0);
const [openDialog, setOpenDialog] = useState<boolean>(false);

Expand All @@ -99,8 +86,7 @@ const ExperimentsPage: React.FunctionComponent = () => {
const [size, setSize] = useState(5);
const [datasetId, setDatasetId] = useState("");
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [expanded, setExpanded] = useState<ExpandedState>({});
const [groupLimit, setGroupLimit] = useState<Record<string, number>>({});
const { groupLimit, renderMoreRow } = useGroupLimitsConfig();

const { data, isPending } = useGroupedExperimentsList({
workspaceName,
Expand Down Expand Up @@ -147,7 +133,9 @@ const ExperimentsPage: React.FunctionComponent = () => {

const columns = useMemo(() => {
return [
generateExperimentNameColumDef<GroupedExperiment>(),
generateExperimentNameColumDef<GroupedExperiment>({
size: columnsWidth["name"],
}),
generateGroupedCellDef<GroupedExperiment, unknown>({
id: GROUPING_COLUMN,
label: "Dataset",
Expand Down Expand Up @@ -178,27 +166,6 @@ const ExperimentsPage: React.FunctionComponent = () => {
];
}, [selectedColumns, columnsWidth, columnsOrder]);

useEffect(() => {
const updateForExpandedState: Record<string, boolean> = {};
groupIds.forEach((groupId) => {
const id = `${GROUPING_COLUMN}:${groupId}`;
if (!openGroupsRef.current[id]) {
openGroupsRef.current[id] = true;
updateForExpandedState[id] = true;
}
});

if (Object.keys(updateForExpandedState).length) {
setExpanded((state) => {
if (state === true) return state;
return {
...state,
...updateForExpandedState,
};
});
}
}, [groupIds]);

const resizeConfig = useMemo(
() => ({
enabled: true,
Expand All @@ -207,22 +174,9 @@ const ExperimentsPage: React.FunctionComponent = () => {
[setColumnsWidth],
);

const groupingConfig = useMemo(
() => ({
groupedColumnMode: false as const,
grouping: [GROUPING_COLUMN] as GroupingState,
}),
[],
);

const expandingConfig = useMemo(
() => ({
autoResetExpanded: false,
expanded,
setExpanded,
}),
[expanded, setExpanded],
);
const expandingConfig = useExpandingConfig({
groupIds,
});

const handleNewExperimentClick = useCallback(() => {
setOpenDialog(true);
Expand All @@ -245,32 +199,6 @@ const ExperimentsPage: React.FunctionComponent = () => {
[navigate, workspaceName],
);

const renderMoreRow = useCallback((row: Row<GroupedExperiment>) => {
return (
<tr key={row.id} className="border-b">
<td colSpan={row.getAllCells().length} className="px-2 py-1">
<Button
variant="link"
className="w-full"
onClick={() => {
setGroupLimit((state) => {
return {
...state,
[row.original.dataset_id]:
(state[row.original.dataset_id] ||
DEFAULT_EXPERIMENTS_PER_GROUP) +
DEFAULT_EXPERIMENTS_PER_GROUP,
};
});
}}
>
Load {DEFAULT_EXPERIMENTS_PER_GROUP} more experiments
</Button>
</td>
</tr>
);
}, []);

if (isPending) {
return <Loader />;
}
Expand Down Expand Up @@ -322,7 +250,7 @@ const ExperimentsPage: React.FunctionComponent = () => {
setRowSelection,
}}
expandingConfig={expandingConfig}
groupingConfig={groupingConfig}
groupingConfig={GROUPING_CONFIG}
getRowId={getRowId}
noData={
<DataTableNoData title={noDataText}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button";
import { Experiment } from "@/types/datasets";
import { useNavigate } from "@tanstack/react-router";
import useAppStore from "@/store/AppStore";
import FilterExperimentsToCompareDialog from "@/components/pages/ExperimentsPage/FilterExperimentsToCompareDialog";
import FilterExperimentsToCompareDialog from "@/components/pages/ExperimentsShared/FilterExperimentsToCompareDialog";
import useExperimentBatchDeleteMutation from "@/api/datasets/useExperimentBatchDeleteMutation";
import ConfirmDialog from "@/components/shared/ConfirmDialog/ConfirmDialog";
import TooltipWrapper from "@/components/shared/TooltipWrapper/TooltipWrapper";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
import { Checkbox } from "@/components/ui/checkbox";
import React from "react";
import { CellContext, ColumnDef, flexRender } from "@tanstack/react-table";
import { Checkbox } from "@/components/ui/checkbox";
import {
CellContext,
ColumnDef,
flexRender,
GroupingState,
Row,
} from "@tanstack/react-table";
import { ColumnData } from "@/types/shared";
import { Button } from "@/components/ui/button";
import { ChevronDown, ChevronUp, Text } from "lucide-react";
import { mapColumnDataFields } from "@/lib/table";
import { cn } from "@/lib/utils";
import CellWrapper from "@/components/shared/DataTableCells/CellWrapper";
import {
checkIsMoreRowId,
GroupedExperiment,
GROUPING_COLUMN,
} from "@/hooks/useGroupedExperimentsList";
import ResourceLink, {
RESOURCE_TYPE,
} from "@/components/shared/ResourceLink/ResourceLink";

export const GROUPING_CONFIG = {
groupedColumnMode: false as const,
grouping: [GROUPING_COLUMN] as GroupingState,
};

export const getRowId = (e: GroupedExperiment) => e.id;
export const getIsMoreRow = (row: Row<GroupedExperiment>) =>
checkIsMoreRowId(row?.original?.id || "");

export const generateExperimentNameColumDef = <TData,>() => {
export const generateExperimentNameColumDef = <TData,>({
size,
asResource = false,
}: {
size?: number;
asResource?: boolean;
}) => {
return {
accessorKey: "name",
header: ({ table }) => (
Expand All @@ -28,25 +57,43 @@ export const generateExperimentNameColumDef = <TData,>() => {
<span className="truncate">Name</span>
</div>
),
cell: (context) => (
<CellWrapper
metadata={context.column.columnDef.meta}
tableMetadata={context.table.options.meta}
>
<Checkbox
style={{
marginLeft: `${context.row.depth * 28}px`,
}}
onClick={(event) => event.stopPropagation()}
checked={context.row.getIsSelected()}
disabled={!context.row.getCanSelect()}
onCheckedChange={(value) => context.row.toggleSelected(!!value)}
aria-label="Select row"
/>
<span className="ml-6 truncate">{context.getValue() as string}</span>
</CellWrapper>
),
size: 180,
cell: (context) => {
const data = context.row.original as GroupedExperiment;
return (
<CellWrapper
metadata={context.column.columnDef.meta}
tableMetadata={context.table.options.meta}
>
<Checkbox
style={{
marginLeft: `${context.row.depth * 28}px`,
}}
onClick={(event) => event.stopPropagation()}
checked={context.row.getIsSelected()}
disabled={!context.row.getCanSelect()}
onCheckedChange={(value) => context.row.toggleSelected(!!value)}
aria-label="Select row"
/>
{asResource ? (
<div className="ml-6 min-w-1 max-w-full">
<ResourceLink
id={data.dataset_id}
name={data.name}
resource={RESOURCE_TYPE.experiment}
search={{
experiments: [data.id],
}}
/>
</div>
) : (
<span className="ml-6 truncate">
{context.getValue() as string}
</span>
)}
</CellWrapper>
);
},
size: size ?? 180,
minSize: 100,
enableSorting: false,
enableHiding: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { ExpandedState } from "@tanstack/react-table";
import { GROUPING_COLUMN } from "@/hooks/useGroupedExperimentsList";

export type UseExpandingConfigProps = {
groupIds: string[];
};

export const useExpandingConfig = ({ groupIds }: UseExpandingConfigProps) => {
const openGroupsRef = useRef<Record<string, boolean>>({});
const [expanded, setExpanded] = useState<ExpandedState>({});

useEffect(() => {
const updateForExpandedState: Record<string, boolean> = {};
groupIds.forEach((groupId) => {
const id = `${GROUPING_COLUMN}:${groupId}`;
if (!openGroupsRef.current[id]) {
openGroupsRef.current[id] = true;
updateForExpandedState[id] = true;
}
});

if (Object.keys(updateForExpandedState).length) {
setExpanded((state) => {
if (state === true) return state;
return {
...state,
...updateForExpandedState,
};
});
}
}, [groupIds]);

return useMemo(
() => ({
autoResetExpanded: false,
expanded,
setExpanded,
}),
[expanded, setExpanded],
);
};
Loading
Loading