Add target comparison modal, integration goal progress, and session planning + full catalog expansion
Features added this session: - Target comparison: side-by-side overlay (CompareModal) from Targets page via ⊕ button on each row; shows altitude curves, key times, filter recommendations and per-filter integration progress for two targets simultaneously - Integration goal progress dashboard card: per-target keeper minutes vs goal hours (from CLAUDE.md §16.3) broken down by filter, with color-coded progress bars; powered by new stats.integration_goals backend query - Session planning timeline: Gantt-style "Plan Tonight" section on Dashboard (PlanningTimeline component) — search targets, set durations, sequential scheduling from dusk, overrun warnings, clipboard export - Slew-optimized run order toggle (nearest-neighbor sort by RA/Dec angular distance) - Best Nights 14-day card + Monthly Highlights card on Dashboard Catalog expansions: - Sharpless (Sh2), VdB, LDN, Barnard dark nebulae, LBN, Melotte, Collinder, Gum, RCW, Abell PN, Abell GC, PGC bright subset - Caldwell/Arp/Melotte/Collinder number columns + cross-reference maps - Weather score multiplier applied to composite sort - galaxy_cluster type (ACO badge) throughout TypeBadge, CSS, filter chips Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ pub async fn init_db(database_url: &str) -> anyhow::Result<SqlitePool> {
|
||||
.context("failed to connect to SQLite")?;
|
||||
|
||||
run_schema(&pool).await?;
|
||||
run_migrations(&pool).await?;
|
||||
seed_horizon(&pool).await?;
|
||||
|
||||
Ok(pool)
|
||||
@@ -34,6 +35,26 @@ async fn run_schema(pool: &SqlitePool) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Additive migrations for columns added after initial schema creation.
|
||||
/// SQLite doesn't support IF NOT EXISTS for ADD COLUMN, so we check the error and ignore it.
|
||||
async fn run_migrations(pool: &SqlitePool) -> anyhow::Result<()> {
|
||||
let migrations: &[&str] = &[
|
||||
"ALTER TABLE nightly_cache ADD COLUMN is_visible_tonight INTEGER DEFAULT 0",
|
||||
"ALTER TABLE catalog ADD COLUMN caldwell_num INTEGER",
|
||||
"ALTER TABLE catalog ADD COLUMN arp_num INTEGER",
|
||||
"ALTER TABLE catalog ADD COLUMN melotte_num INTEGER",
|
||||
"ALTER TABLE catalog ADD COLUMN collinder_num INTEGER",
|
||||
];
|
||||
for sql in migrations {
|
||||
match sqlx::query(sql).execute(pool).await {
|
||||
Ok(_) => tracing::info!("Migration applied: {}", &sql[..sql.len().min(60)]),
|
||||
Err(e) if e.to_string().contains("duplicate column") => {}
|
||||
Err(e) => tracing::warn!("Migration skipped ({}): {}", sql, e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn seed_horizon(pool: &SqlitePool) -> anyhow::Result<()> {
|
||||
let count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM horizon")
|
||||
.fetch_one(pool)
|
||||
|
||||
Reference in New Issue
Block a user