Compare commits

..

16 Commits

Author SHA1 Message Date
Nicolas Mowen
bbe18d5d6b Don't show admin action buttons on export card 2025-12-04 10:32:45 -07:00
Nicolas Mowen
b3abede6cb Remove examples 2025-12-04 09:50:25 -07:00
Nicolas Mowen
7544d9caf8 More improvements to prompt 2025-12-04 09:18:29 -07:00
Nicolas Mowen
eb75c76ed4 Formatting and prompt improvements for review summary report 2025-12-04 09:09:06 -07:00
Nicolas Mowen
12e5f274dd Use contextual information from other cameras to inform report summary 2025-12-04 09:00:37 -07:00
Josh Hawkins
130dc76a01 only redirect to login page once on 401
attempt to fix ios pwa safari redirect storm
2025-12-03 21:59:57 -06:00
Josh Hawkins
87e67d22e2 adjust HLS gap controller params
defaults to false, should help to recover from hangs and stalling in tracking details videos on chrome
2025-12-03 21:44:02 -06:00
Nicolas Mowen
f25f1f689b Add explanation for review report 2025-12-03 13:53:54 -07:00
Josh Hawkins
7450e0a276 remove periods 2025-12-03 14:37:37 -06:00
Josh Hawkins
49be4a53cd clarify replace rules in lpr docs 2025-12-03 14:17:41 -06:00
Josh Hawkins
b71223b79c clarify zone name tip 2025-12-03 14:15:23 -06:00
Nicolas Mowen
a07d392678 Remove warning for coral 2025-12-03 13:01:05 -07:00
Nicolas Mowen
a75c2d2abb Remove yolov9 specification for warning 2025-12-03 12:55:11 -07:00
Nicolas Mowen
f6a5e9819e Specifically validate provided end_time for manual events 2025-12-03 11:44:08 -07:00
Nicolas Mowen
f2ce5572bd Don't require state classification models to select all classes 2025-12-03 11:13:27 -07:00
Nicolas Mowen
e473117705 Remove source_type from API 2025-12-03 11:11:44 -07:00
5 changed files with 9 additions and 44 deletions

View File

@ -1,5 +1,5 @@
{ {
"documentTitle": "Classification Models - Frigate", "documentTitle": "Classification Models",
"details": { "details": {
"scoreInfo": "Score represents the average classification confidence across all detections of this object." "scoreInfo": "Score represents the average classification confidence across all detections of this object."
}, },

View File

@ -1,12 +0,0 @@
// Module-level flag to prevent multiple simultaneous redirects
// (eg, when multiple SWR queries fail with 401 at once, or when
// both ApiProvider and ProtectedRoute try to redirect)
let _isRedirectingToLogin = false;
export function isRedirectingToLogin(): boolean {
return _isRedirectingToLogin;
}
export function setRedirectingToLogin(value: boolean): void {
_isRedirectingToLogin = value;
}

View File

@ -3,10 +3,13 @@ import { SWRConfig } from "swr";
import { WsProvider } from "./ws"; import { WsProvider } from "./ws";
import axios from "axios"; import axios from "axios";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { isRedirectingToLogin, setRedirectingToLogin } from "./auth-redirect";
axios.defaults.baseURL = `${baseUrl}api/`; axios.defaults.baseURL = `${baseUrl}api/`;
// Module-level flag to prevent multiple simultaneous redirects
// (eg, when multiple SWR queries fail with 401 at once)
let isRedirectingToLogin = false;
type ApiProviderType = { type ApiProviderType = {
children?: ReactNode; children?: ReactNode;
options?: Record<string, unknown>; options?: Record<string, unknown>;
@ -32,8 +35,8 @@ export function ApiProvider({ children, options }: ApiProviderType) {
) { ) {
// redirect to the login page if not already there // redirect to the login page if not already there
const loginPage = error.response.headers.get("location") ?? "login"; const loginPage = error.response.headers.get("location") ?? "login";
if (window.location.href !== loginPage && !isRedirectingToLogin()) { if (window.location.href !== loginPage && !isRedirectingToLogin) {
setRedirectingToLogin(true); isRedirectingToLogin = true;
window.location.href = loginPage; window.location.href = loginPage;
} }
} }

View File

@ -1,11 +1,7 @@
import { useContext, useEffect } from "react"; import { useContext } from "react";
import { Navigate, Outlet } from "react-router-dom"; import { Navigate, Outlet } from "react-router-dom";
import { AuthContext } from "@/context/auth-context"; import { AuthContext } from "@/context/auth-context";
import ActivityIndicator from "../indicators/activity-indicator"; import ActivityIndicator from "../indicators/activity-indicator";
import {
isRedirectingToLogin,
setRedirectingToLogin,
} from "@/api/auth-redirect";
export default function ProtectedRoute({ export default function ProtectedRoute({
requiredRoles, requiredRoles,
@ -14,20 +10,6 @@ export default function ProtectedRoute({
}) { }) {
const { auth } = useContext(AuthContext); const { auth } = useContext(AuthContext);
// Redirect to login page when not authenticated
// don't use <Navigate> because we need a full page load to reset state
useEffect(() => {
if (
!auth.isLoading &&
auth.isAuthenticated &&
!auth.user &&
!isRedirectingToLogin()
) {
setRedirectingToLogin(true);
window.location.href = "/login";
}
}, [auth.isLoading, auth.isAuthenticated, auth.user]);
if (auth.isLoading) { if (auth.isLoading) {
return ( return (
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" /> <ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
@ -41,9 +23,7 @@ export default function ProtectedRoute({
// Authenticated mode (8971): require login // Authenticated mode (8971): require login
if (!auth.user) { if (!auth.user) {
return ( return <Navigate to="/login" replace />;
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
);
} }
// If role is null (shouldnt happen if isAuthenticated, but type safety), fallback // If role is null (shouldnt happen if isAuthenticated, but type safety), fallback

View File

@ -84,12 +84,6 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
const [page, setPage] = useState<string>("train"); const [page, setPage] = useState<string>("train");
const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100); const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100);
// title
useEffect(() => {
document.title = `${model.name} - ${t("documentTitle")}`;
}, [model.name, t]);
// model state // model state
const [wasTraining, setWasTraining] = useState(false); const [wasTraining, setWasTraining] = useState(false);