feat: add temporal context and contextual help
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user