@adventurelabs/scout-core 2.0.15 → 2.0.17
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 +1 -0
- package/dist/client/index.js +1 -0
- package/dist/helpers/artifactMedia.js +1 -4
- package/dist/helpers/eventMedia.d.ts +12 -0
- package/dist/helpers/eventMedia.js +29 -0
- package/dist/helpers/lifecycle_server.d.ts +4 -0
- package/dist/helpers/media_urls.d.ts +3 -9
- package/dist/helpers/media_urls.js +3 -7
- package/dist/helpers/storagePath.d.ts +2 -0
- package/dist/helpers/storagePath.js +4 -0
- package/dist/helpers/tags.queries.js +4 -0
- package/dist/hooks/useInfiniteQuery.d.ts +2 -1
- package/dist/hooks/useInfiniteQuery.js +89 -66
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/store/api.d.ts +20 -20
- package/dist/store/api.js +4 -14
- package/dist/types/db.d.ts +4 -7
- package/dist/types/supabase.d.ts +16 -0
- package/package.json +1 -1
package/dist/client/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from "../types";
|
|
|
3
3
|
export * from "../helpers/artifactMedia";
|
|
4
4
|
export * from "../helpers/bounding_boxes";
|
|
5
5
|
export * from "../helpers/email";
|
|
6
|
+
export * from "../helpers/eventMedia";
|
|
6
7
|
export * from "../helpers/eventUtils";
|
|
7
8
|
export { default as get_gps_center } from "../helpers/gps";
|
|
8
9
|
export * from "../helpers/herd_modules_equal";
|
package/dist/client/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "../types";
|
|
|
6
6
|
export * from "../helpers/artifactMedia";
|
|
7
7
|
export * from "../helpers/bounding_boxes";
|
|
8
8
|
export * from "../helpers/email";
|
|
9
|
+
export * from "../helpers/eventMedia";
|
|
9
10
|
export * from "../helpers/eventUtils";
|
|
10
11
|
export { default as get_gps_center } from "../helpers/gps";
|
|
11
12
|
export * from "../helpers/herd_modules_equal";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNonEmptyStorageFilePath } from "./storagePath";
|
|
1
|
+
import { isNonEmptyStorageFilePath, signedUrlForPath } from "./storagePath";
|
|
2
2
|
/** Collect unique non-empty storage paths used for artifact media signing. */
|
|
3
3
|
export function collectArtifactStoragePaths(artifacts) {
|
|
4
4
|
const seen = new Set();
|
|
@@ -17,9 +17,6 @@ export function collectArtifactStoragePaths(artifacts) {
|
|
|
17
17
|
}
|
|
18
18
|
return paths;
|
|
19
19
|
}
|
|
20
|
-
function signedUrlForPath(path, urlMap) {
|
|
21
|
-
return isNonEmptyStorageFilePath(path) ? urlMap.get(path) ?? null : null;
|
|
22
|
-
}
|
|
23
20
|
/** Attach signed URLs for original, thumbnail, and proxy storage paths. */
|
|
24
21
|
export function withArtifactMediaUrls(artifact, urlMap) {
|
|
25
22
|
return {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ISignedMediaUrls } from "../types/db";
|
|
2
|
+
/** Events arrive as table rows and as the event_and_tags composite, so match on shape. */
|
|
3
|
+
export type IEventMediaPaths = {
|
|
4
|
+
file_path?: string | null;
|
|
5
|
+
thumbnail_file_path?: string | null;
|
|
6
|
+
proxy_file_path?: string | null;
|
|
7
|
+
media_url?: string | null;
|
|
8
|
+
};
|
|
9
|
+
/** Collect unique non-empty storage paths used for event media signing. */
|
|
10
|
+
export declare function collectEventStoragePaths(events: Iterable<IEventMediaPaths | null | undefined>): string[];
|
|
11
|
+
/** Attach signed URLs for original, thumbnail, and proxy storage paths. */
|
|
12
|
+
export declare function withEventMediaUrls<T extends IEventMediaPaths>(event: T, urlMap: Map<string, string | null | undefined>): T & ISignedMediaUrls;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isNonEmptyStorageFilePath, signedUrlForPath } from "./storagePath";
|
|
2
|
+
/** Collect unique non-empty storage paths used for event media signing. */
|
|
3
|
+
export function collectEventStoragePaths(events) {
|
|
4
|
+
const seen = new Set();
|
|
5
|
+
const paths = [];
|
|
6
|
+
for (const event of events) {
|
|
7
|
+
for (const path of [
|
|
8
|
+
event?.file_path,
|
|
9
|
+
event?.thumbnail_file_path,
|
|
10
|
+
event?.proxy_file_path,
|
|
11
|
+
]) {
|
|
12
|
+
if (isNonEmptyStorageFilePath(path) && !seen.has(path)) {
|
|
13
|
+
seen.add(path);
|
|
14
|
+
paths.push(path);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return paths;
|
|
19
|
+
}
|
|
20
|
+
/** Attach signed URLs for original, thumbnail, and proxy storage paths. */
|
|
21
|
+
export function withEventMediaUrls(event, urlMap) {
|
|
22
|
+
return {
|
|
23
|
+
...event,
|
|
24
|
+
// Events predating file_path carry an absolute media_url with nothing to sign.
|
|
25
|
+
media_url: signedUrlForPath(event.file_path, urlMap) ?? event.media_url ?? null,
|
|
26
|
+
thumbnail_url: signedUrlForPath(event.thumbnail_file_path, urlMap),
|
|
27
|
+
proxy_url: signedUrlForPath(event.proxy_file_path, urlMap),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -103,12 +103,16 @@ export declare function server_update_event_lifecycle(event_id: number, lifecycl
|
|
|
103
103
|
origin_roll: number | null;
|
|
104
104
|
processing_blocked_at: string | null;
|
|
105
105
|
processing_blocked_reason: string | null;
|
|
106
|
+
proxy_file_path: string | null;
|
|
107
|
+
proxy_generated_at: string | null;
|
|
106
108
|
segmented_at: string | null;
|
|
107
109
|
sensor_pitch: number | null;
|
|
108
110
|
sensor_roll: number | null;
|
|
109
111
|
sensor_yaw: number | null;
|
|
110
112
|
session_id: number | null;
|
|
111
113
|
tagged_at: string | null;
|
|
114
|
+
thumbnail_file_path: string | null;
|
|
115
|
+
thumbnail_generated_at: string | null;
|
|
112
116
|
timestamp_observation: string;
|
|
113
117
|
tracked_at: string | null;
|
|
114
118
|
} | null>>;
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import type { IArtifact, IArtifactWithMediaUrl } from "../types/db";
|
|
2
|
+
import type { IArtifact, IArtifactWithMediaUrl, ISignedMediaUrls } from "../types/db";
|
|
3
3
|
import type { Database } from "../types/supabase";
|
|
4
|
-
type
|
|
5
|
-
file_path?: string | null;
|
|
6
|
-
media_url?: string | null;
|
|
7
|
-
};
|
|
4
|
+
import { type IEventMediaPaths } from "./eventMedia";
|
|
8
5
|
export declare function createSignedUrlMap(client: SupabaseClient<Database>, paths: Iterable<string | null | undefined>): Promise<Map<string, string | null>>;
|
|
9
|
-
export declare function addEventMediaUrls<T extends
|
|
10
|
-
media_url: string | null;
|
|
11
|
-
}>>;
|
|
6
|
+
export declare function addEventMediaUrls<T extends IEventMediaPaths>(client: SupabaseClient<Database>, events: T[]): Promise<Array<T & ISignedMediaUrls>>;
|
|
12
7
|
export declare function addArtifactMediaUrls(client: SupabaseClient<Database>, artifacts: IArtifact[]): Promise<IArtifactWithMediaUrl[]>;
|
|
13
|
-
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { collectArtifactStoragePaths, withArtifactMediaUrls, } from "./artifactMedia";
|
|
2
|
+
import { collectEventStoragePaths, withEventMediaUrls, } from "./eventMedia";
|
|
2
3
|
import { generateSignedUrlsBatchWithClient } from "./storage_internal";
|
|
3
4
|
import { isNonEmptyStorageFilePath } from "./storagePath";
|
|
4
5
|
export async function createSignedUrlMap(client, paths) {
|
|
@@ -7,13 +8,8 @@ export async function createSignedUrlMap(client, paths) {
|
|
|
7
8
|
return new Map(uniquePaths.map((path, index) => [path, urls[index]]));
|
|
8
9
|
}
|
|
9
10
|
export async function addEventMediaUrls(client, events) {
|
|
10
|
-
const urlMap = await createSignedUrlMap(client, events
|
|
11
|
-
return events.map((event) => (
|
|
12
|
-
...event,
|
|
13
|
-
media_url: isNonEmptyStorageFilePath(event.file_path)
|
|
14
|
-
? urlMap.get(event.file_path) ?? event.media_url ?? null
|
|
15
|
-
: event.media_url ?? null,
|
|
16
|
-
}));
|
|
11
|
+
const urlMap = await createSignedUrlMap(client, collectEventStoragePaths(events));
|
|
12
|
+
return events.map((event) => withEventMediaUrls(event, urlMap));
|
|
17
13
|
}
|
|
18
14
|
export async function addArtifactMediaUrls(client, artifacts) {
|
|
19
15
|
const urlMap = await createSignedUrlMap(client, collectArtifactStoragePaths(artifacts));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** True when we can sign storage: non-null and not blank after trim. */
|
|
2
2
|
export declare function isNonEmptyStorageFilePath(path: string | null | undefined): path is string;
|
|
3
|
+
/** Signed URL for a storage path, or null when the path is blank or went unsigned. */
|
|
4
|
+
export declare function signedUrlForPath(path: string | null | undefined, urlMap: Map<string, string | null | undefined>): string | null;
|
|
3
5
|
/** Assumes DB `file_path` is always `bucket/object/...` */
|
|
4
6
|
export declare function parseStorageFilePath(filePath: string): {
|
|
5
7
|
bucket: string;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
export function isNonEmptyStorageFilePath(path) {
|
|
3
3
|
return path != null && path.trim() !== "";
|
|
4
4
|
}
|
|
5
|
+
/** Signed URL for a storage path, or null when the path is blank or went unsigned. */
|
|
6
|
+
export function signedUrlForPath(path, urlMap) {
|
|
7
|
+
return isNonEmptyStorageFilePath(path) ? urlMap.get(path) ?? null : null;
|
|
8
|
+
}
|
|
5
9
|
/** Assumes DB `file_path` is always `bucket/object/...` */
|
|
6
10
|
export function parseStorageFilePath(filePath) {
|
|
7
11
|
const cleaned = filePath.trim().replace(/^\/+|\/+$/g, "");
|
|
@@ -340,6 +340,10 @@ export async function get_event_and_tags_by_event_id_query(client, event_id) {
|
|
|
340
340
|
embedded_at: data[0].embedded_at ?? null,
|
|
341
341
|
segmented_at: data[0].segmented_at ?? null,
|
|
342
342
|
tagged_at: data[0].tagged_at ?? null,
|
|
343
|
+
thumbnail_file_path: data[0].thumbnail_file_path ?? null,
|
|
344
|
+
thumbnail_generated_at: data[0].thumbnail_generated_at ?? null,
|
|
345
|
+
proxy_file_path: data[0].proxy_file_path ?? null,
|
|
346
|
+
proxy_generated_at: data[0].proxy_generated_at ?? null,
|
|
343
347
|
};
|
|
344
348
|
const [eventWithUrl] = await addEventMediaUrls(client, [transformedData]);
|
|
345
349
|
return IWebResponse.success(eventWithUrl).to_compatible();
|
|
@@ -18,10 +18,11 @@ export interface InfiniteRefetchOptions {
|
|
|
18
18
|
}
|
|
19
19
|
export interface InfiniteScrollData<T> {
|
|
20
20
|
items: T[];
|
|
21
|
-
/** True
|
|
21
|
+
/** True while a request is in flight and no pages are held: initial load, or a reset. */
|
|
22
22
|
isLoading: boolean;
|
|
23
23
|
/** True while a `refetch` is in flight, including a preserve-pages refresh. */
|
|
24
24
|
isRefreshing: boolean;
|
|
25
|
+
/** True while a later page is being fetched, with earlier pages already shown. */
|
|
25
26
|
isLoadingMore: boolean;
|
|
26
27
|
hasMore: boolean;
|
|
27
28
|
loadMore: () => void;
|
|
@@ -51,26 +51,26 @@ function sameCursor(left, right) {
|
|
|
51
51
|
}
|
|
52
52
|
const rowId = (row) => row.id;
|
|
53
53
|
const feedRowKey = (row) => `${row.sort_ts ?? ""}_${row.sort_id ?? ""}_${row.feed_type ?? ""}`;
|
|
54
|
-
|
|
55
|
-
* Holds the cursor of the page the live query should request.
|
|
56
|
-
*
|
|
57
|
-
* State is tagged with `key`, and state carrying a stale key reads as null, so a new entity
|
|
58
|
-
* is never requested with the previous entity's cursor.
|
|
59
|
-
*/
|
|
60
|
-
function useCursor(key) {
|
|
61
|
-
const [stored, setStored] = useState(() => ({ key, cursor: null }));
|
|
62
|
-
const setCursor = useCallback((cursor) => setStored({ key, cursor }), [key]);
|
|
63
|
-
return {
|
|
64
|
-
key,
|
|
65
|
-
cursor: stored.key === key ? stored.cursor : null,
|
|
66
|
-
setCursor,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
const noPages = (key) => ({
|
|
54
|
+
const emptyPaging = (key) => ({
|
|
70
55
|
key,
|
|
56
|
+
cursor: null,
|
|
71
57
|
pages: [],
|
|
72
58
|
refreshQueue: null,
|
|
73
59
|
});
|
|
60
|
+
/**
|
|
61
|
+
* Holds the paging state for `key`, read by the query args and by the engine.
|
|
62
|
+
*
|
|
63
|
+
* State carrying a stale key reads as empty, so a new entity starts from its first page in
|
|
64
|
+
* the same render rather than waiting for an effect to clear the previous one.
|
|
65
|
+
*/
|
|
66
|
+
function usePaging(key) {
|
|
67
|
+
const [stored, setStored] = useState(() => emptyPaging(key));
|
|
68
|
+
// Memoized so the empty fallback keeps a stable identity: `items` is derived from
|
|
69
|
+
// `state.pages`, and a fresh array each render would churn consumer dependencies.
|
|
70
|
+
const state = useMemo(() => (stored.key === key ? stored : emptyPaging(key)), [key, stored]);
|
|
71
|
+
const update = useCallback((change) => setStored((previous) => change(previous.key === key ? previous : emptyPaging(key))), [key]);
|
|
72
|
+
return { cursor: state.cursor, state, update };
|
|
73
|
+
}
|
|
74
74
|
function upsertPage(state, page, rowKey) {
|
|
75
75
|
const index = state.pages.findIndex((loaded) => sameCursor(loaded.cursor, page.cursor));
|
|
76
76
|
if (index === -1) {
|
|
@@ -97,27 +97,33 @@ const dropRefreshedCursor = (state) => {
|
|
|
97
97
|
/**
|
|
98
98
|
* Accumulates cursor-paginated responses into a list.
|
|
99
99
|
*
|
|
100
|
-
* A single query subscription serves every page: the cursor
|
|
101
|
-
* being requested, and each response is upserted into `pages` under that cursor. A
|
|
100
|
+
* A single query subscription serves every page: the paging state's cursor decides which
|
|
101
|
+
* page is being requested, and each response is upserted into `pages` under that cursor. A
|
|
102
102
|
* preserve-pages refresh walks the cursor back through the loaded pages one at a time,
|
|
103
|
-
* replacing each in place.
|
|
104
|
-
*
|
|
103
|
+
* replacing each in place. Changing entity or filters changes the paging key, which empties
|
|
104
|
+
* the list and abandons any refresh in the same render.
|
|
105
105
|
*/
|
|
106
|
-
function useInfinitePages({
|
|
107
|
-
const [stored, setStored] = useState(() => noPages(key));
|
|
106
|
+
function useInfinitePages({ cursor, state, update }, query, mapping) {
|
|
108
107
|
const latest = useRef({ query, mapping });
|
|
109
108
|
latest.current = { query, mapping };
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
const setCursor = useCallback((next) => update((previous) => sameCursor(previous.cursor, next)
|
|
110
|
+
? previous
|
|
111
|
+
: { ...previous, cursor: next }), [update]);
|
|
112
|
+
/**
|
|
113
|
+
* Re-requests the page the query currently points at. RTK's `refetch` throws
|
|
114
|
+
* synchronously when the query is skipped, so callers see a rejection instead of a fault
|
|
115
|
+
* at the call site.
|
|
116
|
+
*/
|
|
117
|
+
const requestPage = useCallback(async () => latest.current.query.refetch().unwrap(), []);
|
|
118
|
+
const { currentData, isFetching } = query;
|
|
119
|
+
const page = useMemo(() => currentData === undefined
|
|
120
|
+
? undefined
|
|
121
|
+
: latest.current.mapping.toPage(currentData), [currentData]);
|
|
116
122
|
useEffect(() => {
|
|
117
|
-
if (!page
|
|
123
|
+
if (!page)
|
|
118
124
|
return;
|
|
119
125
|
update((previous) => upsertPage(previous, { ...page, cursor }, latest.current.mapping.rowKey));
|
|
120
|
-
}, [cursor,
|
|
126
|
+
}, [cursor, page, update]);
|
|
121
127
|
useEffect(() => {
|
|
122
128
|
const queue = state.refreshQueue;
|
|
123
129
|
if (!queue)
|
|
@@ -128,29 +134,31 @@ function useInfinitePages({ key, cursor, setCursor }, query, mapping) {
|
|
|
128
134
|
return;
|
|
129
135
|
}
|
|
130
136
|
let cancelled = false;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
// A refresh that cannot run drops its cursor and moves on, so a rejection never leaves
|
|
138
|
+
// the queue stuck.
|
|
139
|
+
void (async () => {
|
|
140
|
+
try {
|
|
141
|
+
const response = await requestPage();
|
|
142
|
+
if (cancelled)
|
|
143
|
+
return;
|
|
144
|
+
const { mapping } = latest.current;
|
|
145
|
+
const refreshed = mapping.toPage(response);
|
|
146
|
+
update((previous) =>
|
|
147
|
+
// Only apply while this cursor is still the one being refreshed.
|
|
148
|
+
previous.refreshQueue &&
|
|
149
|
+
sameCursor(previous.refreshQueue[0], refreshing)
|
|
150
|
+
? dropRefreshedCursor(upsertPage(previous, { ...refreshed, cursor: refreshing }, mapping.rowKey))
|
|
151
|
+
: previous);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
if (!cancelled)
|
|
155
|
+
update(dropRefreshedCursor);
|
|
156
|
+
}
|
|
157
|
+
})();
|
|
150
158
|
return () => {
|
|
151
159
|
cancelled = true;
|
|
152
160
|
};
|
|
153
|
-
}, [cursor, setCursor, state.refreshQueue, update]);
|
|
161
|
+
}, [cursor, requestPage, setCursor, state.refreshQueue, update]);
|
|
154
162
|
/** Both modes queue the cursors to re-request, so a refetch always reaches the network. */
|
|
155
163
|
const refetch = useCallback((options) => {
|
|
156
164
|
update((previous) => options?.preservePages && previous.pages.length > 0
|
|
@@ -158,17 +166,32 @@ function useInfinitePages({ key, cursor, setCursor }, query, mapping) {
|
|
|
158
166
|
...previous,
|
|
159
167
|
refreshQueue: previous.pages.map((loaded) => loaded.cursor),
|
|
160
168
|
}
|
|
161
|
-
: { ...
|
|
162
|
-
}, [
|
|
169
|
+
: { ...emptyPaging(previous.key), refreshQueue: [null] });
|
|
170
|
+
}, [update]);
|
|
163
171
|
const lastPage = state.pages[state.pages.length - 1];
|
|
164
172
|
const nextCursor = lastPage?.nextCursor ?? null;
|
|
165
173
|
const hasMore = Boolean(lastPage?.hasMore) && nextCursor !== null;
|
|
166
174
|
const isRefreshing = state.refreshQueue !== null;
|
|
167
175
|
const loadMore = useCallback(() => {
|
|
168
|
-
if (!hasMore || nextCursor === null ||
|
|
176
|
+
if (!hasMore || nextCursor === null || isFetching || isRefreshing)
|
|
177
|
+
return;
|
|
178
|
+
// The cursor already resting on `nextCursor` means that page's request failed, since a
|
|
179
|
+
// loaded page would have moved `nextCursor` on. Re-setting it would be a no-op, so the
|
|
180
|
+
// failed request is retried instead of leaving the list unable to advance.
|
|
181
|
+
if (sameCursor(cursor, nextCursor)) {
|
|
182
|
+
void requestPage().catch(() => { });
|
|
169
183
|
return;
|
|
184
|
+
}
|
|
170
185
|
setCursor(nextCursor);
|
|
171
|
-
}, [
|
|
186
|
+
}, [
|
|
187
|
+
cursor,
|
|
188
|
+
hasMore,
|
|
189
|
+
isFetching,
|
|
190
|
+
isRefreshing,
|
|
191
|
+
nextCursor,
|
|
192
|
+
requestPage,
|
|
193
|
+
setCursor,
|
|
194
|
+
]);
|
|
172
195
|
const items = useMemo(() => {
|
|
173
196
|
const seen = new Set();
|
|
174
197
|
return state.pages
|
|
@@ -185,9 +208,9 @@ function useInfinitePages({ key, cursor, setCursor }, query, mapping) {
|
|
|
185
208
|
}, [state.pages]);
|
|
186
209
|
return {
|
|
187
210
|
items,
|
|
188
|
-
isLoading:
|
|
211
|
+
isLoading: state.pages.length === 0 && (isFetching || isRefreshing),
|
|
189
212
|
isRefreshing,
|
|
190
|
-
isLoadingMore:
|
|
213
|
+
isLoadingMore: isFetching && state.pages.length > 0 && !isRefreshing,
|
|
191
214
|
hasMore,
|
|
192
215
|
loadMore,
|
|
193
216
|
refetch,
|
|
@@ -261,7 +284,7 @@ const analysisTasksPage = (response) => ({
|
|
|
261
284
|
// =====================================================
|
|
262
285
|
export const useInfiniteSessionsByHerd = (herdId, options) => {
|
|
263
286
|
const filtersKey = useFiltersKey(options);
|
|
264
|
-
const paging =
|
|
287
|
+
const paging = usePaging(`herd:${herdId}|${filtersKey}`);
|
|
265
288
|
const query = useGetSessionsInfiniteByHerdQuery({ herdId, cursor: paging.cursor, ...flightArgs(options) }, { skip: !options.enabled || !herdId });
|
|
266
289
|
return useInfinitePages(paging, query, {
|
|
267
290
|
toPage: sessionsPage,
|
|
@@ -270,7 +293,7 @@ export const useInfiniteSessionsByHerd = (herdId, options) => {
|
|
|
270
293
|
};
|
|
271
294
|
export const useInfiniteSessionsByDevice = (deviceId, options) => {
|
|
272
295
|
const filtersKey = useFiltersKey(options);
|
|
273
|
-
const paging =
|
|
296
|
+
const paging = usePaging(`device:${deviceId}|${filtersKey}`);
|
|
274
297
|
const query = useGetSessionsInfiniteByDeviceQuery({ deviceId, cursor: paging.cursor, ...flightArgs(options) }, { skip: !options.enabled || !deviceId });
|
|
275
298
|
return useInfinitePages(paging, query, {
|
|
276
299
|
toPage: sessionsPage,
|
|
@@ -282,7 +305,7 @@ export const useInfiniteSessionsByDevice = (deviceId, options) => {
|
|
|
282
305
|
// =====================================================
|
|
283
306
|
export const useInfiniteEventsByHerd = (herdId, options) => {
|
|
284
307
|
const filtersKey = useFiltersKey(options);
|
|
285
|
-
const paging =
|
|
308
|
+
const paging = usePaging(`herd:${herdId}|${filtersKey}`);
|
|
286
309
|
const query = useGetEventsInfiniteByHerdQuery({ herdId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !herdId });
|
|
287
310
|
return useInfinitePages(paging, query, {
|
|
288
311
|
toPage: eventsPage,
|
|
@@ -291,7 +314,7 @@ export const useInfiniteEventsByHerd = (herdId, options) => {
|
|
|
291
314
|
};
|
|
292
315
|
export const useInfiniteEventsByDevice = (deviceId, options) => {
|
|
293
316
|
const filtersKey = useFiltersKey(options);
|
|
294
|
-
const paging =
|
|
317
|
+
const paging = usePaging(`device:${deviceId}|${filtersKey}`);
|
|
295
318
|
const query = useGetEventsInfiniteByDeviceQuery({ deviceId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !deviceId });
|
|
296
319
|
return useInfinitePages(paging, query, {
|
|
297
320
|
toPage: eventsPage,
|
|
@@ -303,7 +326,7 @@ export const useInfiniteEventsByDevice = (deviceId, options) => {
|
|
|
303
326
|
// =====================================================
|
|
304
327
|
export const useInfiniteArtifactsByHerd = (herdId, options) => {
|
|
305
328
|
const filtersKey = useFiltersKey(options);
|
|
306
|
-
const paging =
|
|
329
|
+
const paging = usePaging(`herd:${herdId}|${filtersKey}`);
|
|
307
330
|
const query = useGetArtifactsInfiniteByHerdQuery({ herdId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !herdId });
|
|
308
331
|
return useInfinitePages(paging, query, {
|
|
309
332
|
toPage: artifactsPage,
|
|
@@ -312,7 +335,7 @@ export const useInfiniteArtifactsByHerd = (herdId, options) => {
|
|
|
312
335
|
};
|
|
313
336
|
export const useInfiniteArtifactsByDevice = (deviceId, options) => {
|
|
314
337
|
const filtersKey = useFiltersKey(options);
|
|
315
|
-
const paging =
|
|
338
|
+
const paging = usePaging(`device:${deviceId}|${filtersKey}`);
|
|
316
339
|
const query = useGetArtifactsInfiniteByDeviceQuery({ deviceId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !deviceId });
|
|
317
340
|
return useInfinitePages(paging, query, {
|
|
318
341
|
toPage: artifactsPage,
|
|
@@ -324,7 +347,7 @@ export const useInfiniteArtifactsByDevice = (deviceId, options) => {
|
|
|
324
347
|
// =====================================================
|
|
325
348
|
export const useInfiniteFeedByHerd = (herdId, options) => {
|
|
326
349
|
const filtersKey = useFiltersKey(options);
|
|
327
|
-
const paging =
|
|
350
|
+
const paging = usePaging(`herd:${herdId}|${filtersKey}`);
|
|
328
351
|
const query = useGetFeedInfiniteByHerdQuery({ herdId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !herdId });
|
|
329
352
|
return useInfinitePages(paging, query, {
|
|
330
353
|
toPage: feedPage,
|
|
@@ -333,7 +356,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
|
|
|
333
356
|
};
|
|
334
357
|
export const useInfiniteFeedByDevice = (deviceId, options) => {
|
|
335
358
|
const filtersKey = useFiltersKey(options);
|
|
336
|
-
const paging =
|
|
359
|
+
const paging = usePaging(`device:${deviceId}|${filtersKey}`);
|
|
337
360
|
const query = useGetFeedInfiniteByDeviceQuery({ deviceId, cursor: paging.cursor, ...rangeArgs(options) }, { skip: !options.enabled || !deviceId });
|
|
338
361
|
return useInfinitePages(paging, query, {
|
|
339
362
|
toPage: feedPage,
|
|
@@ -342,7 +365,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
|
|
|
342
365
|
};
|
|
343
366
|
export const useInfiniteAnalysisJobs = (options) => {
|
|
344
367
|
const status = options.status ?? null;
|
|
345
|
-
const paging =
|
|
368
|
+
const paging = usePaging(`status:${status}`);
|
|
346
369
|
const query = useGetAnalysisJobsInfiniteQuery({
|
|
347
370
|
cursor: paging.cursor,
|
|
348
371
|
status,
|
|
@@ -357,7 +380,7 @@ export const useInfiniteAnalysisJobs = (options) => {
|
|
|
357
380
|
export const useInfiniteAnalysisTasks = (options) => {
|
|
358
381
|
const status = options.status ?? null;
|
|
359
382
|
const jobId = options.job_id ?? null;
|
|
360
|
-
const paging =
|
|
383
|
+
const paging = usePaging(`job:${jobId}|status:${status}`);
|
|
361
384
|
const query = useGetAnalysisTasksInfiniteQuery({
|
|
362
385
|
cursor: paging.cursor,
|
|
363
386
|
status,
|
package/dist/server/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from "../types";
|
|
|
4
4
|
export * from "../helpers/artifactMedia";
|
|
5
5
|
export * from "../helpers/bounding_boxes";
|
|
6
6
|
export * from "../helpers/email";
|
|
7
|
+
export * from "../helpers/eventMedia";
|
|
7
8
|
export * from "../helpers/eventUtils";
|
|
8
9
|
export { default as get_gps_center } from "../helpers/gps";
|
|
9
10
|
export * from "../helpers/herd_modules_equal";
|
package/dist/server/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "../types";
|
|
|
6
6
|
export * from "../helpers/artifactMedia";
|
|
7
7
|
export * from "../helpers/bounding_boxes";
|
|
8
8
|
export * from "../helpers/email";
|
|
9
|
+
export * from "../helpers/eventMedia";
|
|
9
10
|
export * from "../helpers/eventUtils";
|
|
10
11
|
export { default as get_gps_center } from "../helpers/gps";
|
|
11
12
|
export * from "../helpers/herd_modules_equal";
|
package/dist/store/api.d.ts
CHANGED
|
@@ -151,7 +151,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
151
151
|
isFetching: false;
|
|
152
152
|
isSuccess: false;
|
|
153
153
|
isError: false;
|
|
154
|
-
}, "data" | "
|
|
154
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
155
155
|
isLoading: true;
|
|
156
156
|
isFetching: boolean;
|
|
157
157
|
data: undefined;
|
|
@@ -260,7 +260,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
260
260
|
isFetching: false;
|
|
261
261
|
isSuccess: false;
|
|
262
262
|
isError: false;
|
|
263
|
-
}, "data" | "
|
|
263
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
264
264
|
isLoading: true;
|
|
265
265
|
isFetching: boolean;
|
|
266
266
|
data: undefined;
|
|
@@ -367,7 +367,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
367
367
|
isFetching: false;
|
|
368
368
|
isSuccess: false;
|
|
369
369
|
isError: false;
|
|
370
|
-
}, "data" | "
|
|
370
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
371
371
|
isLoading: true;
|
|
372
372
|
isFetching: boolean;
|
|
373
373
|
data: undefined;
|
|
@@ -476,7 +476,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
476
476
|
isFetching: false;
|
|
477
477
|
isSuccess: false;
|
|
478
478
|
isError: false;
|
|
479
|
-
}, "data" | "
|
|
479
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
480
480
|
isLoading: true;
|
|
481
481
|
isFetching: boolean;
|
|
482
482
|
data: undefined;
|
|
@@ -583,7 +583,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
583
583
|
isFetching: false;
|
|
584
584
|
isSuccess: false;
|
|
585
585
|
isError: false;
|
|
586
|
-
}, "data" | "
|
|
586
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
587
587
|
isLoading: true;
|
|
588
588
|
isFetching: boolean;
|
|
589
589
|
data: undefined;
|
|
@@ -692,7 +692,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
692
692
|
isFetching: false;
|
|
693
693
|
isSuccess: false;
|
|
694
694
|
isError: false;
|
|
695
|
-
}, "data" | "
|
|
695
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
696
696
|
isLoading: true;
|
|
697
697
|
isFetching: boolean;
|
|
698
698
|
data: undefined;
|
|
@@ -799,7 +799,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
799
799
|
isFetching: false;
|
|
800
800
|
isSuccess: false;
|
|
801
801
|
isError: false;
|
|
802
|
-
}, "data" | "
|
|
802
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
803
803
|
isLoading: true;
|
|
804
804
|
isFetching: boolean;
|
|
805
805
|
data: undefined;
|
|
@@ -908,7 +908,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
908
908
|
isFetching: false;
|
|
909
909
|
isSuccess: false;
|
|
910
910
|
isError: false;
|
|
911
|
-
}, "data" | "
|
|
911
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
912
912
|
isLoading: true;
|
|
913
913
|
isFetching: boolean;
|
|
914
914
|
data: undefined;
|
|
@@ -1015,7 +1015,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1015
1015
|
isFetching: false;
|
|
1016
1016
|
isSuccess: false;
|
|
1017
1017
|
isError: false;
|
|
1018
|
-
}, "data" | "
|
|
1018
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1019
1019
|
isLoading: true;
|
|
1020
1020
|
isFetching: boolean;
|
|
1021
1021
|
data: undefined;
|
|
@@ -1124,7 +1124,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1124
1124
|
isFetching: false;
|
|
1125
1125
|
isSuccess: false;
|
|
1126
1126
|
isError: false;
|
|
1127
|
-
}, "data" | "
|
|
1127
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1128
1128
|
isLoading: true;
|
|
1129
1129
|
isFetching: boolean;
|
|
1130
1130
|
data: undefined;
|
|
@@ -1231,7 +1231,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1231
1231
|
isFetching: false;
|
|
1232
1232
|
isSuccess: false;
|
|
1233
1233
|
isError: false;
|
|
1234
|
-
}, "data" | "
|
|
1234
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1235
1235
|
isLoading: true;
|
|
1236
1236
|
isFetching: boolean;
|
|
1237
1237
|
data: undefined;
|
|
@@ -1340,7 +1340,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1340
1340
|
isFetching: false;
|
|
1341
1341
|
isSuccess: false;
|
|
1342
1342
|
isError: false;
|
|
1343
|
-
}, "data" | "
|
|
1343
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1344
1344
|
isLoading: true;
|
|
1345
1345
|
isFetching: boolean;
|
|
1346
1346
|
data: undefined;
|
|
@@ -1445,7 +1445,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1445
1445
|
isFetching: false;
|
|
1446
1446
|
isSuccess: false;
|
|
1447
1447
|
isError: false;
|
|
1448
|
-
}, "data" | "
|
|
1448
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1449
1449
|
isLoading: true;
|
|
1450
1450
|
isFetching: boolean;
|
|
1451
1451
|
data: undefined;
|
|
@@ -1538,7 +1538,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1538
1538
|
isFetching: false;
|
|
1539
1539
|
isSuccess: false;
|
|
1540
1540
|
isError: false;
|
|
1541
|
-
}, "data" | "
|
|
1541
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1542
1542
|
isLoading: true;
|
|
1543
1543
|
isFetching: boolean;
|
|
1544
1544
|
data: undefined;
|
|
@@ -1629,7 +1629,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1629
1629
|
isFetching: false;
|
|
1630
1630
|
isSuccess: false;
|
|
1631
1631
|
isError: false;
|
|
1632
|
-
}, "data" | "
|
|
1632
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1633
1633
|
isLoading: true;
|
|
1634
1634
|
isFetching: boolean;
|
|
1635
1635
|
data: undefined;
|
|
@@ -1722,7 +1722,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1722
1722
|
isFetching: false;
|
|
1723
1723
|
isSuccess: false;
|
|
1724
1724
|
isError: false;
|
|
1725
|
-
}, "data" | "
|
|
1725
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1726
1726
|
isLoading: true;
|
|
1727
1727
|
isFetching: boolean;
|
|
1728
1728
|
data: undefined;
|
|
@@ -1813,7 +1813,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1813
1813
|
isFetching: false;
|
|
1814
1814
|
isSuccess: false;
|
|
1815
1815
|
isError: false;
|
|
1816
|
-
}, "data" | "
|
|
1816
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1817
1817
|
isLoading: true;
|
|
1818
1818
|
isFetching: boolean;
|
|
1819
1819
|
data: undefined;
|
|
@@ -1906,7 +1906,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1906
1906
|
isFetching: false;
|
|
1907
1907
|
isSuccess: false;
|
|
1908
1908
|
isError: false;
|
|
1909
|
-
}, "data" | "
|
|
1909
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
1910
1910
|
isLoading: true;
|
|
1911
1911
|
isFetching: boolean;
|
|
1912
1912
|
data: undefined;
|
|
@@ -1997,7 +1997,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
1997
1997
|
isFetching: false;
|
|
1998
1998
|
isSuccess: false;
|
|
1999
1999
|
isError: false;
|
|
2000
|
-
}, "data" | "
|
|
2000
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
2001
2001
|
isLoading: true;
|
|
2002
2002
|
isFetching: boolean;
|
|
2003
2003
|
data: undefined;
|
|
@@ -2090,7 +2090,7 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
|
|
|
2090
2090
|
isFetching: false;
|
|
2091
2091
|
isSuccess: false;
|
|
2092
2092
|
isError: false;
|
|
2093
|
-
}, "data" | "
|
|
2093
|
+
}, "data" | "isFetching" | "isLoading"> & {
|
|
2094
2094
|
isLoading: true;
|
|
2095
2095
|
isFetching: boolean;
|
|
2096
2096
|
data: undefined;
|
package/dist/store/api.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react";
|
|
3
3
|
import { addArtifactMediaUrls, addEventMediaUrls, createSignedUrlMap, } from "../helpers/media_urls";
|
|
4
4
|
import { collectArtifactStoragePaths, withArtifactMediaUrls, } from "../helpers/artifactMedia";
|
|
5
|
-
import {
|
|
5
|
+
import { collectEventStoragePaths, withEventMediaUrls, } from "../helpers/eventMedia";
|
|
6
6
|
async function signedUrlMapForFeedRows(supabase, rows) {
|
|
7
7
|
return createSignedUrlMap(supabase, rows.flatMap((row) => [
|
|
8
|
-
row.event_data
|
|
8
|
+
...collectEventStoragePaths([row.event_data]),
|
|
9
9
|
...(row.artifact_data
|
|
10
10
|
? collectArtifactStoragePaths([row.artifact_data])
|
|
11
11
|
: []),
|
|
@@ -434,12 +434,7 @@ export const scoutApi = createApi({
|
|
|
434
434
|
const items = resultRows.map((row) => ({
|
|
435
435
|
...row,
|
|
436
436
|
event_data: row.event_data
|
|
437
|
-
?
|
|
438
|
-
...row.event_data,
|
|
439
|
-
media_url: isNonEmptyStorageFilePath(row.event_data.file_path)
|
|
440
|
-
? urlMap.get(row.event_data.file_path) ?? null
|
|
441
|
-
: null,
|
|
442
|
-
}
|
|
437
|
+
? withEventMediaUrls(row.event_data, urlMap)
|
|
443
438
|
: null,
|
|
444
439
|
artifact_data: row.artifact_data
|
|
445
440
|
? withArtifactMediaUrls(row.artifact_data, urlMap)
|
|
@@ -504,12 +499,7 @@ export const scoutApi = createApi({
|
|
|
504
499
|
const items = resultRows.map((row) => ({
|
|
505
500
|
...row,
|
|
506
501
|
event_data: row.event_data
|
|
507
|
-
?
|
|
508
|
-
...row.event_data,
|
|
509
|
-
media_url: isNonEmptyStorageFilePath(row.event_data.file_path)
|
|
510
|
-
? urlMap.get(row.event_data.file_path) ?? null
|
|
511
|
-
: null,
|
|
512
|
-
}
|
|
502
|
+
? withEventMediaUrls(row.event_data, urlMap)
|
|
513
503
|
: null,
|
|
514
504
|
artifact_data: row.artifact_data
|
|
515
505
|
? withArtifactMediaUrls(row.artifact_data, urlMap)
|
package/dist/types/db.d.ts
CHANGED
|
@@ -217,14 +217,13 @@ export type BatteryCycleCountUpdate = Database["public"]["Tables"]["battery_cycl
|
|
|
217
217
|
export type IMinimalSubjectForArtifact = Database["public"]["Functions"]["get_minimal_subjects_for_artifact"]["Returns"][number];
|
|
218
218
|
export type IAnalysisJob = Database["public"]["Tables"]["analysis_jobs"]["Row"];
|
|
219
219
|
export type IAnalysisTask = Database["public"]["Tables"]["analysis_tasks"]["Row"];
|
|
220
|
-
export type
|
|
220
|
+
export type ISignedMediaUrls = {
|
|
221
221
|
media_url?: string | null;
|
|
222
222
|
thumbnail_url?: string | null;
|
|
223
223
|
proxy_url?: string | null;
|
|
224
224
|
};
|
|
225
|
-
export type
|
|
226
|
-
|
|
227
|
-
};
|
|
225
|
+
export type IArtifactWithMediaUrl = IArtifact & ISignedMediaUrls;
|
|
226
|
+
export type IEventWithMediaUrl = IEvent & ISignedMediaUrls;
|
|
228
227
|
export type IVersionsSoftwareWithBuildUrl = IVersionsSoftware & {
|
|
229
228
|
build_artifact_url?: string | null;
|
|
230
229
|
};
|
|
@@ -368,9 +367,7 @@ export type IFeedItem = {
|
|
|
368
367
|
feed_type: string | null;
|
|
369
368
|
sort_ts: string | null;
|
|
370
369
|
sort_id: number | null;
|
|
371
|
-
event_data: (IEventAndTagsPrettyLocation &
|
|
372
|
-
media_url?: string | null;
|
|
373
|
-
}) | null;
|
|
370
|
+
event_data: (IEventAndTagsPrettyLocation & ISignedMediaUrls) | null;
|
|
374
371
|
artifact_data: IArtifactWithMediaUrl | null;
|
|
375
372
|
};
|
|
376
373
|
export type ISessionWithCoordinates = Database["public"]["CompositeTypes"]["session_with_coordinates"];
|
package/dist/types/supabase.d.ts
CHANGED
|
@@ -1504,12 +1504,16 @@ export type Database = {
|
|
|
1504
1504
|
origin_roll: number | null;
|
|
1505
1505
|
processing_blocked_at: string | null;
|
|
1506
1506
|
processing_blocked_reason: string | null;
|
|
1507
|
+
proxy_file_path: string | null;
|
|
1508
|
+
proxy_generated_at: string | null;
|
|
1507
1509
|
segmented_at: string | null;
|
|
1508
1510
|
sensor_pitch: number | null;
|
|
1509
1511
|
sensor_roll: number | null;
|
|
1510
1512
|
sensor_yaw: number | null;
|
|
1511
1513
|
session_id: number | null;
|
|
1512
1514
|
tagged_at: string | null;
|
|
1515
|
+
thumbnail_file_path: string | null;
|
|
1516
|
+
thumbnail_generated_at: string | null;
|
|
1513
1517
|
timestamp_observation: string;
|
|
1514
1518
|
tracked_at: string | null;
|
|
1515
1519
|
};
|
|
@@ -1538,12 +1542,16 @@ export type Database = {
|
|
|
1538
1542
|
origin_roll?: number | null;
|
|
1539
1543
|
processing_blocked_at?: string | null;
|
|
1540
1544
|
processing_blocked_reason?: string | null;
|
|
1545
|
+
proxy_file_path?: string | null;
|
|
1546
|
+
proxy_generated_at?: string | null;
|
|
1541
1547
|
segmented_at?: string | null;
|
|
1542
1548
|
sensor_pitch?: number | null;
|
|
1543
1549
|
sensor_roll?: number | null;
|
|
1544
1550
|
sensor_yaw?: number | null;
|
|
1545
1551
|
session_id?: number | null;
|
|
1546
1552
|
tagged_at?: string | null;
|
|
1553
|
+
thumbnail_file_path?: string | null;
|
|
1554
|
+
thumbnail_generated_at?: string | null;
|
|
1547
1555
|
timestamp_observation?: string;
|
|
1548
1556
|
tracked_at?: string | null;
|
|
1549
1557
|
};
|
|
@@ -1572,12 +1580,16 @@ export type Database = {
|
|
|
1572
1580
|
origin_roll?: number | null;
|
|
1573
1581
|
processing_blocked_at?: string | null;
|
|
1574
1582
|
processing_blocked_reason?: string | null;
|
|
1583
|
+
proxy_file_path?: string | null;
|
|
1584
|
+
proxy_generated_at?: string | null;
|
|
1575
1585
|
segmented_at?: string | null;
|
|
1576
1586
|
sensor_pitch?: number | null;
|
|
1577
1587
|
sensor_roll?: number | null;
|
|
1578
1588
|
sensor_yaw?: number | null;
|
|
1579
1589
|
session_id?: number | null;
|
|
1580
1590
|
tagged_at?: string | null;
|
|
1591
|
+
thumbnail_file_path?: string | null;
|
|
1592
|
+
thumbnail_generated_at?: string | null;
|
|
1581
1593
|
timestamp_observation?: string;
|
|
1582
1594
|
tracked_at?: string | null;
|
|
1583
1595
|
};
|
|
@@ -7015,6 +7027,10 @@ export type Database = {
|
|
|
7015
7027
|
embedded_at: string | null;
|
|
7016
7028
|
segmented_at: string | null;
|
|
7017
7029
|
tagged_at: string | null;
|
|
7030
|
+
thumbnail_file_path: string | null;
|
|
7031
|
+
thumbnail_generated_at: string | null;
|
|
7032
|
+
proxy_file_path: string | null;
|
|
7033
|
+
proxy_generated_at: string | null;
|
|
7018
7034
|
};
|
|
7019
7035
|
event_plus_tags: {
|
|
7020
7036
|
id: number | null;
|