Compare commits

...

3 Commits

4 changed files with 49 additions and 15 deletions

View File

@ -53,7 +53,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
import { MdImageSearch } from "react-icons/md";
import { useTranslation } from "react-i18next";
import { getTranslatedLabel } from "@/utils/i18n";
import { CameraNameLabel } from "../camera/FriendlyNameLabel";
import { CameraNameLabel, ZoneNameLabel } from "../camera/FriendlyNameLabel";
type InputWithTagsProps = {
inputFocused: boolean;
@ -831,6 +831,8 @@ export default function InputWithTags({
getTranslatedLabel(value)
) : filterType === "cameras" ? (
<CameraNameLabel camera={value} />
) : filterType === "zones" ? (
<ZoneNameLabel zone={value} />
) : (
value.replaceAll("_", " ")
)}
@ -934,6 +936,11 @@ export default function InputWithTags({
<CameraNameLabel camera={suggestion} />
{")"}
</>
) : currentFilterType === "zones" ? (
<>
{suggestion} {" ("} <ZoneNameLabel zone={suggestion} />
{")"}
</>
) : (
suggestion
)
@ -943,6 +950,8 @@ export default function InputWithTags({
{currentFilterType ? (
currentFilterType === "cameras" ? (
<CameraNameLabel camera={suggestion} />
) : currentFilterType === "zones" ? (
<ZoneNameLabel zone={suggestion} />
) : (
formatFilterValues(currentFilterType, suggestion)
)

View File

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

View File

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

View File

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