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; } diff --git a/echo/frontend/src/components/chat/hooks/index.ts b/echo/frontend/src/components/chat/hooks/index.ts index 974a3393..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], }); }; @@ -121,12 +122,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/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/conversation/hooks/index.ts b/echo/frontend/src/components/conversation/hooks/index.ts index b524d236..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 }, @@ -644,6 +641,7 @@ export const useConversationChunks = ( _eq: conversationId, }, }, + limit: 1, // Only need to check if chunks exist sort: "timestamp", }), ), @@ -681,7 +679,18 @@ export const useConversationsByProjectId = ( }, ], }, - { chunks: ["*"] }, + { + chunks: [ + "id", + "conversation_id", + "transcript", + "source", + "path", + "timestamp", + "created_at", + "error", + ], + }, ], filter: { chunks: { @@ -765,21 +774,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 +826,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 +887,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/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/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/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/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/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/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( 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..b93d2020 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, @@ -845,7 +860,6 @@ export const getProjectConversationCounts = async (projectId: string) => { fields: [ "id", "is_finished", - "summary", "participant_name", "updated_at", "created_at", 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`, }); diff --git a/echo/frontend/src/routes/project/ProjectRoutes.tsx b/echo/frontend/src/routes/project/ProjectRoutes.tsx index 8846aa13..41230e03 100644 --- a/echo/frontend/src/routes/project/ProjectRoutes.tsx +++ b/echo/frontend/src/routes/project/ProjectRoutes.tsx @@ -12,7 +12,17 @@ import { getProjectTranscriptsLink } from "@/lib/api"; export const ProjectSettingsRoute = () => { const { projectId } = useParams(); - const projectQuery = useProjectById({ projectId: projectId ?? "" }); + const query = useMemo( + () => ({ + fields: ["id", "name", "context", "updated_at", "language"], + }), + [], + ); + const projectQuery = useProjectById({ + projectId: projectId ?? "", + // @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 ?? "" }); + const query = useMemo( + () => ({ + deep: { + 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"], + }, + ], + }), + [], + ); + 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 // biome-ignore lint/correctness/useExhaustiveDependencies: needs to be fixed 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", }, 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 () => { diff --git a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx index 81704eb7..7c7e6d57 100644 --- a/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx +++ b/echo/frontend/src/routes/project/conversation/ProjectConversationTranscript.tsx @@ -27,9 +27,11 @@ export const ProjectConversationTranscript = () => { const { conversationId } = useParams(); const conversationQuery = useConversationById({ conversationId: conversationId ?? "", - loadConversationChunks: true, + loadConversationChunks: false, + query: { + fields: ["id", "participant_name", "is_finished"], + }, }); - const { ref: loadMoreRef, inView } = useInView(); const {