mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Various bugfixes and improvements (#11624)
* various bugfixes and improvements * add separator * no separator
This commit is contained in:
parent
3dd401f57a
commit
f1c0422d5e
@ -131,13 +131,16 @@ export default function MotionMaskEditPane({
|
|||||||
|
|
||||||
axios
|
axios
|
||||||
.put(`config/set?${queryString}`, {
|
.put(`config/set?${queryString}`, {
|
||||||
requires_restart: 1,
|
requires_restart: 0,
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success(`${polygon.name || "Motion Mask"} has been saved.`, {
|
toast.success(
|
||||||
position: "top-center",
|
`${polygon.name || "Motion Mask"} has been saved. Restart Frigate to apply changes.`,
|
||||||
});
|
{
|
||||||
|
position: "top-center",
|
||||||
|
},
|
||||||
|
);
|
||||||
updateConfig();
|
updateConfig();
|
||||||
} else {
|
} else {
|
||||||
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
||||||
|
@ -189,13 +189,16 @@ export default function ObjectMaskEditPane({
|
|||||||
|
|
||||||
axios
|
axios
|
||||||
.put(`config/set?${queryString}`, {
|
.put(`config/set?${queryString}`, {
|
||||||
requires_restart: 1,
|
requires_restart: 0,
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success(`${polygon.name || "Object Mask"} has been saved.`, {
|
toast.success(
|
||||||
position: "top-center",
|
`${polygon.name || "Object Mask"} has been saved. Restart Frigate to apply changes.`,
|
||||||
});
|
{
|
||||||
|
position: "top-center",
|
||||||
|
},
|
||||||
|
);
|
||||||
updateConfig();
|
updateConfig();
|
||||||
} else {
|
} else {
|
||||||
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
||||||
|
@ -197,7 +197,7 @@ export default function ZoneEditPane({
|
|||||||
await axios.put(
|
await axios.put(
|
||||||
`config/set?cameras.${polygon.camera}.zones.${polygon.name}${renameAlertQueries}${renameDetectionQueries}`,
|
`config/set?cameras.${polygon.camera}.zones.${polygon.name}${renameAlertQueries}${renameDetectionQueries}`,
|
||||||
{
|
{
|
||||||
requires_restart: 1,
|
requires_restart: 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -257,13 +257,16 @@ export default function ZoneEditPane({
|
|||||||
axios
|
axios
|
||||||
.put(
|
.put(
|
||||||
`config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}${inertiaQuery}${loiteringTimeQuery}${objectQueries}${alertQueries}${detectionQueries}`,
|
`config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}${inertiaQuery}${loiteringTimeQuery}${objectQueries}${alertQueries}${detectionQueries}`,
|
||||||
{ requires_restart: 1 },
|
{ requires_restart: 0 },
|
||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
toast.success(`Zone (${zoneName}) has been saved.`, {
|
toast.success(
|
||||||
position: "top-center",
|
`Zone (${zoneName}) has been saved. Restart Frigate to apply changes.`,
|
||||||
});
|
{
|
||||||
|
position: "top-center",
|
||||||
|
},
|
||||||
|
);
|
||||||
updateConfig();
|
updateConfig();
|
||||||
} else {
|
} else {
|
||||||
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
toast.error(`Failed to save config changes: ${res.statusText}`, {
|
||||||
|
@ -7,6 +7,7 @@ import { MinimapBounds, Tick, Timestamp } from "./segment-metadata";
|
|||||||
import { useMotionSegmentUtils } from "@/hooks/use-motion-segment-utils";
|
import { useMotionSegmentUtils } from "@/hooks/use-motion-segment-utils";
|
||||||
import { isDesktop, isMobile } from "react-device-detect";
|
import { isDesktop, isMobile } from "react-device-detect";
|
||||||
import useTapUtils from "@/hooks/use-tap-utils";
|
import useTapUtils from "@/hooks/use-tap-utils";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type MotionSegmentProps = {
|
type MotionSegmentProps = {
|
||||||
events: ReviewSegment[];
|
events: ReviewSegment[];
|
||||||
@ -170,7 +171,16 @@ export function MotionSegment({
|
|||||||
<div
|
<div
|
||||||
key={segmentKey}
|
key={segmentKey}
|
||||||
data-segment-id={segmentKey}
|
data-segment-id={segmentKey}
|
||||||
className={`segment ${firstHalfSegmentWidth > 0 || secondHalfSegmentWidth > 0 ? "has-data" : ""} ${segmentClasses} bg-gradient-to-r ${severityColorsBg[severity[0]]}`}
|
className={cn(
|
||||||
|
"segment",
|
||||||
|
{
|
||||||
|
"has-data":
|
||||||
|
firstHalfSegmentWidth > 0 || secondHalfSegmentWidth > 0,
|
||||||
|
},
|
||||||
|
segmentClasses,
|
||||||
|
severity[0] && "bg-gradient-to-r",
|
||||||
|
severity[0] && severityColorsBg[severity[0]],
|
||||||
|
)}
|
||||||
onClick={segmentClick}
|
onClick={segmentClick}
|
||||||
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
|
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
|
||||||
>
|
>
|
||||||
@ -210,7 +220,14 @@ export function MotionSegment({
|
|||||||
<div
|
<div
|
||||||
key={`${segmentKey}_motion_data_1`}
|
key={`${segmentKey}_motion_data_1`}
|
||||||
data-motion-value={secondHalfSegmentWidth}
|
data-motion-value={secondHalfSegmentWidth}
|
||||||
className={`${isDesktop && animationClassesSecondHalf} h-[2px] rounded-full bg-motion_review`}
|
className={cn(
|
||||||
|
isDesktop && animationClassesSecondHalf,
|
||||||
|
"h-[2px]",
|
||||||
|
"rounded-full",
|
||||||
|
secondHalfSegmentWidth
|
||||||
|
? "bg-motion_review"
|
||||||
|
: "bg-muted-foreground",
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
width: secondHalfSegmentWidth || 1,
|
width: secondHalfSegmentWidth || 1,
|
||||||
}}
|
}}
|
||||||
@ -223,7 +240,14 @@ export function MotionSegment({
|
|||||||
<div
|
<div
|
||||||
key={`${segmentKey}_motion_data_2`}
|
key={`${segmentKey}_motion_data_2`}
|
||||||
data-motion-value={firstHalfSegmentWidth}
|
data-motion-value={firstHalfSegmentWidth}
|
||||||
className={`${isDesktop && animationClassesFirstHalf} h-[2px] rounded-full bg-motion_review`}
|
className={cn(
|
||||||
|
isDesktop && animationClassesFirstHalf,
|
||||||
|
"h-[2px]",
|
||||||
|
"rounded-full",
|
||||||
|
firstHalfSegmentWidth
|
||||||
|
? "bg-motion_review"
|
||||||
|
: "bg-muted-foreground",
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
width: firstHalfSegmentWidth || 1,
|
width: firstHalfSegmentWidth || 1,
|
||||||
}}
|
}}
|
||||||
|
@ -267,14 +267,27 @@ export default function DraggableGridLayout({
|
|||||||
const [{ width: containerWidth, height: containerHeight }] =
|
const [{ width: containerWidth, height: containerHeight }] =
|
||||||
useResizeObserver(gridContainerRef);
|
useResizeObserver(gridContainerRef);
|
||||||
|
|
||||||
|
const scrollBarWidth = useMemo(() => {
|
||||||
|
if (containerWidth && containerHeight && containerRef.current) {
|
||||||
|
return (
|
||||||
|
containerRef.current.offsetWidth - containerRef.current.clientWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}, [containerRef, containerHeight, containerWidth]);
|
||||||
|
|
||||||
|
const availableWidth = useMemo(
|
||||||
|
() => (scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth),
|
||||||
|
[containerWidth, scrollBarWidth],
|
||||||
|
);
|
||||||
|
|
||||||
const hasScrollbar = useMemo(() => {
|
const hasScrollbar = useMemo(() => {
|
||||||
return (
|
if (containerHeight && containerRef.current) {
|
||||||
containerHeight &&
|
return (
|
||||||
containerRef.current &&
|
containerRef.current.offsetHeight < containerRef.current.scrollHeight
|
||||||
containerRef.current.offsetHeight <
|
);
|
||||||
(gridContainerRef.current?.scrollHeight ?? 0)
|
}
|
||||||
);
|
}, [containerRef, containerHeight]);
|
||||||
}, [containerRef, gridContainerRef, containerHeight]);
|
|
||||||
|
|
||||||
// fullscreen state
|
// fullscreen state
|
||||||
|
|
||||||
@ -295,13 +308,13 @@ export default function DraggableGridLayout({
|
|||||||
// subtract container margin, 1 camera takes up at least 4 rows
|
// subtract container margin, 1 camera takes up at least 4 rows
|
||||||
// account for additional margin on bottom of each row
|
// account for additional margin on bottom of each row
|
||||||
return (
|
return (
|
||||||
((containerWidth ?? window.innerWidth) - 2 * marginValue) /
|
((availableWidth ?? window.innerWidth) - 2 * marginValue) /
|
||||||
12 /
|
12 /
|
||||||
aspectRatio -
|
aspectRatio -
|
||||||
marginValue +
|
marginValue +
|
||||||
marginValue / 4
|
marginValue / 4
|
||||||
);
|
);
|
||||||
}, [containerWidth, marginValue]);
|
}, [availableWidth, marginValue]);
|
||||||
|
|
||||||
const handleResize: ItemCallback = (
|
const handleResize: ItemCallback = (
|
||||||
_: Layout[],
|
_: Layout[],
|
||||||
@ -312,7 +325,7 @@ export default function DraggableGridLayout({
|
|||||||
const heightDiff = layoutItem.h - oldLayoutItem.h;
|
const heightDiff = layoutItem.h - oldLayoutItem.h;
|
||||||
const widthDiff = layoutItem.w - oldLayoutItem.w;
|
const widthDiff = layoutItem.w - oldLayoutItem.w;
|
||||||
const changeCoef = oldLayoutItem.w / oldLayoutItem.h;
|
const changeCoef = oldLayoutItem.w / oldLayoutItem.h;
|
||||||
if (Math.abs(heightDiff) < Math.abs(widthDiff)) {
|
if (Math.abs(heightDiff) < Math.abs(widthDiff) || layoutItem.w == 12) {
|
||||||
layoutItem.h = layoutItem.w / changeCoef;
|
layoutItem.h = layoutItem.w / changeCoef;
|
||||||
placeholder.h = layoutItem.w / changeCoef;
|
placeholder.h = layoutItem.w / changeCoef;
|
||||||
} else {
|
} else {
|
||||||
@ -545,6 +558,7 @@ const BirdseyeLivePlayerGridItem = React.forwardRef<
|
|||||||
birdseyeConfig={birdseyeConfig}
|
birdseyeConfig={birdseyeConfig}
|
||||||
liveMode={liveMode}
|
liveMode={liveMode}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
containerRef={ref as React.RefObject<HTMLDivElement>}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@ -603,6 +617,7 @@ const LivePlayerGridItem = React.forwardRef<
|
|||||||
cameraConfig={cameraConfig}
|
cameraConfig={cameraConfig}
|
||||||
preferredLiveMode={preferredLiveMode}
|
preferredLiveMode={preferredLiveMode}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
containerRef={ref as React.RefObject<HTMLDivElement>}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,12 +42,24 @@ export default function LiveBirdseyeView() {
|
|||||||
return config.birdseye.width / config.birdseye.height;
|
return config.birdseye.width / config.birdseye.height;
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
|
const windowAspectRatio = useMemo(() => {
|
||||||
|
return windowWidth / windowHeight;
|
||||||
|
}, [windowWidth, windowHeight]);
|
||||||
|
|
||||||
|
const containerAspectRatio = useMemo(() => {
|
||||||
|
if (!containerRef.current) {
|
||||||
|
return windowAspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerRef.current.clientWidth / containerRef.current.clientHeight;
|
||||||
|
}, [windowAspectRatio, containerRef]);
|
||||||
|
|
||||||
const growClassName = useMemo(() => {
|
const growClassName = useMemo(() => {
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
if (isPortrait) {
|
if (isPortrait) {
|
||||||
return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
|
return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
|
||||||
} else {
|
} else {
|
||||||
if (cameraAspectRatio > 16 / 9) {
|
if (cameraAspectRatio > containerAspectRatio) {
|
||||||
return "absolute left-0 top-[50%] -translate-y-[50%]";
|
return "absolute left-0 top-[50%] -translate-y-[50%]";
|
||||||
} else {
|
} else {
|
||||||
return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
|
return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
|
||||||
@ -56,7 +68,7 @@ export default function LiveBirdseyeView() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
if (cameraAspectRatio > 16 / 9) {
|
if (cameraAspectRatio > containerAspectRatio) {
|
||||||
return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
|
return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
|
||||||
} else {
|
} else {
|
||||||
return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
|
return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
|
||||||
@ -64,7 +76,7 @@ export default function LiveBirdseyeView() {
|
|||||||
} else {
|
} else {
|
||||||
return "absolute top-0 bottom-0 left-[50%] -translate-x-[50%]";
|
return "absolute top-0 bottom-0 left-[50%] -translate-x-[50%]";
|
||||||
}
|
}
|
||||||
}, [cameraAspectRatio, fullscreen, isPortrait]);
|
}, [cameraAspectRatio, containerAspectRatio, fullscreen, isPortrait]);
|
||||||
|
|
||||||
const preferredLiveMode = useMemo(() => {
|
const preferredLiveMode = useMemo(() => {
|
||||||
if (!config || !config.birdseye.restream) {
|
if (!config || !config.birdseye.restream) {
|
||||||
@ -78,18 +90,6 @@ export default function LiveBirdseyeView() {
|
|||||||
return "mse";
|
return "mse";
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
const windowAspectRatio = useMemo(() => {
|
|
||||||
return windowWidth / windowHeight;
|
|
||||||
}, [windowWidth, windowHeight]);
|
|
||||||
|
|
||||||
const containerAspectRatio = useMemo(() => {
|
|
||||||
if (!containerRef.current) {
|
|
||||||
return windowAspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
return containerRef.current.clientWidth / containerRef.current.clientHeight;
|
|
||||||
}, [windowAspectRatio, containerRef]);
|
|
||||||
|
|
||||||
const aspectRatio = useMemo<number>(() => {
|
const aspectRatio = useMemo<number>(() => {
|
||||||
if (isMobile || fullscreen) {
|
if (isMobile || fullscreen) {
|
||||||
return cameraAspectRatio;
|
return cameraAspectRatio;
|
||||||
|
@ -113,7 +113,7 @@ export default function MotionTunerView({
|
|||||||
axios
|
axios
|
||||||
.put(
|
.put(
|
||||||
`config/set?cameras.${selectedCamera}.motion.threshold=${motionSettings.threshold}&cameras.${selectedCamera}.motion.contour_area=${motionSettings.contour_area}&cameras.${selectedCamera}.motion.improve_contrast=${motionSettings.improve_contrast}`,
|
`config/set?cameras.${selectedCamera}.motion.threshold=${motionSettings.threshold}&cameras.${selectedCamera}.motion.contour_area=${motionSettings.contour_area}&cameras.${selectedCamera}.motion.improve_contrast=${motionSettings.improve_contrast}`,
|
||||||
{ requires_restart: 1 },
|
{ requires_restart: 0 },
|
||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
Loading…
Reference in New Issue
Block a user