feat(workbench): expand SCADA monitoring and investigation presentation
This commit is contained in:
@@ -41,6 +41,13 @@ export type PresentationHistoryControls = {
|
||||
entries: PresentationHistoryEntry[];
|
||||
selectedId: number | null;
|
||||
onSelect: (id: number | null) => void;
|
||||
playback?: {
|
||||
playing: boolean;
|
||||
speed: number;
|
||||
onToggle: () => void;
|
||||
onSpeedChange: (speed: number) => void;
|
||||
onSeek: (id: number) => void;
|
||||
};
|
||||
};
|
||||
export const emptyPresentationView = (): PresentationView => ({
|
||||
charts: [],
|
||||
@@ -58,6 +65,8 @@ export class PresentationViewHistory {
|
||||
current = emptyPresentationView();
|
||||
entries: PresentationHistoryEntry[] = [];
|
||||
selectedId: number | null = null;
|
||||
playing = false;
|
||||
playbackIds: number[] = [];
|
||||
private sequence = 0;
|
||||
|
||||
get currentEntryId() {
|
||||
@@ -91,30 +100,33 @@ export class PresentationViewHistory {
|
||||
taskTitle: string | null,
|
||||
metadata: { key?: string; taskId?: string; createdAt?: number } = {}
|
||||
) {
|
||||
const id = ++this.sequence;
|
||||
this.entries = [
|
||||
...this.entries,
|
||||
{
|
||||
id,
|
||||
label,
|
||||
source,
|
||||
taskTitle,
|
||||
createdAt: Date.now(),
|
||||
...metadata,
|
||||
status: "running",
|
||||
snapshot: this.current
|
||||
}
|
||||
];
|
||||
const existing = metadata.key ? this.entries.find((entry) => entry.key === metadata.key) : null;
|
||||
const id = existing?.id ?? ++this.sequence;
|
||||
const entry: PresentationHistoryEntry = {
|
||||
id,
|
||||
label,
|
||||
source,
|
||||
taskTitle,
|
||||
createdAt: existing?.createdAt ?? Date.now(),
|
||||
...metadata,
|
||||
status: "running",
|
||||
snapshot: this.current
|
||||
};
|
||||
this.entries = existing
|
||||
? this.entries.map((previous) => previous.id === id ? entry : previous)
|
||||
: [...this.entries, entry];
|
||||
return id;
|
||||
}
|
||||
finish(
|
||||
id: number,
|
||||
status: Exclude<PresentationHistoryEntry["status"], "running">,
|
||||
message?: string,
|
||||
snapshot = this.current
|
||||
snapshot = this.current,
|
||||
expected?: PresentationHistoryEntry
|
||||
) {
|
||||
// Hydration can replace this row before an older cancelled request settles.
|
||||
this.entries = this.entries.map((entry) =>
|
||||
entry.id === id ? { ...entry, status, message, snapshot } : entry
|
||||
entry.id === id && (!expected || entry === expected) ? { ...entry, status, message, snapshot } : entry
|
||||
);
|
||||
}
|
||||
record(
|
||||
@@ -128,12 +140,34 @@ export class PresentationViewHistory {
|
||||
return id;
|
||||
}
|
||||
select(id: number | null) {
|
||||
this.pausePlayback();
|
||||
if (id !== null && !this.entries.some((entry) => entry.id === id && entry.status !== "running"))
|
||||
return false;
|
||||
this.selectedId = id;
|
||||
return true;
|
||||
}
|
||||
startPlayback(entries: PresentationHistoryEntry[]) {
|
||||
this.playbackIds = entries.filter((entry) => entry.status === "completed").map((entry) => entry.id);
|
||||
if (!this.playbackIds.length) return false;
|
||||
const index = this.playbackIds.indexOf(this.selectedId ?? -1);
|
||||
if (index < 0 || index === this.playbackIds.length - 1) this.selectedId = this.playbackIds[0];
|
||||
this.playing = true;
|
||||
return true;
|
||||
}
|
||||
advancePlayback() {
|
||||
if (!this.playing) return false;
|
||||
const next = this.playbackIds[this.playbackIds.indexOf(this.selectedId ?? -1) + 1];
|
||||
if (next === undefined) {
|
||||
this.pausePlayback();
|
||||
return false;
|
||||
}
|
||||
this.selectedId = next;
|
||||
return true;
|
||||
}
|
||||
pausePlayback() { this.playing = false; }
|
||||
reset() {
|
||||
this.pausePlayback();
|
||||
this.playbackIds = [];
|
||||
this.current = emptyPresentationView();
|
||||
this.entries = [];
|
||||
this.selectedId = null;
|
||||
|
||||
Reference in New Issue
Block a user