mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-19 01:17:06 +03:00
run lint
This commit is contained in:
parent
a5eb3d355d
commit
ecb213bf9a
@ -127,7 +127,9 @@ export function CameraLineGraph({
|
||||
className="size-2"
|
||||
style={{ color: GRAPH_COLORS[labelIdx] }}
|
||||
/>
|
||||
<div className="text-xs text-muted-foreground">{t("ui.system.cameras.label." + label)}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{t("ui.system.cameras.label." + label)}
|
||||
</div>
|
||||
<div className="text-xs text-primary">
|
||||
{lastValues[labelIdx]}
|
||||
{unit}
|
||||
|
||||
@ -178,10 +178,20 @@ export function CombinedStorageGraph({
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead><Trans>ui.system.storage.cameraStorage.camera</Trans></TableHead>
|
||||
<TableHead><Trans>ui.system.storage.cameraStorage.storageUsed</Trans></TableHead>
|
||||
<TableHead><Trans>ui.system.storage.cameraStorage.percentageOfTotalUsed</Trans></TableHead>
|
||||
<TableHead><Trans>ui.system.storage.cameraStorage.bandwidth</Trans></TableHead>
|
||||
<TableHead>
|
||||
<Trans>ui.system.storage.cameraStorage.camera</Trans>
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans>ui.system.storage.cameraStorage.storageUsed</Trans>
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans>
|
||||
ui.system.storage.cameraStorage.percentageOfTotalUsed
|
||||
</Trans>
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans>ui.system.storage.cameraStorage.bandwidth</Trans>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@ -193,7 +203,9 @@ export function CombinedStorageGraph({
|
||||
className="size-3 rounded-md"
|
||||
style={{ backgroundColor: item.color }}
|
||||
></div>
|
||||
{item.name === "Unused" ? t("ui.system.storage.cameraStorage.unused"): item.name.replaceAll("_", " ")}
|
||||
{item.name === "Unused"
|
||||
? t("ui.system.storage.cameraStorage.unused")
|
||||
: item.name.replaceAll("_", " ")}
|
||||
{item.name === "Unused" && (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
@ -209,7 +221,9 @@ export function CombinedStorageGraph({
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80">
|
||||
<div className="space-y-2">
|
||||
<Trans>ui.system.storage.cameraStorage.unused.tips</Trans>
|
||||
<Trans>
|
||||
ui.system.storage.cameraStorage.unused.tips
|
||||
</Trans>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
@ -67,7 +67,9 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
|
||||
>
|
||||
<div className="scrollbar-container w-full flex-col overflow-y-auto overflow-x-hidden">
|
||||
<DropdownMenuLabel>
|
||||
{t("ui.menu.user.current", {user: profile?.username || t("ui.menu.user.anonymous")})}
|
||||
{t("ui.menu.user.current", {
|
||||
user: profile?.username || t("ui.menu.user.anonymous"),
|
||||
})}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator className={isDesktop ? "mt-3" : "mt-1"} />
|
||||
<MenuItem
|
||||
@ -78,7 +80,9 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
|
||||
>
|
||||
<a className="flex" href={logoutUrl}>
|
||||
<LuLogOut className="mr-2 size-4" />
|
||||
<span><Trans>ui.menu.user.logout</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.menu.user.logout</Trans>
|
||||
</span>
|
||||
</a>
|
||||
</MenuItem>
|
||||
</div>
|
||||
|
||||
@ -104,7 +104,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent side="right">
|
||||
<p><Trans>ui.settings</Trans></p>
|
||||
<p>
|
||||
<Trans>ui.settings</Trans>
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
@ -148,7 +150,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
</MenuItem>
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuLabel><Trans>ui.system</Trans></DropdownMenuLabel>
|
||||
<DropdownMenuLabel>
|
||||
<Trans>ui.system</Trans>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup className={isDesktop ? "" : "flex flex-col"}>
|
||||
<Link to="/system#general">
|
||||
@ -161,7 +165,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
aria-label="System metrics"
|
||||
>
|
||||
<LuActivity className="mr-2 size-4" />
|
||||
<span><Trans>ui.systemMetrics</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.systemMetrics</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Link to="/logs">
|
||||
@ -174,7 +180,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
aria-label="System logs"
|
||||
>
|
||||
<LuList className="mr-2 size-4" />
|
||||
<span><Trans>ui.systemLogs</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.systemLogs</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</Link>
|
||||
</DropdownMenuGroup>
|
||||
@ -193,7 +201,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
aria-label="Settings"
|
||||
>
|
||||
<LuSettings className="mr-2 size-4" />
|
||||
<span><Trans>ui.settings</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.settings</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<Link to="/config">
|
||||
@ -206,7 +216,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
aria-label="Configuration editor"
|
||||
>
|
||||
<LuPenSquare className="mr-2 size-4" />
|
||||
<span><Trans>ui.configurationEditor</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.configurationEditor</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</Link>
|
||||
<SubItem>
|
||||
@ -218,7 +230,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
}
|
||||
>
|
||||
<LuLanguages className="mr-2 size-4" />
|
||||
<span><Trans>ui.languages</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.languages</Trans>
|
||||
</span>
|
||||
</SubItemTrigger>
|
||||
<Portal>
|
||||
<SubItemContent
|
||||
@ -242,7 +256,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.language.en</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.language.en</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.language.en</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
@ -260,7 +276,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.language.zhCN</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.language.zhCN</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.language.zhCN</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
@ -278,7 +296,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.withSystem</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.withSystem</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.withSystem</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
</SubItemContent>
|
||||
@ -297,7 +317,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
}
|
||||
>
|
||||
<LuSunMoon className="mr-2 size-4" />
|
||||
<span><Trans>ui.darkMode</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.darkMode</Trans>
|
||||
</span>
|
||||
</SubItemTrigger>
|
||||
<Portal>
|
||||
<SubItemContent
|
||||
@ -321,7 +343,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.darkMode.light</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.darkMode.light</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.darkMode.light</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
@ -339,7 +363,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.darkMode.dark</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.darkMode.dark</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.darkMode.dark</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
@ -357,7 +383,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
<Trans>ui.withSystem</Trans>
|
||||
</>
|
||||
) : (
|
||||
<span className="ml-6 mr-2"><Trans>ui.withSystem</Trans></span>
|
||||
<span className="ml-6 mr-2">
|
||||
<Trans>ui.withSystem</Trans>
|
||||
</span>
|
||||
)}
|
||||
</MenuItem>
|
||||
</SubItemContent>
|
||||
@ -372,7 +400,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
}
|
||||
>
|
||||
<LuSunMoon className="mr-2 size-4" />
|
||||
<span><Trans>ui.theme</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.theme</Trans>
|
||||
</span>
|
||||
</SubItemTrigger>
|
||||
<Portal>
|
||||
<SubItemContent
|
||||
@ -420,7 +450,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
aria-label={t("ui.documentation.label")}
|
||||
>
|
||||
<LuLifeBuoy className="mr-2 size-4" />
|
||||
<span><Trans>ui.documentation</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.documentation</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</a>
|
||||
<a
|
||||
@ -446,7 +478,9 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
onClick={() => setRestartDialogOpen(true)}
|
||||
>
|
||||
<LuRotateCw className="mr-2 size-4" />
|
||||
<span><Trans>ui.restart</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.restart</Trans>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</Content>
|
||||
|
||||
@ -61,7 +61,9 @@ export default function NavItem({
|
||||
<TooltipTrigger>{content}</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent side="right">
|
||||
<p><Trans>{item.title}</Trans></p>
|
||||
<p>
|
||||
<Trans>{item.title}</Trans>
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
|
||||
@ -74,7 +74,9 @@ export default function CameraInfoDialog({
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="capitalize">
|
||||
{t("ui.system.cameras.info.cameraProbeInfo", {camera: camera.name.replaceAll("_", " ")})}
|
||||
{t("ui.system.cameras.info.cameraProbeInfo", {
|
||||
camera: camera.name.replaceAll("_", " "),
|
||||
})}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DialogDescription>
|
||||
@ -95,7 +97,9 @@ export default function CameraInfoDialog({
|
||||
<div className="" key={idx}>
|
||||
{codec.width ? (
|
||||
<div className="text-muted-foreground">
|
||||
<div className="ml-2"><Trans>ui.system.cameras.info.video</Trans></div>
|
||||
<div className="ml-2">
|
||||
<Trans>ui.system.cameras.info.video</Trans>
|
||||
</div>
|
||||
<div className="ml-5">
|
||||
<div>
|
||||
<Trans>ui.system.cameras.info.codec</Trans>
|
||||
@ -107,7 +111,9 @@ export default function CameraInfoDialog({
|
||||
<div>
|
||||
{codec.width && codec.height ? (
|
||||
<>
|
||||
<Trans>ui.system.cameras.info.resolution</Trans>{" "}
|
||||
<Trans>
|
||||
ui.system.cameras.info.resolution
|
||||
</Trans>{" "}
|
||||
<span className="text-primary">
|
||||
{" "}
|
||||
{codec.width}x{codec.height} (
|
||||
@ -121,7 +127,9 @@ export default function CameraInfoDialog({
|
||||
</>
|
||||
) : (
|
||||
<span>
|
||||
<Trans>ui.system.cameras.info.resolution</Trans>{" "}
|
||||
<Trans>
|
||||
ui.system.cameras.info.resolution
|
||||
</Trans>{" "}
|
||||
<span className="text-primary">
|
||||
Unknown
|
||||
</span>
|
||||
@ -154,7 +162,11 @@ export default function CameraInfoDialog({
|
||||
</div>
|
||||
) : (
|
||||
<div className="px-2">
|
||||
<div>{t("ui.system.cameras.info.error", {error: stream.stderr})}</div>
|
||||
<div>
|
||||
{t("ui.system.cameras.info.error", {
|
||||
error: stream.stderr,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -163,7 +175,9 @@ export default function CameraInfoDialog({
|
||||
) : (
|
||||
<div className="flex flex-col items-center">
|
||||
<ActivityIndicator />
|
||||
<div className="mt-2"><Trans>ui.system.cameras.info.fetching</Trans></div>
|
||||
<div className="mt-2">
|
||||
<Trans>ui.system.cameras.info.fetching</Trans>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -64,7 +64,9 @@ export default function CreateUserDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.createUser</Trans></DialogTitle>
|
||||
<DialogTitle>
|
||||
<Trans>ui.settingView.users.dialog.createUser</Trans>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
@ -72,7 +74,9 @@ export default function CreateUserDialog({
|
||||
name="user"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.users.dialog.createUser.user</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>ui.settingView.users.dialog.createUser.user</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
@ -87,7 +91,11 @@ export default function CreateUserDialog({
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.users.dialog.createUser.password</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>
|
||||
ui.settingView.users.dialog.createUser.password
|
||||
</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
|
||||
@ -22,9 +22,13 @@ export default function DeleteUserDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.deleteUser</Trans></DialogTitle>
|
||||
<DialogTitle>
|
||||
<Trans>ui.settingView.users.dialog.deleteUser</Trans>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div><Trans>ui.settingView.users.dialog.deleteUser.warn</Trans></div>
|
||||
<div>
|
||||
<Trans>ui.settingView.users.dialog.deleteUser.warn</Trans>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
|
||||
@ -26,7 +26,9 @@ export default function SetPasswordDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent onOpenAutoFocus={(e) => e.preventDefault()}>
|
||||
<DialogHeader>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.setPassword</Trans></DialogTitle>
|
||||
<DialogTitle>
|
||||
<Trans>ui.settingView.users.dialog.setPassword</Trans>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
|
||||
@ -85,7 +85,9 @@ export default function RestartDialog({
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel><Trans>ui.cancel</Trans></AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
<Trans>ui.cancel</Trans>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleRestart}>
|
||||
<Trans>ui.dialog.restart.button</Trans>
|
||||
</AlertDialogAction>
|
||||
@ -105,7 +107,9 @@ export default function RestartDialog({
|
||||
<Trans>ui.dialog.restart.restarting.title</Trans>
|
||||
</SheetTitle>
|
||||
<SheetDescription className="text-center">
|
||||
<div>{t("ui.dialog.restart.restarting.content", {countdown})}</div>
|
||||
<div>
|
||||
{t("ui.dialog.restart.restarting.content", { countdown })}
|
||||
</div>
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<Button
|
||||
|
||||
@ -215,11 +215,15 @@ export default function MotionMaskEditPane({
|
||||
<>
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<Heading as="h3" className="my-2">
|
||||
{polygon.name.length ? t("ui.settingView.masksAndZonesSettings.motionMasks.edit") : t("ui.settingView.masksAndZonesSettings.motionMasks.add")}
|
||||
{polygon.name.length
|
||||
? t("ui.settingView.masksAndZonesSettings.motionMasks.edit")
|
||||
: t("ui.settingView.masksAndZonesSettings.motionMasks.add")}
|
||||
</Heading>
|
||||
<div className="my-3 space-y-3 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.context</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.context
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<div className="flex items-center text-primary">
|
||||
@ -229,7 +233,9 @@ export default function MotionMaskEditPane({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.context.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.context.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -239,7 +245,7 @@ export default function MotionMaskEditPane({
|
||||
<div className="my-2 flex w-full flex-row justify-between text-sm">
|
||||
<div className="my-1 inline-flex">
|
||||
{t("ui.settingView.masksAndZonesSettings.motionMasks.point", {
|
||||
count: polygons[activePolygonIndex].points.length
|
||||
count: polygons[activePolygonIndex].points.length,
|
||||
})}
|
||||
{polygons[activePolygonIndex].isFinished && (
|
||||
<FaCheckCircle className="ml-2 size-5" />
|
||||
@ -253,7 +259,10 @@ export default function MotionMaskEditPane({
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-3 text-sm text-muted-foreground">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.clickDrawPolygon</Trans>Click to draw a polygon on the image.
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.clickDrawPolygon
|
||||
</Trans>
|
||||
Click to draw a polygon on the image.
|
||||
</div>
|
||||
|
||||
<Separator className="my-3 bg-secondary" />
|
||||
@ -261,19 +270,26 @@ export default function MotionMaskEditPane({
|
||||
{polygonArea && polygonArea >= 0.35 && (
|
||||
<>
|
||||
<div className="mb-3 text-sm text-danger">
|
||||
{t("ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge", {
|
||||
polygonArea: Math.round(polygonArea * 100)
|
||||
})}
|
||||
{t(
|
||||
"ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge",
|
||||
{
|
||||
polygonArea: Math.round(polygonArea * 100),
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-3 text-sm text-primary">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge.tips</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge.tips
|
||||
</Trans>
|
||||
<Link
|
||||
to="https://github.com/blakeblackshear/frigate/discussions/13040"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="my-3 block"
|
||||
>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.polygonAreaTooLarge.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -322,7 +338,9 @@ export default function MotionMaskEditPane({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Trans>ui.save</Trans>
|
||||
|
||||
@ -249,11 +249,15 @@ export default function ObjectMaskEditPane({
|
||||
<>
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<Heading as="h3" className="my-2">
|
||||
{polygon.name.length ? t("ui.settingView.masksAndZonesSettings.objectMasks.edit") : t("ui.settingView.masksAndZonesSettings.objectMasks.add")}
|
||||
{polygon.name.length
|
||||
? t("ui.settingView.masksAndZonesSettings.objectMasks.edit")
|
||||
: t("ui.settingView.masksAndZonesSettings.objectMasks.add")}
|
||||
</Heading>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks.context</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.context
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-3 bg-secondary" />
|
||||
@ -261,7 +265,7 @@ export default function ObjectMaskEditPane({
|
||||
<div className="my-2 flex w-full flex-row justify-between text-sm">
|
||||
<div className="my-1 inline-flex">
|
||||
{t("ui.settingView.masksAndZonesSettings.objectMasks.point", {
|
||||
count: polygons[activePolygonIndex].points.length
|
||||
count: polygons[activePolygonIndex].points.length,
|
||||
})}
|
||||
{polygons[activePolygonIndex].isFinished && (
|
||||
<FaCheckCircle className="ml-2 size-5" />
|
||||
@ -275,7 +279,9 @@ export default function ObjectMaskEditPane({
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-3 text-sm text-muted-foreground">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks.clickDrawPolygon</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.clickDrawPolygon
|
||||
</Trans>
|
||||
Click to draw a polygon on the image.
|
||||
</div>
|
||||
|
||||
@ -301,7 +307,11 @@ export default function ObjectMaskEditPane({
|
||||
name="objects"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.masksAndZonesSettings.objectMasks.objects</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.objects
|
||||
</Trans>
|
||||
</FormLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
defaultValue={field.value}
|
||||
@ -317,7 +327,9 @@ export default function ObjectMaskEditPane({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks.objects.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.objects.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -414,7 +426,11 @@ export function ZoneObjectSelector({ camera }: ZoneObjectSelectorProps) {
|
||||
return (
|
||||
<>
|
||||
<SelectGroup>
|
||||
<SelectItem value="all_labels"><Trans>ui.settingView.masksAndZonesSettings.objectMasks.objects.allObjectTypes</Trans></SelectItem>
|
||||
<SelectItem value="all_labels">
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.objects.allObjectTypes
|
||||
</Trans>
|
||||
</SelectItem>
|
||||
<SelectSeparator className="bg-secondary" />
|
||||
{allLabels.map((item) => (
|
||||
<SelectItem key={item} value={item}>
|
||||
|
||||
@ -332,7 +332,9 @@ export default function ZoneEditPane({
|
||||
<>
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<Heading as="h3" className="my-2">
|
||||
{polygon.name.length ? t("ui.settingView.masksAndZonesSettings.zone.edit") : t("ui.settingView.masksAndZonesSettings.zone.add")}
|
||||
{polygon.name.length
|
||||
? t("ui.settingView.masksAndZonesSettings.zone.edit")
|
||||
: t("ui.settingView.masksAndZonesSettings.zone.add")}
|
||||
</Heading>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
@ -343,7 +345,9 @@ export default function ZoneEditPane({
|
||||
{polygons && activePolygonIndex !== undefined && (
|
||||
<div className="my-2 flex w-full flex-row justify-between text-sm">
|
||||
<div className="my-1 inline-flex">
|
||||
{t("ui.settingView.masksAndZonesSettings.zone.point", { count: polygons[activePolygonIndex].points.length })}
|
||||
{t("ui.settingView.masksAndZonesSettings.zone.point", {
|
||||
count: polygons[activePolygonIndex].points.length,
|
||||
})}
|
||||
|
||||
{polygons[activePolygonIndex].isFinished && (
|
||||
<FaCheckCircle className="ml-2 size-5" />
|
||||
@ -357,7 +361,9 @@ export default function ZoneEditPane({
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-3 text-sm text-muted-foreground">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.clickDrawPolygon</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.clickDrawPolygon
|
||||
</Trans>
|
||||
</div>
|
||||
|
||||
<Separator className="my-3 bg-secondary" />
|
||||
@ -369,16 +375,22 @@ export default function ZoneEditPane({
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.masksAndZonesSettings.zone.name</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.name</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
placeholder={t("ui.settingView.masksAndZonesSettings.zone.name.inputPlaceHolder")}
|
||||
placeholder={t(
|
||||
"ui.settingView.masksAndZonesSettings.zone.name.inputPlaceHolder",
|
||||
)}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.name.tips</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.name.tips
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -390,7 +402,11 @@ export default function ZoneEditPane({
|
||||
name="inertia"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.masksAndZonesSettings.zone.inertia</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.inertia
|
||||
</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
@ -399,7 +415,9 @@ export default function ZoneEditPane({
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.inertia.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.inertia.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -411,7 +429,11 @@ export default function ZoneEditPane({
|
||||
name="loitering_time"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.masksAndZonesSettings.zone.loiteringTime</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.loiteringTime
|
||||
</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
@ -420,7 +442,9 @@ export default function ZoneEditPane({
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.loiteringTime.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.loiteringTime.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -428,9 +452,13 @@ export default function ZoneEditPane({
|
||||
/>
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.masksAndZonesSettings.zone.objects</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.objects</Trans>
|
||||
</FormLabel>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.objects.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.objects.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<ZoneObjectSelector
|
||||
camera={polygon.camera}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createContext, useContext, useState, useEffect, useMemo } from 'react';
|
||||
import i18next from 'i18next';
|
||||
import { createContext, useContext, useState, useEffect, useMemo } from "react";
|
||||
import i18next from "i18next";
|
||||
|
||||
type LanguageProviderState = {
|
||||
language: string;
|
||||
@ -8,17 +8,18 @@ type LanguageProviderState = {
|
||||
};
|
||||
|
||||
const initialState: LanguageProviderState = {
|
||||
language: i18next.language || 'en',
|
||||
systemLanguage: 'en',
|
||||
language: i18next.language || "en",
|
||||
systemLanguage: "en",
|
||||
setLanguage: () => null,
|
||||
};
|
||||
|
||||
const LanguageProviderContext = createContext<LanguageProviderState>(initialState);
|
||||
const LanguageProviderContext =
|
||||
createContext<LanguageProviderState>(initialState);
|
||||
|
||||
export function LanguageProvider({
|
||||
children,
|
||||
defaultLanguage = 'en',
|
||||
storageKey = 'frigate-ui-language',
|
||||
defaultLanguage = "en",
|
||||
storageKey = "frigate-ui-language",
|
||||
...props
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
@ -27,27 +28,26 @@ export function LanguageProvider({
|
||||
}) {
|
||||
const [language, setLanguage] = useState<string>(() => {
|
||||
try {
|
||||
|
||||
const storedData = localStorage.getItem(storageKey);
|
||||
const newLanguage = storedData || defaultLanguage;
|
||||
i18next.changeLanguage(newLanguage);
|
||||
return newLanguage;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error retrieving language data from storage:', error);
|
||||
console.error("Error retrieving language data from storage:", error);
|
||||
return defaultLanguage;
|
||||
}
|
||||
});
|
||||
|
||||
const systemLanguage = useMemo<string | undefined>(() => {
|
||||
if (typeof window === 'undefined') return undefined;
|
||||
if (typeof window === "undefined") return undefined;
|
||||
return window.navigator.language;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (language === systemLanguage) return;
|
||||
i18next.changeLanguage(language);
|
||||
}, [language]);
|
||||
}, [language, systemLanguage]);
|
||||
|
||||
const value = {
|
||||
language,
|
||||
|
||||
@ -16,19 +16,16 @@ function providers({ children }: TProvidersProps) {
|
||||
<RecoilRoot>
|
||||
<ApiProvider>
|
||||
<ThemeProvider defaultTheme="system" storageKey="frigate-ui-theme">
|
||||
<TooltipProvider>
|
||||
<IconContext.Provider value={{ size: "20" }}>
|
||||
<StatusBarMessagesProvider>{children}</StatusBarMessagesProvider>
|
||||
</IconContext.Provider>
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
<LanguageProvider>
|
||||
<TooltipProvider>
|
||||
<IconContext.Provider value={{ size: "20" }}>
|
||||
<StatusBarMessagesProvider>{children}</StatusBarMessagesProvider>
|
||||
<StatusBarMessagesProvider>
|
||||
{children}
|
||||
</StatusBarMessagesProvider>
|
||||
</IconContext.Provider>
|
||||
</TooltipProvider>
|
||||
</LanguageProvider>
|
||||
</ThemeProvider>
|
||||
</ApiProvider>
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
@ -125,7 +125,7 @@ export function ThemeProvider({
|
||||
|
||||
return (
|
||||
<ThemeProviderContext.Provider {...props} value={value}>
|
||||
|
||||
{children}
|
||||
</ThemeProviderContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -72,6 +72,6 @@ export default function useNavigation(
|
||||
enabled: isDesktop && config?.face_recognition.enabled,
|
||||
},
|
||||
] as NavData[],
|
||||
[config?.face_recognition.enabled, variant],
|
||||
[config?.face_recognition?.enabled, variant],
|
||||
);
|
||||
}
|
||||
|
||||
@ -73,7 +73,10 @@ export default function useStats(stats: FrigateStats | undefined) {
|
||||
|
||||
if (!isNaN(ffmpegAvg) && ffmpegAvg >= CameraFfmpegThreshold.error) {
|
||||
problems.push({
|
||||
text: t("ui.stats.ffmpegHighCpuUsage", {camera: capitalizeFirstLetter(name.replaceAll("_", " ")), ffmpegAvg}),//`${capitalizeFirstLetter(name.replaceAll("_", " "))} has high FFMPEG CPU usage (${ffmpegAvg}%)`,
|
||||
text: t("ui.stats.ffmpegHighCpuUsage", {
|
||||
camera: capitalizeFirstLetter(name.replaceAll("_", " ")),
|
||||
ffmpegAvg,
|
||||
}), //`${capitalizeFirstLetter(name.replaceAll("_", " "))} has high FFMPEG CPU usage (${ffmpegAvg}%)`,
|
||||
color: "text-danger",
|
||||
relevantLink: "/system#cameras",
|
||||
});
|
||||
@ -81,7 +84,10 @@ export default function useStats(stats: FrigateStats | undefined) {
|
||||
|
||||
if (!isNaN(detectAvg) && detectAvg >= CameraDetectThreshold.error) {
|
||||
problems.push({
|
||||
text: t("ui.stats.detectHighCpuUsage", {camera: capitalizeFirstLetter(name.replaceAll("_", " ")), detectAvg}),//`${capitalizeFirstLetter(name.replaceAll("_", " "))} has high detect CPU usage (${detectAvg}%)`,
|
||||
text: t("ui.stats.detectHighCpuUsage", {
|
||||
camera: capitalizeFirstLetter(name.replaceAll("_", " ")),
|
||||
detectAvg,
|
||||
}), //`${capitalizeFirstLetter(name.replaceAll("_", " "))} has high detect CPU usage (${detectAvg}%)`,
|
||||
color: "text-danger",
|
||||
relevantLink: "/system#cameras",
|
||||
});
|
||||
|
||||
@ -200,7 +200,9 @@ function ConfigEditor() {
|
||||
onClick={() => handleCopyConfig()}
|
||||
>
|
||||
<LuCopy className="text-secondary-foreground" />
|
||||
<span className="hidden md:block"><Trans>ui.configEditorView.copyConfig</Trans></span>
|
||||
<span className="hidden md:block">
|
||||
<Trans>ui.configEditorView.copyConfig</Trans>
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
@ -212,7 +214,9 @@ function ConfigEditor() {
|
||||
<LuSave className="absolute left-0 top-0 size-3 text-secondary-foreground" />
|
||||
<MdOutlineRestartAlt className="absolute size-4 translate-x-1 translate-y-1/2 text-secondary-foreground" />
|
||||
</div>
|
||||
<span className="hidden md:block"><Trans>ui.configEditorView.saveAndRestart</Trans></span>
|
||||
<span className="hidden md:block">
|
||||
<Trans>ui.configEditorView.saveAndRestart</Trans>
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
@ -221,7 +225,9 @@ function ConfigEditor() {
|
||||
onClick={() => onHandleSaveConfig("saveonly")}
|
||||
>
|
||||
<LuSave className="text-secondary-foreground" />
|
||||
<span className="hidden md:block"><Trans>ui.configEditorView.saveOnly</Trans></span>
|
||||
<span className="hidden md:block">
|
||||
<Trans>ui.configEditorView.saveOnly</Trans>
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -148,7 +148,9 @@ export default function Settings() {
|
||||
data-nav-item={item}
|
||||
aria-label={`Select ${item}`}
|
||||
>
|
||||
<div className="capitalize">{t("ui.settingView.menu." + item)}</div>
|
||||
<div className="capitalize">
|
||||
{t("ui.settingView.menu." + item)}
|
||||
</div>
|
||||
</ToggleGroupItem>
|
||||
))}
|
||||
</ToggleGroup>
|
||||
|
||||
@ -71,7 +71,9 @@ function System() {
|
||||
{item == "general" && <LuActivity className="size-4" />}
|
||||
{item == "storage" && <LuHardDrive className="size-4" />}
|
||||
{item == "cameras" && <FaVideo className="size-4" />}
|
||||
{isDesktop && <div className="capitalize">{t("ui.system." + item)}</div>}
|
||||
{isDesktop && (
|
||||
<div className="capitalize">{t("ui.system." + item)}</div>
|
||||
)}
|
||||
</ToggleGroupItem>
|
||||
))}
|
||||
</ToggleGroup>
|
||||
@ -79,7 +81,8 @@ function System() {
|
||||
<div className="flex h-full items-center">
|
||||
{lastUpdated && (
|
||||
<div className="h-full content-center text-sm text-muted-foreground">
|
||||
<Trans>ui.system.lastRefreshed</Trans><TimeAgo time={lastUpdated * 1000} dense />
|
||||
<Trans>ui.system.lastRefreshed</Trans>
|
||||
<TimeAgo time={lastUpdated * 1000} dense />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -12,16 +12,24 @@ i18n
|
||||
// if you're using a language detector, do not define the lng option
|
||||
|
||||
backend: {
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json"
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json",
|
||||
},
|
||||
|
||||
react: {
|
||||
transSupportBasicHtmlNodes: true,
|
||||
transKeepBasicHtmlNodesFor: ["br", "strong", "i", "em", "li", "p", "code"],
|
||||
transKeepBasicHtmlNodesFor: [
|
||||
"br",
|
||||
"strong",
|
||||
"i",
|
||||
"em",
|
||||
"li",
|
||||
"p",
|
||||
"code",
|
||||
],
|
||||
},
|
||||
interpolation: {
|
||||
escapeValue: false // react already safes from xss
|
||||
}
|
||||
escapeValue: false, // react already safes from xss
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
@ -365,7 +365,11 @@ export default function LiveCameraView({
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && <div className="text-primary"><Trans>ui.back</Trans></div>}
|
||||
{isDesktop && (
|
||||
<div className="text-primary">
|
||||
<Trans>ui.back</Trans>
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-2.5 rounded-lg"
|
||||
@ -385,7 +389,11 @@ export default function LiveCameraView({
|
||||
}}
|
||||
>
|
||||
<LuHistory className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && <div className="text-primary"><Trans>ui.history</Trans></div>}
|
||||
{isDesktop && (
|
||||
<div className="text-primary">
|
||||
<Trans>ui.history</Trans>
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
@ -849,7 +857,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
|
||||
isActive={detectState == "ON"}
|
||||
title={detectState == "ON" ? t("ui.live.detect.disable") : t("ui.live.detect.enable")}
|
||||
title={
|
||||
detectState == "ON"
|
||||
? t("ui.live.detect.disable")
|
||||
: t("ui.live.detect.enable")
|
||||
}
|
||||
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
@ -857,7 +869,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
|
||||
isActive={recordState == "ON"}
|
||||
title={recordState == "ON" ? t("ui.live.recording.disable") : t("ui.live.recording.enable")}
|
||||
title={
|
||||
recordState == "ON"
|
||||
? t("ui.live.recording.disable")
|
||||
: t("ui.live.recording.enable")
|
||||
}
|
||||
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
@ -865,7 +881,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
|
||||
isActive={snapshotState == "ON"}
|
||||
title={snapshotState == "ON" ? t("ui.live.snapshots.disable") : t("ui.live.snapshots.enable")}
|
||||
title={
|
||||
snapshotState == "ON"
|
||||
? t("ui.live.snapshots.disable")
|
||||
: t("ui.live.snapshots.enable")
|
||||
}
|
||||
onClick={() => sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
{audioDetectEnabled && (
|
||||
@ -874,7 +894,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={audioState == "ON" ? LuEar : LuEarOff}
|
||||
isActive={audioState == "ON"}
|
||||
title={audioState == "ON" ? t("ui.live.audioDetect.disable") : t("ui.live.audioDetect.enable")}
|
||||
title={
|
||||
audioState == "ON"
|
||||
? t("ui.live.audioDetect.disable")
|
||||
: t("ui.live.audioDetect.enable")
|
||||
}
|
||||
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
)}
|
||||
@ -884,7 +908,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={autotrackingState == "ON" ? TbViewfinder : TbViewfinderOff}
|
||||
isActive={autotrackingState == "ON"}
|
||||
title={autotrackingState == "ON" ? t("ui.live.autotracking.disable") : t("ui.live.autotracking.enable")}
|
||||
title={
|
||||
autotrackingState == "ON"
|
||||
? t("ui.live.autotracking.disable")
|
||||
: t("ui.live.autotracking.enable")
|
||||
}
|
||||
onClick={() =>
|
||||
sendAutotracking(autotrackingState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
|
||||
@ -124,7 +124,9 @@ export default function AuthenticationView() {
|
||||
}}
|
||||
>
|
||||
<FaUserEdit />
|
||||
<div className="hidden md:block"><Trans>ui.settingView.users.updatePassword</Trans></div>
|
||||
<div className="hidden md:block">
|
||||
<Trans>ui.settingView.users.updatePassword</Trans>
|
||||
</div>
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
@ -136,7 +138,9 @@ export default function AuthenticationView() {
|
||||
}}
|
||||
>
|
||||
<HiTrash />
|
||||
<div className="hidden md:block"><Trans>ui.delete</Trans></div>
|
||||
<div className="hidden md:block">
|
||||
<Trans>ui.delete</Trans>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -253,7 +253,9 @@ export default function CameraSettingsView({
|
||||
<div className="max-w-6xl">
|
||||
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>
|
||||
<Trans>ui.settingView.cameraSettings.reviewClassification.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.cameraSettings.reviewClassification.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -262,7 +264,9 @@ export default function CameraSettingsView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.cameraSettings.reviewClassification.readTheDocumentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.cameraSettings.reviewClassification.readTheDocumentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -295,7 +299,9 @@ export default function CameraSettingsView({
|
||||
<MdCircle className="ml-3 size-2 text-severity_alert" />
|
||||
</FormLabel>
|
||||
<FormDescription>
|
||||
<Trans>ui.settingView.cameraSettings.reviewClassification.selectAlertsZones</Trans>
|
||||
<Trans>
|
||||
ui.settingView.cameraSettings.reviewClassification.selectAlertsZones
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</div>
|
||||
<div className="max-w-md rounded-lg bg-secondary p-4 md:max-w-full">
|
||||
@ -344,17 +350,40 @@ export default function CameraSettingsView({
|
||||
</>
|
||||
) : (
|
||||
<div className="font-normal text-destructive">
|
||||
<Trans>ui.settingView.cameraSettings.reviewClassification.noDefinedZones</Trans>
|
||||
<Trans>
|
||||
ui.settingView.cameraSettings.reviewClassification.noDefinedZones
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
<FormMessage />
|
||||
<div className="text-sm">
|
||||
{watchedAlertsZones && watchedAlertsZones.length > 0
|
||||
?
|
||||
t("ui.settingView.cameraSettings.reviewClassification.zoneObjectAlertsTips", { alertsLabels, zone: watchedAlertsZones.map((zone) => capitalizeFirstLetter(zone).replaceAll("_", " ")).join(", "), cameraName: capitalizeFirstLetter(cameraConfig?.name ?? "",).replaceAll("_", " ") })
|
||||
:
|
||||
t("ui.settingView.cameraSettings.reviewClassification.objectAlertsTips", { alertsLabels, cameraName: capitalizeFirstLetter(cameraConfig?.name ?? "",).replaceAll("_", " ") })
|
||||
}
|
||||
? t(
|
||||
"ui.settingView.cameraSettings.reviewClassification.zoneObjectAlertsTips",
|
||||
{
|
||||
alertsLabels,
|
||||
zone: watchedAlertsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"ui.settingView.cameraSettings.reviewClassification.objectAlertsTips",
|
||||
{
|
||||
alertsLabels,
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
@ -447,35 +476,50 @@ export default function CameraSettingsView({
|
||||
<div className="text-sm">
|
||||
{watchedDetectionsZones &&
|
||||
watchedDetectionsZones.length > 0
|
||||
?
|
||||
!selectDetections ?
|
||||
t("ui.settingView.cameraSettings.reviewClassification.zoneObjectDetectionsTips", {
|
||||
? !selectDetections
|
||||
? t(
|
||||
"ui.settingView.cameraSettings.reviewClassification.zoneObjectDetectionsTips",
|
||||
{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll("_", " "),
|
||||
).join(", "),
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
})
|
||||
:
|
||||
t("ui.settingView.cameraSettings.reviewClassification.zoneObjectDetectionsTips.notSelectDetections",{
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"ui.settingView.cameraSettings.reviewClassification.zoneObjectDetectionsTips.notSelectDetections",
|
||||
{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll("_", " "),
|
||||
).join(", "),
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
})
|
||||
:
|
||||
t("ui.settingView.cameraSettings.reviewClassification.objectDetectionsTips", {
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"ui.settingView.cameraSettings.reviewClassification.objectDetectionsTips",
|
||||
{
|
||||
detectionsLabels,
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
})
|
||||
}
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
@ -502,7 +546,9 @@ export default function CameraSettingsView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Trans>ui.save</Trans>
|
||||
|
||||
@ -432,12 +432,18 @@ export default function MasksAndZonesView({
|
||||
<div className="my-3 flex flex-row items-center justify-between">
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="text-md cursor-default"><Trans>ui.settingView.masksAndZonesSettings.zone</Trans></div>
|
||||
<div className="text-md cursor-default">
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone
|
||||
</Trans>
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -446,7 +452,9 @@ export default function MasksAndZonesView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.zone.desc.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.desc.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -467,7 +475,11 @@ export default function MasksAndZonesView({
|
||||
<LuPlus />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent><Trans>ui.settingView.masksAndZonesSettings.zone.add</Trans></TooltipContent>
|
||||
<TooltipContent>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.zone.add
|
||||
</Trans>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{allPolygons
|
||||
@ -497,13 +509,17 @@ export default function MasksAndZonesView({
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="text-md cursor-default">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks
|
||||
</Trans>
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -512,7 +528,9 @@ export default function MasksAndZonesView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.motionMasks.desc.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.desc.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -533,7 +551,11 @@ export default function MasksAndZonesView({
|
||||
<LuPlus />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent><Trans>ui.settingView.masksAndZonesSettings.motionMasks.add</Trans></TooltipContent>
|
||||
<TooltipContent>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.motionMasks.add
|
||||
</Trans>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{allPolygons
|
||||
@ -565,13 +587,17 @@ export default function MasksAndZonesView({
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="text-md cursor-default">
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks
|
||||
</Trans>
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -580,7 +606,9 @@ export default function MasksAndZonesView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.masksAndZonesSettings.objectMasks.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -601,7 +629,11 @@ export default function MasksAndZonesView({
|
||||
<LuPlus />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent><Trans>ui.settingView.masksAndZonesSettings.objectMasks.add</Trans></TooltipContent>
|
||||
<TooltipContent>
|
||||
<Trans>
|
||||
ui.settingView.masksAndZonesSettings.objectMasks.add
|
||||
</Trans>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{allPolygons
|
||||
|
||||
@ -194,7 +194,9 @@ export default function MotionTunerView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.motionDetectionTuner.desc.documentation</Trans>{" "}
|
||||
<Trans>
|
||||
ui.settingView.motionDetectionTuner.desc.documentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -208,7 +210,9 @@ export default function MotionTunerView({
|
||||
</Label>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.motionDetectionTuner.Threshold.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.motionDetectionTuner.Threshold.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -237,7 +241,9 @@ export default function MotionTunerView({
|
||||
</Label>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.motionDetectionTuner.contourArea.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.motionDetectionTuner.contourArea.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -262,9 +268,15 @@ export default function MotionTunerView({
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="improve-contrast"><Trans>ui.settingView.motionDetectionTuner.improveContrast</Trans></Label>
|
||||
<Label htmlFor="improve-contrast">
|
||||
<Trans>
|
||||
ui.settingView.motionDetectionTuner.improveContrast
|
||||
</Trans>
|
||||
</Label>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<Trans>ui.settingView.motionDetectionTuner.improveContrast.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.motionDetectionTuner.improveContrast.desc
|
||||
</Trans>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
@ -297,7 +309,9 @@ export default function MotionTunerView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Trans>ui.save</Trans>
|
||||
|
||||
@ -252,11 +252,15 @@ export default function NotificationView({
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel><Trans>ui.settingView.notification.email</Trans></FormLabel>
|
||||
<FormLabel>
|
||||
<Trans>ui.settingView.notification.email</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark] md:w-72"
|
||||
placeholder={t("ui.settingView.notification.email.placeholder")}
|
||||
placeholder={t(
|
||||
"ui.settingView.notification.email.placeholder",
|
||||
)}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -286,7 +290,9 @@ export default function NotificationView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Trans>ui.save</Trans>
|
||||
@ -336,7 +342,9 @@ export default function NotificationView({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{registration != null ? t("ui.settingView.notification.unregisterDevice") : t("ui.settingView.notification.registerDevice")}
|
||||
{registration != null
|
||||
? t("ui.settingView.notification.unregisterDevice")
|
||||
: t("ui.settingView.notification.registerDevice")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -47,7 +47,9 @@ export default function ObjectSettingsView({
|
||||
info: (
|
||||
<>
|
||||
<p className="mb-2">
|
||||
<strong><Trans>ui.settingView.debug.boundingBoxes.colors</Trans></strong>
|
||||
<strong>
|
||||
<Trans>ui.settingView.debug.boundingBoxes.colors</Trans>
|
||||
</strong>
|
||||
</p>
|
||||
<ul className="list-disc space-y-1 pl-5">
|
||||
<Trans>ui.settingView.debug.boundingBoxes.colors.info</Trans>
|
||||
@ -148,9 +150,11 @@ export default function ObjectSettingsView({
|
||||
<div className="mb-5 space-y-3 text-sm text-muted-foreground">
|
||||
<p>
|
||||
{t("ui.settingView.debug.detectorDesc", {
|
||||
detectors: config ? Object.keys(config?.detectors)
|
||||
detectors: config
|
||||
? Object.keys(config?.detectors)
|
||||
.map((detector) => capitalizeFirstLetter(detector))
|
||||
.join(",") : ""
|
||||
.join(",")
|
||||
: "",
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
@ -175,8 +179,12 @@ export default function ObjectSettingsView({
|
||||
|
||||
<Tabs defaultValue="debug" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="debug"><Trans>ui.settingView.debug.debugging</Trans></TabsTrigger>
|
||||
<TabsTrigger value="objectlist"><Trans>ui.settingView.debug.objectList</Trans></TabsTrigger>
|
||||
<TabsTrigger value="debug">
|
||||
<Trans>ui.settingView.debug.debugging</Trans>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="objectlist">
|
||||
<Trans>ui.settingView.debug.objectList</Trans>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="debug">
|
||||
<div className="flex w-full flex-col space-y-6">
|
||||
@ -329,7 +337,9 @@ function ObjectList(objects?: ObjectType[]) {
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="p-3 text-center"><Trans>ui.settingView.debug.noObjects</Trans></div>
|
||||
<div className="p-3 text-center">
|
||||
<Trans>ui.settingView.debug.noObjects</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -173,7 +173,9 @@ export default function SearchSettingsView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
<Trans>ui.settingView.searchSettings.semanticSearch.readTheDocumentation</Trans>
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.readTheDocumentation
|
||||
</Trans>
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -192,7 +194,9 @@ export default function SearchSettingsView({
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="enabled"><Trans>ui.enabled</Trans></Label>
|
||||
<Label htmlFor="enabled">
|
||||
<Trans>ui.enabled</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
@ -207,26 +211,42 @@ export default function SearchSettingsView({
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="reindex"><Trans>ui.settingView.searchSettings.semanticSearch.reindexOnStartup</Trans></Label>
|
||||
<Label htmlFor="reindex">
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.reindexOnStartup
|
||||
</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-sm text-muted-foreground">
|
||||
<Trans>ui.settingView.searchSettings.semanticSearch.reindexOnStartup.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.reindexOnStartup.desc
|
||||
</Trans>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-md"><Trans>ui.settingView.searchSettings.semanticSearch.modelSize</Trans></div>
|
||||
<div className="text-md">
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.modelSize
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="space-y-1 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.searchSettings.semanticSearch.modelSize.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.modelSize.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<ul className="list-disc pl-5 text-sm">
|
||||
<li>
|
||||
<Trans>ui.settingView.searchSettings.semanticSearch.modelSize.small.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.modelSize.small.desc
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>ui.settingView.searchSettings.semanticSearch.modelSize.large.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.searchSettings.semanticSearch.modelSize.large.desc
|
||||
</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -240,7 +260,10 @@ export default function SearchSettingsView({
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-20">
|
||||
{t("ui.settingView.searchSettings.semanticSearch.modelSize." + searchSettings.model_size)}
|
||||
{t(
|
||||
"ui.settingView.searchSettings.semanticSearch.modelSize." +
|
||||
searchSettings.model_size,
|
||||
)}
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@ -250,7 +273,10 @@ export default function SearchSettingsView({
|
||||
className="cursor-pointer"
|
||||
value={size}
|
||||
>
|
||||
{t("ui.settingView.searchSettings.semanticSearch.modelSize." + size)}
|
||||
{t(
|
||||
"ui.settingView.searchSettings.semanticSearch.modelSize." +
|
||||
size,
|
||||
)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
@ -274,7 +300,9 @@ export default function SearchSettingsView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
<span>
|
||||
<Trans>ui.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
t("ui.save")
|
||||
|
||||
@ -83,12 +83,16 @@ export default function UiSettingsView() {
|
||||
onCheckedChange={setAutoLive}
|
||||
/>
|
||||
<Label className="cursor-pointer" htmlFor="auto-live">
|
||||
<Trans>ui.settingView.generalSettings.automaticLiveView</Trans>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.automaticLiveView
|
||||
</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.generalSettings.automaticLiveView.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.automaticLiveView.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -105,7 +109,9 @@ export default function UiSettingsView() {
|
||||
</div>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.generalSettings.playAlertVideos.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.playAlertVideos.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -114,10 +120,14 @@ export default function UiSettingsView() {
|
||||
<div className="my-3 flex w-full flex-col space-y-6">
|
||||
<div className="mt-2 space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-md"><Trans>ui.settingView.generalSettings.storedLayouts</Trans></div>
|
||||
<div className="text-md">
|
||||
<Trans>ui.settingView.generalSettings.storedLayouts</Trans>
|
||||
</div>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
<Trans>ui.settingView.generalSettings.storedLayouts.desc</Trans>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.storedLayouts.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -125,7 +135,9 @@ export default function UiSettingsView() {
|
||||
aria-label="Clear all saved layouts"
|
||||
onClick={clearStoredLayouts}
|
||||
>
|
||||
<Trans>ui.settingView.generalSettings.storedLayouts.clearAll</Trans>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.storedLayouts.clearAll
|
||||
</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -137,9 +149,17 @@ export default function UiSettingsView() {
|
||||
|
||||
<div className="mt-2 space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-md"><Trans>ui.settingView.generalSettings.recordingsViewer.defaultPlaybackRate</Trans></div>
|
||||
<div className="text-md">
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.recordingsViewer.defaultPlaybackRate
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p><Trans>ui.settingView.generalSettings.recordingsViewer.defaultPlaybackRate.desc</Trans></p>
|
||||
<p>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.recordingsViewer.defaultPlaybackRate.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -172,9 +192,17 @@ export default function UiSettingsView() {
|
||||
|
||||
<div className="mt-2 space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-md"><Trans>ui.settingView.generalSettings.calendar.firstWeekday</Trans></div>
|
||||
<div className="text-md">
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.calendar.firstWeekday
|
||||
</Trans>
|
||||
</div>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p><Trans>ui.settingView.generalSettings.calendar.firstWeekday.desc</Trans></p>
|
||||
<p>
|
||||
<Trans>
|
||||
ui.settingView.generalSettings.calendar.firstWeekday.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -183,7 +211,10 @@ export default function UiSettingsView() {
|
||||
onValueChange={(value) => setWeekStartsOn(parseInt(value))}
|
||||
>
|
||||
<SelectTrigger className="w-32">
|
||||
{t("ui.settingView.generalSettings.calendar.firstWeekday." + WEEK_STARTS_ON[weekStartsOn ?? 0].toLowerCase())}
|
||||
{t(
|
||||
"ui.settingView.generalSettings.calendar.firstWeekday." +
|
||||
WEEK_STARTS_ON[weekStartsOn ?? 0].toLowerCase(),
|
||||
)}
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@ -193,7 +224,10 @@ export default function UiSettingsView() {
|
||||
className="cursor-pointer"
|
||||
value={index.toString()}
|
||||
>
|
||||
{t("ui.settingView.generalSettings.calendar.firstWeekday."+day.toLowerCase())}
|
||||
{t(
|
||||
"ui.settingView.generalSettings.calendar.firstWeekday." +
|
||||
day.toLowerCase(),
|
||||
)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
|
||||
@ -224,11 +224,15 @@ export default function CameraMetrics({
|
||||
|
||||
return (
|
||||
<div className="scrollbar-container mt-4 flex size-full flex-col gap-3 overflow-y-auto">
|
||||
<div className="text-sm font-medium text-muted-foreground"><Trans>ui.system.cameras.overview</Trans></div>
|
||||
<div className="text-sm font-medium text-muted-foreground">
|
||||
<Trans>ui.system.cameras.overview</Trans>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3">
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.cameras.framesAndDetections</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.cameras.framesAndDetections</Trans>
|
||||
</div>
|
||||
<CameraLineGraph
|
||||
graphId="overall-stats"
|
||||
unit=""
|
||||
@ -295,7 +299,9 @@ export default function CameraMetrics({
|
||||
)}
|
||||
{Object.keys(cameraFpsSeries).includes(camera.name) ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.cameras.framesAndDetections</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.cameras.framesAndDetections</Trans>
|
||||
</div>
|
||||
<CameraLineGraph
|
||||
graphId={`${camera.name}-dps`}
|
||||
unit=""
|
||||
|
||||
@ -459,7 +459,9 @@ export default function GeneralMetrics({
|
||||
>
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.detectorInferenceSpeed</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.detectorInferenceSpeed</Trans>
|
||||
</div>
|
||||
{detInferenceTimeSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -497,7 +499,9 @@ export default function GeneralMetrics({
|
||||
)}
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.detectorCpuUsage</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.detectorCpuUsage</Trans>
|
||||
</div>
|
||||
{detCpuSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -515,7 +519,9 @@ export default function GeneralMetrics({
|
||||
)}
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.detectorMemoryUsage</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.detectorMemoryUsage</Trans>
|
||||
</div>
|
||||
{detMemSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -558,7 +564,9 @@ export default function GeneralMetrics({
|
||||
>
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.gpuUsage</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.gpuUsage</Trans>
|
||||
</div>
|
||||
{gpuSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -578,7 +586,9 @@ export default function GeneralMetrics({
|
||||
<>
|
||||
{gpuMemSeries && (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.gpuMemroy</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.gpuMemroy</Trans>
|
||||
</div>
|
||||
{gpuMemSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -600,7 +610,9 @@ export default function GeneralMetrics({
|
||||
<>
|
||||
{gpuEncSeries && gpuEncSeries?.length != 0 && (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.gpuEncoder</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.gpuEncoder</Trans>
|
||||
</div>
|
||||
{gpuEncSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -622,7 +634,9 @@ export default function GeneralMetrics({
|
||||
<>
|
||||
{gpuDecSeries && gpuDecSeries?.length != 0 && (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.gpuDecoder</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.gpuDecoder</Trans>
|
||||
</div>
|
||||
{gpuDecSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
@ -670,7 +684,9 @@ export default function GeneralMetrics({
|
||||
)}
|
||||
{statsHistory.length != 0 ? (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5"><Trans>ui.system.general.processMemoryUsage</Trans></div>
|
||||
<div className="mb-5">
|
||||
<Trans>ui.system.general.processMemoryUsage</Trans>
|
||||
</div>
|
||||
{otherProcessMemSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
key={series.name}
|
||||
|
||||
@ -51,7 +51,9 @@ export default function StorageMetrics({
|
||||
|
||||
return (
|
||||
<div className="scrollbar-container mt-4 flex size-full flex-col overflow-y-auto">
|
||||
<div className="text-sm font-medium text-muted-foreground"><Trans>ui.system.storage.overview</Trans></div>
|
||||
<div className="text-sm font-medium text-muted-foreground">
|
||||
<Trans>ui.system.storage.overview</Trans>
|
||||
</div>
|
||||
<div className="mt-4 grid grid-cols-1 gap-2 sm:grid-cols-3">
|
||||
<div className="flex-col rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5 flex flex-row items-center justify-between">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user