This commit is contained in:
Josh Hawkins 2026-04-07 09:41:56 -05:00
parent acf4b4093b
commit 8e5483f0c0
3 changed files with 81 additions and 9 deletions

View File

@ -62,7 +62,10 @@
"zones": "Zones",
"ratio": "Ratio",
"area": "Area",
"score": "Score"
"score": "Score",
"computedScore": "Computed Score",
"topScore": "Top Score",
"toggleAdvancedScores": "Toggle advanced scores"
}
},
"annotationSettings": {

View File

@ -9,7 +9,12 @@ import { FrigateConfig } from "@/types/frigateConfig";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import { use24HourTime } from "@/hooks/use-date-utils";
import { getIconForLabel } from "@/utils/iconUtil";
import { LuCircle, LuFolderX } from "react-icons/lu";
import {
LuChevronDown,
LuChevronRight,
LuCircle,
LuFolderX,
} from "react-icons/lu";
import { cn } from "@/lib/utils";
import HlsVideoPlayer from "@/components/player/HlsVideoPlayer";
import { baseUrl } from "@/api/baseUrl";
@ -899,6 +904,7 @@ function LifecycleIconRow({
const { t } = useTranslation(["views/explore", "components/player"]);
const { data: config } = useSWR<FrigateConfig>("config");
const [isOpen, setIsOpen] = useState(false);
const [showAdvancedScores, setShowAdvancedScores] = useState(false);
const navigate = useNavigate();
const isAdmin = useIsAdmin();
@ -993,12 +999,31 @@ function LifecycleIconRow({
[item.data.box],
);
const score = useMemo(() => {
if (item.data.score !== undefined) {
return (item.data.score * 100).toFixed(0) + "%";
}
return "N/A";
}, [item.data.score]);
const currentScore = useMemo(
() =>
item.data.score !== undefined
? (item.data.score * 100).toFixed(0) + "%"
: null,
[item.data.score],
);
const computedScore = useMemo(
() =>
item.data.computed_score !== undefined &&
item.data.computed_score !== null &&
item.data.computed_score > 0
? (item.data.computed_score * 100).toFixed(0) + "%"
: null,
[item.data.computed_score],
);
const topScore = useMemo(
() =>
item.data.top_score !== undefined &&
item.data.top_score !== null &&
item.data.top_score > 0
? (item.data.top_score * 100).toFixed(0) + "%"
: null,
[item.data.top_score],
);
return (
<div
@ -1034,8 +1059,50 @@ function LifecycleIconRow({
<span className="text-primary-variant">
{t("trackingDetails.lifecycleItemDesc.header.score")}
</span>
<span className="font-medium text-primary">{score}</span>
<span className="font-medium text-primary">
{currentScore ?? "N/A"}
</span>
{(computedScore || topScore) && (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
setShowAdvancedScores((v) => !v);
}}
className="ml-1 inline-flex items-center text-primary-variant hover:text-primary"
aria-expanded={showAdvancedScores}
aria-label={t(
"trackingDetails.lifecycleItemDesc.header.toggleAdvancedScores",
)}
>
{showAdvancedScores ? (
<LuChevronDown className="size-3.5" />
) : (
<LuChevronRight className="size-3.5" />
)}
</button>
)}
</div>
{showAdvancedScores && computedScore && (
<div className="flex items-center gap-1.5">
<span className="text-primary-variant">
{t(
"trackingDetails.lifecycleItemDesc.header.computedScore",
)}
</span>
<span className="font-medium text-primary">
{computedScore}
</span>
</div>
)}
{showAdvancedScores && topScore && (
<div className="flex items-center gap-1.5">
<span className="text-primary-variant">
{t("trackingDetails.lifecycleItemDesc.header.topScore")}
</span>
<span className="font-medium text-primary">{topScore}</span>
</div>
)}
<div className="flex items-center gap-1.5">
<span className="text-primary-variant">
{t("trackingDetails.lifecycleItemDesc.header.ratio")}

View File

@ -17,6 +17,8 @@ export type TrackingDetailsSequence = {
camera: string;
label: string;
score: number;
computed_score?: number;
top_score?: number;
sub_label: string;
box?: [number, number, number, number];
region: [number, number, number, number];