chore: add ObjectTrack zone friendly name support

This commit is contained in:
ZhaiSoul 2025-10-23 13:57:32 +00:00
parent 450623e927
commit 17e89da6ca
3 changed files with 39 additions and 14 deletions

View File

@ -11,6 +11,7 @@ import {
import { TooltipPortal } from "@radix-ui/react-tooltip"; import { TooltipPortal } from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { resolveZoneName } from "@/hooks/use-zone-friendly-name";
type ObjectTrackOverlayProps = { type ObjectTrackOverlayProps = {
camera: string; camera: string;
@ -127,6 +128,9 @@ export default function ObjectTrackOverlay({
?.filter((event) => event.data.box !== undefined) ?.filter((event) => event.data.box !== undefined)
.map((event) => { .map((event) => {
const [left, top, width, height] = event.data.box!; const [left, top, width, height] = event.data.box!;
event.data.zones_friendly_names = event?.data?.zones?.map((zone) => {
return resolveZoneName(config, zone);
});
return { return {
x: left + width / 2, // Center x x: left + width / 2, // Center x
@ -136,7 +140,7 @@ export default function ObjectTrackOverlay({
}; };
}) || [] }) || []
); );
}, [objectTimeline]); }, [config, objectTimeline]);
// final object path with timeline points included // final object path with timeline points included
const pathPoints = useMemo(() => { const pathPoints = useMemo(() => {

View File

@ -7,7 +7,10 @@ import {
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import { TooltipPortal } from "@radix-ui/react-tooltip"; import { TooltipPortal } from "@radix-ui/react-tooltip";
import { getLifecycleItemDescription } from "@/utils/lifecycleUtil"; import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
import { useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { resolveZoneName } from "@/hooks/use-zone-friendly-name";
import { FrigateConfig } from "@/types/frigateConfig";
import useSWR from "swr";
type ObjectPathProps = { type ObjectPathProps = {
positions?: Position[]; positions?: Position[];
@ -42,16 +45,25 @@ export function ObjectPath({
visible = true, visible = true,
}: ObjectPathProps) { }: ObjectPathProps) {
const { t } = useTranslation(["views/explore"]); const { t } = useTranslation(["views/explore"]);
const { data: config } = useSWR<FrigateConfig>("config");
const getAbsolutePositions = useCallback(() => { const getAbsolutePositions = useCallback(() => {
if (!imgRef.current || !positions) return []; if (!imgRef.current || !positions) return [];
const imgRect = imgRef.current.getBoundingClientRect(); const imgRect = imgRef.current.getBoundingClientRect();
return positions.map((pos) => ({ return positions.map((pos) => {
x: pos.x * imgRect.width, if (config && pos.lifecycle_item) {
y: pos.y * imgRect.height, pos.lifecycle_item.data.zones_friendly_names =
timestamp: pos.timestamp, pos.lifecycle_item?.data.zones.map((zone) => {
lifecycle_item: pos.lifecycle_item, return resolveZoneName(config, zone);
})); });
}, [positions, imgRef]); }
return {
x: pos.x * imgRect.width,
y: pos.y * imgRect.height,
timestamp: pos.timestamp,
lifecycle_item: pos.lifecycle_item,
};
});
}, [imgRef, positions, config]);
const generateStraightPath = useCallback((points: Position[]) => { const generateStraightPath = useCallback((points: Position[]) => {
if (!points || points.length < 2) return ""; if (!points || points.length < 2) return "";
@ -103,9 +115,11 @@ export function ObjectPath({
</TooltipTrigger> </TooltipTrigger>
<TooltipPortal> <TooltipPortal>
<TooltipContent side="top" className="smart-capitalize"> <TooltipContent side="top" className="smart-capitalize">
{pos.lifecycle_item <Trans>
? getLifecycleItemDescription(pos.lifecycle_item) {pos.lifecycle_item
: t("objectLifecycle.trackedPoint")} ? getLifecycleItemDescription(pos.lifecycle_item)
: t("objectLifecycle.trackedPoint")}
</Trans>
</TooltipContent> </TooltipContent>
</TooltipPortal> </TooltipPortal>
</Tooltip> </Tooltip>

View File

@ -9,7 +9,7 @@ import {
formatUnixTimestampToDateTime, formatUnixTimestampToDateTime,
formatSecondsToDuration, formatSecondsToDuration,
} from "@/utils/dateUtil"; } from "@/utils/dateUtil";
import { useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import AnnotationOffsetSlider from "@/components/overlay/detail/AnnotationOffsetSlider"; import AnnotationOffsetSlider from "@/components/overlay/detail/AnnotationOffsetSlider";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import useSWR from "swr"; import useSWR from "swr";
@ -27,6 +27,7 @@ import { getTranslatedLabel } from "@/utils/i18n";
import EventMenu from "@/components/timeline/EventMenu"; import EventMenu from "@/components/timeline/EventMenu";
import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog"; import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { resolveZoneName } from "@/hooks/use-zone-friendly-name";
type DetailStreamProps = { type DetailStreamProps = {
reviewItems?: ReviewSegment[]; reviewItems?: ReviewSegment[];
@ -503,6 +504,10 @@ function LifecycleItem({ event, isActive, onSeek }: LifecycleItemProps) {
const { t } = useTranslation("views/events"); const { t } = useTranslation("views/events");
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
event.data.zones_friendly_names = event?.data?.zones?.map((zone) => {
return resolveZoneName(config, zone);
});
const formattedEventTimestamp = config const formattedEventTimestamp = config
? formatUnixTimestampToDateTime(event.timestamp ?? 0, { ? formatUnixTimestampToDateTime(event.timestamp ?? 0, {
timezone: config.ui.timezone, timezone: config.ui.timezone,
@ -536,7 +541,9 @@ function LifecycleItem({ event, isActive, onSeek }: LifecycleItemProps) {
<LifecycleIcon lifecycleItem={event} className="size-3" /> <LifecycleIcon lifecycleItem={event} className="size-3" />
</div> </div>
<div className="flex w-full flex-row justify-between"> <div className="flex w-full flex-row justify-between">
<div>{getLifecycleItemDescription(event)}</div> <Trans>
<div>{getLifecycleItemDescription(event)}</div>
</Trans>
<div className={cn("p-1 text-xs")}>{formattedEventTimestamp}</div> <div className={cn("p-1 text-xs")}>{formattedEventTimestamp}</div>
</div> </div>
</div> </div>