mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-22 16:18:22 +03:00
upgrade to React 19, react-konva v19, eslint-plugin-react-hooks v5
Core React 19 upgrade with all necessary type fixes: - Update RefObject types to accept T | null (React 19 refs always nullable) - Add JSX namespace imports (no longer global in React 19) - Add initial values to useRef calls (required in React 19) - Fix ReactElement.props unknown type in config-form components - Fix IconWrapper interface to use HTMLAttributes instead of index signature - Add monaco-editor as dev dependency for type declarations - Upgrade react-konva to v19, eslint-plugin-react-hooks to v5
This commit is contained in:
parent
cf7535338a
commit
7626bc0344
4035
web/package-lock.json
generated
4035
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -63,17 +63,17 @@
|
|||||||
"monaco-yaml": "^5.3.1",
|
"monaco-yaml": "^5.3.1",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"nosleep.js": "^0.12.0",
|
"nosleep.js": "^0.12.0",
|
||||||
"react": "^18.3.1",
|
"react": "^19.2.4",
|
||||||
"react-apexcharts": "^1.4.1",
|
"react-apexcharts": "^1.4.1",
|
||||||
"react-day-picker": "^9.7.0",
|
"react-day-picker": "^9.7.0",
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^19.2.4",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-grid-layout": "^2.2.2",
|
"react-grid-layout": "^2.2.2",
|
||||||
"react-hook-form": "^7.52.1",
|
"react-hook-form": "^7.52.1",
|
||||||
"react-i18next": "^15.2.0",
|
"react-i18next": "^15.2.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^19.2.3",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-router-dom": "^6.30.3",
|
"react-router-dom": "^6.30.3",
|
||||||
"react-swipeable": "^7.0.2",
|
"react-swipeable": "^7.0.2",
|
||||||
@ -99,9 +99,10 @@
|
|||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"@testing-library/jest-dom": "^6.6.2",
|
"@testing-library/jest-dom": "^6.6.2",
|
||||||
"@types/lodash": "^4.17.12",
|
"@types/lodash": "^4.17.12",
|
||||||
|
"monaco-editor": "^0.52.0",
|
||||||
"@types/node": "^20.14.10",
|
"@types/node": "^20.14.10",
|
||||||
"@types/react": "^18.3.2",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/react-icons": "^3.0.0",
|
"@types/react-icons": "^3.0.0",
|
||||||
"@types/react-transition-group": "^4.4.10",
|
"@types/react-transition-group": "^4.4.10",
|
||||||
"@types/strftime": "^0.9.8",
|
"@types/strftime": "^0.9.8",
|
||||||
@ -114,7 +115,7 @@
|
|||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-jest": "^28.2.0",
|
"eslint-plugin-jest": "^28.2.0",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.8",
|
"eslint-plugin-react-refresh": "^0.4.8",
|
||||||
"eslint-plugin-vitest-globals": "^1.5.0",
|
"eslint-plugin-vitest-globals": "^1.5.0",
|
||||||
"fake-indexeddb": "^6.0.0",
|
"fake-indexeddb": "^6.0.0",
|
||||||
|
|||||||
@ -114,10 +114,17 @@ interface PropertyElement {
|
|||||||
content: React.ReactElement;
|
content: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Shape of the props that RJSF injects into each property element. */
|
||||||
|
interface RjsfElementProps {
|
||||||
|
schema?: { type?: string | string[] };
|
||||||
|
uiSchema?: Record<string, unknown> & {
|
||||||
|
"ui:widget"?: string;
|
||||||
|
"ui:options"?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function isObjectLikeElement(item: PropertyElement) {
|
function isObjectLikeElement(item: PropertyElement) {
|
||||||
const fieldSchema = item.content.props?.schema as
|
const fieldSchema = (item.content.props as RjsfElementProps)?.schema;
|
||||||
| { type?: string | string[] }
|
|
||||||
| undefined;
|
|
||||||
return fieldSchema?.type === "object";
|
return fieldSchema?.type === "object";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,16 +170,21 @@ function GridLayoutObjectFieldTemplate(
|
|||||||
|
|
||||||
// Override the properties rendering with grid layout
|
// Override the properties rendering with grid layout
|
||||||
const isHiddenProp = (prop: (typeof properties)[number]) =>
|
const isHiddenProp = (prop: (typeof properties)[number]) =>
|
||||||
prop.content.props.uiSchema?.["ui:widget"] === "hidden";
|
(prop.content.props as RjsfElementProps).uiSchema?.["ui:widget"] ===
|
||||||
|
"hidden";
|
||||||
|
|
||||||
const visibleProps = properties.filter((prop) => !isHiddenProp(prop));
|
const visibleProps = properties.filter((prop) => !isHiddenProp(prop));
|
||||||
|
|
||||||
// Separate regular and advanced properties
|
// Separate regular and advanced properties
|
||||||
const advancedProps = visibleProps.filter(
|
const advancedProps = visibleProps.filter(
|
||||||
(p) => p.content.props.uiSchema?.["ui:options"]?.advanced === true,
|
(p) =>
|
||||||
|
(p.content.props as RjsfElementProps).uiSchema?.["ui:options"]
|
||||||
|
?.advanced === true,
|
||||||
);
|
);
|
||||||
const regularProps = visibleProps.filter(
|
const regularProps = visibleProps.filter(
|
||||||
(p) => p.content.props.uiSchema?.["ui:options"]?.advanced !== true,
|
(p) =>
|
||||||
|
(p.content.props as RjsfElementProps).uiSchema?.["ui:options"]
|
||||||
|
?.advanced !== true,
|
||||||
);
|
);
|
||||||
const hasModifiedAdvanced = advancedProps.some((prop) =>
|
const hasModifiedAdvanced = advancedProps.some((prop) =>
|
||||||
isPathModified([...fieldPath, prop.name]),
|
isPathModified([...fieldPath, prop.name]),
|
||||||
|
|||||||
@ -448,6 +448,12 @@ export function FieldTemplate(props: FieldTemplateProps) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const errorsProps = errors?.props as
|
||||||
|
| { errors?: unknown[] }
|
||||||
|
| undefined;
|
||||||
|
const hasFieldErrors =
|
||||||
|
!!errors && (errorsProps?.errors?.length ?? 0) > 0;
|
||||||
|
|
||||||
const renderStandardLabel = () => {
|
const renderStandardLabel = () => {
|
||||||
if (!shouldRenderStandardLabel) {
|
if (!shouldRenderStandardLabel) {
|
||||||
return null;
|
return null;
|
||||||
@ -459,7 +465,7 @@ export function FieldTemplate(props: FieldTemplateProps) {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"text-sm font-medium",
|
"text-sm font-medium",
|
||||||
isModified && "text-danger",
|
isModified && "text-danger",
|
||||||
errors && errors.props?.errors?.length > 0 && "text-destructive",
|
hasFieldErrors && "text-destructive",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{finalLabel}
|
{finalLabel}
|
||||||
@ -497,7 +503,7 @@ export function FieldTemplate(props: FieldTemplateProps) {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"text-sm font-medium",
|
"text-sm font-medium",
|
||||||
isModified && "text-danger",
|
isModified && "text-danger",
|
||||||
errors && errors.props?.errors?.length > 0 && "text-destructive",
|
hasFieldErrors && "text-destructive",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{finalLabel}
|
{finalLabel}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// Custom MultiSchemaFieldTemplate to handle anyOf [Type, null] fields
|
// Custom MultiSchemaFieldTemplate to handle anyOf [Type, null] fields
|
||||||
// Renders simple nullable types as single inputs instead of dropdowns
|
// Renders simple nullable types as single inputs instead of dropdowns
|
||||||
|
|
||||||
|
import type { JSX } from "react";
|
||||||
import {
|
import {
|
||||||
MultiSchemaFieldTemplateProps,
|
MultiSchemaFieldTemplateProps,
|
||||||
StrictRJSFSchema,
|
StrictRJSFSchema,
|
||||||
|
|||||||
@ -25,6 +25,15 @@ import {
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { AddPropertyButton, AdvancedCollapsible } from "../components";
|
import { AddPropertyButton, AdvancedCollapsible } from "../components";
|
||||||
|
|
||||||
|
/** Shape of the props that RJSF injects into each property element. */
|
||||||
|
interface RjsfElementProps {
|
||||||
|
schema?: { type?: string | string[] };
|
||||||
|
uiSchema?: Record<string, unknown> & {
|
||||||
|
"ui:widget"?: string;
|
||||||
|
"ui:options"?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
|
export function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
@ -182,16 +191,21 @@ export function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
|
|||||||
uiSchema?.["ui:options"]?.disableNestedCard === true;
|
uiSchema?.["ui:options"]?.disableNestedCard === true;
|
||||||
|
|
||||||
const isHiddenProp = (prop: (typeof properties)[number]) =>
|
const isHiddenProp = (prop: (typeof properties)[number]) =>
|
||||||
prop.content.props.uiSchema?.["ui:widget"] === "hidden";
|
(prop.content.props as RjsfElementProps).uiSchema?.["ui:widget"] ===
|
||||||
|
"hidden";
|
||||||
|
|
||||||
const visibleProps = properties.filter((prop) => !isHiddenProp(prop));
|
const visibleProps = properties.filter((prop) => !isHiddenProp(prop));
|
||||||
|
|
||||||
// Check for advanced section grouping
|
// Check for advanced section grouping
|
||||||
const advancedProps = visibleProps.filter(
|
const advancedProps = visibleProps.filter(
|
||||||
(p) => p.content.props.uiSchema?.["ui:options"]?.advanced === true,
|
(p) =>
|
||||||
|
(p.content.props as RjsfElementProps).uiSchema?.["ui:options"]
|
||||||
|
?.advanced === true,
|
||||||
);
|
);
|
||||||
const regularProps = visibleProps.filter(
|
const regularProps = visibleProps.filter(
|
||||||
(p) => p.content.props.uiSchema?.["ui:options"]?.advanced !== true,
|
(p) =>
|
||||||
|
(p.content.props as RjsfElementProps).uiSchema?.["ui:options"]
|
||||||
|
?.advanced !== true,
|
||||||
);
|
);
|
||||||
const hasModifiedAdvanced = advancedProps.some((prop) =>
|
const hasModifiedAdvanced = advancedProps.some((prop) =>
|
||||||
checkSubtreeModified([...fieldPath, prop.name]),
|
checkSubtreeModified([...fieldPath, prop.name]),
|
||||||
@ -333,9 +347,7 @@ export function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
|
|||||||
|
|
||||||
const ungrouped = items.filter((item) => !grouped.has(item.name));
|
const ungrouped = items.filter((item) => !grouped.has(item.name));
|
||||||
const isObjectLikeField = (item: (typeof properties)[number]) => {
|
const isObjectLikeField = (item: (typeof properties)[number]) => {
|
||||||
const fieldSchema = item.content.props.schema as
|
const fieldSchema = (item.content.props as RjsfElementProps)?.schema;
|
||||||
| { type?: string | string[] }
|
|
||||||
| undefined;
|
|
||||||
return fieldSchema?.type === "object";
|
return fieldSchema?.type === "object";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
|
import type { JSX } from "react";
|
||||||
import { FunctionComponent, useEffect, useMemo, useState } from "react";
|
import { FunctionComponent, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
interface IProp {
|
interface IProp {
|
||||||
|
|||||||
@ -102,7 +102,7 @@ export function MobilePagePortal({
|
|||||||
type MobilePageContentProps = {
|
type MobilePageContentProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
scrollerRef?: React.RefObject<HTMLDivElement>;
|
scrollerRef?: React.RefObject<HTMLDivElement | null>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MobilePageContent({
|
export function MobilePageContent({
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import Konva from "konva";
|
|||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||||
|
|
||||||
type DebugDrawingLayerProps = {
|
type DebugDrawingLayerProps = {
|
||||||
containerRef: React.RefObject<HTMLDivElement>;
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
||||||
cameraWidth: number;
|
cameraWidth: number;
|
||||||
cameraHeight: number;
|
cameraHeight: number;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,7 +17,7 @@ type ObjectPathProps = {
|
|||||||
color?: number[];
|
color?: number[];
|
||||||
width?: number;
|
width?: number;
|
||||||
pointRadius?: number;
|
pointRadius?: number;
|
||||||
imgRef: React.RefObject<HTMLImageElement>;
|
imgRef: React.RefObject<HTMLImageElement | null>;
|
||||||
onPointClick?: (index: number) => void;
|
onPointClick?: (index: number) => void;
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
} from "@/components/ui/sheet";
|
} from "@/components/ui/sheet";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { isMobile } from "react-device-detect";
|
import { isMobile } from "react-device-detect";
|
||||||
|
import type { JSX } from "react";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
type PlatformAwareDialogProps = {
|
type PlatformAwareDialogProps = {
|
||||||
|
|||||||
@ -91,7 +91,7 @@ export default function HlsVideoPlayer({
|
|||||||
|
|
||||||
// playback
|
// playback
|
||||||
|
|
||||||
const hlsRef = useRef<Hls>();
|
const hlsRef = useRef<Hls>(undefined);
|
||||||
const [useHlsCompat, setUseHlsCompat] = useState(false);
|
const [useHlsCompat, setUseHlsCompat] = useState(false);
|
||||||
const [loadedMetadata, setLoadedMetadata] = useState(false);
|
const [loadedMetadata, setLoadedMetadata] = useState(false);
|
||||||
const [bufferTimeout, setBufferTimeout] = useState<NodeJS.Timeout>();
|
const [bufferTimeout, setBufferTimeout] = useState<NodeJS.Timeout>();
|
||||||
|
|||||||
@ -51,10 +51,10 @@ export default function WebRtcPlayer({
|
|||||||
|
|
||||||
// camera states
|
// camera states
|
||||||
|
|
||||||
const pcRef = useRef<RTCPeerConnection | undefined>();
|
const pcRef = useRef<RTCPeerConnection | undefined>(undefined);
|
||||||
const videoRef = useRef<HTMLVideoElement | null>(null);
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
const [bufferTimeout, setBufferTimeout] = useState<NodeJS.Timeout>();
|
const [bufferTimeout, setBufferTimeout] = useState<NodeJS.Timeout>();
|
||||||
const videoLoadTimeoutRef = useRef<NodeJS.Timeout>();
|
const videoLoadTimeoutRef = useRef<NodeJS.Timeout>(undefined);
|
||||||
|
|
||||||
const PeerConnection = useCallback(
|
const PeerConnection = useCallback(
|
||||||
async (media: string) => {
|
async (media: string) => {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { snapPointToLines } from "@/utils/canvasUtil";
|
|||||||
import { usePolygonStates } from "@/hooks/use-polygon-states";
|
import { usePolygonStates } from "@/hooks/use-polygon-states";
|
||||||
|
|
||||||
type PolygonCanvasProps = {
|
type PolygonCanvasProps = {
|
||||||
containerRef: RefObject<HTMLDivElement>;
|
containerRef: RefObject<HTMLDivElement | null>;
|
||||||
camera: string;
|
camera: string;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import Konva from "konva";
|
|||||||
import { Vector2d } from "konva/lib/types";
|
import { Vector2d } from "konva/lib/types";
|
||||||
|
|
||||||
type PolygonDrawerProps = {
|
type PolygonDrawerProps = {
|
||||||
stageRef: RefObject<Konva.Stage>;
|
stageRef: RefObject<Konva.Stage | null>;
|
||||||
points: number[][];
|
points: number[][];
|
||||||
distances: number[];
|
distances: number[];
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|||||||
@ -37,8 +37,8 @@ export type EventReviewTimelineProps = {
|
|||||||
events: ReviewSegment[];
|
events: ReviewSegment[];
|
||||||
visibleTimestamps?: number[];
|
visibleTimestamps?: number[];
|
||||||
severityType: ReviewSeverity;
|
severityType: ReviewSeverity;
|
||||||
timelineRef?: RefObject<HTMLDivElement>;
|
timelineRef?: RefObject<HTMLDivElement | null>;
|
||||||
contentRef: RefObject<HTMLDivElement>;
|
contentRef: RefObject<HTMLDivElement | null>;
|
||||||
onHandlebarDraggingChange?: (isDragging: boolean) => void;
|
onHandlebarDraggingChange?: (isDragging: boolean) => void;
|
||||||
isZooming: boolean;
|
isZooming: boolean;
|
||||||
zoomDirection: TimelineZoomDirection;
|
zoomDirection: TimelineZoomDirection;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ type EventSegmentProps = {
|
|||||||
minimapStartTime?: number;
|
minimapStartTime?: number;
|
||||||
minimapEndTime?: number;
|
minimapEndTime?: number;
|
||||||
severityType: ReviewSeverity;
|
severityType: ReviewSeverity;
|
||||||
contentRef: RefObject<HTMLDivElement>;
|
contentRef: RefObject<HTMLDivElement | null>;
|
||||||
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
||||||
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
|
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
|
||||||
dense: boolean;
|
dense: boolean;
|
||||||
|
|||||||
@ -41,8 +41,8 @@ export type MotionReviewTimelineProps = {
|
|||||||
events: ReviewSegment[];
|
events: ReviewSegment[];
|
||||||
motion_events: MotionData[];
|
motion_events: MotionData[];
|
||||||
noRecordingRanges?: RecordingSegment[];
|
noRecordingRanges?: RecordingSegment[];
|
||||||
contentRef: RefObject<HTMLDivElement>;
|
contentRef: RefObject<HTMLDivElement | null>;
|
||||||
timelineRef?: RefObject<HTMLDivElement>;
|
timelineRef?: RefObject<HTMLDivElement | null>;
|
||||||
onHandlebarDraggingChange?: (isDragging: boolean) => void;
|
onHandlebarDraggingChange?: (isDragging: boolean) => void;
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
isZooming: boolean;
|
isZooming: boolean;
|
||||||
|
|||||||
@ -20,8 +20,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
|||||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||||
|
|
||||||
export type ReviewTimelineProps = {
|
export type ReviewTimelineProps = {
|
||||||
timelineRef: RefObject<HTMLDivElement>;
|
timelineRef: RefObject<HTMLDivElement | null>;
|
||||||
contentRef: RefObject<HTMLDivElement>;
|
contentRef: RefObject<HTMLDivElement | null>;
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
timelineDuration: number;
|
timelineDuration: number;
|
||||||
timelineStartAligned: number;
|
timelineStartAligned: number;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import {
|
|||||||
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
|
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
|
||||||
|
|
||||||
export type SummaryTimelineProps = {
|
export type SummaryTimelineProps = {
|
||||||
reviewTimelineRef: React.RefObject<HTMLDivElement>;
|
reviewTimelineRef: React.RefObject<HTMLDivElement | null>;
|
||||||
timelineStart: number;
|
timelineStart: number;
|
||||||
timelineEnd: number;
|
timelineEnd: number;
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { EventSegment } from "./EventSegment";
|
|||||||
import { ReviewSegment, ReviewSeverity } from "@/types/review";
|
import { ReviewSegment, ReviewSeverity } from "@/types/review";
|
||||||
|
|
||||||
type VirtualizedEventSegmentsProps = {
|
type VirtualizedEventSegmentsProps = {
|
||||||
timelineRef: React.RefObject<HTMLDivElement>;
|
timelineRef: React.RefObject<HTMLDivElement | null>;
|
||||||
segments: number[];
|
segments: number[];
|
||||||
events: ReviewSegment[];
|
events: ReviewSegment[];
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
@ -19,7 +19,7 @@ type VirtualizedEventSegmentsProps = {
|
|||||||
minimapStartTime?: number;
|
minimapStartTime?: number;
|
||||||
minimapEndTime?: number;
|
minimapEndTime?: number;
|
||||||
severityType: ReviewSeverity;
|
severityType: ReviewSeverity;
|
||||||
contentRef: React.RefObject<HTMLDivElement>;
|
contentRef: React.RefObject<HTMLDivElement | null>;
|
||||||
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
||||||
dense: boolean;
|
dense: boolean;
|
||||||
alignStartDateToTimeline: (timestamp: number) => number;
|
alignStartDateToTimeline: (timestamp: number) => number;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import MotionSegment from "./MotionSegment";
|
|||||||
import { ReviewSegment, MotionData } from "@/types/review";
|
import { ReviewSegment, MotionData } from "@/types/review";
|
||||||
|
|
||||||
type VirtualizedMotionSegmentsProps = {
|
type VirtualizedMotionSegmentsProps = {
|
||||||
timelineRef: React.RefObject<HTMLDivElement>;
|
timelineRef: React.RefObject<HTMLDivElement | null>;
|
||||||
segments: number[];
|
segments: number[];
|
||||||
events: ReviewSegment[];
|
events: ReviewSegment[];
|
||||||
motion_events: MotionData[];
|
motion_events: MotionData[];
|
||||||
@ -19,7 +19,7 @@ type VirtualizedMotionSegmentsProps = {
|
|||||||
showMinimap: boolean;
|
showMinimap: boolean;
|
||||||
minimapStartTime?: number;
|
minimapStartTime?: number;
|
||||||
minimapEndTime?: number;
|
minimapEndTime?: number;
|
||||||
contentRef: React.RefObject<HTMLDivElement>;
|
contentRef: React.RefObject<HTMLDivElement | null>;
|
||||||
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
||||||
dense: boolean;
|
dense: boolean;
|
||||||
motionOnly: boolean;
|
motionOnly: boolean;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { JSX } from "react";
|
||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { Button } from "./button";
|
import { Button } from "./button";
|
||||||
import { Calendar } from "./calendar";
|
import { Calendar } from "./calendar";
|
||||||
@ -124,8 +125,8 @@ export function DateRangePicker({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Refs to store the values of range and rangeCompare when the date picker is opened
|
// Refs to store the values of range and rangeCompare when the date picker is opened
|
||||||
const openedRangeRef = useRef<DateRange | undefined>();
|
const openedRangeRef = useRef<DateRange | undefined>(undefined);
|
||||||
const openedRangeCompareRef = useRef<DateRange | undefined>();
|
const openedRangeCompareRef = useRef<DateRange | undefined>(undefined);
|
||||||
|
|
||||||
const [selectedPreset, setSelectedPreset] = useState<string | undefined>(
|
const [selectedPreset, setSelectedPreset] = useState<string | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { ForwardedRef, forwardRef } from "react";
|
import { ForwardedRef, forwardRef } from "react";
|
||||||
import { IconType } from "react-icons";
|
import { IconType } from "react-icons";
|
||||||
|
|
||||||
interface IconWrapperProps {
|
interface IconWrapperProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
icon: IconType;
|
icon: IconType;
|
||||||
className?: string;
|
className?: string;
|
||||||
[key: string]: any;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IconWrapper = forwardRef(
|
const IconWrapper = forwardRef(
|
||||||
|
|||||||
@ -8,10 +8,10 @@ import { useTranslation } from "react-i18next";
|
|||||||
import useUserInteraction from "./use-user-interaction";
|
import useUserInteraction from "./use-user-interaction";
|
||||||
|
|
||||||
type DraggableElementProps = {
|
type DraggableElementProps = {
|
||||||
contentRef: React.RefObject<HTMLElement>;
|
contentRef: React.RefObject<HTMLElement | null>;
|
||||||
timelineRef: React.RefObject<HTMLDivElement>;
|
timelineRef: React.RefObject<HTMLDivElement | null>;
|
||||||
segmentsRef: React.RefObject<HTMLDivElement>;
|
segmentsRef: React.RefObject<HTMLDivElement | null>;
|
||||||
draggableElementRef: React.RefObject<HTMLDivElement>;
|
draggableElementRef: React.RefObject<HTMLDivElement | null>;
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
showDraggableElement: boolean;
|
showDraggableElement: boolean;
|
||||||
draggableElementTime?: number;
|
draggableElementTime?: number;
|
||||||
|
|||||||
@ -78,7 +78,7 @@ function removeEventListeners(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useFullscreen<T extends HTMLElement = HTMLElement>(
|
export function useFullscreen<T extends HTMLElement = HTMLElement>(
|
||||||
elementRef: RefObject<T>,
|
elementRef: RefObject<T | null>,
|
||||||
) {
|
) {
|
||||||
const [fullscreen, setFullscreen] = useState<boolean>(false);
|
const [fullscreen, setFullscreen] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
const useImageLoaded = (): [
|
const useImageLoaded = (): [
|
||||||
React.RefObject<HTMLImageElement>,
|
React.RefObject<HTMLImageElement | null>,
|
||||||
boolean,
|
boolean,
|
||||||
() => void,
|
() => void,
|
||||||
] => {
|
] => {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { useCallback } from "react";
|
|||||||
export type TimelineUtilsProps = {
|
export type TimelineUtilsProps = {
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
timelineDuration?: number;
|
timelineDuration?: number;
|
||||||
timelineRef?: React.RefObject<HTMLElement>;
|
timelineRef?: React.RefObject<HTMLElement | null>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useTimelineUtils({
|
export function useTimelineUtils({
|
||||||
|
|||||||
@ -11,7 +11,7 @@ type UseTimelineZoomProps = {
|
|||||||
zoomLevels: ZoomSettings[];
|
zoomLevels: ZoomSettings[];
|
||||||
onZoomChange: (newZoomLevel: number) => void;
|
onZoomChange: (newZoomLevel: number) => void;
|
||||||
pinchThresholdPercent?: number;
|
pinchThresholdPercent?: number;
|
||||||
timelineRef: React.RefObject<HTMLDivElement>;
|
timelineRef: React.RefObject<HTMLDivElement | null>;
|
||||||
timelineDuration: number;
|
timelineDuration: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
type UseUserInteractionProps = {
|
type UseUserInteractionProps = {
|
||||||
elementRef: React.RefObject<HTMLElement>;
|
elementRef: React.RefObject<HTMLElement | null>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function useUserInteraction({ elementRef }: UseUserInteractionProps) {
|
function useUserInteraction({ elementRef }: UseUserInteractionProps) {
|
||||||
const [userInteracting, setUserInteracting] = useState(false);
|
const [userInteracting, setUserInteracting] = useState(false);
|
||||||
const interactionTimeout = useRef<NodeJS.Timeout>();
|
const interactionTimeout = useRef<NodeJS.Timeout>(undefined);
|
||||||
const isProgrammaticScroll = useRef(false);
|
const isProgrammaticScroll = useRef(false);
|
||||||
|
|
||||||
const setProgrammaticScroll = useCallback(() => {
|
const setProgrammaticScroll = useCallback(() => {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export type VideoResolutionType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function useVideoDimensions(
|
export function useVideoDimensions(
|
||||||
containerRef: React.RefObject<HTMLDivElement>,
|
containerRef: React.RefObject<HTMLDivElement | null>,
|
||||||
) {
|
) {
|
||||||
const [{ width: containerWidth, height: containerHeight }] =
|
const [{ width: containerWidth, height: containerHeight }] =
|
||||||
useResizeObserver(containerRef);
|
useResizeObserver(containerRef);
|
||||||
|
|||||||
@ -56,7 +56,7 @@ type DraggableGridLayoutProps = {
|
|||||||
cameras: CameraConfig[];
|
cameras: CameraConfig[];
|
||||||
cameraGroup: string;
|
cameraGroup: string;
|
||||||
cameraRef: (node: HTMLElement | null) => void;
|
cameraRef: (node: HTMLElement | null) => void;
|
||||||
containerRef: React.RefObject<HTMLDivElement>;
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
||||||
includeBirdseye: boolean;
|
includeBirdseye: boolean;
|
||||||
onSelectCamera: (camera: string) => void;
|
onSelectCamera: (camera: string) => void;
|
||||||
windowVisible: boolean;
|
windowVisible: boolean;
|
||||||
|
|||||||
@ -419,7 +419,7 @@ export default function SearchView({
|
|||||||
>();
|
>();
|
||||||
|
|
||||||
// keep track of previous ref to outline thumbnail when dialog closes
|
// keep track of previous ref to outline thumbnail when dialog closes
|
||||||
const prevSearchDetailRef = useRef<SearchResult | undefined>();
|
const prevSearchDetailRef = useRef<SearchResult | undefined>(undefined);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchDetail === undefined && prevSearchDetailRef.current) {
|
if (searchDetail === undefined && prevSearchDetailRef.current) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user