@adventurelabs/scout-core 2.0.18 → 2.1.0
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/client/index.d.ts +4 -0
- package/dist/client/index.js +4 -0
- package/dist/helpers/cache.d.ts +4 -4
- package/dist/helpers/cache.js +52 -17
- package/dist/helpers/eventMedia.d.ts +6 -4
- package/dist/helpers/eventMedia.js +7 -6
- package/dist/helpers/gallery.d.ts +4 -0
- package/dist/helpers/gallery.js +5 -0
- package/dist/helpers/gallery.queries.d.ts +14 -0
- package/dist/helpers/gallery.queries.js +49 -0
- package/dist/helpers/galleryMedia.d.ts +9 -0
- package/dist/helpers/galleryMedia.js +41 -0
- package/dist/helpers/herd_modules.queries.js +14 -6
- package/dist/helpers/mediaRows.d.ts +12 -0
- package/dist/helpers/mediaRows.js +80 -0
- package/dist/helpers/mediaState.d.ts +33 -0
- package/dist/helpers/mediaState.js +86 -0
- package/dist/helpers/media_urls.d.ts +2 -1
- package/dist/helpers/media_urls.js +13 -2
- package/dist/helpers/parts.d.ts +7 -2
- package/dist/helpers/parts.js +16 -7
- package/dist/helpers/parts_server.d.ts +1 -1
- package/dist/helpers/product_catalog.d.ts +9 -0
- package/dist/helpers/product_catalog.js +36 -0
- package/dist/helpers/session_incidents_server.d.ts +5 -0
- package/dist/helpers/storage_internal.d.ts +4 -3
- package/dist/helpers/storage_internal.js +46 -14
- package/dist/helpers/tags.queries.js +2 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useInfiniteQuery.d.ts +3 -1
- package/dist/hooks/useInfiniteQuery.js +37 -43
- package/dist/hooks/useScoutRealtimeBroadcast.d.ts +4 -0
- package/dist/hooks/useScoutRealtimeBroadcast.js +76 -11
- package/dist/hooks/useScoutRefresh.js +18 -11
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +4 -0
- package/dist/store/api.d.ts +389 -9
- package/dist/store/api.js +163 -75
- package/dist/store/configureStore.d.ts +4 -0
- package/dist/store/hooks.d.ts +4 -1
- package/dist/store/hooks.js +16 -0
- package/dist/store/scout.d.ts +4 -2
- package/dist/store/scout.js +21 -2
- package/dist/types/db.d.ts +19 -5
- package/dist/types/herd_module.d.ts +12 -1
- package/dist/types/supabase.d.ts +77 -0
- package/package.json +4 -2
package/dist/store/api.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react";
|
|
3
|
-
import { addArtifactMediaUrls, addEventMediaUrls, createSignedUrlMap, } from "../helpers/media_urls";
|
|
3
|
+
import { addArtifactMediaUrls, addEventMediaUrls, addGalleryMediaUrls, createSignedUrlMap, } from "../helpers/media_urls";
|
|
4
4
|
import { collectArtifactStoragePaths, withArtifactMediaUrls, } from "../helpers/artifactMedia";
|
|
5
5
|
import { collectEventStoragePaths, withEventMediaUrls, } from "../helpers/eventMedia";
|
|
6
|
+
import { normalizePageLimit, splitOverFetchedPage } from "../helpers/mediaRows";
|
|
6
7
|
async function signedUrlMapForFeedRows(supabase, rows) {
|
|
7
8
|
return createSignedUrlMap(supabase, rows.flatMap((row) => [
|
|
8
9
|
...collectEventStoragePaths([row.event_data]),
|
|
@@ -11,11 +12,65 @@ async function signedUrlMapForFeedRows(supabase, rows) {
|
|
|
11
12
|
: []),
|
|
12
13
|
]));
|
|
13
14
|
}
|
|
15
|
+
/** Cursor for the row a page ends on, shared by the feed and gallery projections. */
|
|
16
|
+
const cursorForRow = (row) => row
|
|
17
|
+
? {
|
|
18
|
+
timestamp: row.sort_ts ?? "",
|
|
19
|
+
id: row.sort_id ?? 0,
|
|
20
|
+
feed_type: row.feed_type ?? "",
|
|
21
|
+
}
|
|
22
|
+
: null;
|
|
23
|
+
/** Signs a gallery page, over-fetched by one on the same contract as the feed. */
|
|
24
|
+
async function toGalleryResponse(supabase, rows, limit) {
|
|
25
|
+
const { rows: resultRows, hasMore } = splitOverFetchedPage(rows, limit);
|
|
26
|
+
const items = await addGalleryMediaUrls(supabase, resultRows);
|
|
27
|
+
// `last` is absent when limit is 0, which still over-fetches one row and so reports hasMore.
|
|
28
|
+
const last = resultRows[resultRows.length - 1];
|
|
29
|
+
return {
|
|
30
|
+
items,
|
|
31
|
+
nextCursor: hasMore && last
|
|
32
|
+
? cursorForRow({
|
|
33
|
+
sort_ts: last.sort_ts,
|
|
34
|
+
sort_id: last.id,
|
|
35
|
+
feed_type: last.feed_type,
|
|
36
|
+
})
|
|
37
|
+
: null,
|
|
38
|
+
hasMore,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Signs a feed page; the RPCs return `limit + 1` rows, so an exactly-full page is terminal. */
|
|
42
|
+
async function toFeedResponse(supabase, rows, limit) {
|
|
43
|
+
const { rows: resultRows, hasMore } = splitOverFetchedPage(rows, limit);
|
|
44
|
+
let urlMap = new Map();
|
|
45
|
+
try {
|
|
46
|
+
urlMap = await signedUrlMapForFeedRows(supabase, resultRows);
|
|
47
|
+
}
|
|
48
|
+
catch (urlError) {
|
|
49
|
+
console.warn("Failed to generate signed URLs for feed:", urlError);
|
|
50
|
+
}
|
|
51
|
+
const items = resultRows.map((row) => ({
|
|
52
|
+
...row,
|
|
53
|
+
event_data: row.event_data
|
|
54
|
+
? withEventMediaUrls(row.event_data, urlMap)
|
|
55
|
+
: null,
|
|
56
|
+
artifact_data: row.artifact_data
|
|
57
|
+
? withArtifactMediaUrls(row.artifact_data, urlMap)
|
|
58
|
+
: null,
|
|
59
|
+
}));
|
|
60
|
+
return {
|
|
61
|
+
items,
|
|
62
|
+
nextCursor: hasMore
|
|
63
|
+
? cursorForRow(resultRows[resultRows.length - 1])
|
|
64
|
+
: null,
|
|
65
|
+
hasMore,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
14
68
|
// Custom serialize function to exclude supabase client
|
|
15
69
|
const serializeQueryArgs = ({ queryArgs, endpointDefinition, endpointName, }) => {
|
|
16
70
|
const { supabase, ...serializableArgs } = queryArgs;
|
|
17
71
|
return JSON.stringify({ endpointName, args: serializableArgs });
|
|
18
72
|
};
|
|
73
|
+
const validEntityId = (id) => Number.isSafeInteger(id) && id > 0;
|
|
19
74
|
// Create the API slice
|
|
20
75
|
export const scoutApi = createApi({
|
|
21
76
|
reducerPath: "scoutApi",
|
|
@@ -400,15 +455,19 @@ export const scoutApi = createApi({
|
|
|
400
455
|
getFeedInfiniteByHerd: builder.query({
|
|
401
456
|
serializeQueryArgs,
|
|
402
457
|
async queryFn({ herdId, limit = 20, cursor, rangeStart, rangeEnd, supabase, }) {
|
|
458
|
+
const pageLimit = normalizePageLimit(limit);
|
|
403
459
|
try {
|
|
404
|
-
if (!herdId) {
|
|
460
|
+
if (!validEntityId(herdId)) {
|
|
405
461
|
return {
|
|
406
|
-
error: {
|
|
462
|
+
error: {
|
|
463
|
+
status: "CUSTOM_ERROR",
|
|
464
|
+
error: "Herd ID must be a positive safe integer",
|
|
465
|
+
},
|
|
407
466
|
};
|
|
408
467
|
}
|
|
409
468
|
const { data, error } = await supabase.rpc("get_feed_infinite_by_herd", {
|
|
410
469
|
herd_id_caller: herdId,
|
|
411
|
-
limit_caller:
|
|
470
|
+
limit_caller: pageLimit + 1,
|
|
412
471
|
cursor_timestamp: cursor?.timestamp ?? null,
|
|
413
472
|
cursor_id: cursor?.id ?? null,
|
|
414
473
|
cursor_feed_type: cursor?.feed_type ?? null,
|
|
@@ -420,60 +479,35 @@ export const scoutApi = createApi({
|
|
|
420
479
|
error: { status: "SUPABASE_ERROR", error: error.message },
|
|
421
480
|
};
|
|
422
481
|
}
|
|
423
|
-
const rows = data || [];
|
|
424
|
-
// Full page (rows.length >= limit) means there might be more; only signal hasMore when we have a nextCursor
|
|
425
|
-
const hasMore = rows.length >= limit;
|
|
426
|
-
const resultRows = hasMore ? rows.slice(0, limit) : rows;
|
|
427
|
-
let urlMap = new Map();
|
|
428
|
-
try {
|
|
429
|
-
urlMap = await signedUrlMapForFeedRows(supabase, resultRows);
|
|
430
|
-
}
|
|
431
|
-
catch (urlError) {
|
|
432
|
-
console.warn("Failed to generate signed URLs for feed:", urlError);
|
|
433
|
-
}
|
|
434
|
-
const items = resultRows.map((row) => ({
|
|
435
|
-
...row,
|
|
436
|
-
event_data: row.event_data
|
|
437
|
-
? withEventMediaUrls(row.event_data, urlMap)
|
|
438
|
-
: null,
|
|
439
|
-
artifact_data: row.artifact_data
|
|
440
|
-
? withArtifactMediaUrls(row.artifact_data, urlMap)
|
|
441
|
-
: null,
|
|
442
|
-
}));
|
|
443
|
-
const last = resultRows[resultRows.length - 1];
|
|
444
|
-
const nextCursor = resultRows.length > 0
|
|
445
|
-
? {
|
|
446
|
-
timestamp: last.sort_ts ?? "",
|
|
447
|
-
id: last.sort_id ?? 0,
|
|
448
|
-
feed_type: last.feed_type ?? "",
|
|
449
|
-
}
|
|
450
|
-
: null;
|
|
451
482
|
return {
|
|
452
|
-
data:
|
|
453
|
-
items,
|
|
454
|
-
nextCursor,
|
|
455
|
-
hasMore: nextCursor != null && hasMore,
|
|
456
|
-
},
|
|
483
|
+
data: await toFeedResponse(supabase, data || [], pageLimit),
|
|
457
484
|
};
|
|
458
485
|
}
|
|
459
486
|
catch (err) {
|
|
460
487
|
return { error: { status: "FETCH_ERROR", error: String(err) } };
|
|
461
488
|
}
|
|
462
489
|
},
|
|
463
|
-
providesTags: () => [
|
|
490
|
+
providesTags: () => [
|
|
491
|
+
{ type: "Event", id: "LIST" },
|
|
492
|
+
{ type: "Artifact", id: "LIST" },
|
|
493
|
+
],
|
|
464
494
|
}),
|
|
465
495
|
getFeedInfiniteByDevice: builder.query({
|
|
466
496
|
serializeQueryArgs,
|
|
467
497
|
async queryFn({ deviceId, limit = 20, cursor, rangeStart, rangeEnd, supabase, }) {
|
|
498
|
+
const pageLimit = normalizePageLimit(limit);
|
|
468
499
|
try {
|
|
469
|
-
if (!deviceId) {
|
|
500
|
+
if (!validEntityId(deviceId)) {
|
|
470
501
|
return {
|
|
471
|
-
error: {
|
|
502
|
+
error: {
|
|
503
|
+
status: "CUSTOM_ERROR",
|
|
504
|
+
error: "Device ID must be a positive safe integer",
|
|
505
|
+
},
|
|
472
506
|
};
|
|
473
507
|
}
|
|
474
508
|
const { data, error } = await supabase.rpc("get_feed_infinite_by_device", {
|
|
475
509
|
device_id_caller: deviceId,
|
|
476
|
-
limit_caller:
|
|
510
|
+
limit_caller: pageLimit + 1,
|
|
477
511
|
cursor_timestamp: cursor?.timestamp ?? null,
|
|
478
512
|
cursor_id: cursor?.id ?? null,
|
|
479
513
|
cursor_feed_type: cursor?.feed_type ?? null,
|
|
@@ -485,47 +519,101 @@ export const scoutApi = createApi({
|
|
|
485
519
|
error: { status: "SUPABASE_ERROR", error: error.message },
|
|
486
520
|
};
|
|
487
521
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
522
|
+
return {
|
|
523
|
+
data: await toFeedResponse(supabase, data || [], pageLimit),
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
catch (err) {
|
|
527
|
+
return { error: { status: "FETCH_ERROR", error: String(err) } };
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
providesTags: () => [
|
|
531
|
+
{ type: "Event", id: "LIST" },
|
|
532
|
+
{ type: "Artifact", id: "LIST" },
|
|
533
|
+
],
|
|
534
|
+
}),
|
|
535
|
+
// =====================================================
|
|
536
|
+
// GALLERY INFINITE QUERIES (lean merged events + artifacts)
|
|
537
|
+
// =====================================================
|
|
538
|
+
getGalleryInfiniteByHerd: builder.query({
|
|
539
|
+
serializeQueryArgs,
|
|
540
|
+
async queryFn({ herdId, limit = 20, cursor, rangeStart, rangeEnd, supabase, }) {
|
|
541
|
+
const pageLimit = normalizePageLimit(limit);
|
|
542
|
+
try {
|
|
543
|
+
if (!validEntityId(herdId)) {
|
|
544
|
+
return {
|
|
545
|
+
error: {
|
|
546
|
+
status: "CUSTOM_ERROR",
|
|
547
|
+
error: "Herd ID must be a positive safe integer",
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
const { data, error } = await supabase.rpc("get_gallery_infinite_by_herd", {
|
|
552
|
+
herd_id_caller: herdId,
|
|
553
|
+
limit_caller: pageLimit + 1,
|
|
554
|
+
cursor_timestamp: cursor?.timestamp ?? null,
|
|
555
|
+
cursor_id: cursor?.id ?? null,
|
|
556
|
+
cursor_feed_type: cursor?.feed_type ?? null,
|
|
557
|
+
range_start: rangeStart ?? null,
|
|
558
|
+
range_end: rangeEnd ?? null,
|
|
559
|
+
});
|
|
560
|
+
if (error) {
|
|
561
|
+
return {
|
|
562
|
+
error: { status: "SUPABASE_ERROR", error: error.message },
|
|
563
|
+
};
|
|
495
564
|
}
|
|
496
|
-
catch (urlError) {
|
|
497
|
-
console.warn("Failed to generate signed URLs for feed:", urlError);
|
|
498
|
-
}
|
|
499
|
-
const items = resultRows.map((row) => ({
|
|
500
|
-
...row,
|
|
501
|
-
event_data: row.event_data
|
|
502
|
-
? withEventMediaUrls(row.event_data, urlMap)
|
|
503
|
-
: null,
|
|
504
|
-
artifact_data: row.artifact_data
|
|
505
|
-
? withArtifactMediaUrls(row.artifact_data, urlMap)
|
|
506
|
-
: null,
|
|
507
|
-
}));
|
|
508
|
-
const last = resultRows[resultRows.length - 1];
|
|
509
|
-
const nextCursor = resultRows.length > 0
|
|
510
|
-
? {
|
|
511
|
-
timestamp: last.sort_ts ?? "",
|
|
512
|
-
id: last.sort_id ?? 0,
|
|
513
|
-
feed_type: last.feed_type ?? "",
|
|
514
|
-
}
|
|
515
|
-
: null;
|
|
516
565
|
return {
|
|
517
|
-
data:
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
566
|
+
data: await toGalleryResponse(supabase, data || [], pageLimit),
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
return { error: { status: "FETCH_ERROR", error: String(err) } };
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
providesTags: () => [
|
|
574
|
+
{ type: "Event", id: "LIST" },
|
|
575
|
+
{ type: "Artifact", id: "LIST" },
|
|
576
|
+
],
|
|
577
|
+
}),
|
|
578
|
+
getGalleryInfiniteByDevice: builder.query({
|
|
579
|
+
serializeQueryArgs,
|
|
580
|
+
async queryFn({ deviceId, limit = 20, cursor, rangeStart, rangeEnd, supabase, }) {
|
|
581
|
+
const pageLimit = normalizePageLimit(limit);
|
|
582
|
+
try {
|
|
583
|
+
if (!validEntityId(deviceId)) {
|
|
584
|
+
return {
|
|
585
|
+
error: {
|
|
586
|
+
status: "CUSTOM_ERROR",
|
|
587
|
+
error: "Device ID must be a positive safe integer",
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
const { data, error } = await supabase.rpc("get_gallery_infinite_by_device", {
|
|
592
|
+
device_id_caller: deviceId,
|
|
593
|
+
limit_caller: pageLimit + 1,
|
|
594
|
+
cursor_timestamp: cursor?.timestamp ?? null,
|
|
595
|
+
cursor_id: cursor?.id ?? null,
|
|
596
|
+
cursor_feed_type: cursor?.feed_type ?? null,
|
|
597
|
+
range_start: rangeStart ?? null,
|
|
598
|
+
range_end: rangeEnd ?? null,
|
|
599
|
+
});
|
|
600
|
+
if (error) {
|
|
601
|
+
return {
|
|
602
|
+
error: { status: "SUPABASE_ERROR", error: error.message },
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
return {
|
|
606
|
+
data: await toGalleryResponse(supabase, data || [], pageLimit),
|
|
522
607
|
};
|
|
523
608
|
}
|
|
524
609
|
catch (err) {
|
|
525
610
|
return { error: { status: "FETCH_ERROR", error: String(err) } };
|
|
526
611
|
}
|
|
527
612
|
},
|
|
528
|
-
providesTags: () => [
|
|
613
|
+
providesTags: () => [
|
|
614
|
+
{ type: "Event", id: "LIST" },
|
|
615
|
+
{ type: "Artifact", id: "LIST" },
|
|
616
|
+
],
|
|
529
617
|
}),
|
|
530
618
|
// =====================================================
|
|
531
619
|
// ANALYSIS JOBS / TASKS INFINITE (platform superadmin RLS)
|
|
@@ -634,4 +722,4 @@ export const scoutApi = createApi({
|
|
|
634
722
|
}),
|
|
635
723
|
});
|
|
636
724
|
// Export hooks for usage in functional components
|
|
637
|
-
export const { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, useGetFeedInfiniteByHerdQuery, useGetFeedInfiniteByDeviceQuery, useGetAnalysisJobsInfiniteQuery, useGetAnalysisTasksInfiniteQuery, } = scoutApi;
|
|
725
|
+
export const { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, useGetFeedInfiniteByHerdQuery, useGetFeedInfiniteByDeviceQuery, useGetGalleryInfiniteByHerdQuery, useGetGalleryInfiniteByDeviceQuery, useGetAnalysisJobsInfiniteQuery, useGetAnalysisTasksInfiniteQuery, } = scoutApi;
|
|
@@ -21,6 +21,8 @@ export declare const configureScoutStore: () => import("@reduxjs/toolkit").Enhan
|
|
|
21
21
|
}, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
|
|
22
22
|
getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").FeedInfiniteByHerdQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
|
|
23
23
|
getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").FeedInfiniteByDeviceQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
|
|
24
|
+
getGalleryInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").GalleryInfiniteByHerdQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").GalleryInfiniteResponse, "scoutApi", unknown>;
|
|
25
|
+
getGalleryInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").GalleryInfiniteByDeviceQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").GalleryInfiniteResponse, "scoutApi", unknown>;
|
|
24
26
|
getAnalysisJobsInfinite: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").AnalysisJobsInfiniteQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").AnalysisJobsInfiniteResponse, "scoutApi", unknown>;
|
|
25
27
|
getAnalysisTasksInfinite: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").AnalysisTasksInfiniteQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").AnalysisTasksInfiniteResponse, "scoutApi", unknown>;
|
|
26
28
|
}, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", "scoutApi">;
|
|
@@ -48,6 +50,8 @@ export declare const configureScoutStore: () => import("@reduxjs/toolkit").Enhan
|
|
|
48
50
|
}, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
|
|
49
51
|
getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").FeedInfiniteByHerdQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
|
|
50
52
|
getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").FeedInfiniteByDeviceQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
|
|
53
|
+
getGalleryInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").GalleryInfiniteByHerdQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").GalleryInfiniteResponse, "scoutApi", unknown>;
|
|
54
|
+
getGalleryInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").GalleryInfiniteByDeviceQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").GalleryInfiniteResponse, "scoutApi", unknown>;
|
|
51
55
|
getAnalysisJobsInfinite: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").AnalysisJobsInfiniteQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").AnalysisJobsInfiniteResponse, "scoutApi", unknown>;
|
|
52
56
|
getAnalysisTasksInfinite: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").AnalysisTasksInfiniteQueryArgs, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", import("./api").AnalysisTasksInfiniteResponse, "scoutApi", unknown>;
|
|
53
57
|
}, "Session" | "Event" | "Artifact" | "AnalysisJob" | "AnalysisTask", "scoutApi">;
|
package/dist/store/hooks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LoadingPerformance } from "./scout";
|
|
2
|
-
import { ISessionSummary } from "../types/db";
|
|
2
|
+
import { IDevice, IPart, IProduct, IProductCatalog, ISessionSummary } from "../types/db";
|
|
3
3
|
export declare const useAppDispatch: import("react-redux").UseDispatch<import("redux").Dispatch<import("redux").UnknownAction>>;
|
|
4
4
|
export declare const useHerdModulesLoadingState: () => any;
|
|
5
5
|
export declare const useIsHerdModulesLoading: () => boolean;
|
|
@@ -10,4 +10,7 @@ export declare const useHerdModulesLoadingDuration: () => any;
|
|
|
10
10
|
export declare const useLoadingPerformance: () => LoadingPerformance;
|
|
11
11
|
export declare const useSessionSummariesByHerd: (herdId: number) => ISessionSummary | null;
|
|
12
12
|
export declare const useHasSessionSummaries: (herdId: number) => boolean;
|
|
13
|
+
export declare const useProductCatalog: () => IProductCatalog;
|
|
14
|
+
export declare const useProductForPart: (part: Pick<IPart, "product_number"> | null | undefined) => IProduct | null;
|
|
15
|
+
export declare const useProductsForDevice: (device: Pick<IDevice, "parts"> | null | undefined) => IProduct[];
|
|
13
16
|
export declare const useHerdModulesLoadingTimeAgo: () => string | null;
|
package/dist/store/hooks.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
2
3
|
import { useDispatch, useSelector } from "react-redux";
|
|
3
4
|
import { EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
5
|
+
import { EMPTY_PRODUCT_CATALOG, get_product_for_part, get_products_for_device, } from "../helpers/product_catalog";
|
|
4
6
|
// Simple wrapper for useDispatch to maintain compatibility
|
|
5
7
|
export const useAppDispatch = useDispatch;
|
|
6
8
|
// Selector hook for herd modules loading state
|
|
@@ -50,6 +52,20 @@ export const useHasSessionSummaries = (herdId) => {
|
|
|
50
52
|
return !!herdModule?.session_summaries;
|
|
51
53
|
});
|
|
52
54
|
};
|
|
55
|
+
// Selector hook for the shared product catalog referenced by device parts
|
|
56
|
+
export const useProductCatalog = () => {
|
|
57
|
+
return useSelector((state) => state.scout.product_catalog ?? EMPTY_PRODUCT_CATALOG);
|
|
58
|
+
};
|
|
59
|
+
// Selector hook for the product a part references
|
|
60
|
+
export const useProductForPart = (part) => {
|
|
61
|
+
const catalog = useProductCatalog();
|
|
62
|
+
return useMemo(() => get_product_for_part(catalog, part), [catalog, part]);
|
|
63
|
+
};
|
|
64
|
+
// Selector hook for the distinct products across a device's parts
|
|
65
|
+
export const useProductsForDevice = (device) => {
|
|
66
|
+
const catalog = useProductCatalog();
|
|
67
|
+
return useMemo(() => get_products_for_device(catalog, device), [catalog, device]);
|
|
68
|
+
};
|
|
53
69
|
// Selector hook for getting formatted loading time (e.g., "2.5s ago")
|
|
54
70
|
export const useHerdModulesLoadingTimeAgo = () => {
|
|
55
71
|
return useSelector((state) => {
|
package/dist/store/scout.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IUser } from "../types/db";
|
|
1
|
+
import { IProductCatalog, IUser } from "../types/db";
|
|
2
2
|
import { IHerdModule, EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
3
3
|
import { EnumDataSource, IDataSourceInfo } from "../types/data_source";
|
|
4
4
|
import { MapDeviceIdToConnectivity } from "../types/connectivity";
|
|
@@ -16,6 +16,8 @@ export interface LoadingPerformance {
|
|
|
16
16
|
}
|
|
17
17
|
export interface ScoutState {
|
|
18
18
|
herd_modules: IHerdModule[];
|
|
19
|
+
/** One shared copy of every product referenced by device parts. */
|
|
20
|
+
product_catalog: IProductCatalog;
|
|
19
21
|
herd_modules_content_hash: string | null;
|
|
20
22
|
status: EnumScoutStateStatus;
|
|
21
23
|
herd_modules_loading_state: EnumHerdModulesLoadingState;
|
|
@@ -31,5 +33,5 @@ export interface ScoutState {
|
|
|
31
33
|
export interface RootState {
|
|
32
34
|
scout: ScoutState;
|
|
33
35
|
}
|
|
34
|
-
export declare const resetScoutState: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"scout/resetScoutState">, setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setHerdModulesLoadingState: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadingState">, setLoadingPerformance: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setLoadingPerformance">, setHerdModulesLoadedInMs: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadedInMs">, setHerdModulesApiServerProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiServerProcessingDuration">, setHerdModulesApiTotalRequestDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiTotalRequestDuration">, setUserApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUserApiDuration">, setDataProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataProcessingDuration">, setCacheLoadDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setCacheLoadDuration">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, setDataSource: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSource">, setDataSourceInfo: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSourceInfo">, updateSessionSummariesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionSummariesForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, 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">, setActiveHerdGpsTrackersConnectivity: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdGpsTrackersConnectivity">;
|
|
36
|
+
export declare const resetScoutState: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"scout/resetScoutState">, setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, mergeProductCatalog: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/mergeProductCatalog">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setHerdModulesLoadingState: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadingState">, setLoadingPerformance: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setLoadingPerformance">, setHerdModulesLoadedInMs: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadedInMs">, setHerdModulesApiServerProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiServerProcessingDuration">, setHerdModulesApiTotalRequestDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiTotalRequestDuration">, setUserApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUserApiDuration">, setDataProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataProcessingDuration">, setCacheLoadDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setCacheLoadDuration">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, setDataSource: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSource">, setDataSourceInfo: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSourceInfo">, updateSessionSummariesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionSummariesForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, 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">, setActiveHerdGpsTrackersConnectivity: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdGpsTrackersConnectivity">;
|
|
35
37
|
export declare const scoutReducer: import("redux").Reducer<ScoutState>;
|
package/dist/store/scout.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createSlice, current } from "@reduxjs/toolkit";
|
|
2
|
+
import { dequal } from "dequal";
|
|
2
3
|
import { EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
3
4
|
import { EnumDataSource } from "../types/data_source";
|
|
4
5
|
import { herdModulesSemanticallyEqual } from "../helpers/herd_modules_equal";
|
|
6
|
+
import { EMPTY_PRODUCT_CATALOG } from "../helpers/product_catalog";
|
|
5
7
|
export var EnumScoutStateStatus;
|
|
6
8
|
(function (EnumScoutStateStatus) {
|
|
7
9
|
EnumScoutStateStatus["LOADING"] = "LOADING";
|
|
@@ -9,6 +11,7 @@ export var EnumScoutStateStatus;
|
|
|
9
11
|
})(EnumScoutStateStatus || (EnumScoutStateStatus = {}));
|
|
10
12
|
const initialState = {
|
|
11
13
|
herd_modules: [],
|
|
14
|
+
product_catalog: EMPTY_PRODUCT_CATALOG,
|
|
12
15
|
herd_modules_content_hash: null,
|
|
13
16
|
status: EnumScoutStateStatus.LOADING,
|
|
14
17
|
herd_modules_loading_state: EnumHerdModulesLoadingState.NOT_LOADING,
|
|
@@ -41,6 +44,10 @@ const scoutSlice = createSlice({
|
|
|
41
44
|
const contentHash = Array.isArray(payload)
|
|
42
45
|
? null
|
|
43
46
|
: payload.contentHash ?? null;
|
|
47
|
+
const productCatalog = Array.isArray(payload)
|
|
48
|
+
? current(state.product_catalog)
|
|
49
|
+
: payload.productCatalog ??
|
|
50
|
+
current(state.product_catalog);
|
|
44
51
|
if (state.active_herd_id &&
|
|
45
52
|
!modules.some((module) => module.herd.id?.toString() === state.active_herd_id)) {
|
|
46
53
|
state.active_herd_id = null;
|
|
@@ -52,13 +59,25 @@ const scoutSlice = createSlice({
|
|
|
52
59
|
return;
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
|
-
else if (herdModulesSemanticallyEqual(current(state.herd_modules), modules)
|
|
62
|
+
else if (herdModulesSemanticallyEqual(current(state.herd_modules), modules) &&
|
|
63
|
+
dequal(current(state.product_catalog), productCatalog)) {
|
|
56
64
|
return;
|
|
57
65
|
}
|
|
58
66
|
state.herd_modules = modules;
|
|
67
|
+
state.product_catalog = productCatalog;
|
|
59
68
|
state.herd_modules_content_hash = contentHash;
|
|
60
69
|
state.lastRefreshed = Date.now();
|
|
61
70
|
},
|
|
71
|
+
/**
|
|
72
|
+
* Merges products (built with `build_product_catalog`) into the shared
|
|
73
|
+
* catalog, for parts that arrive after the initial load.
|
|
74
|
+
*/
|
|
75
|
+
mergeProductCatalog: (state, action) => {
|
|
76
|
+
const incoming = action.payload;
|
|
77
|
+
Object.assign(state.product_catalog.products, incoming.products);
|
|
78
|
+
Object.assign(state.product_catalog.product_id_by_number, incoming.product_id_by_number);
|
|
79
|
+
state.herd_modules_content_hash = null;
|
|
80
|
+
},
|
|
62
81
|
setStatus: (state, action) => {
|
|
63
82
|
state.status = action.payload;
|
|
64
83
|
},
|
|
@@ -211,5 +230,5 @@ const scoutSlice = createSlice({
|
|
|
211
230
|
},
|
|
212
231
|
},
|
|
213
232
|
});
|
|
214
|
-
export const { resetScoutState, setHerdModules, setStatus, setHerdModulesLoadingState, setLoadingPerformance, setHerdModulesLoadedInMs, setHerdModulesApiServerProcessingDuration, setHerdModulesApiTotalRequestDuration, setUserApiDuration, setDataProcessingDuration, setCacheLoadDuration, setActiveHerdId, setActiveDeviceId, setDataSource, setDataSourceInfo, updateSessionSummariesForHerdModule, appendPlansToHerdModule, setUser, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, setActiveHerdGpsTrackersConnectivity, } = scoutSlice.actions;
|
|
233
|
+
export const { resetScoutState, setHerdModules, mergeProductCatalog, setStatus, setHerdModulesLoadingState, setLoadingPerformance, setHerdModulesLoadedInMs, setHerdModulesApiServerProcessingDuration, setHerdModulesApiTotalRequestDuration, setUserApiDuration, setDataProcessingDuration, setCacheLoadDuration, setActiveHerdId, setActiveDeviceId, setDataSource, setDataSourceInfo, updateSessionSummariesForHerdModule, appendPlansToHerdModule, setUser, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, setActiveHerdGpsTrackersConnectivity, } = scoutSlice.actions;
|
|
215
234
|
export const scoutReducer = scoutSlice.reducer;
|
package/dist/types/db.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type IUserProfileRow = Database["public"]["Tables"]["users"]["Row"];
|
|
|
14
14
|
export type IDeviceRow = Database["public"]["Tables"]["devices"]["Row"];
|
|
15
15
|
export type IDevice = Database["public"]["CompositeTypes"]["device_pretty_location"] & {
|
|
16
16
|
api_keys_scout?: IApiKeyScout[];
|
|
17
|
-
parts?:
|
|
17
|
+
parts?: IPart[];
|
|
18
18
|
};
|
|
19
19
|
export type IPin = Database["public"]["CompositeTypes"]["pins_pretty_location"];
|
|
20
20
|
export type IEvent = Database["public"]["Tables"]["events"]["Row"];
|
|
@@ -198,10 +198,14 @@ export type OperatingContextContactCreateInput = Pick<OperatingContextContactIns
|
|
|
198
198
|
export type OperatingContextContactUpdateInput = Partial<Pick<OperatingContextContactCreateInput, "contact_id">> & LifecyclePatch;
|
|
199
199
|
export type HerdOperatingPermissionCreateInput = Pick<HerdOperatingPermissionInsert, "herd_id" | "operating_permission_id">;
|
|
200
200
|
export type HerdOperatingPermissionUpdateInput = Partial<Pick<HerdOperatingPermissionCreateInput, "operating_permission_id">> & LifecyclePatch;
|
|
201
|
-
/**
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Products stored once and shared by every part that references them
|
|
203
|
+
* (parts.product_number -> product_numbers -> products).
|
|
204
|
+
*/
|
|
205
|
+
export interface IProductCatalog {
|
|
206
|
+
products: Record<number, IProduct>;
|
|
207
|
+
product_id_by_number: Record<string, number>;
|
|
208
|
+
}
|
|
205
209
|
export type IUserCredential = Database["public"]["Tables"]["user_credentials"]["Row"];
|
|
206
210
|
export type IUserLastActivity = Database["public"]["Tables"]["user_last_activity"]["Row"];
|
|
207
211
|
export type IHerdCredential = Database["public"]["Tables"]["herd_credentials"]["Row"];
|
|
@@ -222,6 +226,10 @@ export type ISignedMediaUrls = {
|
|
|
222
226
|
thumbnail_url?: string | null;
|
|
223
227
|
proxy_url?: string | null;
|
|
224
228
|
};
|
|
229
|
+
/** What a row holds, resolved from its file extension first and its stored media_type/modality second. */
|
|
230
|
+
export type MediaKind = MediaType | "unknown";
|
|
231
|
+
/** Availability of the media a view shows; `url_unavailable` means it exists but went unsigned. */
|
|
232
|
+
export type MediaStatus = "ready" | "processing" | "blocked" | "url_unavailable";
|
|
225
233
|
export type IArtifactWithMediaUrl = IArtifact & ISignedMediaUrls;
|
|
226
234
|
export type IEventWithMediaUrl = IEvent & ISignedMediaUrls;
|
|
227
235
|
export type IVersionsSoftwareWithBuildUrl = IVersionsSoftware & {
|
|
@@ -370,6 +378,12 @@ export type IFeedItem = {
|
|
|
370
378
|
event_data: (IEventAndTagsPrettyLocation & ISignedMediaUrls) | null;
|
|
371
379
|
artifact_data: IArtifactWithMediaUrl | null;
|
|
372
380
|
};
|
|
381
|
+
/** Lean merged events/artifacts row: media paths and a tag count, not `feed_item`'s arrays. */
|
|
382
|
+
export type IGalleryItemRow = Database["public"]["CompositeTypes"]["gallery_item"];
|
|
383
|
+
export type IGalleryItem = IGalleryItemRow & ISignedMediaUrls & {
|
|
384
|
+
media_kind: MediaKind;
|
|
385
|
+
media_status: MediaStatus;
|
|
386
|
+
};
|
|
373
387
|
export type ISessionWithCoordinates = Database["public"]["CompositeTypes"]["session_with_coordinates"];
|
|
374
388
|
export type IConnectivityWithCoordinates = Database["public"]["CompositeTypes"]["connectivity_with_coordinates"];
|
|
375
389
|
export type IEmbeddingSearchResult = Database["public"]["CompositeTypes"]["embedding_search_result"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDevice, IHerdPrettyLocation, IPlan, ILayer, IProvider, IUserAndRole, IZoneWithActions, ISessionSummary, ISessionUsageOverTime } from "../types/db";
|
|
1
|
+
import { IDevice, IHerdPrettyLocation, IPlan, ILayer, IProductCatalog, IProvider, IUserAndRole, IZoneWithActions, ISessionSummary, ISessionUsageOverTime } from "../types/db";
|
|
2
2
|
import { EnumWebResponse } from "./requests";
|
|
3
3
|
export declare enum EnumHerdModulesLoadingState {
|
|
4
4
|
NOT_LOADING = "NOT_LOADING",
|
|
@@ -19,8 +19,18 @@ export interface IHerdModule {
|
|
|
19
19
|
session_summaries: ISessionSummary | null;
|
|
20
20
|
session_usage: ISessionUsageOverTime | null;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Herd modules plus the single shared copy of every product their parts
|
|
24
|
+
* reference. Devices hold bare parts; resolve products with the
|
|
25
|
+
* `get_product_for_*` helpers instead of storing them per device.
|
|
26
|
+
*/
|
|
27
|
+
export interface IHerdModulesSnapshot {
|
|
28
|
+
herd_modules: IHerdModule[];
|
|
29
|
+
product_catalog: IProductCatalog;
|
|
30
|
+
}
|
|
22
31
|
export interface IHerdModulesResponse {
|
|
23
32
|
data: IHerdModule[];
|
|
33
|
+
product_catalog: IProductCatalog;
|
|
24
34
|
time_finished: number;
|
|
25
35
|
server_processing_time_ms: number;
|
|
26
36
|
content_hash: string;
|
|
@@ -29,6 +39,7 @@ export interface IHerdModulesResponseWithStatus {
|
|
|
29
39
|
status: EnumWebResponse;
|
|
30
40
|
msg: string;
|
|
31
41
|
data: IHerdModule[] | null;
|
|
42
|
+
product_catalog: IProductCatalog;
|
|
32
43
|
time_finished: number;
|
|
33
44
|
time_sent: number;
|
|
34
45
|
server_processing_time_ms: number;
|