Various bugfixes and improvements (#11624)

* various bugfixes and improvements

* add separator

* no separator
This commit is contained in:
Josh Hawkins 2024-05-29 13:05:28 -05:00 committed by GitHub
parent 3dd401f57a
commit f1c0422d5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 90 additions and 42 deletions

View File

@ -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(
`${polygon.name || "Motion Mask"} has been saved. Restart Frigate to apply changes.`,
{
position: "top-center", 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}`, {

View File

@ -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(
`${polygon.name || "Object Mask"} has been saved. Restart Frigate to apply changes.`,
{
position: "top-center", 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}`, {

View File

@ -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(
`Zone (${zoneName}) has been saved. Restart Frigate to apply changes.`,
{
position: "top-center", 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}`, {

View File

@ -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,
}} }}

View File

@ -267,14 +267,27 @@ export default function DraggableGridLayout({
const [{ width: containerWidth, height: containerHeight }] = const [{ width: containerWidth, height: containerHeight }] =
useResizeObserver(gridContainerRef); useResizeObserver(gridContainerRef);
const hasScrollbar = useMemo(() => { const scrollBarWidth = useMemo(() => {
if (containerWidth && containerHeight && containerRef.current) {
return ( return (
containerHeight && containerRef.current.offsetWidth - containerRef.current.clientWidth
containerRef.current &&
containerRef.current.offsetHeight <
(gridContainerRef.current?.scrollHeight ?? 0)
); );
}, [containerRef, gridContainerRef, containerHeight]); }
return 0;
}, [containerRef, containerHeight, containerWidth]);
const availableWidth = useMemo(
() => (scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth),
[containerWidth, scrollBarWidth],
);
const hasScrollbar = useMemo(() => {
if (containerHeight && containerRef.current) {
return (
containerRef.current.offsetHeight < containerRef.current.scrollHeight
);
}
}, [containerRef, 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>

View File

@ -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;

View File

@ -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) {