Skip to content

Commit 31233c4

Browse files
committed
update: source display in analysis insight, correctly showing decisions in analysis detail, correctly shows approved trade order in rebalance detail modal
1 parent 8481c42 commit 31233c4

File tree

10 files changed

+853
-145
lines changed

10 files changed

+853
-145
lines changed

src/components/AnalysisDetailModal.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,11 +500,20 @@ export default function AnalysisDetailModal({ ticker, analysisId, isOpen, onClos
500500
<>
501501
{/* Analysis Summary Bar */}
502502
{(() => {
503-
// Determine which decision to display based on analysis type
504-
const isRebalanceAnalysis = !!analysisData.rebalance_request_id;
505-
const displayDecision = isRebalanceAnalysis
506-
? analysisData.decision
507-
: (analysisData.agent_insights?.portfolioManager?.finalDecision?.action || analysisData.decision);
503+
// Debug to see what data we have
504+
console.log('Analysis Summary Bar - agent_insights:', analysisData.agent_insights);
505+
console.log('Analysis Summary Bar - portfolioManager:', analysisData.agent_insights?.portfolioManager);
506+
console.log('Analysis Summary Bar - tradeOrder:', analysisData.tradeOrder);
507+
508+
// Always show portfolio manager's decision if available, otherwise fall back to the main decision
509+
// Check multiple possible locations for the portfolio manager's decision
510+
const displayDecision = analysisData.tradeOrder?.action || // From actual trade order
511+
analysisData.agent_insights?.portfolioManager?.finalDecision?.action ||
512+
analysisData.agent_insights?.portfolioManager?.decision?.action ||
513+
analysisData.agent_insights?.portfolioManager?.action ||
514+
analysisData.decision;
515+
516+
console.log('Display decision resolved to:', displayDecision);
508517

509518
const shouldShow = displayDecision || analysisData.confidence !== undefined || analysisData.startedAt;
510519

src/components/PortfolioPositions.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
44
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
55
import { Badge } from "@/components/ui/badge";
66
import { Button } from "@/components/ui/button";
7-
import { TrendingUp, TrendingDown, RefreshCw, Loader2, Eye, Activity, Clock, AlertCircle, AlertTriangle } from "lucide-react";
7+
import { TrendingUp, TrendingDown, RefreshCw, Loader2, Eye, Activity, Clock, AlertCircle, AlertTriangle, Lock } from "lucide-react";
88
import { alpacaAPI } from "@/lib/alpaca";
99
import { useAuth } from "@/lib/auth";
1010
import { supabase } from "@/lib/supabase";
1111
import { useToast } from "@/hooks/use-toast";
1212
import { useAlpacaConnectionStore } from "@/hooks/useAlpacaConnection";
13+
import { useRBAC } from "@/hooks/useRBAC";
1314
import {
1415
AlertDialog,
1516
AlertDialogContent,
@@ -52,6 +53,7 @@ export default function PortfolioPositions({ onSelectStock, selectedStock }: Por
5253
const { apiSettings, isAuthenticated, user } = useAuth();
5354
const { toast } = useToast();
5455
const { isConnected: isAlpacaConnected } = useAlpacaConnectionStore();
56+
const { hasRebalanceAccess } = useRBAC();
5557
const [positions, setPositions] = useState<Position[]>([]);
5658
const [loading, setLoading] = useState(false);
5759
const [error, setError] = useState<string | null>(null);
@@ -63,6 +65,7 @@ export default function PortfolioPositions({ onSelectStock, selectedStock }: Por
6365
const [runningRebalance, setRunningRebalance] = useState<string | null>(null); // Store rebalance_request_id
6466
const [runningAnalysesCount, setRunningAnalysesCount] = useState(0);
6567
const [showAnalysisAlert, setShowAnalysisAlert] = useState(false);
68+
const [showRebalanceAccessAlert, setShowRebalanceAccessAlert] = useState(false);
6669

6770
// Use ref to track previous running rebalance
6871
const previousRunningRef = useRef<string | null>(null);
@@ -73,6 +76,12 @@ export default function PortfolioPositions({ onSelectStock, selectedStock }: Por
7376
return;
7477
}
7578

79+
// Check if user has rebalance access
80+
if (!hasRebalanceAccess()) {
81+
setShowRebalanceAccessAlert(true);
82+
return;
83+
}
84+
7685
// Check if there are running analyses
7786
if (runningAnalysesCount > 0) {
7887
setShowAnalysisAlert(true);
@@ -379,6 +388,11 @@ export default function PortfolioPositions({ onSelectStock, selectedStock }: Por
379388
<AlertTriangle className="h-4 w-4 mr-1" />
380389
Connection Error
381390
</>
391+
) : !hasRebalanceAccess() ? (
392+
<>
393+
<Lock className="h-4 w-4 mr-1" />
394+
Rebalance
395+
</>
382396
) : (
383397
<>
384398
<RefreshCw className="h-4 w-4 mr-1" />
@@ -667,6 +681,31 @@ export default function PortfolioPositions({ onSelectStock, selectedStock }: Por
667681
</AlertDialogFooter>
668682
</AlertDialogContent>
669683
</AlertDialog>
684+
685+
{/* No Rebalance Access Alert Dialog */}
686+
<AlertDialog open={showRebalanceAccessAlert} onOpenChange={setShowRebalanceAccessAlert}>
687+
<AlertDialogContent>
688+
<AlertDialogHeader>
689+
<AlertDialogTitle className="flex items-center gap-2">
690+
<Lock className="h-5 w-5 text-yellow-500" />
691+
Rebalance Access Required
692+
</AlertDialogTitle>
693+
<AlertDialogDescription className="space-y-2">
694+
<p>
695+
Your current subscription plan doesn't include portfolio rebalancing features.
696+
</p>
697+
<p>
698+
Please upgrade your plan to access portfolio rebalancing capabilities.
699+
</p>
700+
</AlertDialogDescription>
701+
</AlertDialogHeader>
702+
<AlertDialogFooter>
703+
<AlertDialogAction onClick={() => setShowRebalanceAccessAlert(false)}>
704+
OK
705+
</AlertDialogAction>
706+
</AlertDialogFooter>
707+
</AlertDialogContent>
708+
</AlertDialog>
670709
</>
671710
);
672711
}

src/components/RebalanceDetailModal.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,12 @@ export default function RebalanceDetailModal({ rebalanceId, isOpen, onClose, reb
272272
// Fetch order statuses for all positions in this rebalance
273273
const { data: tradingActions } = await supabase
274274
.from('trading_actions')
275-
.select('id, ticker, status, metadata')
275+
.select('*') // Select all fields including metadata
276276
.eq('rebalance_request_id', rebalanceId)
277277
.eq('user_id', user.id);
278+
279+
// Store tradingActions for later use (even if empty)
280+
let tradingActionsData = tradingActions || [];
278281

279282
if (tradingActions && tradingActions.length > 0) {
280283
const newOrderStatuses = new Map();
@@ -650,7 +653,10 @@ export default function RebalanceDetailModal({ rebalanceId, isOpen, onClose, reb
650653
// Include opportunity reasoning for insights tab access
651654
opportunity_reasoning: rebalanceRequest.opportunity_reasoning,
652655

653-
relatedAnalyses: rebalanceAnalyses || []
656+
relatedAnalyses: rebalanceAnalyses || [],
657+
658+
// Include trading_actions data for proper status tracking
659+
trading_actions: tradingActionsData
654660
};
655661

656662
if (mounted) {

src/components/analysis-detail/AnalysisActionsTab.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,34 @@ export default function AnalysisActionsTab({
3939
);
4040
}
4141

42+
// Get the portfolio manager's decision - check all possible locations
43+
const portfolioManagerDecision = analysisData.tradeOrder?.action || // From actual trade order
44+
analysisData.agent_insights?.portfolioManager?.finalDecision?.action ||
45+
analysisData.agent_insights?.portfolioManager?.decision?.action ||
46+
analysisData.agent_insights?.portfolioManager?.action ||
47+
analysisData.agent_insights?.portfolioManager?.decision ||
48+
analysisData.decision;
49+
4250
return (
4351
<div className="space-y-4">
4452
{/* Summary Cards */}
4553
<div className="grid grid-cols-3 gap-4">
4654
<Card className="p-4">
4755
<div className="flex items-center justify-between">
48-
<span className="text-sm text-muted-foreground">Decision</span>
49-
{analysisData.decision === 'BUY' ? (
56+
<span className="text-sm text-muted-foreground">Portfolio Decision</span>
57+
{portfolioManagerDecision === 'BUY' ? (
5058
<TrendingUp className="w-4 h-4 text-green-500" />
51-
) : analysisData.decision === 'SELL' ? (
59+
) : portfolioManagerDecision === 'SELL' ? (
5260
<TrendingDown className="w-4 h-4 text-red-500" />
5361
) : (
5462
<Activity className="w-4 h-4 text-gray-500" />
5563
)}
5664
</div>
57-
<p className={`text-lg font-semibold ${analysisData.decision === 'BUY' ? 'text-green-600' :
58-
analysisData.decision === 'SELL' ? 'text-red-600' :
65+
<p className={`text-lg font-semibold ${portfolioManagerDecision === 'BUY' ? 'text-green-600' :
66+
portfolioManagerDecision === 'SELL' ? 'text-red-600' :
5967
'text-gray-600'
6068
}`}>
61-
{analysisData.decision}
69+
{portfolioManagerDecision || 'HOLD'}
6270
</p>
6371
</Card>
6472
<Card className="p-4">

src/components/analysis-detail/AnalysisInsightsTab.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
import MarkdownRenderer from "../MarkdownRenderer";
2727
import MarketAnalystInsight from "./MarketAnalystInsight";
2828
import FundamentalsAnalystInsight from "./FundamentalsAnalystInsight";
29+
import SourcesSection, { CompactSourceBadges } from "./SourcesSection";
2930

3031
interface AnalysisInsightsTabProps {
3132
analysisData: any;
@@ -456,6 +457,10 @@ export default function AnalysisInsightsTab({
456457
);
457458
}
458459

460+
// Check if this agent has sources (News, Social Media, Fundamentals, Macro analysts)
461+
const hasPerplefinaSources = ['newsAnalyst', 'socialMediaAnalyst', 'fundamentalsAnalyst', 'macroAnalyst'].includes(agent);
462+
const sources = hasPerplefinaSources && insight?.sources ? insight.sources : null;
463+
459464
// Default rendering for all other agents
460465
const isCollapsed = collapsedCards.has(agent);
461466
return (
@@ -464,14 +469,24 @@ export default function AnalysisInsightsTab({
464469
<CollapsibleTrigger asChild>
465470
<CardHeader className="bg-muted/30 cursor-pointer hover:bg-muted/40 transition-colors">
466471
<CardTitle className="text-base flex items-center justify-between">
467-
<div className="flex items-center gap-2">
472+
<div className="flex items-center gap-2 flex-1 min-w-0">
468473
{getAgentIcon(agent)}
469-
{formatAgentName(agent)}
474+
<span className="shrink-0">{formatAgentName(agent)}</span>
475+
476+
{/* Show compact source badges when collapsed */}
477+
{isCollapsed && sources && sources.length > 0 && (
478+
<CompactSourceBadges
479+
sources={sources}
480+
agentName={formatAgentName(agent)}
481+
maxVisible={3}
482+
showLabels={false}
483+
/>
484+
)}
470485
</div>
471486
<Button
472487
variant="ghost"
473488
size="sm"
474-
className="h-6 w-6 p-0"
489+
className="h-6 w-6 p-0 shrink-0"
475490
onClick={(e) => {
476491
e.stopPropagation();
477492
toggleCollapse(agent);
@@ -485,6 +500,14 @@ export default function AnalysisInsightsTab({
485500
<CollapsibleContent>
486501
<CardContent className="pt-4">
487502
<MarkdownRenderer content={insightContent} />
503+
504+
{/* Show sources using the new compact component */}
505+
{sources && sources.length > 0 && (
506+
<SourcesSection
507+
sources={sources}
508+
agentName={formatAgentName(agent)}
509+
/>
510+
)}
488511
</CardContent>
489512
</CollapsibleContent>
490513
</Card>

0 commit comments

Comments
 (0)