Skip to content

feat: implement live mission control event timeline (#172) - #183

Merged
krishkhinchi merged 1 commit into
7-Blocks:mainfrom
Pranitrane:feature/172-live-mission-control-timeline
Aug 10, 2026
Merged

feat: implement live mission control event timeline (#172)#183
krishkhinchi merged 1 commit into
7-Blocks:mainfrom
Pranitrane:feature/172-live-mission-control-timeline

Conversation

@Pranitrane

@Pranitrane Pranitrane commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

This PR implements the Live Mission Control Event Timeline feature (#172), providing satellite operators with a real-time, continuously streaming operational event feed across critical orbital activities.

Key Accomplishments & Technical Details:

  1. Real-Time Event Streaming & Engine:

    • Created eventTimelineStore.ts (Zustand) and custom hook useEventTimeline.ts with a built-in live realistic event generator.
    • Includes stream controls (Live Stream toggle, Pause/Resume, and a SIMULATE INCIDENT emergency alert trigger).
    • Automatically records high/critical priority incidents into Kepler's central operational audit log (logbookStore.ts).
  2. Multi-Dimensional Navigation, Filtering & Search:

    • Category Filters: LAUNCH, CONJUNCTION, MANEUVER, DEBRIS, SPACE_WEATHER, and SYSTEM.
    • Severity Indicators: Color-coded badges for CRITICAL (red glow), HIGH (orange glow), MEDIUM (amber), and LOW (cyan).
    • Time Range Filters: LAST 1 HOUR, LAST 24 HOURS, LAST 7 DAYS, and ALL TIME.
    • Real-Time Fuzzy Search: Matches across event titles, descriptions, NORAD IDs, satellite names, and COSPAR IDs.
    • Chronological Sorting: Toggle between NEWEST FIRST and OLDEST FIRST.
  3. High-Priority Incident Alert Banner & Expandable Cards:

    • Prominent hazard alert banner (HighPriorityIncidentBanner.tsx) highlighting active unacknowledged critical alerts with direct action triggers ("ACKNOWLEDGE", "PLAN MANEUVER", "RISK CENTER").
    • Expandable cards (EventTimelineCard.tsx) with Framer Motion animations, exact UTC timestamps (YYYY-MM-DD HH:mm:ss UTC), relative time badges (T-minus/elapsed), telemetry metrics grids (miss distance, probability, altitude, velocity, Kp index, delta-V), external reference links (Space-Track, CelesTrak, NOAA SWPC), and quick action buttons ("Track on 3D Globe", "Plan Maneuver", "Space Weather", "Log to Logbook").
  4. Integration & Routing:

    • Registered /dashboard/timeline route in App.tsx.
    • Added Event Timeline to the primary navigation sidebar in MainLayout.tsx.
    • Linked the main Dashboard collision section directly to the full event stream view.
  5. Backend FastAPI Endpoint:

    • Created /api/v1/events endpoint in backend/api/v1/endpoints/events.py with multi-field filtering support (category, severity, search, limit) and registered it in backend/api/router.py.

Related Issue

Fixes #172

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 📚 Documentation update
  • 🚀 Performance improvement
  • 🎨 UI/UX enhancement
  • 🔧 Refactoring
  • 🧹 Chore / Maintenance
  • 🔒 Security improvement

Screenshots / Screen Recordings

Event Timeline Dashboard & Stream Controls
Live Mission Control Event Timeline

(Real-time streaming, status metrics, category filter pills, search input bar, high-priority emergency banner, and expandable telemetry cards in action.)

Testing Performed

  • Tested locally (Vite dev server and browser visual verification)
  • Tested relevant functionality (Live streaming toggle, incident simulation, filter combinations, card expansion, UTC clock rendering, and quick action navigation)
  • Checked for linting errors (npm run lint checked)
  • Checked for TypeScript/build errors (npx tsc --noEmit verified with 0 errors)
  • Tested responsive behavior (Mobile sidebar collapse, tablet, and desktop layouts)

Breaking Changes

None. All new routes, components, and backend endpoints are additive and preserve backwards compatibility with existing dashboard modules.

Checklist

  • I have read and followed the contributing guidelines.
  • My code follows the project's coding standards and guidelines.
  • I have completed testing of my changes.
  • I have updated documentation where applicable.
  • I have checked that my changes do not introduce unintended regressions.

ECSoC26 Submission

ECSoC26 contributors only — select your difficulty level by checking exactly one box below.
Leaving all boxes unchecked, or checking more than one, will cause the automation to fail.

  • ECSoC26-L1 – Beginner
  • ECSoC26-L2 – Intermediate
  • ECSoC26-L3 – Advanced

CodeAnt-AI Description

Add a live mission event timeline for monitoring orbital activity

What Changed

  • Added a dedicated timeline showing launches, conjunctions, maneuvers, debris, space weather, and system events as they arrive
  • Events can be searched, filtered by category, severity, time range, or satellite details, and sorted by newest or oldest
  • High-priority incidents appear in an alert banner with acknowledge, maneuver planning, and risk-center actions
  • Expanded event cards show UTC timestamps, telemetry, external data sources, and links to the 3D globe, weather monitor, or logbook
  • Added controls to pause or resume the live stream, simulate an emergency conjunction, and reset filters
  • Added a mission events API and links from the dashboard navigation and collision timeline

Impact

✅ Faster access to active orbital alerts
✅ Clearer conjunction and space-weather response actions
✅ Searchable mission activity history

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features
    • Added a Live Mission Event Timeline with UTC timestamps, event details, telemetry, references, and acknowledgment controls.
    • Added filtering by category, severity, time range, and text search, plus sorting and live-stream controls.
    • Added high-priority incident alerts with severity indicators and navigation actions.
    • Added event simulation and logbook integration for critical events.
    • Added Event Timeline navigation and a dashboard link to the full event stream.

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR daeed88 Aug 09, 2026 · 14:36 14:38

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@github-actions github-actions Bot added backend Backend development ECSoC26 Official label for ECSoC26 event contributions. bug Something isn't working ECSoC26-L3 Level 3 contribution for the ECSoC26 event. documentation Improvements or additions to documentation enhancement New feature or request frontend Frontend development size/XL Very large or complex contribution. type:backend Changes backend services or server-side logic. type:bug Fixes an existing bug or unexpected behavior. type:documentation Improves project documentation. type:feature Introduces a new feature or enhancement. type:frontend Changes frontend or client-side code. labels Aug 9, 2026
@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 9, 2026
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a mission-events API and a frontend event timeline. The timeline supports live event generation, filtering, search, severity handling, incident simulation, acknowledgments, expandable details, and dashboard navigation.

Changes

Mission event timeline

Layer / File(s) Summary
Event contract and API
frontend/src/types/events.ts, backend/api/v1/endpoints/events.py, backend/api/router.py, frontend/src/services/api.ts
Defines event types, adds five static backend events, registers GET /events, applies filters, and adds the typed frontend API method.
Timeline state and streaming
frontend/src/store/eventTimelineStore.ts, frontend/src/hooks/useEventTimeline.ts
Adds seeded event state, generated events, bounded storage, acknowledgments, incident simulation, live streaming, filtering, sorting, and derived statistics.
Timeline page and controls
frontend/src/pages/EventTimeline.tsx, frontend/src/components/timeline/*
Adds the timeline page, metrics, incident banner, filter controls, empty state, animated event cards, telemetry, references, and event actions.
Dashboard integration
frontend/src/App.tsx, frontend/src/components/layouts/MainLayout.tsx, frontend/src/pages/Dashboard.tsx, frontend/tsconfig.app.json
Adds the timeline route, sidebar entry, dashboard link, and TypeScript configuration updates.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EventTimelinePage
  participant useEventTimeline
  participant useEventTimelineStore
  participant EventTimelineCard
  EventTimelinePage->>useEventTimeline: subscribe to timeline state
  useEventTimeline->>useEventTimelineStore: start live streaming
  useEventTimelineStore-->>useEventTimeline: generate event
  useEventTimeline-->>EventTimelinePage: provide filtered events
  EventTimelinePage->>EventTimelineCard: render event
  EventTimelineCard->>useEventTimeline: acknowledge event
  useEventTimeline->>useEventTimelineStore: update event status
Loading

Possibly related PRs

  • 7-Blocks/Kepler#43: Established dashboard routing and layout files extended by this PR.
  • 7-Blocks/Kepler#59: Shares timeline/dashboard frontend files and the motion dependency used by the new components.
  • 7-Blocks/Kepler#173: Added logbook functionality used by high-severity timeline events.

Suggested reviewers: krishkhinchi

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: implementing the live mission control event timeline.
Description check ✅ Passed The description includes all required sections, links issue #172, documents implementation details, and reports testing results.
Linked Issues check ✅ Passed The changes implement real-time streaming, event filtering, search, sorting, expandable details, dashboard integration, and high-priority incident alerts required by issue #172.
Out of Scope Changes check ✅ Passed The changes are related to the event timeline feature, including its API, state management, UI, routing, navigation, and TypeScript configuration.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (redundant_comments, ai_padded_prose). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@github-actions github-actions Bot added the AI Artificial Intelligence and Machine Learning label Aug 9, 2026
Comment thread backend/api/v1/endpoints/events.py
Comment thread backend/api/v1/endpoints/events.py
Comment thread frontend/src/pages/EventTimeline.tsx
Comment thread frontend/src/components/timeline/EventTimelineCard.tsx
Comment thread frontend/src/components/timeline/HighPriorityIncidentBanner.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (11)
backend/api/v1/endpoints/events.py (1)

8-14: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Remove the unused database session and model imports.

The handler never uses db. Depends(get_db) still checks out a session from the pool on every request and then discards it. List, OrbitalEvent, CollisionPrediction, and SpaceWeather are also unused.

Drop them until the database-backed implementation replaces the static data. Removing the db parameter also clears the Ruff B008 hint on line 123.

♻️ Proposed cleanup
-from typing import List, Optional
+from typing import Optional
 from datetime import datetime, timezone, timedelta
-from fastapi import APIRouter, Query, Depends
-from sqlalchemy.orm import Session
-
-from database.session import get_db
-from models.db_models import OrbitalEvent, CollisionPrediction, SpaceWeather
+from fastapi import APIRouter, Query
     limit: int = Query(50, ge=1, le=200),
-    db: Session = Depends(get_db)
 ):

Also applies to: 123-123

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/api/v1/endpoints/events.py` around lines 8 - 14, Remove the unused
List, OrbitalEvent, CollisionPrediction, and SpaceWeather imports, then update
the affected event handler to remove its db parameter and Depends(get_db)
dependency. Keep the remaining request parameters and static-data behavior
unchanged.

Source: Linters/SAST tools

frontend/src/hooks/useEventTimeline.ts (2)

124-126: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename unacknowledgedCriticalEvents.

The predicate accepts CRITICAL and HIGH, but the name states Critical only. A reader who wires this value into a critical-only alert path gets HIGH events as well.

Use a name that matches the predicate, for example unacknowledgedPriorityEvents. Update the consumers in the timeline page and the incident banner.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/hooks/useEventTimeline.ts` around lines 124 - 126, Rename
unacknowledgedCriticalEvents to a name reflecting both CRITICAL and HIGH
severities, such as unacknowledgedPriorityEvents, and update all consumers in
the timeline page and incident banner to use the renamed value without changing
the predicate.

22-27: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

The 10-second ticker re-filters the list even when no time filter is active.

currentTime is a dependency of the filteredEvents memo at line 91. Each tick invalidates the memo, so the hook re-filters and re-sorts every event and returns a new array reference. All consumers then re-render.

currentTime is read only inside the filters.timeRange !== 'ALL' branch at line 61. The default filter is 'ALL', so in the default state this work produces no change to the output.

Start the ticker only when a bounded time range is active.

♻️ Proposed refactor
   useEffect(() => {
+    if (filters.timeRange === 'ALL') return;
     const timer = setInterval(() => setCurrentTime(Date.now()), 10000);
     return () => clearInterval(timer);
-  }, []);
+  }, [filters.timeRange]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/hooks/useEventTimeline.ts` around lines 22 - 27, Update the
timer setup in the useEventTimeline hook so the 10-second interval runs only
when filters.timeRange is a bounded range rather than 'ALL'. Stop and clean up
any existing timer when the filter returns to 'ALL', while preserving
currentTime updates for active time-range filtering.
frontend/src/services/api.ts (1)

193-193: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a top-level type import.

The inline import('@/types/events').TimelineEvent[] differs from the import style used by the other methods in this file. A top-level import type reads better and keeps the type imports in one place.

♻️ Proposed refactor

Add to the existing type imports at the top of the file:

+import type { TimelineEvent } from '`@/types/events`';

Then simplify the call:

-    return apiFetch<import('`@/types/events`').TimelineEvent[]>(`/events?${q}`);
+    return apiFetch<TimelineEvent[]>(`/events?${q}`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/services/api.ts` at line 193, Replace the inline import type in
the `apiFetch` call for the events endpoint with a top-level `import type`
alongside the file’s existing type imports, then reference `TimelineEvent[]`
directly in that call while preserving the current request behavior.
frontend/src/components/timeline/EventTimelineFilterBar.tsx (2)

126-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Expose the active category to assistive technology.

The selected pill is indicated only by color classes. Screen reader users cannot determine which category is active. Add aria-pressed={isActive} to each pill.

♻️ Proposed refactor
             <button
               key={cat.value}
+              type="button"
+              aria-pressed={isActive}
               onClick={() => onFilterChange('category', cat.value)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/timeline/EventTimelineFilterBar.tsx` around lines 126
- 142, Update the category buttons rendered in CATEGORIES.map within
EventTimelineFilterBar to include aria-pressed={isActive}, exposing each pill’s
selected state to assistive technology while preserving the existing visual
styling and click behavior.

148-198: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add accessible names to the search input, the clear button, and both selects.

The search input relies on placeholder only. The clear button contains an icon only. Neither select has a label. Screen reader users cannot identify these four controls.

♻️ Proposed refactor
           <input
             type="text"
+            aria-label="Search events by title, NORAD ID, or satellite"
             value={filters.searchQuery}
             <button
+              type="button"
+              aria-label="Clear search query"
               onClick={() => onFilterChange('searchQuery', '')}
           <select
+            aria-label="Filter by severity"
             value={filters.severity}
           <select
+            aria-label="Filter by time range"
             value={filters.timeRange}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/timeline/EventTimelineFilterBar.tsx` around lines 148
- 198, Add accessible names to the search input, the search-query clear button,
and both select controls in the filter bar. Use descriptive aria-labels or
associated labels that identify search, clear search, severity, and time range,
while preserving the existing filtering behavior.
frontend/src/components/timeline/HighPriorityIncidentBanner.tsx (2)

119-136: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Merge the two identical CONJUNCTION conditions.

Lines 119 and 129 evaluate the same condition. Wrap both buttons in a single fragment guarded once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/timeline/HighPriorityIncidentBanner.tsx` around lines
119 - 136, In HighPriorityIncidentBanner, merge the two adjacent
currentIncident.category === 'CONJUNCTION' guards into one shared conditional
wrapper containing both the PLAN MANEUVER and RISK CENTER buttons, preserving
each button’s navigation and styling.

18-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the empty check inside AnimatePresence so the exit animation runs.

The component returns null at line 18 before rendering AnimatePresence. When the operator acknowledges the last incident, React unmounts AnimatePresence and its child together. The exit transition at line 29 never plays for that case. Keep AnimatePresence mounted and render the child conditionally.

♻️ Proposed refactor
-  if (incidents.length === 0) return null;
-
-  const currentIncident = incidents[0]; // Show top urgent incident
-  const isCritical = currentIncident.severity === 'CRITICAL';
+  const currentIncident = incidents[0]; // Show top urgent incident
+  const isCritical = currentIncident?.severity === 'CRITICAL';
 
   return (
     <AnimatePresence mode="wait">
-      <motion.div
-        key={currentIncident.id}
+      {currentIncident && (
+      <motion.div
+        key={currentIncident.id}

Close the conditional after the motion.div closing tag at line 151.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/timeline/HighPriorityIncidentBanner.tsx` around lines
18 - 36, Keep AnimatePresence mounted in HighPriorityIncidentBanner and move the
incidents.length === 0 condition inside it, rendering the motion.div only when
an incident exists. Preserve the currentIncident and severity logic for
non-empty incidents so acknowledging the final incident allows its exit
animation to run.
frontend/src/pages/EventTimeline.tsx (2)

111-134: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Keep AnimatePresence mounted across the empty-state switch.

AnimatePresence sits inside the else branch. When the last event is filtered out, React unmounts AnimatePresence together with its children, so the card exit animations do not play. Move AnimatePresence outside the conditional and render both branches inside it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/EventTimeline.tsx` around lines 111 - 134, Move
AnimatePresence outside the events.length conditional in the timeline render,
keeping it mounted while switching between the empty state and event cards.
Render both branches as its children so EventTimelineCard instances can complete
their exit animations when filters remove the last event.

24-33: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Isolate the 1-second clock to avoid re-rendering the whole event list.

setUtcClock runs every second and re-renders EventTimelinePage. That re-renders HighPriorityIncidentBanner, EventTimelineFilterBar, and every EventTimelineCard in the list. EventTimelineCard is not memoized and animates with motion.div, so the cost grows with the number of events.

Move the clock into a small child component, or memoize the card list.

♻️ Proposed refactor: extract the clock component
+const UtcClock: React.FC = () => {
+  const [utcClock, setUtcClock] = useState<string>('');
+
+  useEffect(() => {
+    const updateClock = () => {
+      setUtcClock(new Date().toUTCString().replace('GMT', 'UTC'));
+    };
+    updateClock();
+    const interval = setInterval(updateClock, 1000);
+    return () => clearInterval(interval);
+  }, []);
+
+  return (
+    <p className="text-[10px] font-bold text-primary-container/80 font-technical-data mt-1 truncate">
+      {utcClock.substring(17, 25)}
+    </p>
+  );
+};

Then render <UtcClock /> in place of the inline paragraph at lines 85-87.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/EventTimeline.tsx` around lines 24 - 33, Extract the
utcClock state and one-second update effect from EventTimelinePage into a small
UtcClock child component, then render UtcClock where the inline clock paragraph
currently appears. Keep the existing UTC formatting and interval cleanup
unchanged so only the clock component re-renders each second, leaving
HighPriorityIncidentBanner, EventTimelineFilterBar, and EventTimelineCard
rendering unaffected.
frontend/src/components/timeline/EventTimelineCard.tsx (1)

64-73: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

formatRelativeTime depends on an external re-render to stay current.

The function reads Date.now() during render. The card holds no timer. Relative labels update only because EventTimelinePage re-renders every second for its UTC clock. If that clock is isolated into its own component, the labels freeze at their mount value.

Derive the relative label from the currentTime value that useEventTimeline already maintains, and pass it as a prop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/timeline/EventTimelineCard.tsx` around lines 64 - 73,
The formatRelativeTime flow should use the currentTime maintained by
useEventTimeline instead of calling Date.now() during render. Pass currentTime
through the relevant component props and use it when calculating each card’s
relative label, ensuring updates remain independent of EventTimelinePage’s UTC
clock re-render.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/api/v1/endpoints/events.py`:
- Around line 19-22: The backend seed timestamps in
backend/api/v1/endpoints/events.py lines 19-22 must be calculated inside the
request handler rather than at module import, using the current time minus each
event’s offset for every response. In frontend/src/store/eventTimelineStore.ts
lines 10-122, replace the eagerly created INITIAL_EVENTS with a lazy factory
invoked during store creation and re-initialization so seed timestamps refresh
whenever the store is rebuilt.
- Around line 153-156: In the events endpoint response, capture the full match
count before the `results` list is truncated by `limit`, then use that saved
count for the metadata `total` field instead of `len(results)`. Keep the sliced
`results` payload unchanged.

In `@frontend/src/components/timeline/EventTimelineCard.tsx`:
- Around line 315-321: Update the EventTimelineCard “TRACK ON 3D GLOBE” action
to render only when event.norad_id exists, and navigate to the dashboard while
passing that NORAD identifier through route state or a query parameter. Update
the Dashboard flow to consume the identifier and call
earthTwinRef.current?.flyToSatellite with it so the globe focuses the event’s
satellite.
- Around line 222-231: Extract the duplicated miss-distance formatting into a
shared formatMissDistance helper that rounds metre values with toFixed(0) and
kilometre values with toFixed(2). Update the conditional render in
frontend/src/components/timeline/EventTimelineCard.tsx lines 222-231 and
frontend/src/components/timeline/HighPriorityIncidentBanner.tsx lines 89-98 to
use the helper.
- Around line 114-117: Make the expandable header div in EventTimelineCard
keyboard operable without changing it to a button: add role="button",
tabIndex={0}, and aria-expanded={expanded}, and handle Enter and Space key
events by toggling expansion while preventing the Space key’s default behavior.
Preserve the existing click toggle and nested acknowledge button.
- Around line 79-80: Update the severityConfig and categoryConfig lookups in
EventTimelineCard so unknown event.severity or event.category values resolve to
safe default configurations instead of undefined. Reuse existing
severity/category config entries where possible, and preserve the current
classes and props behavior for recognized values.
- Around line 297-307: Filter event.external_references before mapping in
EventTimelineCard, allowing only references whose ref.url uses the http: or
https: protocols. Render anchors only for approved URLs, while preserving the
existing link markup and labels for valid references.

In `@frontend/src/components/timeline/EventTimelineFilterBar.tsx`:
- Around line 56-79: Update the stream-status logic and button rendering around
isLive and onTogglePauseStream to handle streamStatus === 'DISCONNECTED'
separately. Render a disabled/disconnected state with an appropriate label and
icon, prevent the pause/resume action, and preserve the existing LIVE and paused
behavior.

In `@frontend/src/components/timeline/HighPriorityIncidentBanner.tsx`:
- Around line 20-21: Update the incident selection in HighPriorityIncidentBanner
so currentIncident is chosen from incidents by highest severity rather than
fixed to incidents[0]. Preserve the existing banner behavior while ensuring
CRITICAL incidents take precedence over HIGH and other severities regardless of
insertion order.

In `@frontend/src/pages/EventTimeline.tsx`:
- Around line 112-127: Update the empty-state rendering around events.length ===
0 to use rawEventsCount: show a “no events yet” message without filter-reset
guidance when rawEventsCount is zero, and retain the current filtered-empty
message and RESET ALL FILTERS button when raw events exist but the filters
produce no matches.
- Around line 84-88: Remove the hardcoded '18:20:00 UTC' fallback from the time
display in EventTimeline, so the utcClock substring renders as an empty
placeholder when no UTC time is available.
- Around line 76-81: Update the stream status text in EventTimeline to choose
its color based on streamStatus: retain the success color for active/healthy
status, and use the appropriate non-success status color for PAUSED and
DISCONNECTED. Keep the existing status text and styling unchanged aside from the
value-based color mapping.

In `@frontend/src/store/eventTimelineStore.ts`:
- Around line 315-339: Update startLiveStreaming to read the current streamSpeed
inside each tick and scale event generation accordingly, while preserving the
documented 1x, 2x, and 5x behavior. Add module-level interval and
reference-count state near eventCounter so repeated callers share one timer;
increment the count on start, create the interval only when transitioning from
zero callers, and have each cleanup decrement the count and clear/reset the
shared interval only when no callers remain.

---

Nitpick comments:
In `@backend/api/v1/endpoints/events.py`:
- Around line 8-14: Remove the unused List, OrbitalEvent, CollisionPrediction,
and SpaceWeather imports, then update the affected event handler to remove its
db parameter and Depends(get_db) dependency. Keep the remaining request
parameters and static-data behavior unchanged.

In `@frontend/src/components/timeline/EventTimelineCard.tsx`:
- Around line 64-73: The formatRelativeTime flow should use the currentTime
maintained by useEventTimeline instead of calling Date.now() during render. Pass
currentTime through the relevant component props and use it when calculating
each card’s relative label, ensuring updates remain independent of
EventTimelinePage’s UTC clock re-render.

In `@frontend/src/components/timeline/EventTimelineFilterBar.tsx`:
- Around line 126-142: Update the category buttons rendered in CATEGORIES.map
within EventTimelineFilterBar to include aria-pressed={isActive}, exposing each
pill’s selected state to assistive technology while preserving the existing
visual styling and click behavior.
- Around line 148-198: Add accessible names to the search input, the
search-query clear button, and both select controls in the filter bar. Use
descriptive aria-labels or associated labels that identify search, clear search,
severity, and time range, while preserving the existing filtering behavior.

In `@frontend/src/components/timeline/HighPriorityIncidentBanner.tsx`:
- Around line 119-136: In HighPriorityIncidentBanner, merge the two adjacent
currentIncident.category === 'CONJUNCTION' guards into one shared conditional
wrapper containing both the PLAN MANEUVER and RISK CENTER buttons, preserving
each button’s navigation and styling.
- Around line 18-36: Keep AnimatePresence mounted in HighPriorityIncidentBanner
and move the incidents.length === 0 condition inside it, rendering the
motion.div only when an incident exists. Preserve the currentIncident and
severity logic for non-empty incidents so acknowledging the final incident
allows its exit animation to run.

In `@frontend/src/hooks/useEventTimeline.ts`:
- Around line 124-126: Rename unacknowledgedCriticalEvents to a name reflecting
both CRITICAL and HIGH severities, such as unacknowledgedPriorityEvents, and
update all consumers in the timeline page and incident banner to use the renamed
value without changing the predicate.
- Around line 22-27: Update the timer setup in the useEventTimeline hook so the
10-second interval runs only when filters.timeRange is a bounded range rather
than 'ALL'. Stop and clean up any existing timer when the filter returns to
'ALL', while preserving currentTime updates for active time-range filtering.

In `@frontend/src/pages/EventTimeline.tsx`:
- Around line 111-134: Move AnimatePresence outside the events.length
conditional in the timeline render, keeping it mounted while switching between
the empty state and event cards. Render both branches as its children so
EventTimelineCard instances can complete their exit animations when filters
remove the last event.
- Around line 24-33: Extract the utcClock state and one-second update effect
from EventTimelinePage into a small UtcClock child component, then render
UtcClock where the inline clock paragraph currently appears. Keep the existing
UTC formatting and interval cleanup unchanged so only the clock component
re-renders each second, leaving HighPriorityIncidentBanner,
EventTimelineFilterBar, and EventTimelineCard rendering unaffected.

In `@frontend/src/services/api.ts`:
- Line 193: Replace the inline import type in the `apiFetch` call for the events
endpoint with a top-level `import type` alongside the file’s existing type
imports, then reference `TimelineEvent[]` directly in that call while preserving
the current request behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fec64c0-e036-4140-b53f-16cb7a254f17

📥 Commits

Reviewing files that changed from the base of the PR and between 9ac97e9 and daeed88.

⛔ Files ignored due to path filters (14)
  • backend/__pycache__/debug_log.cpython-314.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/router.cpython-314.pyc is excluded by !**/*.pyc
  • backend/api/v1/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/api/v1/endpoints/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/api/v1/endpoints/__pycache__/auth.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/__pycache__/main.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/core/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/core/__pycache__/config.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/core/__pycache__/error_handlers.cpython-314.pyc is excluded by !**/*.pyc
  • backend/app/core/__pycache__/exceptions.cpython-314.pyc is excluded by !**/*.pyc
  • backend/schemas/__pycache__/__init__.cpython-314.pyc is excluded by !**/*.pyc
  • backend/schemas/__pycache__/api_schemas.cpython-314.pyc is excluded by !**/*.pyc
📒 Files selected for processing (14)
  • backend/api/router.py
  • backend/api/v1/endpoints/events.py
  • frontend/src/App.tsx
  • frontend/src/components/layouts/MainLayout.tsx
  • frontend/src/components/timeline/EventTimelineCard.tsx
  • frontend/src/components/timeline/EventTimelineFilterBar.tsx
  • frontend/src/components/timeline/HighPriorityIncidentBanner.tsx
  • frontend/src/hooks/useEventTimeline.ts
  • frontend/src/pages/Dashboard.tsx
  • frontend/src/pages/EventTimeline.tsx
  • frontend/src/services/api.ts
  • frontend/src/store/eventTimelineStore.ts
  • frontend/src/types/events.ts
  • frontend/tsconfig.app.json

Comment thread backend/api/v1/endpoints/events.py
Comment thread backend/api/v1/endpoints/events.py
Comment thread frontend/src/components/timeline/EventTimelineCard.tsx
Comment thread frontend/src/components/timeline/EventTimelineCard.tsx
Comment thread frontend/src/components/timeline/EventTimelineCard.tsx
Comment thread frontend/src/components/timeline/HighPriorityIncidentBanner.tsx
Comment thread frontend/src/pages/EventTimeline.tsx
Comment thread frontend/src/pages/EventTimeline.tsx
Comment thread frontend/src/pages/EventTimeline.tsx
Comment thread frontend/src/store/eventTimelineStore.ts

@krishkhinchi krishkhinchi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!

@krishkhinchi
krishkhinchi merged commit b3717a8 into 7-Blocks:main Aug 10, 2026
7 checks passed
@ecsoc-sentinel ecsoc-sentinel Bot added ECSoC26-L2 Level 2 contribution for the ECSoC26 event. and removed ECSoC26-L3 Level 3 contribution for the ECSoC26 event. labels Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Artificial Intelligence and Machine Learning backend Backend development bug Something isn't working documentation Improvements or additions to documentation ECSoC26-L2 Level 2 contribution for the ECSoC26 event. ECSoC26 Official label for ECSoC26 event contributions. enhancement New feature or request frontend Frontend development size/XL Very large or complex contribution. size:XXL This PR changes 1000+ lines, ignoring generated files type:backend Changes backend services or server-side logic. type:bug Fixes an existing bug or unexpected behavior. type:documentation Improves project documentation. type:feature Introduces a new feature or enhancement. type:frontend Changes frontend or client-side code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📡 Live Mission Control Event Timeline

2 participants