Skip to content

Commit

Permalink
Using pagination inside feedbacks side modal
Browse files Browse the repository at this point in the history
  • Loading branch information
overmode committed Jan 2, 2025
1 parent 567745b commit d16a392
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 87 deletions.
140 changes: 75 additions & 65 deletions front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Markdown,
MoreIcon,
Page,
Pagination,
Spinner,
Tabs,
TabsList,
Expand All @@ -29,7 +30,8 @@ import type {
WorkspaceType,
} from "@dust-tt/types";
import { Separator } from "@radix-ui/react-select";
import { useCallback, useContext, useEffect, useState } from "react";
import type { PaginationState } from "@tanstack/react-table";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";

import ConversationViewer from "@app/components/assistant/conversation/ConversationViewer";
import { GenerationContextProvider } from "@app/components/assistant/conversation/GenerationContextProvider";
Expand All @@ -56,8 +58,7 @@ import { useUser } from "@app/lib/swr/user";
import { timeAgoFrom } from "@app/lib/utils";
import type { FetchAssistantTemplateResponse } from "@app/pages/api/w/[wId]/assistant/builder/templates/[tId]";

const MAX_FEEDBACKS_TO_DISPLAY = 500;
const FEEDBACKS_BATCH_SIZE = 100;
const FEEDBACKS_BATCH_SIZE = 50;

interface AssistantBuilderRightPanelProps {
screen: BuilderScreen;
Expand Down Expand Up @@ -422,16 +423,16 @@ const FeedbacksSection = ({
owner: LightWorkspaceType;
assistantId: string;
}) => {
// Used for pagination
const [feedbacksExhausted, setFeedbacksExhausted] = useState(false);
const [currentOldestFeedbackId, setCurrentOldestFeedbackId] = useState<
number | undefined
>(undefined);
// Used for pagination's lastValue: BatchId -> LastFeedbackId
const [lastIdForBatches, setLastIdForBatches] = useState<
Record<number, number>
>({});

const [paginationState, setPaginationState] = useState<PaginationState>({
pageIndex: 0,
pageSize: FEEDBACKS_BATCH_SIZE,
});

// All retrieved Feedbacks
const [feedbacks, setFeedbacks] = useState<
AgentMessageFeedbackWithMetadataType[]
>([]);
// Decreasing version, paginated decreasing id.
const { agentConfigurationFeedbacks, isAgentConfigurationFeedbacksLoading } =
useAgentConfigurationFeedbacksByDescVersion({
Expand All @@ -440,53 +441,53 @@ const FeedbacksSection = ({
withMetadata: true,
paginationParams: {
limit: FEEDBACKS_BATCH_SIZE,
lastValue: currentOldestFeedbackId,
lastValue:
paginationState.pageIndex === 0
? undefined
: lastIdForBatches[paginationState.pageIndex - 1],
orderColumn: "id",
orderDirection: "desc",
},
});

// Handle pagination updates.
useEffect(() => {
if (
!!agentConfigurationFeedbacks &&
agentConfigurationFeedbacks.length > 0
) {
setFeedbacks((prevFeedbacks) => {
const newFeedbacks = agentConfigurationFeedbacks.filter(
(f) => !prevFeedbacks.some((pf) => pf.id === f.id)
) as AgentMessageFeedbackWithMetadataType[];
return [...prevFeedbacks, ...newFeedbacks];
});
}
}, [agentConfigurationFeedbacks]);

// Determine when feedback is exhausted
useEffect(() => {
if (!agentConfigurationFeedbacks) {
return;
}
setFeedbacksExhausted(
agentConfigurationFeedbacks.length === 0 ||
// We limit the number of feedbacks to prevent the page from becoming too slow.
feedbacks.length + FEEDBACKS_BATCH_SIZE > MAX_FEEDBACKS_TO_DISPLAY
);
}, [agentConfigurationFeedbacks, feedbacks]);

const { agentConfigurationHistory, isAgentConfigurationHistoryLoading } =
useAgentConfigurationHistory({
workspaceId: owner.sId,
agentConfigurationId: assistantId,
});

const handleLoadMoreFeedbacks = useCallback(() => {
if (agentConfigurationFeedbacks && agentConfigurationFeedbacks.length > 0) {
// This triggers a re-fetch of the feedbacks.
setCurrentOldestFeedbackId(
agentConfigurationFeedbacks[agentConfigurationFeedbacks.length - 1].id
);
}
}, [agentConfigurationFeedbacks]);
const handleSetPagination = useCallback(
(pagination: PaginationState) => {
// Pagination is not displayed if there are no feedbacks.
if (
!agentConfigurationFeedbacks ||
agentConfigurationFeedbacks.feedbacks.length === 0
) {
return;
}
setLastIdForBatches((prev) => ({
...prev,
...{
[paginationState.pageIndex]:
agentConfigurationFeedbacks.feedbacks[
agentConfigurationFeedbacks.feedbacks.length - 1
].id,
},
}));
setPaginationState(pagination);
},
[agentConfigurationFeedbacks, paginationState.pageIndex]
);

const firstAgentConfigurationInBatch = useMemo(
() =>
agentConfigurationHistory?.find(
(c) =>
c.version ===
agentConfigurationFeedbacks?.feedbacks[0].agentConfigurationVersion
),
[agentConfigurationHistory, agentConfigurationFeedbacks]
);

if (
isAgentConfigurationFeedbacksLoading ||
Expand All @@ -497,12 +498,13 @@ const FeedbacksSection = ({

if (
!isAgentConfigurationFeedbacksLoading &&
(!feedbacks || feedbacks.length === 0)
(!agentConfigurationFeedbacks ||
agentConfigurationFeedbacks.feedbacks.length === 0)
) {
return <div className="mt-3 text-sm text-element-900">No feedbacks.</div>;
}

if (!agentConfigurationHistory) {
if (!agentConfigurationHistory || !firstAgentConfigurationInBatch) {
return (
<div className="mt-3 text-sm text-element-900">
Error loading the previous agent versions.
Expand All @@ -514,16 +516,20 @@ const FeedbacksSection = ({
<div>
<div className="mb-2 flex flex-col">
<AgentConfigurationVersionHeader
agentConfiguration={agentConfigurationHistory[0]}
agentConfigurationVersion={agentConfigurationHistory[0].version}
isLatestVersion={true}
agentConfiguration={firstAgentConfigurationInBatch}
agentConfigurationVersion={firstAgentConfigurationInBatch?.version}
isLatestVersion={
firstAgentConfigurationInBatch?.version ===
agentConfigurationHistory[0].version
}
/>
{feedbacks.map((feedback, index) => {
{agentConfigurationFeedbacks?.feedbacks.map((feedback, index) => {
const isFirstFeedback = index === 0;
const isNewVersion =
!isFirstFeedback &&
feedback.agentConfigurationVersion !==
feedbacks[index - 1].agentConfigurationVersion;
agentConfigurationFeedbacks.feedbacks[index - 1]
.agentConfigurationVersion;
return (
<div key={feedback.id} className="animate-fadeIn">
{isNewVersion && (
Expand All @@ -550,16 +556,20 @@ const FeedbacksSection = ({
);
})}
</div>
{feedbacks && !feedbacksExhausted && (
<div className="mb-2 flex justify-center">
<Button
size="sm"
variant="outline"
label="Load more feedbacks"
onClick={handleLoadMoreFeedbacks}
/>
</div>
)}
{agentConfigurationFeedbacks &&
agentConfigurationFeedbacks.totalFeedbackCount > 0 && (
<div className="my-2 mr-2">
<Pagination
rowCount={agentConfigurationFeedbacks.totalFeedbackCount}
pagination={paginationState}
setPagination={handleSetPagination}
size="xs"
showDetails={true}
// Important: We need to go page by page to keep track of last cursor id.
showPageButtons={false}
/>
</div>
)}
</div>
);
};
Expand Down
31 changes: 20 additions & 11 deletions front/lib/api/assistant/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ export async function getAgentFeedbacks({
paginationParams: PaginationParams;
}): Promise<
Result<
(AgentMessageFeedbackType | AgentMessageFeedbackWithMetadataType)[],
{
feedbacks: (
| AgentMessageFeedbackType
| AgentMessageFeedbackWithMetadataType
)[];
totalFeedbackCount: number;
},
Error
>
> {
Expand Down Expand Up @@ -212,14 +218,17 @@ export async function getAgentFeedbacks({
return new Ok(feedbacksRes);
}

const feedbacks = (
feedbacksRes as AgentMessageFeedbackWithMetadataType[]
).map((feedback) => ({
...feedback,
// Only display conversationId if the feedback was shared
conversationId: feedback.isConversationShared
? feedback.conversationId
: null,
}));
return new Ok(feedbacks);
const feedbacksWithHiddenConversationId = feedbacksRes.feedbacks.map(
(feedback) => ({
...feedback,
// Redact the conversationId if user did not share the conversation.
conversationId: feedback.isConversationShared
? (feedback as AgentMessageFeedbackWithMetadataType).conversationId
: null,
})
);
return new Ok({
feedbacks: feedbacksWithHiddenConversationId,
totalFeedbackCount: feedbacksRes.totalFeedbackCount,
});
}
31 changes: 23 additions & 8 deletions front/lib/resources/agent_message_feedback_resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,32 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb
withMetadata: boolean;
agentConfiguration: LightAgentConfigurationType;
paginationParams: PaginationParams;
}): Promise<
(AgentMessageFeedbackType | AgentMessageFeedbackWithMetadataType)[]
> {
}): Promise<{
feedbacks: (
| AgentMessageFeedbackType
| AgentMessageFeedbackWithMetadataType
)[];
totalFeedbackCount: number;
}> {
const where: WhereOptions<AgentMessageFeedback> = {
// IMPORTANT: Necessary for global models who share ids across workspaces.
workspaceId: workspace.id,
agentConfigurationId: agentConfiguration.sId.toString(),
};

// Get the total feedback count, because needed for pagination
const totalFeedbackCountPromise = AgentMessageFeedback.count({
where,
});

if (paginationParams.lastValue) {
const op = paginationParams.orderDirection === "desc" ? Op.lt : Op.gt;
where[paginationParams.orderColumn as any] = {
[op]: paginationParams.lastValue,
};
}

const agentMessageFeedback = await AgentMessageFeedback.findAll({
const agentMessageFeedbackPromise = AgentMessageFeedback.findAll({
where,
include: [
{
Expand Down Expand Up @@ -156,8 +165,14 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb
limit: paginationParams.limit,
});

return (
agentMessageFeedback
const [agentMessageFeedback, totalFeedbackCount] = await Promise.all([
agentMessageFeedbackPromise,
totalFeedbackCountPromise,
]);

return {
totalFeedbackCount,
feedbacks: agentMessageFeedback
// Typeguard needed because of TypeScript limitations
.filter(
(
Expand Down Expand Up @@ -193,8 +208,8 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb
userImageUrl: feedback.user.imageUrl,
}),
};
})
);
}),
};
}

static async getFeedbackUsageDataForWorkspace({
Expand Down
3 changes: 2 additions & 1 deletion front/lib/swr/assistants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export function useAgentConfigurationFeedbacksByDescVersion({
| AgentMessageFeedbackType
| AgentMessageFeedbackWithMetadataType
)[];
totalFeedbackCount: number;
}> = fetcher;

const urlParams = new URLSearchParams({
Expand All @@ -274,7 +275,7 @@ export function useAgentConfigurationFeedbacksByDescVersion({
);

return {
agentConfigurationFeedbacks: data ? data.feedbacks : null,
agentConfigurationFeedbacks: data ? data : null,
isAgentConfigurationFeedbacksLoading: !error && !data,
isAgentConfigurationFeedbacksError: error,
mutateAgentConfigurationFeedbacks: mutate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import { apiError } from "@app/logger/withlogging";
async function handler(
req: NextApiRequest,
res: NextApiResponse<
WithAPIErrorResponse<{ feedbacks: AgentMessageFeedbackType[] }>
WithAPIErrorResponse<{
feedbacks: AgentMessageFeedbackType[];
totalFeedbackCount: number;
}>
>,
auth: Authenticator
): Promise<void> {
Expand Down Expand Up @@ -77,7 +80,10 @@ async function handler(

const feedbacks = feedbacksRes.value;

res.status(200).json({ feedbacks });
res.status(200).json({
feedbacks: feedbacks.feedbacks,
totalFeedbackCount: feedbacks.totalFeedbackCount,
});
return;

default:
Expand Down

0 comments on commit d16a392

Please sign in to comment.