@adventurelabs/scout-core 1.0.29 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/events.d.ts +8 -3
- package/dist/helpers/events.js +42 -14
- package/dist/hooks/useScoutDbListener.js +34 -7
- package/dist/store/scout.d.ts +13 -1
- package/dist/store/scout.js +28 -1
- package/dist/types/herd_module.d.ts +4 -2
- package/dist/types/herd_module.js +96 -34
- package/package.json +1 -1
package/dist/helpers/events.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { IEvent } from "../types/db";
|
|
2
2
|
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
-
export declare
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export declare enum EnumSessionsVisibility {
|
|
4
|
+
Only = 0,
|
|
5
|
+
Exclude = 1,
|
|
6
|
+
Combine = 2
|
|
7
|
+
}
|
|
8
|
+
export declare function server_get_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<IEvent[]>>;
|
|
9
|
+
export declare function server_get_more_events_by_herd(herd_id: number, offset: number, page_count: number | undefined, includeSessionEvents: boolean): Promise<IWebResponseCompatible<IEvent[]>>;
|
|
10
|
+
export declare function server_get_total_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<number>>;
|
|
6
11
|
export declare function server_create_event(newEvent: any): Promise<IWebResponseCompatible<boolean>>;
|
package/dist/helpers/events.js
CHANGED
|
@@ -2,18 +2,31 @@
|
|
|
2
2
|
import { newServerClient } from "../supabase/server";
|
|
3
3
|
import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
4
4
|
import { addSignedUrlsToEvents } from "./storage";
|
|
5
|
-
export
|
|
5
|
+
export var EnumSessionsVisibility;
|
|
6
|
+
(function (EnumSessionsVisibility) {
|
|
7
|
+
EnumSessionsVisibility[EnumSessionsVisibility["Only"] = 0] = "Only";
|
|
8
|
+
EnumSessionsVisibility[EnumSessionsVisibility["Exclude"] = 1] = "Exclude";
|
|
9
|
+
EnumSessionsVisibility[EnumSessionsVisibility["Combine"] = 2] = "Combine";
|
|
10
|
+
})(EnumSessionsVisibility || (EnumSessionsVisibility = {}));
|
|
11
|
+
export async function server_get_events_by_herd(herd_id, sessions_visibility) {
|
|
6
12
|
const supabase = await newServerClient();
|
|
7
13
|
// fetch events and include devices
|
|
8
14
|
// sort by timestamp
|
|
9
|
-
|
|
15
|
+
let query = supabase
|
|
10
16
|
.from("events")
|
|
11
17
|
.select(`
|
|
12
18
|
*,
|
|
13
19
|
devices: devices!inner(*)
|
|
14
20
|
`)
|
|
15
|
-
.eq("devices.herd_id", herd_id)
|
|
16
|
-
|
|
21
|
+
.eq("devices.herd_id", herd_id);
|
|
22
|
+
// Apply session filter based on sessions_visibility
|
|
23
|
+
if (sessions_visibility === EnumSessionsVisibility.Only) {
|
|
24
|
+
query = query.not("session_id", "is", null);
|
|
25
|
+
}
|
|
26
|
+
else if (sessions_visibility === EnumSessionsVisibility.Exclude) {
|
|
27
|
+
query = query.is("session_id", null);
|
|
28
|
+
}
|
|
29
|
+
const { data } = await query.order("timestamp_observation", { ascending: false });
|
|
17
30
|
// Add signed URLs to events using the same client
|
|
18
31
|
const eventsWithSignedUrls = data
|
|
19
32
|
? await addSignedUrlsToEvents(data, supabase)
|
|
@@ -22,21 +35,29 @@ export async function server_get_events_by_herd(herd_id) {
|
|
|
22
35
|
let response = IWebResponse.success(eventsWithSignedUrls);
|
|
23
36
|
return response.to_compatible();
|
|
24
37
|
}
|
|
25
|
-
export async function server_get_more_events_by_herd(herd_id, offset, page_count = 10) {
|
|
38
|
+
export async function server_get_more_events_by_herd(herd_id, offset, page_count = 10, includeSessionEvents) {
|
|
26
39
|
const from = offset * page_count;
|
|
27
40
|
const to = from + page_count - 1;
|
|
28
41
|
const supabase = await newServerClient();
|
|
29
42
|
// fetch events and include devices
|
|
30
43
|
// sort by timestamp
|
|
31
|
-
|
|
44
|
+
let query = supabase
|
|
32
45
|
.from("events")
|
|
33
46
|
.select(`
|
|
34
47
|
*,
|
|
35
48
|
devices: devices!inner(*)
|
|
36
49
|
`)
|
|
37
50
|
.eq("devices.herd_id", herd_id)
|
|
38
|
-
.range(from, to)
|
|
39
|
-
|
|
51
|
+
.range(from, to);
|
|
52
|
+
if (includeSessionEvents) {
|
|
53
|
+
// Include only events that have a session_id
|
|
54
|
+
query = query.not("session_id", "is", null);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// Include only events that don't have a session_id
|
|
58
|
+
query = query.is("session_id", null);
|
|
59
|
+
}
|
|
60
|
+
const { data } = await query.order("timestamp_observation", { ascending: false });
|
|
40
61
|
// Add signed URLs to events using the same client
|
|
41
62
|
const eventsWithSignedUrls = data
|
|
42
63
|
? await addSignedUrlsToEvents(data, supabase)
|
|
@@ -46,12 +67,19 @@ export async function server_get_more_events_by_herd(herd_id, offset, page_count
|
|
|
46
67
|
return response.to_compatible();
|
|
47
68
|
}
|
|
48
69
|
// function to get total number of events for a herd
|
|
49
|
-
export async function server_get_total_events_by_herd(herd_id) {
|
|
70
|
+
export async function server_get_total_events_by_herd(herd_id, sessions_visibility) {
|
|
50
71
|
const supabase = await newServerClient();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
let query = supabase
|
|
73
|
+
.from("events")
|
|
74
|
+
.select("id", { count: "exact", head: true })
|
|
75
|
+
.eq("devices.herd_id", herd_id);
|
|
76
|
+
if (sessions_visibility === EnumSessionsVisibility.Only) {
|
|
77
|
+
query = query.not("session_id", "is", null);
|
|
78
|
+
}
|
|
79
|
+
else if (sessions_visibility === EnumSessionsVisibility.Exclude) {
|
|
80
|
+
query = query.is("session_id", null);
|
|
81
|
+
}
|
|
82
|
+
const { count, error } = await query;
|
|
55
83
|
if (error) {
|
|
56
84
|
return {
|
|
57
85
|
status: EnumWebResponse.ERROR,
|
|
@@ -60,7 +88,7 @@ export async function server_get_total_events_by_herd(herd_id) {
|
|
|
60
88
|
};
|
|
61
89
|
}
|
|
62
90
|
else {
|
|
63
|
-
return IWebResponse.success(
|
|
91
|
+
return IWebResponse.success(count || 0).to_compatible();
|
|
64
92
|
}
|
|
65
93
|
}
|
|
66
94
|
export async function server_create_event(newEvent) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useAppDispatch } from "../store/hooks";
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
|
-
import { addDevice, addPlan, addTag, deleteDevice, deletePlan, deleteTag, updateDevice, updatePlan, updateTag, } from "../store/scout";
|
|
4
|
+
import { addDevice, addPlan, addTag, addSessionToStore, deleteDevice, deletePlan, deleteSessionFromStore, deleteTag, updateDevice, updatePlan, updateSessionInStore, updateTag, } from "../store/scout";
|
|
5
5
|
export function useScoutDbListener(scoutSupabase) {
|
|
6
6
|
const supabase = useRef(null);
|
|
7
7
|
const channels = useRef([]);
|
|
@@ -56,6 +56,33 @@ export function useScoutDbListener(scoutSupabase) {
|
|
|
56
56
|
console.log("[DB Listener] Plan UPDATE received:", payload.new);
|
|
57
57
|
dispatch(updatePlan(payload.new));
|
|
58
58
|
}
|
|
59
|
+
function handleSessionInserts(payload) {
|
|
60
|
+
console.log("[DB Listener] Session INSERT received:", payload.new);
|
|
61
|
+
dispatch(addSessionToStore(payload.new));
|
|
62
|
+
}
|
|
63
|
+
function handleSessionDeletes(payload) {
|
|
64
|
+
console.log("[DB Listener] Session DELETE received:", payload.old);
|
|
65
|
+
dispatch(deleteSessionFromStore(payload.old));
|
|
66
|
+
}
|
|
67
|
+
function handleSessionUpdates(payload) {
|
|
68
|
+
console.log("[DB Listener] Session UPDATE received:", payload.new);
|
|
69
|
+
dispatch(updateSessionInStore(payload.new));
|
|
70
|
+
}
|
|
71
|
+
function handleConnectivityInserts(payload) {
|
|
72
|
+
console.log("[DB Listener] Connectivity INSERT received:", payload.new);
|
|
73
|
+
// For now, we'll just log connectivity changes since they're related to sessions
|
|
74
|
+
// In the future, we might want to update session connectivity data
|
|
75
|
+
}
|
|
76
|
+
function handleConnectivityDeletes(payload) {
|
|
77
|
+
console.log("[DB Listener] Connectivity DELETE received:", payload.old);
|
|
78
|
+
// For now, we'll just log connectivity changes since they're related to sessions
|
|
79
|
+
// In the future, we might want to update session connectivity data
|
|
80
|
+
}
|
|
81
|
+
function handleConnectivityUpdates(payload) {
|
|
82
|
+
console.log("[DB Listener] Connectivity UPDATE received:", payload.new);
|
|
83
|
+
// For now, we'll just log connectivity changes since they're related to sessions
|
|
84
|
+
// In the future, we might want to update session connectivity data
|
|
85
|
+
}
|
|
59
86
|
useEffect(() => {
|
|
60
87
|
console.log("=== SCOUT DB LISTENER DEBUG ===");
|
|
61
88
|
console.log("[DB Listener] Using shared Supabase client from ScoutRefreshProvider context");
|
|
@@ -91,12 +118,12 @@ export function useScoutDbListener(scoutSupabase) {
|
|
|
91
118
|
.on("postgres_changes", { event: "INSERT", schema: "public", table: "tags" }, handleTagInserts)
|
|
92
119
|
.on("postgres_changes", { event: "DELETE", schema: "public", table: "tags" }, handleTagDeletes)
|
|
93
120
|
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "tags" }, handleTagUpdates)
|
|
94
|
-
.on("postgres_changes", { event: "INSERT", schema: "public", table: "connectivity" },
|
|
95
|
-
.on("postgres_changes", { event: "DELETE", schema: "public", table: "connectivity" },
|
|
96
|
-
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "connectivity" },
|
|
97
|
-
.on("postgres_changes", { event: "INSERT", schema: "public", table: "sessions" },
|
|
98
|
-
.on("postgres_changes", { event: "DELETE", schema: "public", table: "sessions" },
|
|
99
|
-
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "sessions" },
|
|
121
|
+
.on("postgres_changes", { event: "INSERT", schema: "public", table: "connectivity" }, handleConnectivityInserts)
|
|
122
|
+
.on("postgres_changes", { event: "DELETE", schema: "public", table: "connectivity" }, handleConnectivityDeletes)
|
|
123
|
+
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "connectivity" }, handleConnectivityUpdates)
|
|
124
|
+
.on("postgres_changes", { event: "INSERT", schema: "public", table: "sessions" }, handleSessionInserts)
|
|
125
|
+
.on("postgres_changes", { event: "DELETE", schema: "public", table: "sessions" }, handleSessionDeletes)
|
|
126
|
+
.on("postgres_changes", { event: "UPDATE", schema: "public", table: "sessions" }, handleSessionUpdates)
|
|
100
127
|
.subscribe((status) => {
|
|
101
128
|
console.log("[DB Listener] Subscription status:", status);
|
|
102
129
|
if (status === "SUBSCRIBED") {
|
package/dist/store/scout.d.ts
CHANGED
|
@@ -93,11 +93,23 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
|
|
|
93
93
|
payload: any;
|
|
94
94
|
type: string;
|
|
95
95
|
}) => void;
|
|
96
|
+
addSessionToStore: (state: import("immer").WritableDraft<ScoutState>, action: {
|
|
97
|
+
payload: any;
|
|
98
|
+
type: string;
|
|
99
|
+
}) => void;
|
|
100
|
+
deleteSessionFromStore: (state: import("immer").WritableDraft<ScoutState>, action: {
|
|
101
|
+
payload: any;
|
|
102
|
+
type: string;
|
|
103
|
+
}) => void;
|
|
104
|
+
updateSessionInStore: (state: import("immer").WritableDraft<ScoutState>, action: {
|
|
105
|
+
payload: any;
|
|
106
|
+
type: string;
|
|
107
|
+
}) => void;
|
|
96
108
|
setUser: (state: import("immer").WritableDraft<ScoutState>, action: {
|
|
97
109
|
payload: any;
|
|
98
110
|
type: string;
|
|
99
111
|
}) => void;
|
|
100
112
|
}, "scout", "scout", import("@reduxjs/toolkit").SliceSelectors<ScoutState>>;
|
|
101
|
-
export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">;
|
|
113
|
+
export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">, addSessionToStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addSessionToStore">, deleteSessionFromStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteSessionFromStore">, updateSessionInStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionInStore">;
|
|
102
114
|
declare const _default: import("redux").Reducer<ScoutState>;
|
|
103
115
|
export default _default;
|
package/dist/store/scout.js
CHANGED
|
@@ -192,11 +192,38 @@ export const scoutSlice = createSlice({
|
|
|
192
192
|
herd_module.events_page_index = new_page_index;
|
|
193
193
|
}
|
|
194
194
|
},
|
|
195
|
+
addSessionToStore: (state, action) => {
|
|
196
|
+
const session = action.payload;
|
|
197
|
+
// Find the herd module that contains the device for this session
|
|
198
|
+
for (const herd_module of state.herd_modules) {
|
|
199
|
+
const device = herd_module.devices.find((d) => d.id === session.device_id);
|
|
200
|
+
if (device) {
|
|
201
|
+
herd_module.sessions = [session, ...herd_module.sessions];
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
deleteSessionFromStore: (state, action) => {
|
|
207
|
+
const sessionId = action.payload.id;
|
|
208
|
+
for (const herd_module of state.herd_modules) {
|
|
209
|
+
herd_module.sessions = herd_module.sessions.filter((session) => session.id !== sessionId);
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
updateSessionInStore: (state, action) => {
|
|
213
|
+
const updatedSession = action.payload;
|
|
214
|
+
for (const herd_module of state.herd_modules) {
|
|
215
|
+
const sessionIndex = herd_module.sessions.findIndex((session) => session.id === updatedSession.id);
|
|
216
|
+
if (sessionIndex !== -1) {
|
|
217
|
+
herd_module.sessions[sessionIndex] = updatedSession;
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
195
222
|
setUser: (state, action) => {
|
|
196
223
|
state.user = action.payload;
|
|
197
224
|
},
|
|
198
225
|
},
|
|
199
226
|
});
|
|
200
227
|
// Action creators are generated for each case reducer function
|
|
201
|
-
export const { setHerdModules, setStatus, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, } = scoutSlice.actions;
|
|
228
|
+
export const { setHerdModules, setStatus, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, } = scoutSlice.actions;
|
|
202
229
|
export default scoutSlice.reducer;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import { IDevice, IEventWithTags, IHerd, IPlan, IUserAndRole, IZoneWithActions } from "../types/db";
|
|
2
|
+
import { IDevice, IEventWithTags, IHerd, IPlan, IUserAndRole, IZoneWithActions, ISessionWithCoordinates } from "../types/db";
|
|
3
3
|
export declare class HerdModule {
|
|
4
4
|
herd: IHerd;
|
|
5
5
|
devices: IDevice[];
|
|
6
6
|
events: IEventWithTags[];
|
|
7
7
|
zones: IZoneWithActions[];
|
|
8
|
+
sessions: ISessionWithCoordinates[];
|
|
8
9
|
timestamp_last_refreshed: number;
|
|
9
10
|
user_roles: IUserAndRole[] | null;
|
|
10
11
|
events_page_index: number;
|
|
@@ -12,7 +13,7 @@ export declare class HerdModule {
|
|
|
12
13
|
total_events_with_filters: number;
|
|
13
14
|
labels: string[];
|
|
14
15
|
plans: IPlan[];
|
|
15
|
-
constructor(herd: IHerd, devices: IDevice[], events: IEventWithTags[], timestamp_last_refreshed: number, user_roles?: IUserAndRole[] | null, events_page_index?: number, total_events?: number, total_events_with_filters?: number, labels?: string[], plans?: IPlan[], zones?: IZoneWithActions[]);
|
|
16
|
+
constructor(herd: IHerd, devices: IDevice[], events: IEventWithTags[], timestamp_last_refreshed: number, user_roles?: IUserAndRole[] | null, events_page_index?: number, total_events?: number, total_events_with_filters?: number, labels?: string[], plans?: IPlan[], zones?: IZoneWithActions[], sessions?: ISessionWithCoordinates[]);
|
|
16
17
|
to_serializable(): IHerdModule;
|
|
17
18
|
static from_herd(herd: IHerd, client: SupabaseClient): Promise<HerdModule>;
|
|
18
19
|
}
|
|
@@ -28,4 +29,5 @@ export interface IHerdModule {
|
|
|
28
29
|
labels: string[];
|
|
29
30
|
plans: IPlan[];
|
|
30
31
|
zones: IZoneWithActions[];
|
|
32
|
+
sessions: ISessionWithCoordinates[];
|
|
31
33
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { LABELS } from "../constants/annotator";
|
|
2
2
|
import { get_devices_by_herd } from "../helpers/devices";
|
|
3
|
-
import { server_get_total_events_by_herd } from "../helpers/events";
|
|
3
|
+
import { EnumSessionsVisibility, server_get_total_events_by_herd, } from "../helpers/events";
|
|
4
4
|
import { server_get_plans_by_herd } from "../helpers/plans";
|
|
5
5
|
import { server_get_events_and_tags_for_device } from "../helpers/tags";
|
|
6
6
|
import { server_get_users_with_herd_access } from "../helpers/users";
|
|
7
7
|
import { EnumWebResponse } from "./requests";
|
|
8
8
|
import { server_get_more_zones_and_actions_for_herd } from "../helpers/zones";
|
|
9
9
|
import { server_list_api_keys } from "../api_keys/actions";
|
|
10
|
+
import { getSessionsByHerdId } from "../helpers/sessions";
|
|
10
11
|
export class HerdModule {
|
|
11
|
-
constructor(herd, devices, events, timestamp_last_refreshed, user_roles = null, events_page_index = 0, total_events = 0, total_events_with_filters = 0, labels = [], plans = [], zones = []) {
|
|
12
|
+
constructor(herd, devices, events, timestamp_last_refreshed, user_roles = null, events_page_index = 0, total_events = 0, total_events_with_filters = 0, labels = [], plans = [], zones = [], sessions = []) {
|
|
12
13
|
this.user_roles = null;
|
|
13
14
|
this.events_page_index = 0;
|
|
14
15
|
this.total_events = 0;
|
|
@@ -26,6 +27,7 @@ export class HerdModule {
|
|
|
26
27
|
this.labels = labels;
|
|
27
28
|
this.plans = plans;
|
|
28
29
|
this.zones = zones;
|
|
30
|
+
this.sessions = sessions;
|
|
29
31
|
}
|
|
30
32
|
to_serializable() {
|
|
31
33
|
return {
|
|
@@ -40,43 +42,103 @@ export class HerdModule {
|
|
|
40
42
|
labels: this.labels,
|
|
41
43
|
plans: this.plans,
|
|
42
44
|
zones: this.zones,
|
|
45
|
+
sessions: this.sessions,
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
static async from_herd(herd, client) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const new_devices = response_new_devices.data;
|
|
54
|
-
// get api keys for each device... run requests in parallel
|
|
55
|
-
if (new_devices.length > 0) {
|
|
56
|
-
let api_keys_promises = new_devices.map((device) => server_list_api_keys(device.id?.toString() ?? ""));
|
|
57
|
-
let api_keys = await Promise.all(api_keys_promises);
|
|
58
|
-
for (let i = 0; i < new_devices.length; i++) {
|
|
59
|
-
new_devices[i].api_keys_scout = api_keys[i];
|
|
49
|
+
try {
|
|
50
|
+
// load devices
|
|
51
|
+
let response_new_devices = await get_devices_by_herd(herd.id, client);
|
|
52
|
+
if (response_new_devices.status == EnumWebResponse.ERROR ||
|
|
53
|
+
!response_new_devices.data) {
|
|
54
|
+
console.warn("No devices found for herd");
|
|
55
|
+
return new HerdModule(herd, [], [], Date.now());
|
|
60
56
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
const new_devices = response_new_devices.data;
|
|
58
|
+
// get api keys for each device... run requests in parallel
|
|
59
|
+
if (new_devices.length > 0) {
|
|
60
|
+
try {
|
|
61
|
+
let api_keys_promises = new_devices.map((device) => server_list_api_keys(device.id?.toString() ?? "").catch((error) => {
|
|
62
|
+
console.warn(`Failed to get API keys for device ${device.id}:`, error);
|
|
63
|
+
return undefined;
|
|
64
|
+
}));
|
|
65
|
+
let api_keys = await Promise.all(api_keys_promises);
|
|
66
|
+
for (let i = 0; i < new_devices.length; i++) {
|
|
67
|
+
new_devices[i].api_keys_scout = api_keys[i];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.warn("Failed to load API keys for devices:", error);
|
|
72
|
+
// Continue without API keys
|
|
73
|
+
}
|
|
76
74
|
}
|
|
75
|
+
// get recent events for each device... run requests in parallel
|
|
76
|
+
let recent_events_promises = new_devices.map((device) => server_get_events_and_tags_for_device(device.id ?? 0).catch((error) => {
|
|
77
|
+
console.warn(`Failed to get events for device ${device.id}:`, error);
|
|
78
|
+
return { status: EnumWebResponse.ERROR, data: null };
|
|
79
|
+
}));
|
|
80
|
+
// Run all requests in parallel with individual error handling
|
|
81
|
+
const [recent_events, res_zones, res_user_roles, total_event_count, res_plans, res_sessions,] = await Promise.allSettled([
|
|
82
|
+
Promise.all(recent_events_promises),
|
|
83
|
+
server_get_more_zones_and_actions_for_herd(herd.id, 0, 10).catch((error) => {
|
|
84
|
+
console.warn("Failed to get zones and actions:", error);
|
|
85
|
+
return { status: EnumWebResponse.ERROR, data: null };
|
|
86
|
+
}),
|
|
87
|
+
server_get_users_with_herd_access(herd.id).catch((error) => {
|
|
88
|
+
console.warn("Failed to get user roles:", error);
|
|
89
|
+
return { status: EnumWebResponse.ERROR, data: null };
|
|
90
|
+
}),
|
|
91
|
+
server_get_total_events_by_herd(herd.id, EnumSessionsVisibility.Exclude).catch((error) => {
|
|
92
|
+
console.warn("Failed to get total events count:", error);
|
|
93
|
+
return { status: EnumWebResponse.ERROR, data: null };
|
|
94
|
+
}),
|
|
95
|
+
server_get_plans_by_herd(herd.id).catch((error) => {
|
|
96
|
+
console.warn("Failed to get plans:", error);
|
|
97
|
+
return { status: EnumWebResponse.ERROR, data: null };
|
|
98
|
+
}),
|
|
99
|
+
getSessionsByHerdId(client, herd.id).catch((error) => {
|
|
100
|
+
console.warn("Failed to get sessions:", error);
|
|
101
|
+
return [];
|
|
102
|
+
}),
|
|
103
|
+
]);
|
|
104
|
+
// Process recent events with error handling
|
|
105
|
+
if (recent_events.status === "fulfilled") {
|
|
106
|
+
for (let i = 0; i < new_devices.length; i++) {
|
|
107
|
+
try {
|
|
108
|
+
let x = recent_events.value[i]?.data;
|
|
109
|
+
if (recent_events.value[i]?.status == EnumWebResponse.SUCCESS &&
|
|
110
|
+
x) {
|
|
111
|
+
new_devices[i].recent_events = x;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
console.warn(`Failed to process events for device ${new_devices[i].id}:`, error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Extract data with safe fallbacks
|
|
120
|
+
const zones = res_zones.status === "fulfilled" && res_zones.value?.data
|
|
121
|
+
? res_zones.value.data
|
|
122
|
+
: [];
|
|
123
|
+
const user_roles = res_user_roles.status === "fulfilled" && res_user_roles.value?.data
|
|
124
|
+
? res_user_roles.value.data
|
|
125
|
+
: null;
|
|
126
|
+
const total_events = total_event_count.status === "fulfilled" &&
|
|
127
|
+
total_event_count.value?.data
|
|
128
|
+
? total_event_count.value.data
|
|
129
|
+
: 0;
|
|
130
|
+
const plans = res_plans.status === "fulfilled" && res_plans.value?.data
|
|
131
|
+
? res_plans.value.data
|
|
132
|
+
: [];
|
|
133
|
+
const sessions = res_sessions.status === "fulfilled" ? res_sessions.value : [];
|
|
134
|
+
// TODO: store in DB and retrieve on load?
|
|
135
|
+
const newLabels = LABELS;
|
|
136
|
+
return new HerdModule(herd, new_devices, [], Date.now(), user_roles, 0, total_events, total_events, newLabels, plans, zones, sessions);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error("Critical error in HerdModule.from_herd:", error);
|
|
140
|
+
// Return a minimal but valid HerdModule instance to prevent complete failure
|
|
141
|
+
return new HerdModule(herd, [], [], Date.now());
|
|
77
142
|
}
|
|
78
|
-
// TODO: store in DB and retrieve on load?
|
|
79
|
-
const newLabels = LABELS;
|
|
80
|
-
return new HerdModule(herd, new_devices, [], Date.now(), res_user_roles.data, 0, total_event_count.data ? total_event_count.data : 0, total_event_count.data ? total_event_count.data : 0, newLabels, res_plans.data ? res_plans.data : [], res_zones.data ? res_zones.data : []);
|
|
81
143
|
}
|
|
82
144
|
}
|