-
-
{
- if (matchExposure) {
- setMatchedExposure(newValue);
- }
- setExposureTime(newValue);
- }}
- />
- {
- if (matchExposure) {
- setMatchedISO(newValue);
+
+
+ {!autoExposure && (
+ <>
+
-
-
+ onChange={(newValue) => {
+ if (matchExposure) {
+ setMatchedExposure(newValue);
+ }
+ setExposureTime(newValue);
+ }}
+ />
+
{
+ if (matchExposure) {
+ setMatchedISO(newValue);
+ }
+ setGain(newValue);
+ }}
+ />
+
+ >
+ )}
+ {
+ setHwBitrate(newValue);
+ }}
+ />
- )}
+
diff --git a/frontend/src/components/dwe/network/network.tsx b/frontend/src/components/dwe/network/network.tsx
new file mode 100644
index 00000000..3fc432c9
--- /dev/null
+++ b/frontend/src/components/dwe/network/network.tsx
@@ -0,0 +1,28 @@
+import { useContext } from "react";
+import WebsocketContext from "@/contexts/WebsocketContext";
+import NotConnected from "../not-connected";
+import WiredConfig from "./wired/wired-config";
+import WirelessConfig from "./wireless/wireless-config";
+
+const NetworkLayout = () => {
+ const { connected } = useContext(WebsocketContext)!;
+
+ if (!connected) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+export default NetworkLayout;
diff --git a/frontend/src/components/dwe/network/wireless/wireless-config.tsx b/frontend/src/components/dwe/network/wireless/wireless-config.tsx
index cf0b3cb2..8d2e958e 100644
--- a/frontend/src/components/dwe/network/wireless/wireless-config.tsx
+++ b/frontend/src/components/dwe/network/wireless/wireless-config.tsx
@@ -1,29 +1,29 @@
import {
Card,
CardContent,
- CardFooter,
+ CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
+import { WifiOff } from "lucide-react";
export default function WirelessConfig() {
return (
-
-
-
- Wireless Configuration
-
-
-
-
- No supported wireless device found.
-
-
-
-
- For more detailed documentation, refer to our docs.
-
-
-
+
+
+ Wireless Network
+
+ Manage Wi-Fi interfaces and connection profiles.
+
+
+
+
+
+
+ Wi-Fi is not currently supported
+
+
+
+
);
}
diff --git a/frontend/src/components/dwe/preferences/preferences.tsx b/frontend/src/components/dwe/preferences/preferences.tsx
index b77457af..2403437d 100644
--- a/frontend/src/components/dwe/preferences/preferences.tsx
+++ b/frontend/src/components/dwe/preferences/preferences.tsx
@@ -13,8 +13,6 @@ import { TOUR_STEP_IDS } from "@/lib/tour-constants";
import { Button } from "@/components/ui/button";
import { useTour } from "@/components/tour/tour";
import { SettingsCard } from "./settings-card";
-import WiredConfig from "../network/wired/wired-config";
-import WirelessConfig from "../network/wireless/wireless-config";
import FeaturesContext from "@/contexts/FeaturesContext";
import { RangeControl } from "@/components/ui/range-control";
@@ -91,6 +89,8 @@ const PreferencesLayout = () => {
}
}, [recommendHost, host, port, frequencyOffset, connected]);
+ if (!connected) return
;
+
return (
{
className="grid gap-4 [grid-template-columns:repeat(auto-fit,minmax(350px,1fr))]"
id={TOUR_STEP_IDS.DEFAULT_STREAM_PREFS}
>
- {connected ? (
-
-
-
- Default Stream Host
- setHost(e.target.value)}
- placeholder="Enter host IP"
- className={cn(
- !IP_REGEX.test(host) && "border-red-500",
- "bg-background",
- )}
- />
-
-
- Default Stream Port
- setPort(parseInt(e.target.value))}
- placeholder="Enter port"
- min={1024}
- max={65535}
- className={cn(
- (port < 1024 || port > 65535) && "border-red-500",
- "bg-background",
- )}
- />
-
+
+
+
+ Default Stream Host
+ setHost(e.target.value)}
+ placeholder="Enter host IP"
+ className={cn(
+ !IP_REGEX.test(host) && "border-red-500",
+ "bg-background",
+ )}
+ />
+
+
+ Default Stream Port
+ setPort(parseInt(e.target.value))}
+ placeholder="Enter port"
+ min={1024}
+ max={65535}
+ className={cn(
+ (port < 1024 || port > 65535) && "border-red-500",
+ "bg-background",
+ )}
+ />
+
-
- setRecommendHost(!!checked)}
- />
- Recommend Default Host
-
+
+ setRecommendHost(!!checked)}
+ />
+ Recommend Default Host
+
-
-
- {/* Frequency Offset Slider */}
- {features?.serial && (
-
-
-
- Camera Frequency Offset Configuration
-
-
-
-
setFrequencyOffset(val)}
- className="py-2"
- />
-
-
- Adjust the fine-tuning offset for camera clock frequency.
- Use if you are experiencing flickering or synchronization
- issues.
-
+
+
+ {/* Frequency Offset Slider */}
+ {features?.serial && (
+
+
+
+ Camera Frequency Offset Configuration
+
- )}
-
-
- ) : (
-
- )}
+
+ setFrequencyOffset(val)}
+ className="py-2"
+ />
+
+
+ Adjust the fine-tuning offset for camera clock frequency. Use
+ if you are experiencing flickering or synchronization issues.
+
+
+ )}
+
+
@@ -192,11 +187,6 @@ const PreferencesLayout = () => {
-
-
-
{connected && }
-
{connected && }
-
);
};
diff --git a/frontend/src/components/dwe/recordings/recordings.tsx b/frontend/src/components/dwe/recordings/recordings.tsx
index 6d0f3d25..8163c0a2 100644
--- a/frontend/src/components/dwe/recordings/recordings.tsx
+++ b/frontend/src/components/dwe/recordings/recordings.tsx
@@ -1,5 +1,7 @@
import { API_CLIENT } from "@/api";
import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
import {
Table,
TableBody,
@@ -7,16 +9,36 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from "@/components/ui/alert-dialog";
import { components } from "@/schemas/dwe_os_2";
import { Separator } from "@/components/ui/separator";
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import {
+ AlertTriangle,
Download,
FolderArchive,
+ Pencil,
+ Play,
Trash,
Video,
VideoOff,
- X,
} from "lucide-react";
import { useTour } from "@/components/tour/tour";
import { TOUR_STEP_IDS } from "@/lib/tour-constants";
@@ -26,6 +48,7 @@ import {
TooltipTrigger,
TruncatedTooltip,
} from "@/components/ui/tooltip";
+import { toast } from "sonner";
type RecordingInfo = components["schemas"]["RecordingInfo"];
@@ -48,6 +71,21 @@ const formatFileSize = (sizeInMB: number): string => {
}
};
+const formatDate = (value: string | null | undefined): string => {
+ if (!value) return "—";
+ const d = new Date(value);
+ if (isNaN(d.getTime())) return value;
+ return d.toLocaleString(undefined, {
+ year: "numeric",
+ month: "short",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+};
+
+const fullName = (rec: RecordingInfo) => `${rec.name}.${rec.format}`;
+
const Recordings = () => {
const hostAddress: string = window.location.hostname;
const baseUrl = `http://${
@@ -55,8 +93,6 @@ const Recordings = () => {
}`;
const [recordings, setRecordings] = useState