Empty cameras view (#20434)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions

* Don't define camera by default

* Add empty card component and use for camera view

* Add i18n
This commit is contained in:
Nicolas Mowen 2025-10-11 15:40:39 -06:00 committed by GitHub
parent e183ae5ef6
commit 78d487045b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 12 deletions

View File

@ -80,18 +80,7 @@ DEFAULT_CONFIG = """
mqtt: mqtt:
enabled: False enabled: False
cameras: cameras: {} # No cameras defined, UI wizard should be used
name_of_your_camera: # <------ Name the camera
enabled: True
ffmpeg:
inputs:
- path: rtsp://10.0.10.10:554/rtsp # <----- The stream you want to use for detection
roles:
- detect
detect:
enabled: False # <---- disable detection until you have a working camera feed
width: 1280
height: 720
""" """
DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}} DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}}

View File

@ -168,5 +168,10 @@
"label": "Edit Camera Group" "label": "Edit Camera Group"
}, },
"exitEdit": "Exit Editing" "exitEdit": "Exit Editing"
},
"noCameras": {
"title": "No Cameras Set Up",
"description": "Get started by connecting a camera.",
"buttonText": "Add Camera"
} }
} }

View File

@ -0,0 +1,29 @@
import React from "react";
import { Button } from "../ui/button";
import Heading from "../ui/heading";
type EmptyCardProps = {
icon: React.ReactNode;
title: string;
description: string;
buttonText?: string;
};
export function EmptyCard({
icon,
title,
description,
buttonText,
}: EmptyCardProps) {
return (
<div className="flex flex-col items-center gap-2">
{icon}
<Heading as="h4">{title}</Heading>
<div className="text-secondary-foreground">{description}</div>
{buttonText?.length && (
<Button size="sm" variant="select">
{buttonText}
</Button>
)}
</div>
);
}

View File

@ -44,6 +44,8 @@ import { useResizeObserver } from "@/hooks/resize-observer";
import LiveContextMenu from "@/components/menu/LiveContextMenu"; import LiveContextMenu from "@/components/menu/LiveContextMenu";
import { useStreamingSettings } from "@/context/streaming-settings-provider"; import { useStreamingSettings } from "@/context/streaming-settings-provider";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { EmptyCard } from "@/components/card/EmptyCard";
import { BsFillCameraVideoOffFill } from "react-icons/bs";
type LiveDashboardViewProps = { type LiveDashboardViewProps = {
cameras: CameraConfig[]; cameras: CameraConfig[];
@ -352,6 +354,10 @@ export default function LiveDashboardView({
onSaveMuting(true); onSaveMuting(true);
}; };
if (cameras.length == 0) {
return <NoCameraView />;
}
return ( return (
<div <div
className="scrollbar-container size-full select-none overflow-y-auto px-1 pt-2 md:p-2" className="scrollbar-container size-full select-none overflow-y-auto px-1 pt-2 md:p-2"
@ -608,3 +614,18 @@ export default function LiveDashboardView({
</div> </div>
); );
} }
function NoCameraView() {
const { t } = useTranslation(["views/live"]);
return (
<div className="flex size-full items-center justify-center">
<EmptyCard
icon={<BsFillCameraVideoOffFill className="size-8" />}
title={t("noCameras.title")}
description={t("noCameras.description")}
buttonText={t("noCameras.buttonText")}
/>
</div>
);
}