Compare commits

...

2 Commits

5 changed files with 47 additions and 30 deletions

View File

@ -45,8 +45,9 @@ import { useNavigate } from "react-router-dom";
import { ObjectPath } from "./ObjectPath";
import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
import { IoPlayCircleOutline } from "react-icons/io5";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { getTranslatedLabel } from "@/utils/i18n";
import { resolveZoneName } from "@/hooks/use-zone-friendly-name";
type ObjectLifecycleProps = {
className?: string;
@ -62,7 +63,7 @@ export default function ObjectLifecycle({
setPane,
}: ObjectLifecycleProps) {
const { t } = useTranslation(["views/explore"]);
const { data: config } = useSWR<FrigateConfig>("config");
const { data: eventSequence } = useSWR<ObjectLifecycleSequence[]>([
"timeline",
{
@ -70,7 +71,12 @@ export default function ObjectLifecycle({
},
]);
const { data: config } = useSWR<FrigateConfig>("config");
eventSequence?.map((event) => {
event.data.zones_friendly_names = event.data?.zones?.map((zone) => {
return resolveZoneName(config, zone);
});
});
const apiHost = useApiHost();
const navigate = useNavigate();
@ -673,7 +679,9 @@ export default function ObjectLifecycle({
/>
</div>
<div className="flex w-full flex-row justify-between">
<div>{getLifecycleItemDescription(item)}</div>
<Trans>
<div>{getLifecycleItemDescription(item)}</div>
</Trans>
<div className={cn("p-1 text-sm")}>
{formattedEventTimestamp}
</div>
@ -731,7 +739,9 @@ export default function ObjectLifecycle({
}}
/>
<span className="smart-capitalize">
{zone.replaceAll("_", " ")}
{item.data?.zones_friendly_names?.[
zidx
] ?? zone.replaceAll("_", " ")}
</span>
</div>
))}

View File

@ -22,6 +22,7 @@ export type ObjectLifecycleSequence = {
attribute: string;
attribute_box?: [number, number, number, number];
zones: string[];
zones_friendly_names?: string[];
};
class_type: LifecycleClassType;
source_id: string;

View File

@ -1,6 +1,6 @@
import { ObjectLifecycleSequence } from "@/types/timeline";
import { t } from "i18next";
import { getTranslatedLabel } from "./i18n";
import i18n, { getTranslatedLabel } from "./i18n";
export function getLifecycleItemDescription(
lifecycleItem: ObjectLifecycleSequence,
@ -11,6 +11,17 @@ export function getLifecycleItemDescription(
const label = getTranslatedLabel(rawLabel);
let supportedListFormat = false;
let zonesFormatter: Intl.ListFormat | null = null;
if (typeof Intl !== "undefined" && Intl.ListFormat) {
supportedListFormat = true;
zonesFormatter = new Intl.ListFormat(i18n.language, {
style: "long",
type: "conjunction",
});
}
switch (lifecycleItem.class_type) {
case "visible":
return t("objectLifecycle.lifecycleItemDesc.visible", {
@ -21,7 +32,18 @@ export function getLifecycleItemDescription(
return t("objectLifecycle.lifecycleItemDesc.entered_zone", {
ns: "views/explore",
label,
zones: lifecycleItem.data.zones.join(" and ").replaceAll("_", " "),
zones:
supportedListFormat && zonesFormatter
? zonesFormatter.format(
lifecycleItem.data.zones_friendly_names?.map(
(x) => `<strong>${x}</strong>`,
) ??
lifecycleItem.data.zones.map((x) => `<strong>${x}</strong>`),
)
: (
lifecycleItem.data.zones_friendly_names ??
lifecycleItem.data.zones
).join(" and "),
});
case "active":
return t("objectLifecycle.lifecycleItemDesc.active", {

View File

@ -23,7 +23,6 @@ import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import axios from "axios";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
import { capitalizeFirstLetter } from "@/utils/stringUtil";
import { MdCircle } from "react-icons/md";
import { cn } from "@/lib/utils";
import { Trans, useTranslation } from "react-i18next";
@ -88,7 +87,7 @@ export default function CameraSettingsView({
// zones and labels
const getZoneName = useCallback(
(cameraId: string, zoneId: string) =>
(zoneId: string, cameraId?: string) =>
resolveZoneName(config, zoneId, cameraId),
[config],
);
@ -98,7 +97,7 @@ export default function CameraSettingsView({
return Object.entries(cameraConfig.zones).map(([name, zoneData]) => ({
camera: cameraConfig.name,
name,
friendly_name: getZoneName(cameraConfig.name, name),
friendly_name: getZoneName(name, cameraConfig.name),
objects: zoneData.objects,
color: zoneData.color,
}));
@ -557,12 +556,7 @@ export default function CameraSettingsView({
{
alertsLabels,
zone: watchedAlertsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.map((zone) => getZoneName(zone))
.join(", "),
cameraName: selectCameraName,
},
@ -676,12 +670,7 @@ export default function CameraSettingsView({
values={{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.map((zone) => getZoneName(zone))
.join(", "),
cameraName: selectCameraName,
}}
@ -693,12 +682,7 @@ export default function CameraSettingsView({
values={{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.map((zone) => getZoneName(zone))
.join(", "),
cameraName: selectCameraName,
}}

View File

@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2020",
"target": "ES2021",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable", "ES2021.String"],
"lib": ["ES2021", "DOM", "DOM.Iterable", "ES2021.String"],
"module": "ESNext",
"skipLibCheck": true,
"baseUrl": ".",