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