99 lines
2.8 KiB
TypeScript
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();
|
|
}
|