Skip to content

Commit

Permalink
UseSWRInfinity and IntersectionObserver
Browse files Browse the repository at this point in the history
  • Loading branch information
overmode committed Jan 3, 2025
1 parent e1ed828 commit 4c61121
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import {
HandThumbDownIcon,
HandThumbUpIcon,
Page,
Pagination,
Spinner,
} from "@dust-tt/sparkle";
import type {
LightAgentConfigurationType,
LightWorkspaceType,
} from "@dust-tt/types";
import type { PaginationState } from "@tanstack/react-table";
import { useCallback, useMemo, useState } from "react";
import { memo, useCallback, useEffect, useRef } from "react";

import type { AgentMessageFeedbackWithMetadataType } from "@app/lib/api/assistant/feedback";
import {
Expand All @@ -32,33 +30,53 @@ export const FeedbacksSection = ({
owner,
agentConfigurationId,
}: FeedbacksSectionProps) => {
// Used for pagination's lastValue: page index -> last feedback id in page
const [lastIdForPage, setLastIdForPage] = useState<Record<number, number>>(
{}
);

const [paginationState, setPaginationState] = useState<PaginationState>({
pageIndex: 0,
pageSize: FEEDBACKS_PAGE_SIZE,
const {
isAgentConfigurationFeedbacksLoading,
isValidating,
agentConfigurationFeedbacks,
hasMore: feedbacksNotExhausted,
setSize,
size,
} = useAgentConfigurationFeedbacksByDescVersion({
workspaceId: owner.sId,
agentConfigurationId: agentConfigurationId,
limit: FEEDBACKS_PAGE_SIZE,
});

// Decreasing version, paginated decreasing id.
const { agentConfigurationFeedbacks, isAgentConfigurationFeedbacksLoading } =
useAgentConfigurationFeedbacksByDescVersion({
workspaceId: owner.sId,
agentConfigurationId: agentConfigurationId ?? "",
withMetadata: true,
paginationParams: {
limit: FEEDBACKS_PAGE_SIZE,
lastValue:
paginationState.pageIndex === 0
? undefined
: lastIdForPage[paginationState.pageIndex - 1],
orderColumn: "id",
orderDirection: "desc",
// Intersection observer to detect when the user has scrolled to the bottom of the list.
const bottomRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
const target = entries[0];
if (
target.isIntersecting &&
!isValidating &&
!isAgentConfigurationFeedbacksLoading &&
feedbacksNotExhausted
) {
setSize(size + 1);
}
},
disabled: !agentConfigurationId,
});
{
threshold: 0.25,
}
);

if (bottomRef.current) {
observer.observe(bottomRef.current);
}

return () => observer.disconnect();
}, [
bottomRef,
isValidating,
isAgentConfigurationFeedbacksLoading,
agentConfigurationFeedbacks,
setSize,
size,
feedbacksNotExhausted,
]);

const { agentConfigurationHistory, isAgentConfigurationHistoryLoading } =
useAgentConfigurationHistory({
Expand All @@ -67,39 +85,6 @@ export const FeedbacksSection = ({
disabled: !agentConfigurationId,
});

const handleSetPagination = useCallback(
(pagination: PaginationState) => {
// Pagination is not displayed if there are no feedbacks.
if (
!agentConfigurationFeedbacks ||
agentConfigurationFeedbacks.feedbacks.length === 0
) {
return;
}
setLastIdForPage((prev) => ({
...prev,
...{
[paginationState.pageIndex]:
agentConfigurationFeedbacks.feedbacks[
agentConfigurationFeedbacks.feedbacks.length - 1
].id,
},
}));
setPaginationState(pagination);
},
[agentConfigurationFeedbacks, paginationState.pageIndex]
);

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

if (
isAgentConfigurationFeedbacksLoading ||
isAgentConfigurationHistoryLoading
Expand All @@ -109,13 +94,12 @@ export const FeedbacksSection = ({

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

if (!agentConfigurationHistory || !firstAgentConfigurationInPage) {
if (!agentConfigurationHistory) {
return (
<div className="mt-3 text-sm text-element-900">
Error loading the previous agent versions.
Expand All @@ -127,20 +111,16 @@ export const FeedbacksSection = ({
<div>
<div className="mb-2 flex flex-col">
<AgentConfigurationVersionHeader
agentConfiguration={firstAgentConfigurationInPage}
agentConfigurationVersion={firstAgentConfigurationInPage?.version}
isLatestVersion={
firstAgentConfigurationInPage?.version ===
agentConfigurationHistory[0].version
}
agentConfiguration={agentConfigurationHistory[0]}
agentConfigurationVersion={agentConfigurationHistory[0].version}
isLatestVersion={true}
/>
{agentConfigurationFeedbacks?.feedbacks.map((feedback, index) => {
{agentConfigurationFeedbacks?.map((feedback, index) => {
const isFirstFeedback = index === 0;
const isNewVersion =
!isFirstFeedback &&
feedback.agentConfigurationVersion !==
agentConfigurationFeedbacks.feedbacks[index - 1]
.agentConfigurationVersion;
agentConfigurationFeedbacks[index - 1].agentConfigurationVersion;
return (
<div key={feedback.id} className="animate-fadeIn">
{isNewVersion && (
Expand All @@ -158,7 +138,7 @@ export const FeedbacksSection = ({
</div>
)}
<div className="mr-2">
<FeedbackCard
<MemoizedFeedbackCard
owner={owner}
feedback={feedback as AgentMessageFeedbackWithMetadataType}
/>
Expand All @@ -167,20 +147,8 @@ export const FeedbacksSection = ({
);
})}
</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>
)}
{/* Invisible div to act as a scroll anchor for detecting when the user has scrolled to the bottom */}
<div ref={bottomRef} className="h-1.5" />
</div>
);
};
Expand Down Expand Up @@ -222,6 +190,7 @@ interface FeedbackCardProps {
owner: LightWorkspaceType;
feedback: AgentMessageFeedbackWithMetadataType;
}
const MemoizedFeedbackCard = memo(FeedbackCard);
function FeedbackCard({ owner, feedback }: FeedbackCardProps) {
const conversationUrl =
feedback.conversationId &&
Expand Down
29 changes: 9 additions & 20 deletions front/lib/api/assistant/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,7 @@ export async function getAgentFeedbacks({
paginationParams: PaginationParams;
}): Promise<
Result<
{
feedbacks: (
| AgentMessageFeedbackType
| AgentMessageFeedbackWithMetadataType
)[];
totalFeedbackCount: number;
},
(AgentMessageFeedbackType | AgentMessageFeedbackWithMetadataType)[],
Error
>
> {
Expand Down Expand Up @@ -218,17 +212,12 @@ export async function getAgentFeedbacks({
return new Ok(feedbacksRes);
}

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

// 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 agentMessageFeedbackPromise = AgentMessageFeedback.findAll({
const agentMessageFeedback = await AgentMessageFeedback.findAll({
where,
include: [
{
Expand Down Expand Up @@ -166,14 +157,8 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb
limit: paginationParams.limit,
});

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

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

static async getFeedbackUsageDataForWorkspace({
Expand Down
Loading

0 comments on commit 4c61121

Please sign in to comment.