fix tags handlers and schemas
This commit is contained in:
parent
90114ac7a6
commit
f50bfa6cb6
@ -132,8 +132,6 @@ const EditCameraPage = () => {
|
|||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!selectedMask || !points) return
|
if (!selectedMask || !points) return
|
||||||
console.log('type', selectedMask?.type)
|
|
||||||
console.log('save', points)
|
|
||||||
mutate()
|
mutate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,9 @@ import {
|
|||||||
GetCameraWHostWConfig, GetRole,
|
GetCameraWHostWConfig, GetRole,
|
||||||
GetRoleWCameras, GetExportedFile, recordingSchema,
|
GetRoleWCameras, GetExportedFile, recordingSchema,
|
||||||
oidpConfig,
|
oidpConfig,
|
||||||
OIDPConfig
|
OIDPConfig,
|
||||||
|
GetCameraWHost,
|
||||||
|
GetCamera
|
||||||
} from "./frigate.schema";
|
} from "./frigate.schema";
|
||||||
import { FrigateConfig } from "../../types/frigateConfig";
|
import { FrigateConfig } from "../../types/frigateConfig";
|
||||||
import { RecordSummary } from "../../types/record";
|
import { RecordSummary } from "../../types/record";
|
||||||
@ -40,21 +42,13 @@ export const frigateApi = {
|
|||||||
putConfigs: (config: PutConfig[]) => instanceApi.put('apiv1/config', config).then(res => res.data),
|
putConfigs: (config: PutConfig[]) => instanceApi.put('apiv1/config', config).then(res => res.data),
|
||||||
putOIDPConfig: (config: OIDPConfig) => instanceApi.put('apiv1/config/oidp', config).then(res => res.data),
|
putOIDPConfig: (config: OIDPConfig) => instanceApi.put('apiv1/config/oidp', config).then(res => res.data),
|
||||||
putOIDPConfigTest: (config: OIDPConfig) => instanceApi.put('apiv1/config/oidp/test', config).then(res => res.data),
|
putOIDPConfigTest: (config: OIDPConfig) => instanceApi.put('apiv1/config/oidp/test', config).then(res => res.data),
|
||||||
getHosts: () => instanceApi.get<GetFrigateHost[]>('apiv1/frigate-hosts').then(res => {
|
getHosts: () => instanceApi.get<GetFrigateHost[]>('apiv1/frigate-hosts').then(res => res.data),
|
||||||
return res.data
|
getHost: (id: string) => instanceApi.get<GetFrigateHost>(`apiv1/frigate-hosts/${id}`).then(res => res.data),
|
||||||
}),
|
|
||||||
getHost: (id: string) => instanceApi.get<GetFrigateHost>(`apiv1/frigate-hosts/${id}`).then(res => {
|
|
||||||
return res.data
|
|
||||||
}),
|
|
||||||
getCamerasByHostId: (hostId: string) => instanceApi.get<GetCameraWHostWConfig[]>(`apiv1/cameras/host/${hostId}`).then(res => res.data),
|
getCamerasByHostId: (hostId: string) => instanceApi.get<GetCameraWHostWConfig[]>(`apiv1/cameras/host/${hostId}`).then(res => res.data),
|
||||||
getCamerasWHost: () => instanceApi.get<GetCameraWHostWConfig[]>(`apiv1/cameras`).then(res => res.data),
|
getCamerasWHost: () => instanceApi.get<GetCameraWHostWConfig[]>(`apiv1/cameras`).then(res => res.data),
|
||||||
getCameraWHost: (id: string) => instanceApi.get<GetCameraWHostWConfig>(`apiv1/cameras/${id}`).then(res => { return res.data }),
|
getCameraWHost: (id: string) => instanceApi.get<GetCameraWHostWConfig>(`apiv1/cameras/${id}`).then(res => res.data),
|
||||||
putHosts: (hosts: PutFrigateHost[]) => instanceApi.put<GetFrigateHost[]>('apiv1/frigate-hosts', hosts).then(res => {
|
putHosts: (hosts: PutFrigateHost[]) => instanceApi.put<GetFrigateHost[]>('apiv1/frigate-hosts', hosts).then(res => res.data),
|
||||||
return res.data
|
deleteHosts: (hosts: DeleteFrigateHost[]) => instanceApi.delete<GetFrigateHost[]>('apiv1/frigate-hosts', { data: hosts }).then(res => res.data),
|
||||||
}),
|
|
||||||
deleteHosts: (hosts: DeleteFrigateHost[]) => instanceApi.delete<GetFrigateHost[]>('apiv1/frigate-hosts', { data: hosts }).then(res => {
|
|
||||||
return res.data
|
|
||||||
}),
|
|
||||||
getRoles: () => instanceApi.get<GetRole[]>('apiv1/roles').then(res => res.data),
|
getRoles: () => instanceApi.get<GetRole[]>('apiv1/roles').then(res => res.data),
|
||||||
putRoles: () => instanceApi.put<GetRole[]>('apiv1/roles').then(res => res.data),
|
putRoles: () => instanceApi.put<GetRole[]>('apiv1/roles').then(res => res.data),
|
||||||
putRoleWCameras: (roleId: string, cameraIDs: string[]) => instanceApi.put<GetRoleWCameras>(`apiv1/roles/${roleId}/cameras`,
|
putRoleWCameras: (roleId: string, cameraIDs: string[]) => instanceApi.put<GetRoleWCameras>(`apiv1/roles/${roleId}/cameras`,
|
||||||
@ -64,7 +58,9 @@ export const frigateApi = {
|
|||||||
getAdminRole: () => instanceApi.get<GetConfig>('apiv1/config/admin').then(res => res.data),
|
getAdminRole: () => instanceApi.get<GetConfig>('apiv1/config/admin').then(res => res.data),
|
||||||
getUserTags: () => instanceApi.get<GetUserTag[]>('apiv1/tags').then(res => res.data),
|
getUserTags: () => instanceApi.get<GetUserTag[]>('apiv1/tags').then(res => res.data),
|
||||||
putUserTag: (tag: PutUserTag) => instanceApi.put<GetUserTag>('apiv1/tags', tag).then(res => res.data),
|
putUserTag: (tag: PutUserTag) => instanceApi.put<GetUserTag>('apiv1/tags', tag).then(res => res.data),
|
||||||
delUserTag: (tagId: string) => instanceApi.delete<GetUserTag>(`apiv1/tags/${tagId}`).then(res => res.data)
|
delUserTag: (tagId: string) => instanceApi.delete<GetUserTag>(`apiv1/tags/${tagId}`).then(res => res.data),
|
||||||
|
putTagToCamera: (cameraId: string, tagId: string) => instanceApi.put<GetCamera>(`apiv1/cameras/${cameraId}/tag/${tagId}`).then(res => res.data),
|
||||||
|
deleteTagFromCamera: (cameraId: string, tagId: string) => instanceApi.delete<GetCamera>(`apiv1/cameras/${cameraId}/tag/${tagId}`).then(res => res.data),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const proxyPrefix = `${proxyURL.protocol}//${proxyURL.host}/proxy/`
|
export const proxyPrefix = `${proxyURL.protocol}//${proxyURL.host}/proxy/`
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { CameraConfig, FrigateConfig } from "../../types/frigateConfig";
|
import { CameraConfig, FrigateConfig } from "../../types/frigateConfig";
|
||||||
|
import { cameraTag } from "../../types/tags";
|
||||||
|
|
||||||
export const putConfigSchema = z.object({
|
export const putConfigSchema = z.object({
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
@ -48,6 +49,7 @@ const getCameraSchema = z.object({
|
|||||||
name: z.string(),
|
name: z.string(),
|
||||||
url: z.string(),
|
url: z.string(),
|
||||||
state: z.boolean().nullable(),
|
state: z.boolean().nullable(),
|
||||||
|
tags: cameraTag.array()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getRoleSchema = z.object({
|
export const getRoleSchema = z.object({
|
||||||
@ -127,6 +129,7 @@ export type OIDPConfig = z.infer<typeof oidpConfig>
|
|||||||
export type GetFrigateHost = z.infer<typeof getFrigateHostSchema>
|
export type GetFrigateHost = z.infer<typeof getFrigateHostSchema>
|
||||||
// export type GetFrigateHostWithCameras = z.infer<typeof getFrigateHostWithCamerasSchema>
|
// export type GetFrigateHostWithCameras = z.infer<typeof getFrigateHostWithCamerasSchema>
|
||||||
export type GetFrigateHostWConfig = GetFrigateHost & { config: FrigateConfig }
|
export type GetFrigateHostWConfig = GetFrigateHost & { config: FrigateConfig }
|
||||||
|
export type GetCamera = z.infer<typeof getCameraSchema>
|
||||||
export type GetCameraWHost = z.infer<typeof getCameraWithHostSchema>
|
export type GetCameraWHost = z.infer<typeof getCameraWithHostSchema>
|
||||||
export type GetCameraWHostWConfig = GetCameraWHost & { config?: CameraConfig }
|
export type GetCameraWHostWConfig = GetCameraWHost & { config?: CameraConfig }
|
||||||
export type PutFrigateHost = z.infer<typeof putFrigateHostSchema>
|
export type PutFrigateHost = z.infer<typeof putFrigateHostSchema>
|
||||||
|
|||||||
71
src/shared/components/AddBadge.tsx
Normal file
71
src/shared/components/AddBadge.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { ActionIcon, Badge, Button, Menu, rem } from '@mantine/core';
|
||||||
|
import { IconPlus } from '@tabler/icons-react';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import React from 'react';
|
||||||
|
import { frigateQueryKeys, frigateApi } from '../../services/frigate.proxy/frigate.api';
|
||||||
|
import CogwheelLoader from './loaders/CogwheelLoader';
|
||||||
|
import RetryError from './RetryError';
|
||||||
|
|
||||||
|
interface AddBadgeProps {
|
||||||
|
onClick?(tagId: string): void,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const AddBadge: React.FC<AddBadgeProps> = ({
|
||||||
|
onClick
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const { data, isPending, isError, refetch } = useQuery({
|
||||||
|
queryKey: [frigateQueryKeys.getUserTags],
|
||||||
|
queryFn: frigateApi.getUserTags
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleClick = (tagId: string) => {
|
||||||
|
if (onClick) onClick(tagId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPending) return <CogwheelLoader />
|
||||||
|
if (isError) return <RetryError onRetry={refetch} />
|
||||||
|
|
||||||
|
if (!data || data.length < 1) return (
|
||||||
|
<Badge
|
||||||
|
mt='0.2rem'
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<ActionIcon size="xs" color="blue" radius="xl" variant="transparent">
|
||||||
|
<IconPlus size={rem(20)} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
shadow="md"
|
||||||
|
width={200}
|
||||||
|
transitionProps={{ transition: 'pop-top-right' }}
|
||||||
|
position="top-end"
|
||||||
|
withinPortal
|
||||||
|
>
|
||||||
|
<Menu.Target>
|
||||||
|
<Badge
|
||||||
|
mt='0.2rem'
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<ActionIcon size="xs" color="blue" radius="xl" variant="transparent">
|
||||||
|
<IconPlus size={rem(20)} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Badge>
|
||||||
|
</Menu.Target>
|
||||||
|
<Menu.Dropdown>
|
||||||
|
{data.map((item) => (
|
||||||
|
<Menu.Item key={item.id} onClick={() => handleClick(item.id)}>
|
||||||
|
{item.value}
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddBadge;
|
||||||
49
src/shared/components/TagBadge.tsx
Normal file
49
src/shared/components/TagBadge.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { ActionIcon, rem, Badge } from '@mantine/core';
|
||||||
|
import { IconX } from '@tabler/icons-react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const RemoveButton = ({ onClick }: { onClick(): void }) => {
|
||||||
|
return (
|
||||||
|
<ActionIcon onClick={onClick} size="xs" color="blue" radius="xl" variant="transparent">
|
||||||
|
<IconX size={rem(10)} />
|
||||||
|
</ActionIcon>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface TagBadgeProps {
|
||||||
|
value: string,
|
||||||
|
label: string,
|
||||||
|
onClick?(value: string): void,
|
||||||
|
onClose?(value: string): void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const TagBadge: React.FC<TagBadgeProps> = ({
|
||||||
|
value,
|
||||||
|
label,
|
||||||
|
onClick,
|
||||||
|
onClose,
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const handleClick = (value: string) => {
|
||||||
|
if (onClick) onClick(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
if (onClose) onClose(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
mt='0.2rem'
|
||||||
|
mr='0.3rem'
|
||||||
|
variant="outline"
|
||||||
|
pr={3}
|
||||||
|
rightSection={<RemoveButton onClick={handleClose} />}
|
||||||
|
onClick={() => handleClick}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagBadge;
|
||||||
@ -43,7 +43,7 @@ const UserTagsFilter = () => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const { mutate } = useMutation({
|
const { mutate: addTag } = useMutation({
|
||||||
mutationFn: (newTag: PutUserTag) => frigateApi.putUserTag(newTag)
|
mutationFn: (newTag: PutUserTag) => frigateApi.putUserTag(newTag)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.response && error.response.data) {
|
if (error.response && error.response.data) {
|
||||||
@ -52,8 +52,8 @@ const UserTagsFilter = () => {
|
|||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}),
|
}),
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
setSelectedList([...selectedList, data.id])
|
|
||||||
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getUserTags] })
|
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getUserTags] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getCamerasWHost] })
|
||||||
},
|
},
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
if (e && e.message) {
|
if (e && e.message) {
|
||||||
@ -67,7 +67,6 @@ const UserTagsFilter = () => {
|
|||||||
icon: <IconAlertCircle />,
|
icon: <IconAlertCircle />,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getFrigateHosts] })
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -81,6 +80,7 @@ const UserTagsFilter = () => {
|
|||||||
}),
|
}),
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getUserTags] })
|
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getUserTags] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: [frigateQueryKeys.getCamerasWHost] })
|
||||||
const updatedList = selectedList.filter(item => data.id === item)
|
const updatedList = selectedList.filter(item => data.id === item)
|
||||||
setSelectedList(updatedList)
|
setSelectedList(updatedList)
|
||||||
},
|
},
|
||||||
@ -103,9 +103,8 @@ const UserTagsFilter = () => {
|
|||||||
const saveNewTag = (value: string) => {
|
const saveNewTag = (value: string) => {
|
||||||
const newTag: PutUserTag = {
|
const newTag: PutUserTag = {
|
||||||
value,
|
value,
|
||||||
cameraIds: []
|
|
||||||
}
|
}
|
||||||
mutate(newTag)
|
addTag(newTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCreate = (query: string | SelectItem | null | undefined) => {
|
const onCreate = (query: string | SelectItem | null | undefined) => {
|
||||||
@ -128,7 +127,6 @@ const UserTagsFilter = () => {
|
|||||||
if (isError) return <RetryError onRetry={refetch} />
|
if (isError) return <RetryError onRetry={refetch} />
|
||||||
|
|
||||||
const handleOnChange = (value: string[]) => {
|
const handleOnChange = (value: string[]) => {
|
||||||
console.log('cahnged:', value)
|
|
||||||
const updatedList = selectedList.filter(item => value.includes(item))
|
const updatedList = selectedList.filter(item => value.includes(item))
|
||||||
const newItems = value.filter(item => !selectedList.includes(item))
|
const newItems = value.filter(item => !selectedList.includes(item))
|
||||||
setSelectedList([...updatedList, ...newItems])
|
setSelectedList([...updatedList, ...newItems])
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { z } from "zod";
|
|||||||
|
|
||||||
export const putUserTag = z.object({
|
export const putUserTag = z.object({
|
||||||
value: z.string(),
|
value: z.string(),
|
||||||
cameraIds: z.string().array()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getUserTag = z.object({
|
export const getUserTag = z.object({
|
||||||
@ -12,9 +11,14 @@ export const getUserTag = z.object({
|
|||||||
updatedAt: z.string().datetime(),
|
updatedAt: z.string().datetime(),
|
||||||
value: z.string(),
|
value: z.string(),
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
cameraIds: z.string().array(),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const cameraTag = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
value: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type CameraTag = z.infer<typeof cameraTag>
|
||||||
export type GetUserTag = z.infer<typeof getUserTag>
|
export type GetUserTag = z.infer<typeof getUserTag>
|
||||||
export type PutUserTag = z.infer<typeof putUserTag>
|
export type PutUserTag = z.infer<typeof putUserTag>
|
||||||
|
|
||||||
@ -24,3 +28,4 @@ export const mapUserTagsToSelectItems = (tags: GetUserTag[]): SelectItem[] => {
|
|||||||
label: tag.value
|
label: tag.value
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import { Button, Card, Flex, Grid, Group, Text, createStyles } from '@mantine/core';
|
import { Button, Card, Flex, Grid, Group, Text, createStyles } from '@mantine/core';
|
||||||
import { useIntersection } from '@mantine/hooks';
|
import { useIntersection } from '@mantine/hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useAdminRole } from '../hooks/useAdminRole';
|
||||||
import { recordingsPageQuery } from '../pages/RecordingsPage';
|
import { recordingsPageQuery } from '../pages/RecordingsPage';
|
||||||
import { routesPath } from '../router/routes.path';
|
import { routesPath } from '../router/routes.path';
|
||||||
import { mapHostToHostname, proxyApi } from '../services/frigate.proxy/frigate.api';
|
import { mapHostToHostname, proxyApi } from '../services/frigate.proxy/frigate.api';
|
||||||
import { GetCameraWHostWConfig } from '../services/frigate.proxy/frigate.schema';
|
import { GetCameraWHostWConfig } from '../services/frigate.proxy/frigate.schema';
|
||||||
import AutoUpdatedImage from '../shared/components/images/AutoUpdatedImage';
|
import AutoUpdatedImage from '../shared/components/images/AutoUpdatedImage';
|
||||||
import { useTranslation } from 'react-i18next';
|
import CameraTagsList from './CameraTagsList';
|
||||||
import { useAdminRole } from '../hooks/useAdminRole';
|
|
||||||
|
|
||||||
const useStyles = createStyles((theme) => ({
|
const useStyles = createStyles((theme) => ({
|
||||||
mainCard: {
|
mainCard: {
|
||||||
@ -55,7 +56,7 @@ const CameraCard = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (entry?.isIntersecting)
|
if (entry?.isIntersecting)
|
||||||
setRenderImage(true)
|
setRenderImage(true)
|
||||||
}, [entry?.isIntersecting])
|
}, [entry?.isIntersecting])
|
||||||
|
|
||||||
const handleOpenLiveView = () => {
|
const handleOpenLiveView = () => {
|
||||||
const url = routesPath.LIVE_PATH.replace(':id', camera.id)
|
const url = routesPath.LIVE_PATH.replace(':id', camera.id)
|
||||||
@ -73,6 +74,8 @@ const CameraCard = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid.Col md={6} lg={3} p='0.2rem'>
|
<Grid.Col md={6} lg={3} p='0.2rem'>
|
||||||
<Card ref={ref} h='100%' radius="lg" padding='0.5rem' className={classes.mainCard}>
|
<Card ref={ref} h='100%' radius="lg" padding='0.5rem' className={classes.mainCard}>
|
||||||
@ -87,6 +90,7 @@ const CameraCard = ({
|
|||||||
{!isAdmin ? null : <Button size='sm' onClick={handleOpenEditCamera}>{t('edit')}</Button>}
|
{!isAdmin ? null : <Button size='sm' onClick={handleOpenEditCamera}>{t('edit')}</Button>}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Group>
|
</Group>
|
||||||
|
<CameraTagsList camera={camera} />
|
||||||
</Card>
|
</Card>
|
||||||
</Grid.Col >
|
</Grid.Col >
|
||||||
);
|
);
|
||||||
|
|||||||
107
src/widgets/CameraTagsList.tsx
Normal file
107
src/widgets/CameraTagsList.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { Flex } from '@mantine/core';
|
||||||
|
import { dataTagSymbol, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { frigateApi, frigateQueryKeys } from '../services/frigate.proxy/frigate.api';
|
||||||
|
import { GetCameraWHostWConfig } from '../services/frigate.proxy/frigate.schema';
|
||||||
|
import AddBadge from '../shared/components/AddBadge';
|
||||||
|
import TagBadge from '../shared/components/TagBadge';
|
||||||
|
import { CameraTag, PutUserTag } from '../types/tags';
|
||||||
|
import { notifications } from '@mantine/notifications';
|
||||||
|
import { IconAlertCircle } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
|
||||||
|
interface CameraTagsListProps {
|
||||||
|
camera: GetCameraWHostWConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const CameraTagsList: React.FC<CameraTagsListProps> = ({
|
||||||
|
camera
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const [tagsList, setTagsList] = useState<CameraTag[]>(camera.tags)
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setTagsList(camera.tags)
|
||||||
|
},[camera])
|
||||||
|
|
||||||
|
|
||||||
|
const { mutate: addTagToCamera } = useMutation({
|
||||||
|
mutationFn: async (tagId: string) => frigateApi.putTagToCamera(camera.id, tagId)
|
||||||
|
.catch(error => {
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
return Promise.reject(error.response.data)
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
|
}),
|
||||||
|
onSuccess: (data) => {
|
||||||
|
setTagsList(data.tags)
|
||||||
|
},
|
||||||
|
onError: (e) => {
|
||||||
|
if (e && e.message) {
|
||||||
|
notifications.show({
|
||||||
|
id: e.message,
|
||||||
|
withCloseButton: true,
|
||||||
|
autoClose: 5000,
|
||||||
|
title: "Error",
|
||||||
|
message: e.message,
|
||||||
|
color: 'red',
|
||||||
|
icon: <IconAlertCircle />,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const { mutate: deleteTagFromCamera } = useMutation({
|
||||||
|
mutationFn: (tagId: string) => frigateApi.deleteTagFromCamera(camera.id, tagId)
|
||||||
|
.catch(error => {
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
return Promise.reject(error.response.data)
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
|
}),
|
||||||
|
onSuccess: (data) => setTagsList(data.tags),
|
||||||
|
onError: (e) => {
|
||||||
|
if (e && e.message) {
|
||||||
|
notifications.show({
|
||||||
|
id: e.message,
|
||||||
|
withCloseButton: true,
|
||||||
|
autoClose: 5000,
|
||||||
|
title: "Error",
|
||||||
|
message: e.message,
|
||||||
|
color: 'red',
|
||||||
|
icon: <IconAlertCircle />,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleAddTagClick = (tagId: string) => {
|
||||||
|
if (tagId) addTagToCamera(tagId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteTagClick = (tagId: string) => {
|
||||||
|
if (tagId) deleteTagFromCamera(tagId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex justify='end' w='100%' wrap="wrap">
|
||||||
|
{
|
||||||
|
tagsList && tagsList.length > 0 ? tagsList.map(tag => (
|
||||||
|
<TagBadge
|
||||||
|
key={tag.id}
|
||||||
|
value={tag.id}
|
||||||
|
label={tag.value}
|
||||||
|
onClose={handleDeleteTagClick}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
: <></>
|
||||||
|
}
|
||||||
|
<AddBadge
|
||||||
|
onClick={handleAddTagClick}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CameraTagsList;
|
||||||
Loading…
Reference in New Issue
Block a user