mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-26 21:59:02 +03:00
Compare commits
2
Commits
dev
...
8610a3c4e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8610a3c4e5 | ||
|
|
696f2062b6 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"description": {
|
"description": {
|
||||||
"addFace": "Walk through adding a new collection to the Face Library.",
|
"addFace": "Add a new collection to the Face Library by uploading your first image.",
|
||||||
"placeholder": "Enter a name for this collection",
|
"placeholder": "Enter a name for this collection",
|
||||||
"invalidName": "Invalid name. Names can only include letters, numbers, spaces, apostrophes, underscores, and hyphens."
|
"invalidName": "Invalid name. Names can only include letters, numbers, spaces, apostrophes, underscores, and hyphens."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -102,17 +102,23 @@ export default function CreateFaceWizardDialog({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Content
|
<Content
|
||||||
className={cn("flex flex-col gap-4", isDesktop ? "max-w-3xl" : "p-4")}
|
className={cn(
|
||||||
|
"flex flex-col gap-4",
|
||||||
|
isDesktop ? (step == 0 ? "max-w-xl" : "max-w-3xl") : "p-4",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<Header>
|
|
||||||
<Title>{t("button.addFace")}</Title>
|
|
||||||
{isDesktop && <Description>{t("description.addFace")}</Description>}
|
|
||||||
</Header>
|
|
||||||
<StepIndicator
|
<StepIndicator
|
||||||
steps={STEPS}
|
steps={STEPS}
|
||||||
currentStep={step}
|
currentStep={step}
|
||||||
translationNameSpace="views/faceLibrary"
|
translationNameSpace="views/faceLibrary"
|
||||||
|
className="mb-4 justify-start"
|
||||||
|
variant="dots"
|
||||||
/>
|
/>
|
||||||
|
<Header>
|
||||||
|
<Title>{t("button.addFace")}</Title>
|
||||||
|
{isDesktop && <Description>{t("description.addFace")}</Description>}
|
||||||
|
</Header>
|
||||||
|
|
||||||
{step == 0 && (
|
{step == 0 && (
|
||||||
<TextEntry
|
<TextEntry
|
||||||
placeholder={t("description.placeholder")}
|
placeholder={t("description.placeholder")}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export default function Events() {
|
|||||||
camera: resp.data.camera,
|
camera: resp.data.camera,
|
||||||
startTime,
|
startTime,
|
||||||
severity: resp.data.severity,
|
severity: resp.data.severity,
|
||||||
|
timelineType: "detail",
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export type RecordingStartingPoint = {
|
|||||||
camera: string;
|
camera: string;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
severity: ReviewSeverity;
|
severity: ReviewSeverity;
|
||||||
|
timelineType?: "timeline" | "events" | "detail";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RecordingPlayerError = "stalled" | "startup";
|
export type RecordingPlayerError = "stalled" | "startup";
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ import { cn } from "@/lib/utils";
|
|||||||
import { FilterList, LAST_24_HOURS_KEY } from "@/types/filter";
|
import { FilterList, LAST_24_HOURS_KEY } from "@/types/filter";
|
||||||
import { GiSoundWaves } from "react-icons/gi";
|
import { GiSoundWaves } from "react-icons/gi";
|
||||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||||
import ReviewDetailDialog from "@/components/overlay/detail/ReviewDetailDialog";
|
|
||||||
|
|
||||||
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
|
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
@@ -398,6 +396,7 @@ export default function EventView({
|
|||||||
onSelectAllReviews={onSelectAllReviews}
|
onSelectAllReviews={onSelectAllReviews}
|
||||||
setSelectedReviews={setSelectedReviews}
|
setSelectedReviews={setSelectedReviews}
|
||||||
pullLatestData={pullLatestData}
|
pullLatestData={pullLatestData}
|
||||||
|
onOpenRecording={onOpenRecording}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{severity == "significant_motion" && (
|
{severity == "significant_motion" && (
|
||||||
@@ -441,6 +440,7 @@ type DetectionReviewProps = {
|
|||||||
onSelectAllReviews: () => void;
|
onSelectAllReviews: () => void;
|
||||||
setSelectedReviews: (reviews: ReviewSegment[]) => void;
|
setSelectedReviews: (reviews: ReviewSegment[]) => void;
|
||||||
pullLatestData: () => void;
|
pullLatestData: () => void;
|
||||||
|
onOpenRecording: (recordingInfo: RecordingStartingPoint) => void;
|
||||||
};
|
};
|
||||||
function DetectionReview({
|
function DetectionReview({
|
||||||
contentRef,
|
contentRef,
|
||||||
@@ -460,15 +460,12 @@ function DetectionReview({
|
|||||||
onSelectAllReviews,
|
onSelectAllReviews,
|
||||||
setSelectedReviews,
|
setSelectedReviews,
|
||||||
pullLatestData,
|
pullLatestData,
|
||||||
|
onOpenRecording,
|
||||||
}: DetectionReviewProps) {
|
}: DetectionReviewProps) {
|
||||||
const { t } = useTranslation(["views/events"]);
|
const { t } = useTranslation(["views/events"]);
|
||||||
|
|
||||||
const reviewTimelineRef = useRef<HTMLDivElement>(null);
|
const reviewTimelineRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// detail
|
|
||||||
|
|
||||||
const [reviewDetail, setReviewDetail] = useState<ReviewSegment>();
|
|
||||||
|
|
||||||
// preview
|
// preview
|
||||||
|
|
||||||
const [previewTime, setPreviewTime] = useState<number>();
|
const [previewTime, setPreviewTime] = useState<number>();
|
||||||
@@ -688,8 +685,6 @@ function DetectionReview({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ReviewDetailDialog review={reviewDetail} setReview={setReviewDetail} />
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={contentRef}
|
ref={contentRef}
|
||||||
className="no-scrollbar flex flex-1 flex-wrap content-start gap-2 overflow-y-auto md:gap-4"
|
className="no-scrollbar flex flex-1 flex-wrap content-start gap-2 overflow-y-auto md:gap-4"
|
||||||
@@ -750,7 +745,12 @@ function DetectionReview({
|
|||||||
detail: boolean,
|
detail: boolean,
|
||||||
) => {
|
) => {
|
||||||
if (detail) {
|
if (detail) {
|
||||||
setReviewDetail(review);
|
onOpenRecording({
|
||||||
|
camera: review.camera,
|
||||||
|
startTime: review.start_time - REVIEW_PADDING,
|
||||||
|
severity: review.severity,
|
||||||
|
timelineType: "detail",
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
onSelectReview(review, ctrl);
|
onSelectReview(review, ctrl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import {
|
|||||||
ASPECT_VERTICAL_LAYOUT,
|
ASPECT_VERTICAL_LAYOUT,
|
||||||
ASPECT_WIDE_LAYOUT,
|
ASPECT_WIDE_LAYOUT,
|
||||||
RecordingSegment,
|
RecordingSegment,
|
||||||
|
RecordingStartingPoint,
|
||||||
} from "@/types/record";
|
} from "@/types/record";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@@ -141,9 +142,15 @@ export function RecordingView({
|
|||||||
|
|
||||||
// timeline
|
// timeline
|
||||||
|
|
||||||
|
const [recording] = useOverlayState<RecordingStartingPoint>(
|
||||||
|
"recording",
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
const [timelineType, setTimelineType] = useOverlayState<TimelineType>(
|
const [timelineType, setTimelineType] = useOverlayState<TimelineType>(
|
||||||
"timelineType",
|
"timelineType",
|
||||||
"timeline",
|
recording?.timelineType ?? "timeline",
|
||||||
);
|
);
|
||||||
|
|
||||||
const chunkedTimeRange = useMemo(
|
const chunkedTimeRange = useMemo(
|
||||||
|
|||||||
Reference in New Issue
Block a user