From 918323c852c4c0cb0918c71ac5a1793acaf73adf Mon Sep 17 00:00:00 2001 From: Usama Date: Thu, 23 Oct 2025 09:56:25 +0000 Subject: [PATCH 01/13] - project chat query optimized - useConversationsByProjectId, useInfiniteConversationsByProjectId optimized - useinfinite query optimized for Project Home component --- echo/QUERY_OPTIMIZATION_SUMMARY.md | 154 ++++++++++++++++++ .../src/components/chat/hooks/index.ts | 8 +- .../components/conversation/hooks/index.ts | 55 +++++-- .../src/routes/project/ProjectsHome.tsx | 2 +- 4 files changed, 199 insertions(+), 20 deletions(-) create mode 100644 echo/QUERY_OPTIMIZATION_SUMMARY.md diff --git a/echo/QUERY_OPTIMIZATION_SUMMARY.md b/echo/QUERY_OPTIMIZATION_SUMMARY.md new file mode 100644 index 00000000..8f64b36b --- /dev/null +++ b/echo/QUERY_OPTIMIZATION_SUMMARY.md @@ -0,0 +1,154 @@ +# Frontend Query Optimization Summary + +## Overview +This document summarizes the optimizations made to frontend queries to reduce unnecessary data fetching from the database. + +## Changes Made + +### 1. Projects Query (`useInfiniteProjects`) +**File:** `frontend/src/routes/project/ProjectsHome.tsx` + +**Before:** +```typescript +fields: ["count(conversations)", "*"] +``` + +**After:** +```typescript +fields: ["id", "name", "updated_at", "count(conversations)"] +``` + +**Impact:** Reduced from fetching ALL project fields to only 4 specific fields. +**Used in:** Project list view (`ProjectListItem` component) + +--- + +### 2. Conversations List Query (`useConversationsByProjectId` & `useInfiniteConversationsByProjectId`) +**File:** `frontend/src/components/conversation/hooks/index.ts` + +**Before:** +- Fetched all fields from `CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS` (25+ fields) +- Fetched all chunk fields with `["*"]` +- Fetched all tag fields including `created_at` + +**After:** +```typescript +// New minimal fields list for conversation lists +CONVERSATION_LIST_FIELDS = [ + "id", + "created_at", + "participant_name", + "participant_email", + "source", + "duration", + "tags", + "chunks", +] + +// Only fetch specific chunk fields for live status +{ chunks: ["source", "timestamp", "created_at"] } + +// Only fetch necessary tag fields +{ tags: [{ project_tag_id: ["id", "text"] }] } + +// Reduced chunk limit from 1 to 25 when not loading all chunks +``` + +**Impact:** +- Reduced fields from 25+ to 8 base fields +- Reduced chunk fields from all fields to only 3 fields +- Removed unnecessary `created_at` from tags +- More reasonable chunk limit (25 instead of 1) + +**Used in:** Conversation list views (`ConversationAccordion`, `ConversationStatusIndicators`) + +--- + +### 3. Conversation Detail Query (`useConversationById`) +**File:** `frontend/src/components/conversation/hooks/index.ts` + +**Before:** +- Fetched all fields from `CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS` (25+ fields) +- Included `created_at` in tag fields + +**After:** +```typescript +fields: [ + "id", + "summary", + "source", + "is_finished", + "participant_name", + "participant_email", + { linking_conversations: [...] }, + { linked_conversations: [...] }, + { tags: [{ project_tag_id: ["id", "text"] }] }, + ...(loadConversationChunks ? [{ chunks: ["*"] }] : []), +] +``` + +**Impact:** Reduced from 25+ fields to 6 base fields + related data +**Used in:** Conversation overview page (`ProjectConversationOverviewRoute`) + +--- + +### 4. Chat Query (`useChat`) +**File:** `frontend/src/components/chat/hooks/index.ts` + +**Before:** +```typescript +fields: [ + "*", + { used_conversations: ["*"] } +] +``` + +**After:** +```typescript +fields: ["id", "name", "project_id"] +``` + +**Impact:** +- Eliminated fetching ALL chat fields +- Removed unnecessary `used_conversations` relation (not used in UI) +- Reduced to only 3 fields + +**Used in:** Chat route (`ProjectChatRoute`) + +--- + + + +## Testing Recommendations + +Please test the following user flows to ensure everything works correctly: + +1. **Login → Projects:** + - ✓ Project list displays correctly + - ✓ Project names and conversation counts show + - ✓ Last updated timestamps display + +2. **Projects → Conversations:** + - ✓ Conversation list displays correctly + - ✓ Participant names/emails show + - ✓ Tags display properly + - ✓ Live status indicator works + - ✓ Duration badges show + - ✓ Source badges (Upload/Text) display + +3. **Conversation → Overview:** + - ✓ Summary displays + - ✓ Conversation metadata shows + - ✓ Tags can be edited + - ✓ Linked conversations display + +4. **Conversation → Transcript:** + - ✓ Transcript chunks load correctly + - ✓ Audio player works (uses separate query) + +5. **Chat:** + - ✓ Chat name displays + - ✓ Chat can be renamed + - ✓ Chat can be deleted + - ✓ Chat messages work + diff --git a/echo/frontend/src/components/chat/hooks/index.ts b/echo/frontend/src/components/chat/hooks/index.ts index 974a3393..df8fc6ef 100644 --- a/echo/frontend/src/components/chat/hooks/index.ts +++ b/echo/frontend/src/components/chat/hooks/index.ts @@ -121,12 +121,8 @@ export const useChat = (chatId: string) => { queryFn: () => directus.request( readItem("project_chat", chatId, { - fields: [ - "*", - { - used_conversations: ["*"], - }, - ], + // Only fetch fields used in chat UI: id, name, project_id + fields: ["id", "name", "project_id"], }), ), queryKey: ["chats", chatId], diff --git a/echo/frontend/src/components/conversation/hooks/index.ts b/echo/frontend/src/components/conversation/hooks/index.ts index b524d236..f8f916d3 100644 --- a/echo/frontend/src/components/conversation/hooks/index.ts +++ b/echo/frontend/src/components/conversation/hooks/index.ts @@ -681,7 +681,18 @@ export const useConversationsByProjectId = ( }, ], }, - { chunks: ["*"] }, + { + chunks: [ + "id", + "conversation_id", + "transcript", + "source", + "path", + "timestamp", + "created_at", + "error", + ], + }, ], filter: { chunks: { @@ -765,21 +776,13 @@ export const CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS: QueryFields< "project_id", "participant_name", "participant_email", - "participant_user_agent", "tags", "summary", "source", "chunks", - "project_chats", - "project_chat_messages", - "replies", - "conversation_segments", "duration", - "merged_transcript", - "merged_audio_path", "is_finished", "is_audio_processing_finished", - "is_all_chunks_transcribed", "linked_conversations", "linking_conversations", ]; @@ -825,11 +828,26 @@ export const useConversationById = ({ { tags: [ { - project_tag_id: ["id", "text", "created_at"], + project_tag_id: ["id", "text"], }, ], }, - ...(loadConversationChunks ? [{ chunks: ["*"] as any }] : []), + ...(loadConversationChunks + ? [ + { + chunks: [ + "id", + "conversation_id", + "transcript", + "source", + "path", + "timestamp", + "created_at", + "error", + ], + }, + ] + : []), ], ...query, }), @@ -871,11 +889,22 @@ export const useInfiniteConversationsByProjectId = ( { tags: [ { - project_tag_id: ["id", "text", "created_at"], + project_tag_id: ["id", "text"], }, ], }, - { chunks: ["*"] }, + { + chunks: [ + "id", + "conversation_id", + "transcript", + "source", + "path", + "timestamp", + "created_at", + "error", + ], + }, ], filter: { chunks: { diff --git a/echo/frontend/src/routes/project/ProjectsHome.tsx b/echo/frontend/src/routes/project/ProjectsHome.tsx index 2c9c4ea4..ef0b411c 100644 --- a/echo/frontend/src/routes/project/ProjectsHome.tsx +++ b/echo/frontend/src/routes/project/ProjectsHome.tsx @@ -56,7 +56,7 @@ export const ProjectsHomeRoute = () => { error, } = useInfiniteProjects({ query: { - fields: ["count(conversations)", "*"], + fields: ["id", "name", "updated_at", "count(conversations)"], search: debouncedSearchValue, sort: "-updated_at", }, From 6c8ca24a816cd4c3c39f042c1e54d8f99a3e5a6f Mon Sep 17 00:00:00 2001 From: Usama Date: Thu, 23 Oct 2025 10:53:16 +0000 Subject: [PATCH 02/13] - remove redundant db query in the Login component --- echo/frontend/src/routes/auth/Login.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/echo/frontend/src/routes/auth/Login.tsx b/echo/frontend/src/routes/auth/Login.tsx index e11403e3..9a684ca1 100644 --- a/echo/frontend/src/routes/auth/Login.tsx +++ b/echo/frontend/src/routes/auth/Login.tsx @@ -83,15 +83,9 @@ export const LoginRoute = () => { setError(""); await loginMutation.mutateAsync([data.email, data.password]); - const projectsCount = await directus.request( - readItems("project", { limit: 1 }), - ); - const isNewAccount = - searchParams.get("new") === "true" && projectsCount.length === 0; - - if (isNewAccount) { + // Auto-create first project for new users + if (searchParams.get("new") === "true") { toast(t`Setting up your first project`); - await loginMutation.mutateAsync([data.email, data.password]); const project = await createProjectMutation.mutateAsync({ name: t`New Project`, }); From 916aedcd2e737cb819203b579c08b29ee6340d09 Mon Sep 17 00:00:00 2001 From: Usama Date: Thu, 23 Oct 2025 11:39:21 +0000 Subject: [PATCH 03/13] - fetch only required fields for CurrentUser --- echo/frontend/src/components/auth/hooks/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/echo/frontend/src/components/auth/hooks/index.ts b/echo/frontend/src/components/auth/hooks/index.ts index 4a1503bf..7d548df5 100644 --- a/echo/frontend/src/components/auth/hooks/index.ts +++ b/echo/frontend/src/components/auth/hooks/index.ts @@ -18,7 +18,11 @@ export const useCurrentUser = () => useQuery({ queryFn: () => { try { - return directus.request(readUser("me")); + return directus.request( + readUser("me", { + fields: ["id", "first_name", "email", "disable_create_project"], + }), + ); } catch (_error) { return null; } From 7f7c939840226e90dff86d1ad42e15574f4eeb4c Mon Sep 17 00:00:00 2001 From: Usama Date: Thu, 23 Oct 2025 13:18:11 +0000 Subject: [PATCH 04/13] - Optimize project queries by specifying required fields across multiple components --- .../OpenForParticipationSummaryCard.tsx | 7 +++- .../layout/ProjectOverviewLayout.tsx | 12 +++++- .../src/components/project/ProjectSidebar.tsx | 13 ++++++- .../components/project/ProjectTagsInput.tsx | 18 ++++++++- .../src/routes/project/ProjectRoutes.tsx | 37 ++++++++++++++++++- .../ProjectConversationOverview.tsx | 18 ++++++++- 6 files changed, 98 insertions(+), 7 deletions(-) diff --git a/echo/frontend/src/components/conversation/OpenForParticipationSummaryCard.tsx b/echo/frontend/src/components/conversation/OpenForParticipationSummaryCard.tsx index 8888764e..8c756a95 100644 --- a/echo/frontend/src/components/conversation/OpenForParticipationSummaryCard.tsx +++ b/echo/frontend/src/components/conversation/OpenForParticipationSummaryCard.tsx @@ -14,7 +14,12 @@ interface OpenForParticipationSummaryCardProps { export const OpenForParticipationSummaryCard = ({ projectId, }: OpenForParticipationSummaryCardProps) => { - const projectQuery = useProjectById({ projectId }); + const projectQuery = useProjectById({ + projectId, + query: { + fields: ["id", "is_conversation_allowed"], + }, + }); const updateProjectMutation = useUpdateProjectByIdMutation(); const handleOpenForParticipationCheckboxChange = ( diff --git a/echo/frontend/src/components/layout/ProjectOverviewLayout.tsx b/echo/frontend/src/components/layout/ProjectOverviewLayout.tsx index 3a5ef0b0..931f3d94 100644 --- a/echo/frontend/src/components/layout/ProjectOverviewLayout.tsx +++ b/echo/frontend/src/components/layout/ProjectOverviewLayout.tsx @@ -10,7 +10,17 @@ import { TabsWithRouter } from "./TabsWithRouter"; export const ProjectOverviewLayout = () => { const projectId = useParams().projectId; - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + query: { + fields: [ + "id", + "language", + "is_conversation_allowed", + "default_conversation_title", + ], + }, + }); useDocumentTitle(t`Project Overview | Dembrane`); diff --git a/echo/frontend/src/components/project/ProjectSidebar.tsx b/echo/frontend/src/components/project/ProjectSidebar.tsx index 532326e7..25634688 100644 --- a/echo/frontend/src/components/project/ProjectSidebar.tsx +++ b/echo/frontend/src/components/project/ProjectSidebar.tsx @@ -26,7 +26,18 @@ export const ProjectSidebar = () => { const { projectId, conversationId } = useParams(); const qrCodeRef = useRef(null); - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + query: { + fields: [ + "id", + "name", + "language", + "is_conversation_allowed", + "default_conversation_title", + ], + }, + }); const { pathname } = useLocation(); // const { isCollapsed, toggleSidebar } = useSidebarCollapsed(); diff --git a/echo/frontend/src/components/project/ProjectTagsInput.tsx b/echo/frontend/src/components/project/ProjectTagsInput.tsx index 496ea1e2..1a7a106f 100644 --- a/echo/frontend/src/components/project/ProjectTagsInput.tsx +++ b/echo/frontend/src/components/project/ProjectTagsInput.tsx @@ -112,7 +112,23 @@ export const ProjectTagPill = ({ tag }: { tag: ProjectTag }) => { }; export const ProjectTagsInput = (props: { project: Project }) => { - const projectQuery = useProjectById({ projectId: props.project.id }); + const projectQuery = useProjectById({ + projectId: props.project.id, + query: { + deep: { + // @ts-expect-error tags won't be typed + tags: { + _sort: "sort", + }, + }, + fields: [ + "id", + { + tags: ["id", "created_at", "text", "sort"], + }, + ], + }, + }); const createTagMutation = useCreateProjectTagMutation(); const updateTagMutation = useUpdateProjectTagByIdMutation(); diff --git a/echo/frontend/src/routes/project/ProjectRoutes.tsx b/echo/frontend/src/routes/project/ProjectRoutes.tsx index 8846aa13..a2a50e03 100644 --- a/echo/frontend/src/routes/project/ProjectRoutes.tsx +++ b/echo/frontend/src/routes/project/ProjectRoutes.tsx @@ -12,7 +12,12 @@ import { getProjectTranscriptsLink } from "@/lib/api"; export const ProjectSettingsRoute = () => { const { projectId } = useParams(); - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + query: { + fields: ["id", "name", "context", "updated_at", "language"], + }, + }); return ( { export const ProjectPortalSettingsRoute = () => { const { projectId } = useParams(); - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + query: { + deep: { + // @ts-expect-error tags won't be typed + tags: { + _sort: "sort", + }, + }, + fields: [ + "id", + "updated_at", + "language", + "default_conversation_ask_for_participant_name", + "default_conversation_description", + "default_conversation_finish_text", + "default_conversation_title", + "default_conversation_transcript_prompt", + "default_conversation_tutorial_slug", + "get_reply_mode", + "get_reply_prompt", + "is_get_reply_enabled", + "is_project_notification_subscription_allowed", + { + tags: ["id", "created_at", "text", "sort"], + }, + ], + }, + }); // Memoize the project data to ensure stable reference // biome-ignore lint/correctness/useExhaustiveDependencies: needs to be fixed diff --git a/echo/frontend/src/routes/project/conversation/ProjectConversationOverview.tsx b/echo/frontend/src/routes/project/conversation/ProjectConversationOverview.tsx index 2b75dfa9..cb924f16 100644 --- a/echo/frontend/src/routes/project/conversation/ProjectConversationOverview.tsx +++ b/echo/frontend/src/routes/project/conversation/ProjectConversationOverview.tsx @@ -39,7 +39,23 @@ export const ProjectConversationOverviewRoute = () => { 10000, ["id"], ); - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + query: { + deep: { + // @ts-expect-error tags won't be typed + tags: { + _sort: "sort", + }, + }, + fields: [ + "id", + { + tags: ["id", "created_at", "text", "sort"], + }, + ], + }, + }); const useHandleGenerateSummaryManually = useMutation({ mutationFn: async () => { From 8ba9171a1de7a2dd5c0871642910fdae16864657 Mon Sep 17 00:00:00 2001 From: Usama Date: Thu, 23 Oct 2025 14:09:04 +0000 Subject: [PATCH 05/13] - optimize conversation overview and conversation transcript queries further --- echo/QUERY_OPTIMIZATION_SUMMARY.md | 154 ------------------ .../components/conversation/hooks/index.ts | 1 + .../layout/ProjectConversationLayout.tsx | 15 +- .../ProjectConversationTranscript.tsx | 7 +- 4 files changed, 15 insertions(+), 162 deletions(-) delete mode 100644 echo/QUERY_OPTIMIZATION_SUMMARY.md diff --git a/echo/QUERY_OPTIMIZATION_SUMMARY.md b/echo/QUERY_OPTIMIZATION_SUMMARY.md deleted file mode 100644 index 8f64b36b..00000000 --- a/echo/QUERY_OPTIMIZATION_SUMMARY.md +++ /dev/null @@ -1,154 +0,0 @@ -# Frontend Query Optimization Summary - -## Overview -This document summarizes the optimizations made to frontend queries to reduce unnecessary data fetching from the database. - -## Changes Made - -### 1. Projects Query (`useInfiniteProjects`) -**File:** `frontend/src/routes/project/ProjectsHome.tsx` - -**Before:** -```typescript -fields: ["count(conversations)", "*"] -``` - -**After:** -```typescript -fields: ["id", "name", "updated_at", "count(conversations)"] -``` - -**Impact:** Reduced from fetching ALL project fields to only 4 specific fields. -**Used in:** Project list view (`ProjectListItem` component) - ---- - -### 2. Conversations List Query (`useConversationsByProjectId` & `useInfiniteConversationsByProjectId`) -**File:** `frontend/src/components/conversation/hooks/index.ts` - -**Before:** -- Fetched all fields from `CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS` (25+ fields) -- Fetched all chunk fields with `["*"]` -- Fetched all tag fields including `created_at` - -**After:** -```typescript -// New minimal fields list for conversation lists -CONVERSATION_LIST_FIELDS = [ - "id", - "created_at", - "participant_name", - "participant_email", - "source", - "duration", - "tags", - "chunks", -] - -// Only fetch specific chunk fields for live status -{ chunks: ["source", "timestamp", "created_at"] } - -// Only fetch necessary tag fields -{ tags: [{ project_tag_id: ["id", "text"] }] } - -// Reduced chunk limit from 1 to 25 when not loading all chunks -``` - -**Impact:** -- Reduced fields from 25+ to 8 base fields -- Reduced chunk fields from all fields to only 3 fields -- Removed unnecessary `created_at` from tags -- More reasonable chunk limit (25 instead of 1) - -**Used in:** Conversation list views (`ConversationAccordion`, `ConversationStatusIndicators`) - ---- - -### 3. Conversation Detail Query (`useConversationById`) -**File:** `frontend/src/components/conversation/hooks/index.ts` - -**Before:** -- Fetched all fields from `CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS` (25+ fields) -- Included `created_at` in tag fields - -**After:** -```typescript -fields: [ - "id", - "summary", - "source", - "is_finished", - "participant_name", - "participant_email", - { linking_conversations: [...] }, - { linked_conversations: [...] }, - { tags: [{ project_tag_id: ["id", "text"] }] }, - ...(loadConversationChunks ? [{ chunks: ["*"] }] : []), -] -``` - -**Impact:** Reduced from 25+ fields to 6 base fields + related data -**Used in:** Conversation overview page (`ProjectConversationOverviewRoute`) - ---- - -### 4. Chat Query (`useChat`) -**File:** `frontend/src/components/chat/hooks/index.ts` - -**Before:** -```typescript -fields: [ - "*", - { used_conversations: ["*"] } -] -``` - -**After:** -```typescript -fields: ["id", "name", "project_id"] -``` - -**Impact:** -- Eliminated fetching ALL chat fields -- Removed unnecessary `used_conversations` relation (not used in UI) -- Reduced to only 3 fields - -**Used in:** Chat route (`ProjectChatRoute`) - ---- - - - -## Testing Recommendations - -Please test the following user flows to ensure everything works correctly: - -1. **Login → Projects:** - - ✓ Project list displays correctly - - ✓ Project names and conversation counts show - - ✓ Last updated timestamps display - -2. **Projects → Conversations:** - - ✓ Conversation list displays correctly - - ✓ Participant names/emails show - - ✓ Tags display properly - - ✓ Live status indicator works - - ✓ Duration badges show - - ✓ Source badges (Upload/Text) display - -3. **Conversation → Overview:** - - ✓ Summary displays - - ✓ Conversation metadata shows - - ✓ Tags can be edited - - ✓ Linked conversations display - -4. **Conversation → Transcript:** - - ✓ Transcript chunks load correctly - - ✓ Audio player works (uses separate query) - -5. **Chat:** - - ✓ Chat name displays - - ✓ Chat can be renamed - - ✓ Chat can be deleted - - ✓ Chat messages work - diff --git a/echo/frontend/src/components/conversation/hooks/index.ts b/echo/frontend/src/components/conversation/hooks/index.ts index f8f916d3..8d3d7c56 100644 --- a/echo/frontend/src/components/conversation/hooks/index.ts +++ b/echo/frontend/src/components/conversation/hooks/index.ts @@ -644,6 +644,7 @@ export const useConversationChunks = ( _eq: conversationId, }, }, + limit: 1, // Only need to check if chunks exist sort: "timestamp", }), ), diff --git a/echo/frontend/src/components/layout/ProjectConversationLayout.tsx b/echo/frontend/src/components/layout/ProjectConversationLayout.tsx index e3e2fdec..9f4bfca4 100644 --- a/echo/frontend/src/components/layout/ProjectConversationLayout.tsx +++ b/echo/frontend/src/components/layout/ProjectConversationLayout.tsx @@ -2,10 +2,7 @@ import { t } from "@lingui/core/macro"; import { Stack, Title } from "@mantine/core"; import { useParams } from "react-router"; import { ConversationStatusIndicators } from "../conversation/ConversationAccordion"; -import { - CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS, - useConversationById, -} from "../conversation/hooks"; +import { useConversationById } from "../conversation/hooks"; import { TabsWithRouter } from "./TabsWithRouter"; export const ProjectConversationLayout = () => { @@ -21,8 +18,14 @@ export const ProjectConversationLayout = () => { }, }, fields: [ - ...CONVERSATION_FIELDS_WITHOUT_PROCESSING_STATUS, - { chunks: ["transcript"] }, + "id", + "participant_name", + "duration", + "is_finished", + "is_audio_processing_finished", + "created_at", + "updated_at", + { chunks: ["source", "transcript"] }, ], }, }); diff --git a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx index 81704eb7..d567a331 100644 --- a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx +++ b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx @@ -27,9 +27,12 @@ export const ProjectConversationTranscript = () => { const { conversationId } = useParams(); const conversationQuery = useConversationById({ conversationId: conversationId ?? "", - loadConversationChunks: true, + loadConversationChunks: false, + query: { + fields: ["id", "participant_name", "is_finished"], + }, }); - + console.log(conversationQuery.data, " ==>here"); const { ref: loadMoreRef, inView } = useInView(); const { From 0697d5e5a365bfac8063f5b05e124131fcc2cafb Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 05:47:02 +0000 Subject: [PATCH 06/13] - optimize chat queries further --- echo/frontend/src/components/chat/hooks/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/echo/frontend/src/components/chat/hooks/index.ts b/echo/frontend/src/components/chat/hooks/index.ts index df8fc6ef..7f6d47d6 100644 --- a/echo/frontend/src/components/chat/hooks/index.ts +++ b/echo/frontend/src/components/chat/hooks/index.ts @@ -24,7 +24,8 @@ import { directus } from "@/lib/directus"; export const useChatHistory = (chatId: string) => { return useQuery({ - queryFn: () => getChatHistory(chatId ?? ""), + enabled: chatId !== "", + queryFn: () => getChatHistory(chatId), queryKey: ["chats", "history", chatId], }); }; From 82a0b520b7b65b6ca56750d782241a0437f88ba7 Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 06:20:47 +0000 Subject: [PATCH 07/13] - minor updates to finalize conversation queries --- echo/frontend/src/components/conversation/hooks/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/echo/frontend/src/components/conversation/hooks/index.ts b/echo/frontend/src/components/conversation/hooks/index.ts index 8d3d7c56..1dbfb0f8 100644 --- a/echo/frontend/src/components/conversation/hooks/index.ts +++ b/echo/frontend/src/components/conversation/hooks/index.ts @@ -129,7 +129,7 @@ export const useUpdateConversationTagsMutation = () => { try { const validTags = await directus.request( readItems("project_tag", { - fields: ["*"], + fields: ["id"], filter: { id: { _in: projectTagIdList, @@ -153,9 +153,6 @@ export const useUpdateConversationTagsMutation = () => { { project_tag_id: ["id"], }, - { - conversation_id: ["id"], - }, ], filter: { conversation_id: { _eq: conversationId }, From cbe506736e3a41c3708ec1ddd178d23e280b3e89 Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 07:14:56 +0000 Subject: [PATCH 08/13] - finalize report queries optimization --- .../src/components/report/hooks/index.ts | 44 +++++++++++++------ echo/frontend/src/lib/api.ts | 1 - 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/echo/frontend/src/components/report/hooks/index.ts b/echo/frontend/src/components/report/hooks/index.ts index 72892a6f..54c943bf 100644 --- a/echo/frontend/src/components/report/hooks/index.ts +++ b/echo/frontend/src/components/report/hooks/index.ts @@ -48,23 +48,26 @@ export const useCreateProjectReportMutation = () => { export const useGetProjectParticipants = (project_id: string) => { return useQuery({ - enabled: !!project_id, // Only run query if project_id exists + enabled: !!project_id, queryFn: async () => { if (!project_id) return 0; - const submissions = await directus.request( - readItems("project_report_notification_participants", { - fields: ["id"], - filter: { - _and: [ - { project_id: { _eq: project_id } }, - { email_opt_in: { _eq: true } }, - ], + const result = await directus.request( + aggregate("project_report_notification_participants", { + aggregate: { + count: "*", + }, + query: { + filter: { + _and: [ + { project_id: { _eq: project_id } }, + { email_opt_in: { _eq: true } }, + ], + }, }, }), ); - - return submissions.length; + return Number.parseInt(result[0]?.count ?? "0", 10) || 0; }, queryKey: ["projectParticipants", project_id], }); @@ -99,6 +102,7 @@ export const useProjectReportTimelineData = (projectReportId: string) => { const allProjectReports = await directus.request( readItems("project_report", { + fields: ["id", "date_created"], filter: { project_id: { _eq: projectReport.project_id, @@ -247,7 +251,21 @@ export const useDoesProjectReportNeedUpdate = (projectReportId: number) => { export const useProjectReport = (reportId: number) => { return useQuery({ - queryFn: () => directus.request(readItem("project_report", reportId)), + queryFn: () => + directus.request( + readItem("project_report", reportId, { + fields: [ + "id", + "status", + "project_id", + "content", + "show_portal_link", + "language", + "date_created", + "date_updated", + ], + }), + ), queryKey: ["reports", reportId], refetchInterval: 30000, }); @@ -320,7 +338,7 @@ export const useLatestProjectReport = (projectId: string) => { queryFn: async () => { const reports = await directus.request( readItems("project_report", { - fields: ["*"], + fields: ["id", "status", "project_id", "show_portal_link"], filter: { project_id: { _eq: projectId, diff --git a/echo/frontend/src/lib/api.ts b/echo/frontend/src/lib/api.ts index 6104f9b5..a486ff17 100644 --- a/echo/frontend/src/lib/api.ts +++ b/echo/frontend/src/lib/api.ts @@ -845,7 +845,6 @@ export const getProjectConversationCounts = async (projectId: string) => { fields: [ "id", "is_finished", - "summary", "participant_name", "updated_at", "created_at", From fafbd1b1f027e9cdd229e9da8c12d4f9833bb95d Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 07:37:53 +0000 Subject: [PATCH 09/13] - optimize library queries --- .../src/components/library/hooks/index.ts | 27 +++++++++++++++---- echo/frontend/src/lib/api.ts | 19 +++++++++++-- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/echo/frontend/src/components/library/hooks/index.ts b/echo/frontend/src/components/library/hooks/index.ts index 8fae11cd..757b6ca7 100644 --- a/echo/frontend/src/components/library/hooks/index.ts +++ b/echo/frontend/src/components/library/hooks/index.ts @@ -24,9 +24,20 @@ export const useViewById = (projectId: string, viewId: string) => { } as any, }, fields: [ - "*", + "id", + "name", + "summary", + "created_at", { - aspects: ["*", "count(aspect_segment)"], + aspects: [ + "id", + "name", + "short_summary", + "description", + "image_url", + "view_id", + "image_generation_model", + ], }, ], }), @@ -41,13 +52,19 @@ export const useAspectById = (projectId: string, aspectId: string) => { directus.request( readItem("aspect", aspectId, { fields: [ - "*", + "id", + "name", + "image_url", + "long_summary", { aspect_segment: [ - "*", + "id", + "description", + "verbatim_transcript", + "relevant_index", { segment: [ - "*", + "id", { conversation_id: ["id", "participant_name"], }, diff --git a/echo/frontend/src/lib/api.ts b/echo/frontend/src/lib/api.ts index a486ff17..6f1af33d 100644 --- a/echo/frontend/src/lib/api.ts +++ b/echo/frontend/src/lib/api.ts @@ -206,8 +206,23 @@ export const getProjectViews = async (projectId: string) => { return directus.request( readItems("view", { fields: [ - "*", - { aspects: ["*", "count(aspect_segment)", "aspect_segment"] }, + "id", + "name", + "description", + "created_at", + "user_input", + "user_input_description", + { + aspects: [ + "id", + "name", + "short_summary", + "description", + "image_url", + "view_id", + "image_generation_model ", + ], + }, ], filter: { project_analysis_run_id: project_analysis_run?.id, From 4f7990f8c9ff8aa0e2d20dd966906c0ccd6e9651 Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 07:57:05 +0000 Subject: [PATCH 10/13] - optimize project queries further --- .../src/components/dropzone/UploadConversationDropzone.tsx | 3 +++ echo/frontend/src/components/project/hooks/index.ts | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/echo/frontend/src/components/dropzone/UploadConversationDropzone.tsx b/echo/frontend/src/components/dropzone/UploadConversationDropzone.tsx index 4497b681..200676d6 100644 --- a/echo/frontend/src/components/dropzone/UploadConversationDropzone.tsx +++ b/echo/frontend/src/components/dropzone/UploadConversationDropzone.tsx @@ -263,6 +263,9 @@ export const UploadConversationDropzone = ( const uploader = useConversationUploader(); const projectQuery = useProjectById({ projectId: props.projectId, + query: { + fields: ["id"], + }, }); // Handle file rename with the custom hook diff --git a/echo/frontend/src/components/project/hooks/index.ts b/echo/frontend/src/components/project/hooks/index.ts index c2bad4c8..f96f53af 100644 --- a/echo/frontend/src/components/project/hooks/index.ts +++ b/echo/frontend/src/components/project/hooks/index.ts @@ -137,7 +137,9 @@ export const useCreateChatMutation = () => { }; }) => { const project = await directus.request( - readItem("project", payload.project_id.id), + readItem("project", payload.project_id.id, { + fields: ["is_enhanced_audio_processing_enabled"], + }), ); const chat = await directus.request( From 45dc8cce35a4937f5c6dc47c97bf1e05f47a9e4c Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 08:08:20 +0000 Subject: [PATCH 11/13] - space fix --- echo/frontend/src/lib/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/echo/frontend/src/lib/api.ts b/echo/frontend/src/lib/api.ts index 6f1af33d..b93d2020 100644 --- a/echo/frontend/src/lib/api.ts +++ b/echo/frontend/src/lib/api.ts @@ -220,7 +220,7 @@ export const getProjectViews = async (projectId: string) => { "description", "image_url", "view_id", - "image_generation_model ", + "image_generation_model", ], }, ], From 1a6112e596176acc403d30bc711ec8b1ec6f46b2 Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 08:09:01 +0000 Subject: [PATCH 12/13] remove console log --- .../project/conversation/ProjectConversationTranscript.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx index d567a331..7c7e6d57 100644 --- a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx +++ b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx @@ -32,7 +32,6 @@ export const ProjectConversationTranscript = () => { fields: ["id", "participant_name", "is_finished"], }, }); - console.log(conversationQuery.data, " ==>here"); const { ref: loadMoreRef, inView } = useInView(); const { From 4a56de4d1b9ced0c67c51a02ab8bfd1d07373823 Mon Sep 17 00:00:00 2001 From: Usama Date: Fri, 24 Oct 2025 10:20:01 +0000 Subject: [PATCH 13/13] - usememo for projectroutes --- .../src/routes/project/ProjectRoutes.tsx | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/echo/frontend/src/routes/project/ProjectRoutes.tsx b/echo/frontend/src/routes/project/ProjectRoutes.tsx index a2a50e03..41230e03 100644 --- a/echo/frontend/src/routes/project/ProjectRoutes.tsx +++ b/echo/frontend/src/routes/project/ProjectRoutes.tsx @@ -12,11 +12,16 @@ import { getProjectTranscriptsLink } from "@/lib/api"; export const ProjectSettingsRoute = () => { const { projectId } = useParams(); + const query = useMemo( + () => ({ + fields: ["id", "name", "context", "updated_at", "language"], + }), + [], + ); const projectQuery = useProjectById({ projectId: projectId ?? "", - query: { - fields: ["id", "name", "context", "updated_at", "language"], - }, + // @ts-expect-error tags field structure not properly typed in Directus SDK + query, }); return ( { export const ProjectPortalSettingsRoute = () => { const { projectId } = useParams(); - const projectQuery = useProjectById({ - projectId: projectId ?? "", - query: { + const query = useMemo( + () => ({ deep: { - // @ts-expect-error tags won't be typed tags: { _sort: "sort", }, @@ -90,7 +93,13 @@ export const ProjectPortalSettingsRoute = () => { tags: ["id", "created_at", "text", "sort"], }, ], - }, + }), + [], + ); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + // @ts-expect-error tags field structure not properly typed in Directus SDK + query, }); // Memoize the project data to ensure stable reference