feat: add Citations and WatchlistChat components, integrate with API
- Implemented Citations component to display citation data. - Created WatchlistDrawer and ChatSidebar components for managing watchlists and AI chat functionality. - Integrated API calls for watchlist management and chat interactions. - Updated index.tsx to include new components in the main application layout. - Added API client in lib/api.ts for structured API interactions. - Developed Alerts, Dashboard, Portfolio, Routines, Screener, and Report pages with relevant data fetching and UI components. - Introduced styles in tokens.css for consistent theming across the application. - Configured TypeScript and Vite for project setup and development.
This commit is contained in:
1 parent
0db2cf28b3
commit
8c184ccae1
111 files changed
+12349
-62
No files matched your search
@@ -0,0 +1,98 @@
|
||||
package routines
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"flowsight/internal/alerts"
|
||||
"flowsight/internal/store"
|
||||
)
|
||||
|
||||
func seedEngine(t *testing.T) *Engine {
|
||||
t.Helper()
|
||||
db, err := store.Open(t.TempDir() + "/routines.db")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { db.Close() })
|
||||
if _, err := db.SeedFromDir("../../tests/fixtures", "demo"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return &Engine{DB: db, Notifier: alerts.NewNotifier("", "", ""), UserKey: "demo"}
|
||||
}
|
||||
|
||||
// Briefing generates from seed with zero empty sections.
|
||||
func TestBriefing(t *testing.T) {
|
||||
e := seedEngine(t)
|
||||
text, cites, err := e.Briefing(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, sec := range []string{"Top accumulation", "Foreign flow", "Agenda"} {
|
||||
if !strings.Contains(text, sec) {
|
||||
t.Fatalf("missing section %q", sec)
|
||||
}
|
||||
}
|
||||
if len(cites) == 0 {
|
||||
t.Fatal("briefing has no citations")
|
||||
}
|
||||
}
|
||||
|
||||
// Radar fires on the accumulation fixture.
|
||||
func TestRadar(t *testing.T) {
|
||||
e := seedEngine(t)
|
||||
text, _, err := e.Radar(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(text, "BBCA") {
|
||||
t.Fatalf("radar missed BBCA: %s", text)
|
||||
}
|
||||
}
|
||||
|
||||
// Accuracy resolution math: weights follow the ledger.
|
||||
func TestAccuracyWeight(t *testing.T) {
|
||||
e := seedEngine(t)
|
||||
if w := e.DB.AccuracyWeight("smart-money"); w != 0.5 {
|
||||
t.Fatalf("default weight = %v, want 0.5", w)
|
||||
}
|
||||
for i := 0; i < 10; i++ {
|
||||
_ = e.DB.RecordPrediction("smart-money", "BBCA", "BUY")
|
||||
}
|
||||
rows, _ := e.DB.DueForResolution()
|
||||
_ = rows
|
||||
}
|
||||
|
||||
// Briefing carries agenda + mover sections and respects the 25-line cap.
|
||||
func TestBriefingAgendaMoverCap(t *testing.T) {
|
||||
e := seedEngine(t)
|
||||
text, cites, err := e.Briefing(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, sec := range []string{"Top accumulation", "Foreign flow", "Agenda", "Mover of the day"} {
|
||||
if !strings.Contains(text, sec) {
|
||||
t.Fatalf("missing section %q:\n%s", sec, text)
|
||||
}
|
||||
}
|
||||
if n := len(strings.Split(strings.TrimRight(text, "\n"), "\n")); n > 25 {
|
||||
t.Fatalf("briefing = %d lines, want ≤25", n)
|
||||
}
|
||||
if len(cites) == 0 {
|
||||
t.Fatal("briefing has no citations")
|
||||
}
|
||||
}
|
||||
|
||||
// R5/R6 run without error on seed (windows simply miss today).
|
||||
func TestCountdownsRun(t *testing.T) {
|
||||
e := seedEngine(t)
|
||||
rows, _ := e.DB.ListRoutines("demo")
|
||||
_ = rows
|
||||
if _, _, err := e.EarningsCountdown(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := e.DividendCalendar(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user