Files
govoplan-core/webui/src/platform/temporal.ts
T

99 lines
2.8 KiB
TypeScript

export type TemporalValidityMode = "current" | "at" | "all";
export type TemporalDataSelection = {
validityMode: TemporalValidityMode;
validAt: string | null;
recordedAt: string | null;
};
export type TemporalContextChangedEventDetail = {
selection: TemporalDataSelection;
scopeKey: string;
};
export const PLATFORM_TEMPORAL_CONTEXT_CHANGED_EVENT =
"govoplan:temporal-context-changed";
export const DEFAULT_TEMPORAL_DATA_SELECTION: TemporalDataSelection = {
validityMode: "current",
validAt: null,
recordedAt: null
};
let activeSelection = DEFAULT_TEMPORAL_DATA_SELECTION;
export function normalizeTemporalDataSelection(
value: Partial<TemporalDataSelection> | null | undefined
): TemporalDataSelection {
const validityMode = ["current", "at", "all"].includes(
String(value?.validityMode)
)
? value?.validityMode as TemporalValidityMode
: "current";
const validAt = validityMode === "at"
? normalizeTimestamp(value?.validAt)
: null;
if (validityMode === "at" && !validAt) {
throw new Error("i18n:govoplan-core.select_valid_date_time");
}
return {
validityMode,
validAt,
recordedAt: normalizeTimestamp(value?.recordedAt)
};
}
export function temporalDataSelectionIsDefault(
value: TemporalDataSelection
): boolean {
return value.validityMode === "current" && !value.recordedAt;
}
export function temporalDataSelectionKey(value: TemporalDataSelection): string {
return [value.validityMode, value.validAt ?? "", value.recordedAt ?? ""].join(":");
}
export function setActiveTemporalDataSelection(
value: TemporalDataSelection
): void {
activeSelection = normalizeTemporalDataSelection(value);
}
export function activeTemporalDataSelection(): TemporalDataSelection {
return activeSelection;
}
export function temporalRequestHeaders(): Record<string, string> {
const selection = activeTemporalDataSelection();
if (temporalDataSelectionIsDefault(selection)) return {};
const headers: Record<string, string> = {
"X-Govoplan-Validity-Mode": selection.validityMode
};
if (selection.validAt) headers["X-Govoplan-Valid-At"] = selection.validAt;
if (selection.recordedAt) {
headers["X-Govoplan-Recorded-At"] = selection.recordedAt;
}
return headers;
}
export function dispatchTemporalContextChanged(
selection: TemporalDataSelection,
scopeKey: string
): void {
if (typeof window === "undefined") return;
window.dispatchEvent(
new CustomEvent<TemporalContextChangedEventDetail>(
PLATFORM_TEMPORAL_CONTEXT_CHANGED_EVENT,
{ detail: { selection, scopeKey } }
)
);
}
function normalizeTimestamp(value: string | null | undefined): string | null {
const clean = String(value || "").trim();
if (!clean) return null;
const instant = new Date(clean);
if (!Number.isFinite(instant.getTime())) return null;
return instant.toISOString();
}