feat(FN-1219): add mission observability and autopilot dashboard UX

- Add mission observability types and API helpers, and forward mission events through SSE with mission filtering support
- Expand MissionManager with health indicators, activity/event log views, improved autopilot controls, and activity auto-scroll behavior
- Refine mission detail mobile controls and styling updates for responsive observability surfaces
- Add regression coverage for MissionManager behavior/mobile CSS and SSE mission filtering
- Include a changeset documenting the mission dashboard observability update
This commit is contained in:
gsxdsm
2026-04-08 18:08:06 -07:00
parent 61117c8a2b
commit b2f0df5455
9 changed files with 1786 additions and 86 deletions

View File

@@ -24,6 +24,9 @@ import type {
NodeConfig,
NodeStatus,
DiscoveryConfig,
MissionEvent,
MissionHealth,
MissionEventType,
} from "@fusion/core";
import type { PlanningQuestion, PlanningSummary, PlanningResponse } from "@fusion/core";
import type { ScheduledTask, ScheduledTaskCreateInput, ScheduledTaskUpdateInput, AutomationRunResult, AutomationStep } from "@fusion/core";
@@ -3034,6 +3037,43 @@ export function fetchMissionStatus(missionId: string, projectId?: string): Promi
return api<{ status: string }>(withProjectId(`/missions/${encodeURIComponent(missionId)}/status`, projectId));
}
/** Query options for paginated mission event logs. */
export interface MissionEventQueryOptions {
limit?: number;
offset?: number;
eventType?: MissionEventType;
}
/** Paginated mission event log response. */
export interface MissionEventsResponse {
events: MissionEvent[];
total: number;
limit: number;
offset: number;
}
/** Fetch paginated mission observability events. */
export function fetchMissionEvents(
missionId: string,
options?: MissionEventQueryOptions,
projectId?: string,
): Promise<MissionEventsResponse> {
const query = new URLSearchParams();
if (options?.limit !== undefined) query.set("limit", String(options.limit));
if (options?.offset !== undefined) query.set("offset", String(options.offset));
if (options?.eventType !== undefined) query.set("eventType", options.eventType);
const suffix = query.size > 0 ? `?${query.toString()}` : "";
return api<MissionEventsResponse>(
withProjectId(`/missions/${encodeURIComponent(missionId)}/events${suffix}`, projectId),
);
}
/** Fetch computed mission health metrics. */
export function fetchMissionHealth(missionId: string, projectId?: string): Promise<MissionHealth> {
return api<MissionHealth>(withProjectId(`/missions/${encodeURIComponent(missionId)}/health`, projectId));
}
/** Add milestone to mission */
export function createMilestone(
missionId: string,