Skip to content

Commit 45e441d

Browse files
committed
update: many things...
1 parent 826e5fc commit 45e441d

38 files changed

+2493
-3410
lines changed

email_templates/confirmation_email.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
<tr>
2626
<td style="padding-right:0px;padding-left:0px"
2727
align="center">
28-
<img src="https://trading-goose.github.io/goose.png"
29-
alt="TradingGoose"
30-
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31-
<span
28+
<img src="https://avatars.githubusercontent.com/u/226357056?v=4"
29+
alt="TradingGoose"
30+
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31+
<span
3232
style="color:#ffcc00;font-size:36px;font-weight:bolder; text-align:center;outline:none;text-decoration:none;clear:both;display:inline-block!important;border:none;height:auto;float:none;vertical-align:middle;"
3333
align="middle">TradingGoose</span>
3434
</td>

email_templates/invitation_email.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
<tr>
2626
<td style="padding-right:0px;padding-left:0px"
2727
align="center">
28-
<img src="https://trading-goose.github.io/goose.png"
29-
alt="TradingGoose"
30-
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31-
<span
28+
<img src="https://avatars.githubusercontent.com/u/226357056?v=4"
29+
alt="TradingGoose"
30+
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31+
<span
3232
style="color:#ffcc00;font-size:36px;font-weight:bolder;text-align:center;outline:none;text-decoration:none;clear:both;display:inline-block!important;border:none;height:auto;float:none;vertical-align:middle;"
3333
align="middle">TradingGoose</span>
3434
</td>

email_templates/password_reset_email.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
<tr>
2626
<td style="padding-right:0px;padding-left:0px"
2727
align="center">
28-
<img src="https://trading-goose.github.io/goose.png"
29-
alt="TradingGoose"
30-
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31-
<span
28+
<img src="https://avatars.githubusercontent.com/u/226357056?v=4"
29+
alt="TradingGoose"
30+
style="width:60px;height:60px;display:inline-block;vertical-align:middle;margin-right:10px;">
31+
<span
3232
style="color:#ffcc00;font-size:36px;font-weight:bolder;text-align:center;outline:none;text-decoration:none;clear:both;display:inline-block!important;border:none;height:auto;float:none;vertical-align:middle;"
3333
align="middle">TradingGoose</span>
3434
</td>

src/components/AnalysisDetailModal.tsx

Lines changed: 144 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useEffect } from "react";
22
import {
33
Dialog,
44
DialogContent,
@@ -34,7 +34,9 @@ import {
3434
X,
3535
PieChart,
3636
RefreshCw,
37-
PlayCircle
37+
PlayCircle,
38+
ChevronUp,
39+
ChevronDown
3840
} from "lucide-react";
3941
import { Button } from "@/components/ui/button";
4042
import { Progress } from "@/components/ui/progress";
@@ -63,6 +65,7 @@ interface AnalysisDetailModalProps {
6365
isOpen: boolean;
6466
onClose: () => void;
6567
analysisDate?: string; // Optional: for viewing historical analyses
68+
initialTab?: string; // Optional: which tab to open initially
6669
}
6770

6871
// Import extracted components
@@ -75,7 +78,7 @@ import { useOrderActions } from "./analysis-detail/hooks/useOrderActions";
7578
import { getStatusIcon, getDecisionIcon, getDecisionVariant } from "./analysis-detail/utils/statusHelpers";
7679

7780

78-
export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClose, analysisDate }: AnalysisDetailModalProps) {
81+
export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClose, analysisDate, initialTab }: AnalysisDetailModalProps) {
7982
// Use extracted custom hooks
8083
const { analysisData, loading, error, isLiveAnalysis, updateAnalysisData, setError } = useAnalysisData({
8184
ticker,
@@ -91,13 +94,58 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
9194

9295
const { toast } = useToast();
9396
const [isRetrying, setIsRetrying] = useState(false);
97+
const [activeTab, setActiveTab] = useState<string>("");
98+
const [collapsedCards, setCollapsedCards] = useState<Set<string>>(new Set());
99+
100+
// Set initial tab value
101+
useEffect(() => {
102+
if (!activeTab && isOpen) {
103+
// Use initialTab if provided, otherwise default based on live status
104+
setActiveTab(initialTab || (isLiveAnalysis ? "actions" : "insights"));
105+
}
106+
}, [isLiveAnalysis, isOpen, activeTab, initialTab]);
107+
108+
// Handle navigation to insight tab for a specific agent
109+
const handleNavigateToInsight = (agentKey: string) => {
110+
setActiveTab("insights");
111+
// Optionally, we could scroll to the specific agent's insight
112+
// This would require adding an id to each insight card and using scrollIntoView
113+
setTimeout(() => {
114+
let elementId = `insight-${agentKey}`;
115+
116+
// Special handling for Bull/Bear Researcher - navigate to Research Debate if it exists
117+
if ((agentKey === 'bullResearcher' || agentKey === 'bearResearcher') &&
118+
analysisData?.agent_insights?.researchDebate) {
119+
// Navigate to Research Debate instead (first round has the bull researcher ID)
120+
elementId = agentKey === 'bullResearcher' ? 'insight-bullResearcher' : 'insight-researchDebate';
121+
}
122+
123+
const element = document.getElementById(elementId);
124+
if (element) {
125+
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
126+
}
127+
}, 100);
128+
};
94129

95130
// Check if analysis is stale (no update in 5+ minutes)
96131
const isAnalysisStale = () => {
97-
if (!analysisData?.updated_at) return false;
132+
if (!analysisData?.updated_at) {
133+
console.log('No updated_at field in analysisData:', analysisData);
134+
return false;
135+
}
98136
const lastUpdate = new Date(analysisData.updated_at);
99137
const timeSinceUpdate = Date.now() - lastUpdate.getTime();
100-
return timeSinceUpdate > 5 * 60 * 1000; // 5 minutes
138+
const isStale = timeSinceUpdate > 5 * 60 * 1000; // 5 minutes
139+
140+
console.log('Staleness check:', {
141+
updated_at: analysisData.updated_at,
142+
lastUpdate: lastUpdate.toISOString(),
143+
timeSinceUpdate: Math.round(timeSinceUpdate / 1000) + 's',
144+
isStale,
145+
status: analysisData.status
146+
});
147+
148+
return isStale;
101149
};
102150

103151
// Handle retry for error status
@@ -299,23 +347,34 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
299347
</Button>
300348
)}
301349

302-
{(analysisData.status === ANALYSIS_STATUS.RUNNING || analysisData.status === ANALYSIS_STATUS.PENDING) && isAnalysisStale() && (
303-
<Button
304-
variant="outline"
305-
size="sm"
306-
onClick={handleReactivate}
307-
disabled={isRetrying}
308-
className="flex items-center gap-2"
309-
title={`Last updated ${formatDistanceToNow(new Date(analysisData.updated_at))} ago`}
310-
>
311-
{isRetrying ? (
312-
<Loader2 className="w-4 h-4 animate-spin" />
313-
) : (
314-
<PlayCircle className="w-4 h-4" />
315-
)}
316-
Reactivate
317-
</Button>
318-
)}
350+
{(() => {
351+
const shouldShowReactivate = (analysisData.status === ANALYSIS_STATUS.RUNNING || analysisData.status === ANALYSIS_STATUS.PENDING) && isAnalysisStale();
352+
console.log('Reactivate button check:', {
353+
status: analysisData.status,
354+
isRunningOrPending: analysisData.status === ANALYSIS_STATUS.RUNNING || analysisData.status === ANALYSIS_STATUS.PENDING,
355+
isStale: isAnalysisStale(),
356+
shouldShow: shouldShowReactivate,
357+
ANALYSIS_STATUS
358+
});
359+
360+
return shouldShowReactivate && (
361+
<Button
362+
variant="outline"
363+
size="sm"
364+
onClick={handleReactivate}
365+
disabled={isRetrying}
366+
className="flex items-center gap-2"
367+
title={`Last updated ${formatDistanceToNow(new Date(analysisData.updated_at))} ago`}
368+
>
369+
{isRetrying ? (
370+
<Loader2 className="w-4 h-4 animate-spin" />
371+
) : (
372+
<PlayCircle className="w-4 h-4" />
373+
)}
374+
Reactivate
375+
</Button>
376+
);
377+
})()}
319378
</>
320379
)}
321380
</div>
@@ -392,31 +451,67 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
392451
);
393452
})()}
394453

395-
<Tabs defaultValue={isLiveAnalysis ? "actions" : "insights"} className="flex-1">
454+
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1">
396455
<div className="px-6 pt-4 pb-4">
397-
<TabsList className="grid w-full grid-cols-3 max-w-3xl mx-auto">
398-
<TabsTrigger
399-
value="actions"
400-
className="flex items-center gap-2"
401-
>
402-
<CheckSquare className="w-4 h-4" />
403-
Actions
404-
</TabsTrigger>
405-
<TabsTrigger
406-
value="workflow"
407-
className="flex items-center gap-2"
408-
>
409-
<Activity className="w-4 h-4" />
410-
Workflow
411-
</TabsTrigger>
412-
<TabsTrigger
413-
value="insights"
414-
className="flex items-center gap-2"
415-
>
416-
<Brain className="w-4 h-4" />
417-
Insights
418-
</TabsTrigger>
419-
</TabsList>
456+
<div className="relative flex items-center justify-center">
457+
<TabsList className="grid w-full grid-cols-3 max-w-3xl">
458+
<TabsTrigger
459+
value="actions"
460+
className="flex items-center gap-2"
461+
>
462+
<CheckSquare className="w-4 h-4" />
463+
Actions
464+
</TabsTrigger>
465+
<TabsTrigger
466+
value="workflow"
467+
className="flex items-center gap-2"
468+
>
469+
<Activity className="w-4 h-4" />
470+
Workflow
471+
</TabsTrigger>
472+
<TabsTrigger
473+
value="insights"
474+
className="flex items-center gap-2"
475+
>
476+
<Brain className="w-4 h-4" />
477+
Insights
478+
</TabsTrigger>
479+
</TabsList>
480+
{activeTab === "insights" && (
481+
<Button
482+
variant="outline"
483+
size="sm"
484+
onClick={() => {
485+
if (collapsedCards.size === 0) {
486+
// Collapse all - need to get all agent keys
487+
const allAgentKeys = new Set<string>();
488+
if (analysisData?.agent_insights) {
489+
Object.keys(analysisData.agent_insights).forEach(key => {
490+
allAgentKeys.add(key);
491+
});
492+
}
493+
setCollapsedCards(allAgentKeys);
494+
} else {
495+
// Expand all
496+
setCollapsedCards(new Set());
497+
}
498+
}}
499+
className="text-xs absolute right-0"
500+
>
501+
{collapsedCards.size === 0 ? (
502+
<>
503+
<ChevronUp className="h-3 w-3 mr-1" />
504+
Collapse All
505+
</>
506+
) : (
507+
<>
508+
<ChevronDown className="h-3 w-3 mr-1" />
509+
Expand All
510+
</>
511+
)}
512+
</Button>
513+
)}
514+
</div>
420515
</div>
421516

422517
<ScrollArea className="h-[calc(90vh-280px)]">
@@ -439,6 +534,7 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
439534
onApproveOrder={handleApproveOrder}
440535
onRejectOrder={handleRejectOrder}
441536
isOrderExecuted={isOrderExecuted}
537+
onNavigateToInsight={handleNavigateToInsight}
442538
/>
443539
) : (
444540
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
@@ -454,6 +550,8 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
454550
getMessageIcon={getMessageIcon}
455551
getAgentIcon={getAgentIcon}
456552
formatAgentName={formatAgentName}
553+
collapsedCards={collapsedCards}
554+
setCollapsedCards={setCollapsedCards}
457555
/>
458556
</TabsContent>
459557

0 commit comments

Comments
 (0)