aboutsummaryrefslogtreecommitdiff
path: root/jb-ui/src/models/grlEventsSlice.ts
diff options
context:
space:
mode:
Diffstat (limited to 'jb-ui/src/models/grlEventsSlice.ts')
-rw-r--r--jb-ui/src/models/grlEventsSlice.ts46
1 files changed, 28 insertions, 18 deletions
diff --git a/jb-ui/src/models/grlEventsSlice.ts b/jb-ui/src/models/grlEventsSlice.ts
index f77bbc1..912c4ca 100644
--- a/jb-ui/src/models/grlEventsSlice.ts
+++ b/jb-ui/src/models/grlEventsSlice.ts
@@ -1,32 +1,25 @@
import { EventEnvelope } from "@/api_fsb";
import { RootState } from "@/store";
-import { createEntityAdapter, createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit';
const eventAdapter = createEntityAdapter({
selectId: (model: EventEnvelope) => model.event_uuid!,
sortComparer: (a, b) => {
- return b.timestamp!.localeCompare(a.timestamp!);
+ // ASC by timestamp
+ return a.timestamp!.localeCompare(b.timestamp!);
},
});
const grlEventsSlice = createSlice({
name: 'grlEvents',
- // initialState: eventAdapter.getInitialState(),
- initialState: eventAdapter.getInitialState({ latestEvent: null as EventEnvelope | null }),
+ initialState: eventAdapter.getInitialState(),
reducers: {
+ addEvent: eventAdapter.addOne,
addEvents: eventAdapter.addMany,
- upsertEvent: eventAdapter.upsertOne, // add or update
-
- // addEvent: eventAdapter.addOne,
- addEvent: (state, action: PayloadAction<EventEnvelope>) => {
- eventAdapter.addOne(state, action.payload);
- const incoming = action.payload.timestamp!;
- if (!state.latestEvent || incoming.localeCompare(state.latestEvent.timestamp!) > 0) {
- state.latestEvent = action.payload;
- }
- },
+ upsertEvent: eventAdapter.upsertOne, // Add or Update
+
}
})
@@ -35,14 +28,31 @@ export const {
addEvent, addEvents, upsertEvent
} = grlEventsSlice.actions;
-// Add this after the slice, before exports
+
export const eventSelectors = eventAdapter.getSelectors(
(state: RootState) => state.events
);
-export const selectLatestEvents = (count: number) => (state: RootState) =>
- eventSelectors.selectAll(state).slice(0, count);
+export const selectAllEvents = (state: RootState): EventEnvelope[] => eventSelectors.selectAll(state);
+
+const BASE_SPEED = 40; // px/sec at idle
+const MAX_SPEED = 380; // px/sec at surge
+
+const RATE_WINDOW_MS = 10_000; // ms window to measure message frequency
+const RATE_TO_SPEED = 55; // px/sec added per msg/sec
-export const selectLatestEvent = (state: RootState) => state.events.latestEvent;
+
+// --- Speed: derived from arrival rate of recent items ---
+export const selectCurrentSpeed = createSelector(selectAllEvents, (items) => {
+ const now = Date.now();
+
+ const recentCount = items.filter((m) => {
+ const ts = new Date(m.timestamp!).getTime();
+ return now - ts < RATE_WINDOW_MS;
+ }).length;
+
+ const rate = recentCount / (RATE_WINDOW_MS / 1_000); // msgs/sec
+ return Math.min(BASE_SPEED + rate * RATE_TO_SPEED, MAX_SPEED);
+});
export default grlEventsSlice.reducer