fix open recordings from host
This commit is contained in:
parent
2f72689f4e
commit
9472c5224c
@ -101,7 +101,7 @@ export const proxyApi = {
|
|||||||
) =>
|
) =>
|
||||||
instanceApi.get<RecordSummary[]>(`proxy/${hostName}/api/${cameraName}/recordings/summary`, {
|
instanceApi.get<RecordSummary[]>(`proxy/${hostName}/api/${cameraName}/recordings/summary`, {
|
||||||
params: { timezone },
|
params: { timezone },
|
||||||
timeout: 5 * 60 * 1000
|
timeout: 5 * 60 * 1000,
|
||||||
}).then(res => res.data),
|
}).then(res => res.data),
|
||||||
|
|
||||||
// E.g. http://127.0.0.1:5000/api/events?before=1708534799&after=1708448400&camera=CameraName&has_clip=1&include_thumbnails=0&limit=5000
|
// E.g. http://127.0.0.1:5000/api/events?before=1708534799&after=1708448400&camera=CameraName&has_clip=1&include_thumbnails=0&limit=5000
|
||||||
@ -130,7 +130,8 @@ export const proxyApi = {
|
|||||||
limit: limit,
|
limit: limit,
|
||||||
min_score: minScore,
|
min_score: minScore,
|
||||||
max_score: maxScore,
|
max_score: maxScore,
|
||||||
}
|
},
|
||||||
|
timeout: 5 * 60 * 1000,
|
||||||
}).then(res => res.data),
|
}).then(res => res.data),
|
||||||
|
|
||||||
getEventsSummary: (hostName: string, cameraName: string) =>
|
getEventsSummary: (hostName: string, cameraName: string) =>
|
||||||
|
|||||||
@ -18,7 +18,7 @@ interface CameraAccordionProps {
|
|||||||
|
|
||||||
const CameraAccordion = ({
|
const CameraAccordion = ({
|
||||||
camera
|
camera
|
||||||
} : CameraAccordionProps ) => {
|
}: CameraAccordionProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { recordingsStore: recStore } = useContext(Context)
|
const { recordingsStore: recStore } = useContext(Context)
|
||||||
|
|
||||||
@ -35,14 +35,22 @@ const CameraAccordion = ({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const recodItem = (record: RecordSummary) => (
|
const recodItem = (record: RecordSummary) => {
|
||||||
<Accordion.Item key={record.day} value={record.day}>
|
if (host) {
|
||||||
<Accordion.Control key={record.day + 'control'}>{t('day')}: {record.day}</Accordion.Control>
|
return (
|
||||||
<Accordion.Panel key={record.day + 'panel'}>
|
<Accordion.Item key={record.day} value={record.day}>
|
||||||
<DayAccordion key={record.day + 'day'} recordSummary={record} />
|
<Accordion.Control key={record.day + 'control'}>{t('day')}: {record.day}</Accordion.Control>
|
||||||
</Accordion.Panel>
|
<Accordion.Panel key={record.day + 'panel'}>
|
||||||
</Accordion.Item>
|
<DayAccordion
|
||||||
)
|
host={host}
|
||||||
|
camera={camera}
|
||||||
|
key={record.day + 'day'}
|
||||||
|
recordSummary={record} />
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const days = useMemo(() => {
|
const days = useMemo(() => {
|
||||||
if (recordings && camera) {
|
if (recordings && camera) {
|
||||||
|
|||||||
@ -6,21 +6,25 @@ import { mapHostToHostname } from '../../../services/frigate.proxy/frigate.api';
|
|||||||
import { RecordSummary } from '../../../types/record';
|
import { RecordSummary } from '../../../types/record';
|
||||||
import { isProduction } from '../../env.const';
|
import { isProduction } from '../../env.const';
|
||||||
import DayAccordionItem from './DayAccordionItem';
|
import DayAccordionItem from './DayAccordionItem';
|
||||||
|
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
|
||||||
|
|
||||||
interface RecordingAccordionProps {
|
interface RecordingAccordionProps {
|
||||||
recordSummary?: RecordSummary,
|
recordSummary?: RecordSummary
|
||||||
|
host: GetFrigateHost
|
||||||
|
camera: GetCameraWHostWConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
const DayAccordionItemMemo = React.memo(DayAccordionItem)
|
const DayAccordionItemMemo = React.memo(DayAccordionItem)
|
||||||
|
|
||||||
const DayAccordion = ({
|
const DayAccordion = ({
|
||||||
recordSummary,
|
recordSummary,
|
||||||
|
host,
|
||||||
|
camera
|
||||||
}: RecordingAccordionProps) => {
|
}: RecordingAccordionProps) => {
|
||||||
const { recordingsStore: recStore } = useContext(Context)
|
const { recordingsStore: recStore } = useContext(Context)
|
||||||
const [openedValue, setOpenedValue] = useState<string>()
|
const [openedValue, setOpenedValue] = useState<string>()
|
||||||
|
|
||||||
const camera = recStore.filteredCamera
|
const hostName = mapHostToHostname(host)
|
||||||
const hostName = mapHostToHostname(recStore.filteredHost)
|
|
||||||
|
|
||||||
const handleOpenPlayer = useCallback((value?: string) => {
|
const handleOpenPlayer = useCallback((value?: string) => {
|
||||||
if (recStore.playedItem !== value) {
|
if (recStore.playedItem !== value) {
|
||||||
@ -32,11 +36,13 @@ const DayAccordion = ({
|
|||||||
}, [openedValue, recStore]);
|
}, [openedValue, recStore]);
|
||||||
|
|
||||||
const dayItems = useMemo(() => {
|
const dayItems = useMemo(() => {
|
||||||
if (recordSummary && recordSummary.hours.length > 0) {
|
if (recordSummary && recordSummary.hours.length > 0 && hostName && host) {
|
||||||
return recordSummary.hours.map(hour => {
|
return recordSummary.hours.map(hour => {
|
||||||
const played = recordSummary.day + hour.hour === recStore.playedItem;
|
const played = recordSummary.day + hour.hour === recStore.playedItem;
|
||||||
return (
|
return (
|
||||||
<DayAccordionItemMemo
|
<DayAccordionItemMemo
|
||||||
|
camera={camera}
|
||||||
|
host={host}
|
||||||
key={recordSummary.day + hour.hour}
|
key={recordSummary.day + hour.hour}
|
||||||
recordSummary={recordSummary}
|
recordSummary={recordSummary}
|
||||||
recordHour={hour}
|
recordHour={hour}
|
||||||
|
|||||||
@ -12,14 +12,17 @@ import AccordionControlButton from '../buttons/AccordionControlButton';
|
|||||||
import AccordionShareButton from '../buttons/AccordionShareButton';
|
import AccordionShareButton from '../buttons/AccordionShareButton';
|
||||||
import PlayControl from '../buttons/PlayControl';
|
import PlayControl from '../buttons/PlayControl';
|
||||||
import DayPanel from './DayPanel';
|
import DayPanel from './DayPanel';
|
||||||
|
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
|
||||||
|
|
||||||
interface DayAccordionItemProps {
|
interface DayAccordionItemProps {
|
||||||
recordSummary: RecordSummary,
|
recordSummary: RecordSummary,
|
||||||
recordHour: RecordHour,
|
recordHour: RecordHour,
|
||||||
hostName?: string,
|
hostName: string,
|
||||||
cameraName?: string,
|
cameraName: string,
|
||||||
played?: boolean,
|
played?: boolean,
|
||||||
openPlayer?: (value?: string) => void,
|
openPlayer?: (value?: string) => void,
|
||||||
|
camera: GetCameraWHostWConfig
|
||||||
|
host: GetFrigateHost
|
||||||
}
|
}
|
||||||
|
|
||||||
const DayAccordionItem = ({
|
const DayAccordionItem = ({
|
||||||
@ -28,7 +31,9 @@ const DayAccordionItem = ({
|
|||||||
hostName,
|
hostName,
|
||||||
cameraName,
|
cameraName,
|
||||||
played,
|
played,
|
||||||
openPlayer
|
openPlayer,
|
||||||
|
camera,
|
||||||
|
host
|
||||||
}: DayAccordionItemProps) => {
|
}: DayAccordionItemProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -92,6 +97,8 @@ const DayAccordionItem = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Accordion.Control>
|
</Accordion.Control>
|
||||||
<DayPanel
|
<DayPanel
|
||||||
|
camera={camera}
|
||||||
|
host={host}
|
||||||
day={recordSummary.day}
|
day={recordSummary.day}
|
||||||
hour={hour}
|
hour={hour}
|
||||||
events={recordHour.events}
|
events={recordHour.events}
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
import { Accordion, Text } from '@mantine/core';
|
import { Accordion, Text } from '@mantine/core';
|
||||||
import { Suspense, lazy, useState } from 'react';
|
import { Suspense, lazy, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
|
||||||
const EventsAccordion = lazy(() => import('./EventsAccordion'))
|
const EventsAccordion = lazy(() => import('./EventsAccordion'))
|
||||||
|
|
||||||
interface DayEventsAccordionProps {
|
interface DayEventsAccordionProps {
|
||||||
day: string,
|
day: string,
|
||||||
hour: string,
|
hour: string,
|
||||||
qty?: number,
|
qty?: number,
|
||||||
|
camera: GetCameraWHostWConfig
|
||||||
|
host: GetFrigateHost
|
||||||
}
|
}
|
||||||
|
|
||||||
const DayEventsAccordion = ({
|
const DayEventsAccordion = ({
|
||||||
day,
|
day,
|
||||||
hour,
|
hour,
|
||||||
qty,
|
qty,
|
||||||
|
camera,
|
||||||
|
host,
|
||||||
}: DayEventsAccordionProps) => {
|
}: DayEventsAccordionProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [openedItem, setOpenedItem] = useState<string>()
|
const [openedItem, setOpenedItem] = useState<string>()
|
||||||
@ -27,7 +32,11 @@ const DayEventsAccordion = ({
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
{openedItem === hour ?
|
{openedItem === hour ?
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<EventsAccordion day={day} hour={hour} />
|
<EventsAccordion
|
||||||
|
camera={camera}
|
||||||
|
host={host}
|
||||||
|
day={day}
|
||||||
|
hour={hour} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import VideoDownloader from '../../../widgets/VideoDownloader';
|
|||||||
import VideoPlayer from '../players/VideoPlayer';
|
import VideoPlayer from '../players/VideoPlayer';
|
||||||
import DayEventsAccordion from './DayEventsAccordion';
|
import DayEventsAccordion from './DayEventsAccordion';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
|
||||||
|
|
||||||
interface DayPanelProps {
|
interface DayPanelProps {
|
||||||
day: string,
|
day: string,
|
||||||
@ -14,6 +15,8 @@ interface DayPanelProps {
|
|||||||
playedURL?: string,
|
playedURL?: string,
|
||||||
startUnixTime: number,
|
startUnixTime: number,
|
||||||
endUnixTime: number,
|
endUnixTime: number,
|
||||||
|
camera: GetCameraWHostWConfig
|
||||||
|
host: GetFrigateHost
|
||||||
}
|
}
|
||||||
|
|
||||||
const DayPanel = ({
|
const DayPanel = ({
|
||||||
@ -26,6 +29,8 @@ const DayPanel = ({
|
|||||||
playedURL,
|
playedURL,
|
||||||
startUnixTime,
|
startUnixTime,
|
||||||
endUnixTime,
|
endUnixTime,
|
||||||
|
camera,
|
||||||
|
host
|
||||||
}: DayPanelProps) => {
|
}: DayPanelProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
return (
|
return (
|
||||||
@ -42,7 +47,12 @@ const DayPanel = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
: ''}
|
: ''}
|
||||||
{events > 0 ?
|
{events > 0 ?
|
||||||
<DayEventsAccordion day={day} hour={hour} qty={events} />
|
<DayEventsAccordion
|
||||||
|
camera={camera}
|
||||||
|
host={host}
|
||||||
|
day={day}
|
||||||
|
hour={hour}
|
||||||
|
qty={events} />
|
||||||
:
|
:
|
||||||
<Center><Text>{t('notHaveEvents')}</Text></Center>
|
<Center><Text>{t('notHaveEvents')}</Text></Center>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Flex, Text } from '@mantine/core';
|
import { Button, Flex, Group, Text } from '@mantine/core';
|
||||||
import { IconExternalLink } from '@tabler/icons-react';
|
import { IconExternalLink } from '@tabler/icons-react';
|
||||||
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
||||||
import { EventFrigate } from '../../../types/event';
|
import { EventFrigate } from '../../../types/event';
|
||||||
@ -26,12 +26,23 @@ const EventPanel = ({
|
|||||||
<>
|
<>
|
||||||
{playedURL && playedURL === videoURL ? <VideoPlayer videoUrl={playedURL} /> : <></>}
|
{playedURL && playedURL === videoURL ? <VideoPlayer videoUrl={playedURL} /> : <></>}
|
||||||
<Flex w='100%' justify='space-between'>
|
<Flex w='100%' justify='space-between'>
|
||||||
{!hostName ? <></> :
|
<Group spacing='xs'>
|
||||||
<BlobImage
|
<Text fw={700}>{t('camera')}:</Text>
|
||||||
maw={200}
|
<Text>{event.camera}</Text>
|
||||||
fit="contain"
|
</Group>
|
||||||
withPlaceholder
|
<Group>
|
||||||
src={proxyApi.eventThumbnailUrl(hostName, event.id)} />
|
<Text fw={700}>{t('player.startTime')}:</Text>
|
||||||
|
<Text>{unixTimeToDate(event.start_time)}</Text>
|
||||||
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<Text fw={700}>{t('player.duration')}:</Text>
|
||||||
|
<Text>{getDurationFromTimestamps(event.start_time, event.end_time)}</Text>
|
||||||
|
</Group>
|
||||||
|
{!event.data?.score ? <></> :
|
||||||
|
<Group>
|
||||||
|
<Text fw={700}>{t('player.rating')}:</Text>
|
||||||
|
<Text>{(event.data.score * 100).toFixed(2)}%</Text>
|
||||||
|
</Group>
|
||||||
}
|
}
|
||||||
<Flex direction='column' align='end' justify='center'>
|
<Flex direction='column' align='end' justify='center'>
|
||||||
{!hostName ? '' :
|
{!hostName ? '' :
|
||||||
@ -46,13 +57,6 @@ const EventPanel = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
<Text mt='1rem'>{t('camera')}: {event.camera}</Text>
|
|
||||||
<Text>{t('player.object')}: {event.label}</Text>
|
|
||||||
<Text>{t('player.startTime')}: {unixTimeToDate(event.start_time)}</Text>
|
|
||||||
<Text>{t('player.duration')}: {getDurationFromTimestamps(event.start_time, event.end_time)}</Text>
|
|
||||||
{!event.data?.score? <></> :
|
|
||||||
<Text>{t('player.rating')}: {(event.data.score * 100).toFixed(2)}%</Text>
|
|
||||||
}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { observer } from 'mobx-react-lite';
|
|||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { Context } from '../../..';
|
import { Context } from '../../..';
|
||||||
import { frigateQueryKeys, mapHostToHostname, proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
import { frigateQueryKeys, mapHostToHostname, proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
||||||
import { getEventsQuerySchema } from '../../../services/frigate.proxy/frigate.schema';
|
import { GetCameraWHostWConfig, GetFrigateHost, getEventsQuerySchema } from '../../../services/frigate.proxy/frigate.schema';
|
||||||
import { getUnixTime } from '../../utils/dateUtil';
|
import { getUnixTime } from '../../utils/dateUtil';
|
||||||
import RetryError from '../RetryError';
|
import RetryError from '../RetryError';
|
||||||
import EventsAccordionItem from './EventsAccordionItem';
|
import EventsAccordionItem from './EventsAccordionItem';
|
||||||
@ -16,10 +16,10 @@ import EventsAccordionItem from './EventsAccordionItem';
|
|||||||
* @param hostName proxy format, e.g hostName: localhost:4000
|
* @param hostName proxy format, e.g hostName: localhost:4000
|
||||||
*/
|
*/
|
||||||
interface EventsAccordionProps {
|
interface EventsAccordionProps {
|
||||||
day?: string,
|
day: string,
|
||||||
hour?: string,
|
hour: string,
|
||||||
cameraName?: string
|
camera: GetCameraWHostWConfig
|
||||||
hostName?: string
|
host: GetFrigateHost
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,13 +31,13 @@ interface EventsAccordionProps {
|
|||||||
const EventsAccordion = ({
|
const EventsAccordion = ({
|
||||||
day,
|
day,
|
||||||
hour,
|
hour,
|
||||||
|
camera,
|
||||||
|
host,
|
||||||
}: EventsAccordionProps) => {
|
}: EventsAccordionProps) => {
|
||||||
const { recordingsStore: recStore } = useContext(Context)
|
const { recordingsStore: recStore } = useContext(Context)
|
||||||
const [openedItem, setOpenedItem] = useState<string>()
|
const [openedItem, setOpenedItem] = useState<string>()
|
||||||
|
|
||||||
const host = recStore.filteredHost
|
|
||||||
const hostName = mapHostToHostname(host)
|
const hostName = mapHostToHostname(host)
|
||||||
const camera = recStore.filteredCamera
|
|
||||||
const isRequiredParams = host && camera
|
const isRequiredParams = host && camera
|
||||||
|
|
||||||
const { data, isPending, isError, refetch } = useQuery({
|
const { data, isPending, isError, refetch } = useQuery({
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { routesPath } from '../../../router/routes.path';
|
import { routesPath } from '../../../router/routes.path';
|
||||||
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import BlobImage from '../images/BlobImage';
|
||||||
|
|
||||||
|
|
||||||
interface EventsAccordionItemProps {
|
interface EventsAccordionItemProps {
|
||||||
@ -44,7 +45,8 @@ const EventsAccordionItem = ({
|
|||||||
const duration = getDurationFromTimestamps(event.start_time, event.end_time)
|
const duration = getDurationFromTimestamps(event.start_time, event.end_time)
|
||||||
return (
|
return (
|
||||||
<Group>
|
<Group>
|
||||||
<Text>{t('player.object')}: {event.label}</Text>
|
<Text fw={700}>{t('player.object')}:</Text>
|
||||||
|
<Text >{event.label}</Text>
|
||||||
<Text>{time}</Text>
|
<Text>{time}</Text>
|
||||||
{duration ?
|
{duration ?
|
||||||
<Text>{duration}</Text>
|
<Text>{duration}</Text>
|
||||||
@ -77,6 +79,14 @@ const EventsAccordionItem = ({
|
|||||||
<Accordion.Item key={event.id + 'Item'} value={event.id}>
|
<Accordion.Item key={event.id + 'Item'} value={event.id}>
|
||||||
<Accordion.Control key={event.id + 'Control'}>
|
<Accordion.Control key={event.id + 'Control'}>
|
||||||
<Flex justify='space-between'>
|
<Flex justify='space-between'>
|
||||||
|
{!hostName ? <></> :
|
||||||
|
<BlobImage
|
||||||
|
maw={200}
|
||||||
|
mr='1rem'
|
||||||
|
fit="contain"
|
||||||
|
withPlaceholder
|
||||||
|
src={proxyApi.eventThumbnailUrl(hostName, event.id)} />
|
||||||
|
}
|
||||||
{eventLabel(event)}
|
{eventLabel(event)}
|
||||||
<Group>
|
<Group>
|
||||||
<AccordionShareButton recordUrl={eventVideoURL} />
|
<AccordionShareButton recordUrl={eventVideoURL} />
|
||||||
|
|||||||
@ -26,7 +26,7 @@ const SelectedDayList = ({
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (camera && host) {
|
if (camera && host) {
|
||||||
const hostName = mapHostToHostname(host)
|
const hostName = mapHostToHostname(host)
|
||||||
if (hostName){
|
if (hostName) {
|
||||||
return proxyApi.getRecordingsSummary(hostName, camera.name, getResolvedTimeZone())
|
return proxyApi.getRecordingsSummary(hostName, camera.name, getResolvedTimeZone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,14 +44,17 @@ const SelectedDayList = ({
|
|||||||
if (!data) return <Text>Not have response from server</Text>
|
if (!data) return <Text>Not have response from server</Text>
|
||||||
|
|
||||||
const stringDay = dateToQueryString(day)
|
const stringDay = dateToQueryString(day)
|
||||||
const recordingsDay = data.find(record => record.day === stringDay)
|
const recordingsDay = data.find(record => record.day === stringDay)
|
||||||
if (!recordingsDay) return <Center><Text>Not have record at {stringDay}</Text></Center>
|
if (!recordingsDay) return <Center><Text>Not have record at {stringDay}</Text></Center>
|
||||||
|
|
||||||
if (!isProduction) console.log('SelectedDayList rendered')
|
if (!isProduction) console.log('SelectedDayList rendered')
|
||||||
return (
|
return (
|
||||||
<Flex w='100%' h='100%' direction='column' align='center'>
|
<Flex w='100%' h='100%' direction='column' align='center'>
|
||||||
<Text>{host.name} / {camera.name} / {stringDay}</Text>
|
<Text>{host.name} / {camera.name} / {stringDay}</Text>
|
||||||
<DayAccordion recordSummary={recordingsDay} />
|
<DayAccordion
|
||||||
|
host={host}
|
||||||
|
camera={camera}
|
||||||
|
recordSummary={recordingsDay} />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user