Skip to content

Commit 193eda6

Browse files
committed
fix: correct order card display, auto refresh from history page
1 parent 6fe629c commit 193eda6

File tree

5 files changed

+139
-53
lines changed

5 files changed

+139
-53
lines changed

deploy-agents.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/Users/bruzwj/Downloads/.env.local#!/bin/bash
2+
3+
# Deployment script for Supabase Edge Functions
4+
# Run this when Docker is working properly
5+
if [ -f .env.local ]; then
6+
# Load environment variables, handling = signs and quotes properly
7+
set -a
8+
source .env.local
9+
set +a
10+
fi
11+
12+
echo "🚀 Deploying Supabase Edge Functions..."
13+
14+
# Debug: Check if variables are loaded
15+
echo "Debug: SUPABASE_ACCESS_TOKEN is ${#SUPABASE_ACCESS_TOKEN} characters long"
16+
echo "Debug: SUPABASE_PROJECT_REF = $SUPABASE_PROJECT_REF"
17+
18+
# Ensure variables are set
19+
if [ -z "$SUPABASE_ACCESS_TOKEN" ]; then
20+
echo "Error: SUPABASE_ACCESS_TOKEN not found in .env.local"
21+
exit 1
22+
fi
23+
24+
if [ -z "$SUPABASE_PROJECT_REF" ]; then
25+
echo "Error: SUPABASE_PROJECT_REF not found in .env.local"
26+
exit 1
27+
fi
28+
29+
30+
# Deploy all agent functions
31+
agents=(
32+
"agent-macro-analyst"
33+
"agent-market-analyst"
34+
"agent-news-analyst"
35+
"agent-social-media-analyst"
36+
"agent-fundamentals-analyst"
37+
"agent-bull-researcher"
38+
"agent-bear-researcher"
39+
"agent-research-manager"
40+
"agent-trader"
41+
"agent-risky-analyst"
42+
"agent-safe-analyst"
43+
"agent-neutral-analyst"
44+
"agent-risk-manager"
45+
"analysis-portfolio-manager"
46+
"rebalance-portfolio-manager"
47+
"opportunity-agent"
48+
)
49+
50+
echo "📦 Deploying agent functions..."
51+
for agent in "${agents[@]}"; do
52+
echo " 📦 Deploying $agent..."
53+
SUPABASE_ACCESS_TOKEN=$SUPABASE_ACCESS_TOKEN npx supabase functions deploy $agent --project-ref $SUPABASE_PROJECT_REF
54+
done
55+
56+
echo "✅ All functions deployed successfully!"

src/components/RebalanceHistoryTable.tsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,13 @@ export default function RebalanceHistoryTable() {
9393
const [cancelling, setCancelling] = useState(false);
9494
const [deleting, setDeleting] = useState(false);
9595
const [analysisData, setAnalysisData] = useState<{ [key: string]: any[] }>({});
96+
const [activeTab, setActiveTab] = useState<string>("all");
9697

9798
// Date filter states - default to today (using local date to avoid timezone issues)
9899
const today = new Date();
99100
const todayString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
100101
const [selectedDate, setSelectedDate] = useState<string>(todayString);
102+
const isTodaySelected = selectedDate === todayString;
101103

102104
// Track if initial data has been loaded
103105
const [initialLoadComplete, setInitialLoadComplete] = useState(false);
@@ -132,11 +134,11 @@ export default function RebalanceHistoryTable() {
132134
}
133135
}, [user, selectedDate]); // Reload when selectedDate changes
134136

135-
// Separate useEffect for polling running rebalances only
137+
// Separate useEffect for real-time updates on running rebalances only
136138
useEffect(() => {
137-
if (!user || !initialLoadComplete) return;
138-
139-
// Only set up polling if there are actually running rebalances
139+
if (!user || !initialLoadComplete || !isTodaySelected) return;
140+
141+
// Only subscribe if there are running rebalances
140142
if (runningRebalances.length === 0) return;
141143

142144
// Set up real-time subscription for instant updates
@@ -158,16 +160,20 @@ export default function RebalanceHistoryTable() {
158160
)
159161
.subscribe();
160162

161-
// Much slower polling - every 15 seconds instead of 3 seconds
162-
const interval = setInterval(() => {
163-
fetchRebalanceRequests(false); // Don't show loading on polling updates
164-
}, 15000); // Poll every 15 seconds for running rebalances
165-
166163
return () => {
167164
subscription.unsubscribe();
168-
clearInterval(interval);
169165
};
170-
}, [user, runningRebalances.length > 0, selectedDate, initialLoadComplete]); // Use boolean comparison
166+
}, [user, runningRebalances.length > 0, selectedDate, initialLoadComplete, isTodaySelected]); // Use boolean comparison
167+
168+
useEffect(() => {
169+
if (!user || !isTodaySelected) return;
170+
171+
const intervalId = setInterval(() => {
172+
fetchRebalanceRequests(false);
173+
}, 10000);
174+
175+
return () => clearInterval(intervalId);
176+
}, [user, selectedDate, activeTab, isTodaySelected]);
171177

172178
const handleManualRefresh = async () => {
173179
setRefreshing(true);
@@ -191,11 +197,11 @@ export default function RebalanceHistoryTable() {
191197
}
192198
};
193199

194-
const fetchRebalanceRequests = async (isInitialLoad = false) => {
200+
const fetchRebalanceRequests = async (isInitialLoad = false, withSpinner: boolean = isInitialLoad) => {
195201
if (!user) return;
196202

197203
// Only show loading state on initial load or when explicitly requested
198-
if (isInitialLoad) {
204+
if (withSpinner) {
199205
setLoading(true);
200206
}
201207

@@ -285,13 +291,20 @@ export default function RebalanceHistoryTable() {
285291
});
286292
}
287293
} finally {
288-
if (isInitialLoad) {
294+
if (withSpinner) {
289295
setLoading(false);
290296
}
291297
setInitialLoadComplete(true);
292298
}
293299
};
294300

301+
const handleTabChange = (value: string) => {
302+
setActiveTab(value);
303+
if (isTodaySelected) {
304+
fetchRebalanceRequests(false);
305+
}
306+
};
307+
295308
const handleDelete = async () => {
296309
if (!selectedRebalanceId || !user) return;
297310

@@ -837,7 +850,7 @@ export default function RebalanceHistoryTable() {
837850
</div>
838851
</div>
839852

840-
<Tabs defaultValue="all" className="space-y-4">
853+
<Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-4">
841854
<TabsList className="grid w-full grid-cols-4">
842855
<TabsTrigger value="all">
843856
All <span className="hidden sm:inline">({totalCount})</span>

src/components/ScheduleListModal.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ interface Schedule {
6565
timezone: string;
6666
selected_tickers: string[];
6767
include_watchlist: boolean;
68-
include_all_positions: boolean;
6968
last_executed_at?: string;
7069
next_scheduled_at?: string; // Deprecated - calculated dynamically from last_executed_at + interval
7170
execution_count: number;
@@ -522,11 +521,7 @@ export default function ScheduleListModal({ isOpen, onClose }: ScheduleListModal
522521
<div className="text-sm">
523522
<p className="text-muted-foreground mb-1">Stock Selection</p>
524523
<div className="flex items-center gap-2">
525-
{schedule.include_all_positions ? (
526-
<Badge variant="outline" className="text-xs">
527-
All Positions
528-
</Badge>
529-
) : schedule.selected_tickers.length > 0 ? (
524+
{schedule.selected_tickers.length > 0 ? (
530525
<Badge variant="outline" className="text-xs">
531526
{schedule.selected_tickers.length} Selected Stocks
532527
</Badge>

src/components/UnifiedAnalysisHistory.tsx

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ export default function UnifiedAnalysisHistory() {
174174
const [runningAnalyses, setRunningAnalyses] = useState<RunningAnalysisItem[]>([]);
175175
const [canceledAnalyses, setCanceledAnalyses] = useState<AnalysisHistoryItem[]>([]);
176176
const [loading, setLoading] = useState(true); // Start with loading true
177+
const [activeTab, setActiveTab] = useState<string>("all");
177178
const [selectedTicker, setSelectedTicker] = useState<string | null>(null);
178179
const [selectedAnalysisDate, setSelectedAnalysisDate] = useState<string | null>(null);
179180
const [selectedViewAnalysisId, setSelectedViewAnalysisId] = useState<string | null>(null); // For viewing specific analysis
@@ -188,6 +189,7 @@ export default function UnifiedAnalysisHistory() {
188189
const today = new Date();
189190
const todayString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
190191
const [selectedDate, setSelectedDate] = useState<string>(todayString);
192+
const isTodaySelected = selectedDate === todayString;
191193

192194
// Track if initial data has been loaded
193195
const [initialLoadComplete, setInitialLoadComplete] = useState(false);
@@ -221,10 +223,12 @@ export default function UnifiedAnalysisHistory() {
221223
});
222224
};
223225

224-
const loadAllAnalyses = async () => {
226+
const loadAllAnalyses = async (withSpinner: boolean = true) => {
225227
if (!user) return;
226228

227-
setLoading(true);
229+
if (withSpinner) {
230+
setLoading(true);
231+
}
228232
try {
229233
// Build date range for the selected date using local date parsing
230234
const [year, month, day] = selectedDate.split('-').map(Number);
@@ -333,7 +337,9 @@ export default function UnifiedAnalysisHistory() {
333337
});
334338
}
335339
} finally {
336-
setLoading(false);
340+
if (withSpinner) {
341+
setLoading(false);
342+
}
337343
setInitialLoadComplete(true);
338344
}
339345
};
@@ -351,17 +357,26 @@ export default function UnifiedAnalysisHistory() {
351357
}
352358
}, [isAuthenticated, user, selectedDate]); // Reload when selectedDate changes
353359

360+
useEffect(() => {
361+
if (!isAuthenticated || !user || !isTodaySelected) return;
362+
363+
const intervalId = setInterval(() => {
364+
loadAllAnalyses(false);
365+
}, 10000);
366+
367+
return () => clearInterval(intervalId);
368+
}, [isAuthenticated, user, selectedDate, activeTab, isTodaySelected]);
369+
354370
// Only poll for running analyses updates, not the entire list
355371
useEffect(() => {
356-
if (!user || !initialLoadComplete) return;
372+
if (!user || !initialLoadComplete || !isTodaySelected) return;
357373

358374
// Only set up polling if there are actually running analyses
359375
if (runningAnalyses.length === 0) return;
360376

361377
let intervalId: NodeJS.Timeout;
362378

363-
// Much slower polling - every 15 seconds instead of 3-5 seconds
364-
// Users can manually refresh if they want faster updates
379+
// Poll running analyses separately every 10 seconds for live progress
365380
intervalId = setInterval(async () => {
366381
try {
367382
// Only check status of running analyses, don't reload everything
@@ -417,12 +432,19 @@ export default function UnifiedAnalysisHistory() {
417432
} catch (error) {
418433
console.error('Error checking running analyses:', error);
419434
}
420-
}, 15000); // Poll every 15 seconds instead of 3-5 seconds
435+
}, 10000); // Poll every 10 seconds to keep progress fresh
421436

422437
return () => {
423438
if (intervalId) clearInterval(intervalId);
424439
};
425-
}, [user, runningAnalyses.length, selectedDate, initialLoadComplete]); // Keep minimal dependencies
440+
}, [user, runningAnalyses.length, selectedDate, initialLoadComplete, isTodaySelected]); // Keep minimal dependencies
441+
442+
const handleTabChange = (value: string) => {
443+
setActiveTab(value);
444+
if (isTodaySelected) {
445+
loadAllAnalyses(false);
446+
}
447+
};
426448

427449
const viewRunningAnalysis = (ticker: string) => {
428450
setSelectedTicker(ticker);
@@ -951,7 +973,7 @@ export default function UnifiedAnalysisHistory() {
951973
</div>
952974
</div>
953975

954-
<Tabs defaultValue="all" className="space-y-4">
976+
<Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-4">
955977
<TabsList className="grid w-full grid-cols-4">
956978
<TabsTrigger value="all">
957979
All <span className="hidden sm:inline">({displayHistory.length + runningAnalyses.length + displayCanceled.length})</span>

src/components/analysis-detail/TradeOrderCard.tsx

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -70,33 +70,33 @@ export default function TradeOrderCard({
7070
// Extract allocation values from various possible locations
7171
// For rejected orders, ALWAYS use the saved trade order data if available
7272
// to show what was intended at the time of creation, not current values
73-
const beforeAllocation = (isOrderRejected && tradeOrder?.beforeAllocation !== undefined)
73+
const beforeAllocation = (isOrderRejected && tradeOrder?.beforeAllocation !== undefined)
7474
? tradeOrder.beforeAllocation
75-
: tradeOrder?.beforeAllocation ||
76-
finalDecision?.beforeAllocation ||
77-
finalDecision?.currentAllocation ||
78-
finalDecision?.beforePosition?.allocation ||
79-
finalDecision?.currentPosition?.allocation ||
80-
portfolioManagerInsight?.currentAllocation ||
75+
: tradeOrder?.beforeAllocation ??
76+
finalDecision?.beforeAllocation ??
77+
finalDecision?.currentAllocation ??
78+
finalDecision?.beforePosition?.allocation ??
79+
finalDecision?.currentPosition?.allocation ??
80+
portfolioManagerInsight?.currentAllocation ??
8181
0;
8282

8383
const afterAllocation = (isOrderRejected && tradeOrder?.afterAllocation !== undefined)
84-
? tradeOrder.afterAllocation
85-
: tradeOrder?.afterAllocation ||
86-
finalDecision?.afterAllocation ||
87-
finalDecision?.targetAllocation ||
88-
finalDecision?.afterPosition?.allocation ||
89-
finalDecision?.targetPosition?.allocation ||
90-
finalDecision?.percentOfPortfolio ||
91-
portfolioManagerInsight?.targetAllocation ||
92-
portfolioManagerInsight?.percentOfPortfolio ||
84+
? tradeOrder.afterAllocation
85+
: tradeOrder?.afterAllocation ??
86+
finalDecision?.afterAllocation ??
87+
finalDecision?.targetAllocation ??
88+
finalDecision?.afterPosition?.allocation ??
89+
finalDecision?.targetPosition?.allocation ??
90+
finalDecision?.percentOfPortfolio ??
91+
portfolioManagerInsight?.targetAllocation ??
92+
portfolioManagerInsight?.percentOfPortfolio ??
9393
0;
9494

9595
const percentOfPortfolio = (isOrderRejected && tradeOrder?.afterAllocation !== undefined)
9696
? tradeOrder.afterAllocation
97-
: tradeOrder?.afterAllocation ||
98-
finalDecision?.percentOfPortfolio ||
99-
finalDecision?.targetAllocation ||
97+
: tradeOrder?.afterAllocation ??
98+
finalDecision?.percentOfPortfolio ??
99+
finalDecision?.targetAllocation ??
100100
afterAllocation;
101101

102102
// Extract order size information
@@ -123,19 +123,19 @@ export default function TradeOrderCard({
123123
// Also extract before/after shares and values if available
124124
const beforeShares = (isOrderRejected && tradeOrder?.beforeShares !== undefined)
125125
? tradeOrder.beforeShares
126-
: tradeOrder?.beforeShares || finalDecision?.beforePosition?.shares || 0;
126+
: tradeOrder?.beforeShares ?? finalDecision?.beforePosition?.shares ?? 0;
127127

128128
const afterShares = (isOrderRejected && tradeOrder?.afterShares !== undefined)
129129
? tradeOrder.afterShares
130-
: tradeOrder?.afterShares || finalDecision?.afterPosition?.shares || orderShares;
130+
: tradeOrder?.afterShares ?? finalDecision?.afterPosition?.shares ?? orderShares;
131131

132132
const beforeValue = (isOrderRejected && tradeOrder?.beforeValue !== undefined)
133133
? tradeOrder.beforeValue
134-
: tradeOrder?.beforeValue || finalDecision?.beforePosition?.value || 0;
134+
: tradeOrder?.beforeValue ?? finalDecision?.beforePosition?.value ?? 0;
135135

136136
const afterValue = (isOrderRejected && tradeOrder?.afterValue !== undefined)
137137
? tradeOrder.afterValue
138-
: tradeOrder?.afterValue || finalDecision?.afterPosition?.value || orderDollarAmount;
138+
: tradeOrder?.afterValue ?? finalDecision?.afterPosition?.value ?? orderDollarAmount;
139139

140140
// Debug logging to understand data structure
141141
console.log('TradeOrderCard - Full analysisData:', analysisData);

0 commit comments

Comments
 (0)