Skip to content

Commit c9ab57d

Browse files
feat(sessions): add spinner forancing and finalizing states
1 parent 7b09078 commit c9ab57d

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

apps/desktop/src/components/main/body/sessions/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { commands as miscCommands } from "@hypr/plugin-misc";
66

77
import AudioPlayer from "../../../../contexts/audio-player";
88
import { useListener } from "../../../../contexts/listener";
9+
import { useIsSessionEnhancing } from "../../../../hooks/useEnhancedNotes";
910
import * as main from "../../../../store/tinybase/main";
1011
import { rowIdfromTab, type Tab } from "../../../../store/zustand/tabs";
1112
import { StandardTabWrapper } from "../index";
@@ -35,15 +36,19 @@ export const TabItemNote: TabItem<Extract<Tab, { type: "sessions" }>> = ({
3536
main.STORE_ID,
3637
);
3738
const sessionMode = useListener((state) => state.getSessionMode(tab.id));
39+
const isEnhancing = useIsSessionEnhancing(tab.id);
3840
const isActive =
3941
sessionMode === "running_active" || sessionMode === "finalizing";
42+
const isFinalizing = sessionMode === "finalizing";
43+
const showSpinner = isFinalizing || isEnhancing;
4044

4145
return (
4246
<TabItemBase
4347
icon={<StickyNoteIcon className="w-4 h-4" />}
4448
title={title || "Untitled"}
4549
selected={tab.active}
4650
active={isActive}
51+
finalizing={showSpinner}
4752
tabIndex={tabIndex}
4853
handleCloseThis={() => handleCloseThis(tab)}
4954
handleSelectThis={() => handleSelectThis(tab)}

apps/desktop/src/components/main/sidebar/timeline/item.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import { memo, useCallback, useMemo } from "react";
22

33
import { commands as analyticsCommands } from "@hypr/plugin-analytics";
44
import { ContextMenuItem } from "@hypr/ui/components/ui/context-menu";
5+
import { Spinner } from "@hypr/ui/components/ui/spinner";
56
import { cn } from "@hypr/utils";
67

8+
import { useListener } from "../../../../contexts/listener";
9+
import { useIsSessionEnhancing } from "../../../../hooks/useEnhancedNotes";
710
import * as main from "../../../../store/tinybase/main";
811
import { type TabInput, useTabs } from "../../../../store/zustand/tabs";
912
import { id } from "../../../../utils";
@@ -36,6 +39,14 @@ export const TimelineItemComponent = memo(
3639
const timestamp =
3740
item.type === "event" ? item.data.started_at : item.data.created_at;
3841

42+
const sessionId = item.type === "session" ? item.id : null;
43+
const sessionMode = useListener((state) =>
44+
sessionId ? state.getSessionMode(sessionId) : "inactive",
45+
);
46+
const isEnhancing = useIsSessionEnhancing(sessionId ?? "");
47+
const isFinalizing = sessionMode === "finalizing";
48+
const showSpinner = isFinalizing || isEnhancing;
49+
3950
const handleClick = () => {
4051
if (item.type === "event") {
4152
handleEventClick(false);
@@ -171,11 +182,18 @@ export const TimelineItemComponent = memo(
171182
!selected && "hover:bg-neutral-100",
172183
])}
173184
>
174-
<div className="flex flex-col gap-0.5">
175-
<div className="text-sm font-normal truncate">{title}</div>
176-
{displayTime && (
177-
<div className="text-xs text-neutral-500">{displayTime}</div>
185+
<div className="flex items-start gap-2">
186+
{showSpinner && (
187+
<div className="flex-shrink-0 mt-0.5">
188+
<Spinner size={14} />
189+
</div>
178190
)}
191+
<div className="flex flex-col gap-0.5 min-w-0">
192+
<div className="text-sm font-normal truncate">{title}</div>
193+
{displayTime && (
194+
<div className="text-xs text-neutral-500">{displayTime}</div>
195+
)}
196+
</div>
179197
</div>
180198
</InteractiveButton>
181199
);

apps/desktop/src/hooks/useEnhancedNotes.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { useCallback, useEffect } from "react";
1+
import { useCallback, useEffect, useMemo } from "react";
22

33
import { useHasTranscript } from "../components/main/body/sessions/shared";
4+
import { useAITask } from "../contexts/ai-task";
45
import { useListener } from "../contexts/listener";
56
import * as main from "../store/tinybase/main";
7+
import { createTaskId } from "../store/zustand/ai-task/task-configs";
68

79
export function useCreateEnhancedNote() {
810
const store = main.UI.useStore(main.STORE_ID) as main.Store | undefined;
@@ -170,3 +172,24 @@ export function useEnsureDefaultSummary(sessionId: string) {
170172
createEnhancedNote,
171173
]);
172174
}
175+
176+
export function useIsSessionEnhancing(sessionId: string): boolean {
177+
const enhancedNoteIds = main.UI.useSliceRowIds(
178+
main.INDEXES.enhancedNotesBySession,
179+
sessionId,
180+
main.STORE_ID,
181+
);
182+
183+
const taskIds = useMemo(
184+
() => (enhancedNoteIds || []).map((id) => createTaskId(id, "enhance")),
185+
[enhancedNoteIds],
186+
);
187+
188+
const isEnhancing = useAITask((state) => {
189+
return taskIds.some(
190+
(taskId) => state.tasks[taskId]?.status === "generating",
191+
);
192+
});
193+
194+
return isEnhancing;
195+
}

0 commit comments

Comments
 (0)