pcp-tgu-ops-ui: показывать только КА со статусом OPERATIONAL
С остальными КА мы не работаем, поэтому отсекаем их сразу на входе в loadData: фильтруем платформы по статусу и оставляем планы только для эксплуатируемых КА (по norad-id), иначе неoperational-аппарат вернулся бы fallback-строкой по плану в buildPlatformsForInterval.
This commit is contained in:
@@ -10,7 +10,13 @@ import { TguPlanningLayout } from "./TguPlanningLayout";
|
|||||||
import { TguSidebar } from "./TguSidebar";
|
import { TguSidebar } from "./TguSidebar";
|
||||||
import { TguTimeline } from "./TguTimeline";
|
import { TguTimeline } from "./TguTimeline";
|
||||||
import { TguToolbar } from "./TguToolbar";
|
import { TguToolbar } from "./TguToolbar";
|
||||||
import { buildPlatformsForInterval, buildTimelineRows, mapPlans } from "./tguTimelineMapper";
|
import {
|
||||||
|
buildPlatformsForInterval,
|
||||||
|
buildTimelineRows,
|
||||||
|
isOperationalPlatform,
|
||||||
|
mapPlans,
|
||||||
|
operationalSpacecraftIds
|
||||||
|
} from "./tguTimelineMapper";
|
||||||
|
|
||||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -61,19 +67,24 @@ export function TguPlanningPage() {
|
|||||||
fetchPlans(historyDays)
|
fetchPlans(historyDays)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// На морде работаем только с эксплуатируемыми КА — остальные отсекаем сразу
|
||||||
|
// на входе, чтобы они не всплывали ни в списке, ни как fallback-строки по планам.
|
||||||
|
const operationalPlatforms =
|
||||||
|
platformResult.status === "fulfilled" ? platformResult.value.filter(isOperationalPlatform) : [];
|
||||||
|
|
||||||
if (platformResult.status === "rejected") {
|
if (platformResult.status === "rejected") {
|
||||||
setPlatformLoadFailed(true);
|
setPlatformLoadFailed(true);
|
||||||
} else {
|
} else {
|
||||||
setPlatformLoadFailed(false);
|
setPlatformLoadFailed(false);
|
||||||
setRawPlatforms(platformResult.value);
|
setRawPlatforms(operationalPlatforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (planResult.status === "rejected") {
|
if (planResult.status === "rejected") {
|
||||||
setPlans([]);
|
setPlans([]);
|
||||||
setPageError(planResult.reason instanceof Error ? planResult.reason.message : "Не удалось загрузить планы.");
|
setPageError(planResult.reason instanceof Error ? planResult.reason.message : "Не удалось загрузить планы.");
|
||||||
} else {
|
} else {
|
||||||
const platforms = platformResult.status === "fulfilled" ? platformResult.value : [];
|
const operationalIds = operationalSpacecraftIds(operationalPlatforms);
|
||||||
setPlans(mapPlans(planResult.value, platforms));
|
setPlans(mapPlans(planResult.value, operationalPlatforms).filter((plan) => operationalIds.has(plan.spacecraftId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import type { TguPlatform } from "../../model/tguTypes";
|
||||||
|
import { isOperationalPlatform, operationalSpacecraftIds } from "./tguTimelineMapper";
|
||||||
|
|
||||||
|
function platform(overrides: Partial<TguPlatform>): TguPlatform {
|
||||||
|
return { id: "x", noradId: 1, status: "OPERATIONAL", ...overrides };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("isOperationalPlatform", () => {
|
||||||
|
it("принимает только статус OPERATIONAL без учёта регистра и пробелов", () => {
|
||||||
|
expect(isOperationalPlatform(platform({ status: "OPERATIONAL" }))).toBe(true);
|
||||||
|
expect(isOperationalPlatform(platform({ status: " operational " }))).toBe(true);
|
||||||
|
expect(isOperationalPlatform(platform({ status: "STANDBY" }))).toBe(false);
|
||||||
|
expect(isOperationalPlatform(platform({ status: "LOST" }))).toBe(false);
|
||||||
|
expect(isOperationalPlatform(platform({ status: null }))).toBe(false);
|
||||||
|
expect(isOperationalPlatform(platform({ status: undefined }))).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("operationalSpacecraftIds", () => {
|
||||||
|
it("собирает norad-id в виде строк и пропускает платформы без norad-id", () => {
|
||||||
|
const ids = operationalSpacecraftIds([
|
||||||
|
platform({ noradId: 2 }),
|
||||||
|
platform({ noradId: 30 }),
|
||||||
|
platform({ noradId: null }),
|
||||||
|
platform({ noradId: undefined })
|
||||||
|
]);
|
||||||
|
expect(ids).toEqual(new Set(["2", "30"]));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,6 +3,24 @@ import type { TguPlanUi, TguPlatformUi, TimelineRange, TimelineRow } from "../..
|
|||||||
|
|
||||||
const PROBLEM_STATUSES = new Set(["REJECTED", "START_AMBIGUOUS"]);
|
const PROBLEM_STATUSES = new Set(["REJECTED", "START_AMBIGUOUS"]);
|
||||||
|
|
||||||
|
const OPERATIONAL_STATUS = "OPERATIONAL";
|
||||||
|
|
||||||
|
/** На морде показываем только эксплуатируемые КА — с остальными мы не работаем. */
|
||||||
|
export function isOperationalPlatform(platform: TguPlatform): boolean {
|
||||||
|
return (platform.status ?? "").trim().toUpperCase() === OPERATIONAL_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** norad-id эксплуатируемых КА; planId.spacecraftId сопоставляется именно с norad-id. */
|
||||||
|
export function operationalSpacecraftIds(platforms: TguPlatform[]): Set<string> {
|
||||||
|
const ids = new Set<string>();
|
||||||
|
for (const platform of platforms) {
|
||||||
|
if (platform.noradId !== null && platform.noradId !== undefined) {
|
||||||
|
ids.add(String(platform.noradId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
export function mapPlans(plans: TguPlan[], platforms: TguPlatform[]): TguPlanUi[] {
|
export function mapPlans(plans: TguPlan[], platforms: TguPlatform[]): TguPlanUi[] {
|
||||||
const platformByNorad = buildPlatformByNorad(platforms);
|
const platformByNorad = buildPlatformByNorad(platforms);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user