mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-11 01:02:48 +03:00
Update deps (#24623)
* bump backend and frontend dependencies
Bumps every outdated dependency that passed testing, with the code changes each one needs.
- peewee 4.5 and peewee_migrate 2.3: use SqliteDatabase in place of the removed SqliteExtDatabase, and fix types for peewee's bundled stubs
- mypy 2.4.0: remove unused type ignores and add the annotations mypy 2 needs
- pandas 3.0: convert the motion activity index with as_unit("s"), because pandas 3 infers second resolution for whole-second timestamps and the old // 10**9 returned 1
- transformers 5.19: load Jina tokenizers from the saved directory with trust_remote_code off and use CLIPImageProcessor, since v5 removed CLIPFeatureExtractor and remote code pulled in torch
- tensorflow-cpu 2.21: pin protobuf to 7.36 in the TensorRT amd64 image, because the old 3.20.3 pin was installed over TensorFlow and broke its import
- pydantic 2.13 and google-genai 2.29: regenerate the API spec
- ruff 0.16: set an explicit lint select, since 0.16 widened the default rules
- react-router-dom 7: set useTransitions={false} on BrowserRouter to keep v6 update timing, which useSearchEffect relies on
- typescript 6: drop baseUrl and add node types in tsconfig
- radix: update to the latest release and remove the slot patch, which upstream now includes
- apexcharts 7.8: guard the tooltip formatter against null values
- cryptography 50, joserfc 1.7, pywebpush 2.5, openai 3.26, aiohttp, uvicorn, onvif-zeep-async, scipy, framer-motion 14, react-day-picker 10 and other minor and patch bumps
* silence httpx2 request logging
* redownload an incomplete jina tokenizer
An interrupted tokenizer download left the Hugging Face cache directory without the saved tokenizer files, and since the download is skipped whenever that directory exists, every restart failed to load the tokenizer. The Jina constructors now remove a tokenizer directory that has no tokenizer_config.json so the download runs again.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
ruff == 0.15.20
|
||||
ruff == 0.16.10
|
||||
|
||||
# types
|
||||
types-peewee == 4.0.*
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
aiofiles == 25.1.*
|
||||
click == 8.5.*
|
||||
# FastAPI
|
||||
aiohttp == 3.12.*
|
||||
aiohttp == 3.14.*
|
||||
starlette == 1.7.*
|
||||
starlette-context == 0.5.*
|
||||
fastapi[standard-no-fastapi-cloud-cli] == 0.142.*
|
||||
uvicorn == 0.52.*
|
||||
uvicorn == 0.54.*
|
||||
slowapi == 0.1.*
|
||||
joserfc == 1.6.*
|
||||
cryptography == 46.0.*
|
||||
joserfc == 1.7.*
|
||||
cryptography == 50.0.*
|
||||
pathvalidate == 3.3.*
|
||||
markupsafe == 3.0.*
|
||||
python-multipart == 0.0.31
|
||||
python-multipart == 0.0.32
|
||||
# Classification Model Training
|
||||
tensorflow == 2.19.* ; platform_machine == 'aarch64'
|
||||
tensorflow-cpu == 2.19.* ; platform_machine == 'x86_64'
|
||||
tensorflow-cpu == 2.21.* ; platform_machine == 'x86_64'
|
||||
# General
|
||||
mypy == 1.6.1
|
||||
onvif-zeep-async == 4.0.*
|
||||
mypy == 2.4.0
|
||||
onvif-zeep-async == 4.3.*
|
||||
paho-mqtt == 2.1.*
|
||||
pandas == 2.2.*
|
||||
peewee == 3.17.*
|
||||
peewee_migrate == 1.14.*
|
||||
psutil == 7.1.*
|
||||
pydantic == 2.10.*
|
||||
pandas == 3.0.*
|
||||
peewee == 4.5.*
|
||||
peewee_migrate == 2.3.*
|
||||
psutil == 7.2.*
|
||||
pydantic == 2.13.*
|
||||
git+https://github.com/fbcotter/py3nvml#egg=py3nvml
|
||||
pytz == 2025.*
|
||||
pyzmq == 27.1.*
|
||||
pytz == 2026.*
|
||||
pyzmq == 27.2.*
|
||||
ruamel.yaml == 0.19.*
|
||||
tzlocal == 5.2
|
||||
requests == 2.33.*
|
||||
types-requests == 2.32.*
|
||||
tzlocal == 5.4.4
|
||||
requests == 2.34.*
|
||||
types-requests == 2.33.*
|
||||
norfair == 2.3.*
|
||||
setproctitle == 1.3.*
|
||||
ws4py == 0.5.*
|
||||
ws4py == 0.6.*
|
||||
unidecode == 1.4.*
|
||||
titlecase == 2.4.*
|
||||
# Image Manipulation
|
||||
numpy == 1.26.*
|
||||
opencv-python-headless == 4.11.0.*
|
||||
opencv-contrib-python == 4.11.0.*
|
||||
scipy == 1.16.*
|
||||
scipy == 1.17.*
|
||||
# OpenVino & ONNX
|
||||
openvino == 2025.4.*
|
||||
onnxruntime == 1.30.*
|
||||
# Embeddings
|
||||
transformers == 4.45.*
|
||||
transformers == 5.19.*
|
||||
# Generative AI
|
||||
google-genai == 1.58.*
|
||||
google-genai == 2.29.*
|
||||
ollama == 0.6.*
|
||||
openai == 1.65.*
|
||||
openai == 3.26.*
|
||||
# push notifications
|
||||
py-vapid == 1.9.4
|
||||
pywebpush == 2.0.*
|
||||
pywebpush == 2.5.*
|
||||
# alpr
|
||||
pyclipper == 1.4.*
|
||||
shapely == 2.0.*
|
||||
rapidfuzz==3.12.*
|
||||
shapely == 2.2.*
|
||||
rapidfuzz==3.14.*
|
||||
# HailoRT
|
||||
argcomplete==3.7.*
|
||||
contextlib2==0.6.*
|
||||
future==0.18.*
|
||||
contextlib2==21.6.*
|
||||
future==1.0.*
|
||||
netaddr==1.3.*
|
||||
netifaces==0.10.*
|
||||
prometheus-client == 0.26.*
|
||||
@@ -71,6 +71,6 @@ tflite_runtime @ https://github.com/feranick/TFlite-builds/releases/download/v2.
|
||||
sherpa-onnx==1.13.*
|
||||
faster-whisper==1.2.*
|
||||
librosa==0.11.*
|
||||
soundfile==0.13.*
|
||||
soundfile==0.14.*
|
||||
# Memory profiling
|
||||
memray == 1.20.*
|
||||
|
||||
@@ -14,4 +14,4 @@ nvidia-nccl-cu12==2.26.2.post1; platform_machine == 'x86_64'
|
||||
nvidia-nvjitlink-cu12==12.8.93; platform_machine == 'x86_64'
|
||||
onnx==1.16.*; platform_machine == 'x86_64'
|
||||
onnxruntime-gpu==1.24.*; platform_machine == 'x86_64'
|
||||
protobuf==3.20.3; platform_machine == 'x86_64'
|
||||
protobuf==7.36.*; platform_machine == 'x86_64'
|
||||
|
||||
Vendored
+24
-3
@@ -1088,6 +1088,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1131,6 +1132,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1285,6 +1287,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1644,6 +1647,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1691,6 +1695,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1738,6 +1743,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1779,6 +1785,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -1862,6 +1869,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -3483,6 +3491,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Body
|
||||
responses:
|
||||
'200':
|
||||
@@ -5652,6 +5661,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Response Create Trigger Embedding Trigger Embedding Post
|
||||
'422':
|
||||
description: Validation Error
|
||||
@@ -5700,6 +5710,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Response Update Trigger Embedding Trigger Embedding
|
||||
Camera Name Name Put
|
||||
'422':
|
||||
@@ -5742,6 +5753,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Response Delete Trigger Embedding Trigger Embedding
|
||||
Camera Name Name Delete
|
||||
'422':
|
||||
@@ -5778,6 +5790,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Response Get Triggers Status Triggers Status Camera Name
|
||||
Get
|
||||
'422':
|
||||
@@ -7574,6 +7587,7 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
title: Response No Recordings Recordings Unavailable Get
|
||||
'422':
|
||||
description: Validation Error
|
||||
@@ -7777,7 +7791,8 @@ components:
|
||||
title: Update Topic
|
||||
config_data:
|
||||
anyOf:
|
||||
- type: object
|
||||
- additionalProperties: true
|
||||
type: object
|
||||
- type: 'null'
|
||||
title: Config Data
|
||||
skip_save:
|
||||
@@ -8125,6 +8140,7 @@ components:
|
||||
tool_calls:
|
||||
anyOf:
|
||||
- items:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: array
|
||||
- type: 'null'
|
||||
@@ -8420,6 +8436,7 @@ components:
|
||||
- type: 'null'
|
||||
title: Model Type
|
||||
data:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
title: Data
|
||||
type: object
|
||||
@@ -8491,7 +8508,8 @@ components:
|
||||
default: true
|
||||
draw:
|
||||
anyOf:
|
||||
- type: object
|
||||
- additionalProperties: true
|
||||
type: object
|
||||
- type: 'null'
|
||||
title: Draw
|
||||
default: {}
|
||||
@@ -8734,7 +8752,8 @@ components:
|
||||
description: Error message for failed jobs
|
||||
results:
|
||||
anyOf:
|
||||
- type: object
|
||||
- additionalProperties: true
|
||||
type: object
|
||||
- type: 'null'
|
||||
title: Results
|
||||
description: Result metadata for completed jobs
|
||||
@@ -8984,6 +9003,7 @@ components:
|
||||
- type: 'null'
|
||||
title: Base Url
|
||||
provider_options:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
title: Provider Options
|
||||
type: object
|
||||
@@ -9524,6 +9544,7 @@ components:
|
||||
type: string
|
||||
title: Tool Name
|
||||
arguments:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
title: Arguments
|
||||
type: object
|
||||
|
||||
@@ -702,7 +702,7 @@ def motion_activity(
|
||||
df = df[df["camera"] != ""]
|
||||
|
||||
# change types for output
|
||||
df.index = df.index.astype(int) // (10**9)
|
||||
df.index = df.index.as_unit("s").astype(int)
|
||||
normalized = df.reset_index().to_dict("records")
|
||||
return JSONResponse(content=normalized)
|
||||
|
||||
|
||||
+3
-3
@@ -12,8 +12,8 @@ from pathlib import Path
|
||||
|
||||
import psutil
|
||||
import uvicorn
|
||||
from peewee import SqliteDatabase
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
|
||||
from frigate.api.auth import hash_password
|
||||
from frigate.api.fastapi_app import create_fastapi_app
|
||||
@@ -186,7 +186,7 @@ class FrigateApp:
|
||||
self.timeline_queue: Queue = mp.Queue()
|
||||
|
||||
def init_database(self) -> None:
|
||||
def vacuum_db(db: SqliteExtDatabase) -> None:
|
||||
def vacuum_db(db: SqliteDatabase) -> None:
|
||||
logger.info("Running database vacuum")
|
||||
db.execute_sql("VACUUM;")
|
||||
|
||||
@@ -197,7 +197,7 @@ class FrigateApp:
|
||||
logger.error("Unable to write to /config to save DB state")
|
||||
|
||||
# Migrate DB schema
|
||||
migrate_db = SqliteExtDatabase(self.config.database.path)
|
||||
migrate_db = SqliteDatabase(self.config.database.path)
|
||||
|
||||
# Run migrations
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
|
||||
@@ -54,12 +54,12 @@ class PTZMetrics:
|
||||
reset: Event
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.start_time = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.stop_time = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.frame_time = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.zoom_level = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.max_zoom = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.min_zoom = mp.Value("d", 0) # type: ignore[assignment]
|
||||
self.start_time = mp.Value("d", 0)
|
||||
self.stop_time = mp.Value("d", 0)
|
||||
self.frame_time = mp.Value("d", 0)
|
||||
self.zoom_level = mp.Value("d", 0)
|
||||
self.max_zoom = mp.Value("d", 0)
|
||||
self.min_zoom = mp.Value("d", 0)
|
||||
|
||||
self.motor_stopped = mp.Event()
|
||||
self.reset = mp.Event()
|
||||
|
||||
@@ -6,7 +6,7 @@ import logging
|
||||
import os
|
||||
import queue
|
||||
import threading
|
||||
from collections.abc import Callable
|
||||
from collections.abc import Callable, Iterator
|
||||
from dataclasses import dataclass
|
||||
from multiprocessing.synchronize import Event as MpEvent
|
||||
from typing import Any
|
||||
@@ -72,7 +72,7 @@ class WebPushClient(Communicator):
|
||||
# Pull keys from PEM or generate if they do not exist
|
||||
self.vapid = Vapid01.from_file(os.path.join(CONFIG_DIR, "notifications.pem"))
|
||||
|
||||
users: list[dict[str, Any]] = (
|
||||
users: Iterator[dict[str, Any]] = (
|
||||
User.select(User.username, User.notification_tokens).dicts().iterator()
|
||||
)
|
||||
for user in users:
|
||||
|
||||
@@ -580,8 +580,8 @@ class LicensePlateProcessingMixin:
|
||||
boxes = []
|
||||
scores = []
|
||||
|
||||
for index in range(len(contours)): # type: ignore[arg-type]
|
||||
contour = contours[index] # type: ignore[index]
|
||||
for index in range(len(contours)):
|
||||
contour = contours[index]
|
||||
|
||||
# get minimum bounding box (rotated rectangle) around the contour and the smallest side length.
|
||||
points, sside = self._get_min_boxes(contour)
|
||||
@@ -1222,7 +1222,7 @@ class LicensePlateProcessingMixin:
|
||||
"""Look for license plates in image."""
|
||||
self.metrics.alpr_pps.value = self.plates_rec_second.eps()
|
||||
self.metrics.yolov9_lpr_pps.value = self.plates_det_second.eps()
|
||||
camera = obj_data if dedicated_lpr else obj_data["camera"]
|
||||
camera: str = obj_data if dedicated_lpr else obj_data["camera"] # type: ignore[assignment]
|
||||
current_time = int(datetime.datetime.now().timestamp())
|
||||
debug_frame_id = int(datetime.datetime.now().timestamp() * 1000)
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
img = cv2.imread(current_file)
|
||||
|
||||
if img is None:
|
||||
return { # type: ignore[unreachable]
|
||||
return {
|
||||
"message": "Invalid image file.",
|
||||
"success": False,
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
import warnings
|
||||
|
||||
from transformers import AutoFeatureExtractor, AutoTokenizer
|
||||
from transformers import AutoTokenizer, CLIPImageProcessor
|
||||
from transformers.utils.logging import disable_progress_bar
|
||||
|
||||
from frigate.comms.inter_process import InterProcessRequestor
|
||||
@@ -21,12 +21,6 @@ from frigate.util.downloader import ModelDownloader
|
||||
|
||||
from .base_embedding import BaseEmbedding
|
||||
|
||||
warnings.filterwarnings(
|
||||
"ignore",
|
||||
category=FutureWarning,
|
||||
message="The class CLIPFeatureExtractor is deprecated",
|
||||
)
|
||||
|
||||
# disables the progress bar for downloading tokenizers and feature extractors
|
||||
disable_progress_bar()
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -58,6 +52,13 @@ class JinaV1TextEmbedding(BaseEmbedding):
|
||||
self._lock = threading.Lock()
|
||||
files_names = list(self.download_urls.keys()) + [self.tokenizer_file]
|
||||
|
||||
# an interrupted download leaves the hub cache without the saved tokenizer
|
||||
tokenizer_path = os.path.join(self.download_path, self.tokenizer_file)
|
||||
if os.path.isdir(tokenizer_path) and not os.path.exists(
|
||||
os.path.join(tokenizer_path, "tokenizer_config.json")
|
||||
):
|
||||
shutil.rmtree(tokenizer_path)
|
||||
|
||||
if not all(
|
||||
os.path.exists(os.path.join(self.download_path, n)) for n in files_names
|
||||
):
|
||||
@@ -92,7 +93,7 @@ class JinaV1TextEmbedding(BaseEmbedding):
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
self.model_name,
|
||||
trust_remote_code=True,
|
||||
trust_remote_code=False,
|
||||
cache_dir=f"{MODEL_CACHE_DIR}/{self.model_name}/tokenizer",
|
||||
clean_up_tokenization_spaces=True,
|
||||
)
|
||||
@@ -123,9 +124,8 @@ class JinaV1TextEmbedding(BaseEmbedding):
|
||||
f"{MODEL_CACHE_DIR}/{self.model_name}/tokenizer"
|
||||
)
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(
|
||||
self.model_name,
|
||||
cache_dir=tokenizer_path,
|
||||
trust_remote_code=True,
|
||||
tokenizer_path,
|
||||
trust_remote_code=False,
|
||||
clean_up_tokenization_spaces=True,
|
||||
)
|
||||
|
||||
@@ -209,7 +209,7 @@ class JinaV1ImageEmbedding(BaseEmbedding):
|
||||
if self.downloader:
|
||||
self.downloader.wait_for_download()
|
||||
|
||||
self.feature_extractor = AutoFeatureExtractor.from_pretrained(
|
||||
self.feature_extractor = CLIPImageProcessor.from_pretrained(
|
||||
f"{MODEL_CACHE_DIR}/{self.model_name}",
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
|
||||
import numpy as np
|
||||
@@ -60,6 +61,14 @@ class JinaV2Embedding(BaseEmbedding):
|
||||
|
||||
# download the model and tokenizer
|
||||
files_names = list(self.download_urls.keys()) + [self.tokenizer_file]
|
||||
|
||||
# an interrupted download leaves the hub cache without the saved tokenizer
|
||||
tokenizer_path = os.path.join(self.download_path, self.tokenizer_file)
|
||||
if os.path.isdir(tokenizer_path) and not os.path.exists(
|
||||
os.path.join(tokenizer_path, "tokenizer_config.json")
|
||||
):
|
||||
shutil.rmtree(tokenizer_path)
|
||||
|
||||
if not all(
|
||||
os.path.exists(os.path.join(self.download_path, n)) for n in files_names
|
||||
):
|
||||
@@ -97,7 +106,7 @@ class JinaV2Embedding(BaseEmbedding):
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
self.model_name,
|
||||
trust_remote_code=True,
|
||||
trust_remote_code=False,
|
||||
cache_dir=os.path.join(
|
||||
MODEL_CACHE_DIR, self.model_name, "tokenizer"
|
||||
),
|
||||
@@ -129,9 +138,8 @@ class JinaV2Embedding(BaseEmbedding):
|
||||
f"{MODEL_CACHE_DIR}/{self.model_name}/tokenizer"
|
||||
)
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(
|
||||
self.model_name,
|
||||
cache_dir=tokenizer_path,
|
||||
trust_remote_code=True,
|
||||
tokenizer_path,
|
||||
trust_remote_code=False,
|
||||
clean_up_tokenization_spaces=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class EventCleanup(threading.Thread):
|
||||
datetime.datetime.now() - datetime.timedelta(days=expire_days)
|
||||
).timestamp()
|
||||
# grab all events after specific time
|
||||
expired_events: list[Event] = (
|
||||
expired_events: list[Event] = list(
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
@@ -97,7 +97,6 @@ class EventCleanup(threading.Thread):
|
||||
.namedtuples()
|
||||
.iterator()
|
||||
)
|
||||
expired_events = list(expired_events)
|
||||
logger.debug(f"{len(expired_events)} events can be expired")
|
||||
|
||||
# delete the media from disk
|
||||
@@ -159,7 +158,7 @@ class EventCleanup(threading.Thread):
|
||||
datetime.datetime.now() - datetime.timedelta(days=expire_days)
|
||||
).timestamp()
|
||||
# grab all events after specific time
|
||||
expired_events = (
|
||||
camera_events = (
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
@@ -178,7 +177,7 @@ class EventCleanup(threading.Thread):
|
||||
# delete the grabbed clips from disk
|
||||
# only snapshots are stored in /clips
|
||||
# so no need to delete mp4 files
|
||||
for event in expired_events:
|
||||
for event in camera_events:
|
||||
events_to_update.append(str(event.id))
|
||||
deleted = delete_event_snapshot(event)
|
||||
|
||||
@@ -212,7 +211,7 @@ class EventCleanup(threading.Thread):
|
||||
datetime.datetime.now() - datetime.timedelta(days=expire_days)
|
||||
).timestamp()
|
||||
# grab all events after specific time
|
||||
expired_events: list[Event] = (
|
||||
expired_events: list[Event] = list(
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
@@ -225,7 +224,6 @@ class EventCleanup(threading.Thread):
|
||||
.namedtuples()
|
||||
.iterator()
|
||||
)
|
||||
expired_events = list(expired_events)
|
||||
logger.debug(f"{len(expired_events)} events can be expired")
|
||||
# delete the media from disk
|
||||
for expired in expired_events:
|
||||
@@ -235,7 +233,7 @@ class EventCleanup(threading.Thread):
|
||||
try:
|
||||
media_path.unlink(missing_ok=True)
|
||||
if file_extension == "jpg":
|
||||
media_path = Path(
|
||||
media_path = Path( # type: ignore[unreachable]
|
||||
f"{os.path.join(CLIPS_DIR, media_name)}-clean.webp"
|
||||
)
|
||||
media_path.unlink(missing_ok=True)
|
||||
@@ -289,7 +287,7 @@ class EventCleanup(threading.Thread):
|
||||
now - datetime.timedelta(days=camera.record.effective_detection_days)
|
||||
).timestamp()
|
||||
# grab all events after specific time
|
||||
expired_events = (
|
||||
camera_events = (
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
@@ -316,7 +314,7 @@ class EventCleanup(threading.Thread):
|
||||
# delete the grabbed clips from disk
|
||||
# only snapshots are stored in /clips
|
||||
# so no need to delete mp4 files
|
||||
for event in expired_events:
|
||||
for event in camera_events:
|
||||
events_to_update.append(event.id)
|
||||
|
||||
# update the clips attribute for the db entry
|
||||
|
||||
@@ -94,7 +94,7 @@ class EventProcessor(threading.Thread):
|
||||
if update == None:
|
||||
continue
|
||||
|
||||
source_type, event_type, camera, _, event_data = update # type: ignore[misc]
|
||||
source_type, event_type, camera, _, event_data = update
|
||||
|
||||
logger.debug(
|
||||
f"Event received: {source_type} {event_type} {camera} {event_data['id']}"
|
||||
|
||||
@@ -38,7 +38,7 @@ __all__ = [
|
||||
"register_genai_provider",
|
||||
]
|
||||
|
||||
PROVIDERS = {}
|
||||
PROVIDERS: dict[GenAIProviderEnum, type["GenAIClient"]] = {}
|
||||
|
||||
|
||||
def register_genai_provider(key: GenAIProviderEnum) -> Callable:
|
||||
|
||||
@@ -85,6 +85,7 @@ def apply_log_levels(default: str, log_levels: dict[str, LogLevel]) -> None:
|
||||
log_levels = {
|
||||
"absl": LogLevel.error,
|
||||
"httpx": LogLevel.error,
|
||||
"httpx2": LogLevel.error,
|
||||
"h5py": LogLevel.error,
|
||||
"keras": LogLevel.error,
|
||||
"matplotlib": LogLevel.error,
|
||||
|
||||
@@ -360,7 +360,7 @@ class ObjectDetectProcess:
|
||||
# detection_start is set only after detection_queue.get()
|
||||
# returns. If it was reset during the grace period, the process
|
||||
# recovered and may be waiting on the shared queue again.
|
||||
if self.detection_start.value == 0.0: # type: ignore[attr-defined]
|
||||
if self.detection_start.value == 0.0:
|
||||
logging.info("Detection process recovered before restart")
|
||||
return
|
||||
|
||||
@@ -369,7 +369,7 @@ class ObjectDetectProcess:
|
||||
self.detect_process.join()
|
||||
logging.info("Detection process has exited...")
|
||||
|
||||
self.detection_start.value = 0.0 # type: ignore[attr-defined]
|
||||
self.detection_start.value = 0.0
|
||||
|
||||
# Async path for MemryX
|
||||
if self.detector_config.type == "memryx":
|
||||
|
||||
@@ -10,7 +10,7 @@ from multiprocessing.synchronize import Event as MpEvent
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.config import CameraConfig, FrigateConfig, RetainModeEnum
|
||||
from frigate.const import (
|
||||
@@ -88,7 +88,7 @@ class RecordingCleanup(threading.Thread):
|
||||
if (
|
||||
os.stat(f"{self.config.database.path}-wal").st_size / (1024 * 1024)
|
||||
) > MAX_WAL_SIZE:
|
||||
db = SqliteExtDatabase(self.config.database.path)
|
||||
db = SqliteDatabase(self.config.database.path)
|
||||
db.execute_sql("PRAGMA wal_checkpoint(TRUNCATE);")
|
||||
db.close()
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
|
||||
import pytz # type: ignore[import-untyped]
|
||||
import pytz
|
||||
from pathvalidate import sanitize_filename
|
||||
from peewee import DoesNotExist
|
||||
|
||||
|
||||
@@ -859,7 +859,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
|
||||
for box in motion_boxes:
|
||||
if len(box) < 4:
|
||||
continue
|
||||
continue # type: ignore[unreachable]
|
||||
x1, y1, x2, y2 = box
|
||||
|
||||
# Convert pixel coordinates to grid cells
|
||||
|
||||
@@ -6,8 +6,8 @@ from unittest.mock import patch
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.testclient import TestClient
|
||||
from peewee import SqliteDatabase
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
from pydantic import Json
|
||||
|
||||
@@ -38,7 +38,7 @@ class AuthTestClient(TestClient):
|
||||
class BaseTestHttp(unittest.TestCase):
|
||||
def setUp(self, models):
|
||||
# setup clean database for each test run
|
||||
migrate_db = SqliteExtDatabase("test.db")
|
||||
migrate_db = SqliteDatabase("test.db")
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
router = Router(migrate_db)
|
||||
router.run()
|
||||
|
||||
@@ -7,7 +7,7 @@ import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.api.chat import (
|
||||
_execute_find_similar_objects,
|
||||
@@ -98,7 +98,7 @@ class TestExecuteFindSimilarObjects(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
|
||||
self.tmp.close()
|
||||
self.db = SqliteExtDatabase(self.tmp.name)
|
||||
self.db = SqliteDatabase(self.tmp.name)
|
||||
Event.bind(self.db, bind_refs=False, bind_backrefs=False)
|
||||
self.db.connect()
|
||||
self.db.create_tables([Event])
|
||||
|
||||
@@ -12,7 +12,7 @@ from unittest.mock import AsyncMock, patch
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.api.chat import (
|
||||
TOOL_REJECTED_RESULT,
|
||||
@@ -214,7 +214,7 @@ class DatabaseTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
|
||||
self.tmp.close()
|
||||
self.db = SqliteExtDatabase(self.tmp.name)
|
||||
self.db = SqliteDatabase(self.tmp.name)
|
||||
for model in self.models:
|
||||
model.bind(self.db, bind_refs=False, bind_backrefs=False)
|
||||
self.db.connect()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.comms.dispatcher import Dispatcher
|
||||
from frigate.const import INSERT_MANY_RECORDINGS
|
||||
@@ -30,7 +30,7 @@ class TestInsertManyRecordings(unittest.TestCase):
|
||||
"""A duplicate path must not cost the rest of the batch."""
|
||||
|
||||
def setUp(self):
|
||||
self.db = SqliteExtDatabase(":memory:")
|
||||
self.db = SqliteDatabase(":memory:")
|
||||
self.db.bind([Recordings])
|
||||
self.db.create_tables([Recordings])
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import datetime
|
||||
import unittest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.events.cleanup import EventCleanup
|
||||
@@ -15,7 +15,7 @@ class TestEventCleanupSubRetention(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# in-memory database keeps these tests isolated from the shared
|
||||
# on-disk test.db used by the http api tests
|
||||
self.db = SqliteExtDatabase(":memory:")
|
||||
self.db = SqliteDatabase(":memory:")
|
||||
models = [Event, Timeline]
|
||||
self.db.bind(models)
|
||||
self.db.create_tables(models)
|
||||
|
||||
@@ -9,8 +9,8 @@ import logging
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from peewee import SqliteDatabase
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
|
||||
from frigate.api.media_auth import (
|
||||
@@ -208,7 +208,7 @@ class TestExportResolution(unittest.TestCase):
|
||||
"""Export resolution requires a DB lookup."""
|
||||
|
||||
def setUp(self):
|
||||
migrate_db = SqliteExtDatabase("test.db")
|
||||
migrate_db = SqliteDatabase("test.db")
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
Router(migrate_db).run()
|
||||
migrate_db.close()
|
||||
|
||||
@@ -5,8 +5,8 @@ import os
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from peewee import SqliteDatabase
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
|
||||
from frigate.models import Notice, NoticeStats
|
||||
@@ -49,7 +49,7 @@ class TestNoticeKinds(unittest.TestCase):
|
||||
|
||||
class RegistryTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
migrate_db = SqliteExtDatabase("test.db")
|
||||
migrate_db = SqliteDatabase("test.db")
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
router = Router(migrate_db)
|
||||
router.run()
|
||||
|
||||
@@ -4,7 +4,7 @@ import datetime
|
||||
import unittest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.models import Previews, Recordings, ReviewSegment, UserReviewStatus
|
||||
@@ -15,7 +15,7 @@ class TestRecordingCleanupSubRetention(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# in-memory database keeps these tests isolated from the shared
|
||||
# on-disk test.db used by the http api tests
|
||||
self.db = SqliteExtDatabase(":memory:")
|
||||
self.db = SqliteDatabase(":memory:")
|
||||
models = [Previews, Recordings, ReviewSegment, UserReviewStatus]
|
||||
self.db.bind(models)
|
||||
self.db.create_tables(models)
|
||||
|
||||
@@ -8,7 +8,7 @@ import unittest
|
||||
from collections import defaultdict
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.models import Recordings
|
||||
@@ -719,7 +719,7 @@ class TestSegmentChainSeeding(unittest.IsolatedAsyncioTestCase):
|
||||
T0 = datetime.datetime(2026, 6, 10, 14, 30, 22, tzinfo=datetime.UTC).timestamp()
|
||||
|
||||
def setUp(self):
|
||||
self.db = SqliteExtDatabase(":memory:")
|
||||
self.db = SqliteDatabase(":memory:")
|
||||
self.db.bind([Recordings])
|
||||
self.db.create_tables([Recordings])
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import json
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
from frigate.api.media import _vod_response
|
||||
from frigate.const import MAX_SEGMENT_DURATION
|
||||
@@ -24,7 +24,7 @@ class CoverageDbTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# in-memory database keeps these tests isolated from the shared
|
||||
# on-disk test.db used by the http api tests
|
||||
self.db = SqliteExtDatabase(":memory:")
|
||||
self.db = SqliteDatabase(":memory:")
|
||||
models = [Recordings]
|
||||
self.db.bind(models)
|
||||
self.db.create_tables(models)
|
||||
|
||||
@@ -5,9 +5,8 @@ import tempfile
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from peewee import DoesNotExist
|
||||
from peewee import DoesNotExist, SqliteDatabase
|
||||
from peewee_migrate import Router
|
||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
|
||||
from frigate.config import FrigateConfig
|
||||
@@ -20,7 +19,7 @@ from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS
|
||||
class TestHttp(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# setup clean database for each test run
|
||||
migrate_db = SqliteExtDatabase("test.db")
|
||||
migrate_db = SqliteDatabase("test.db")
|
||||
del logging.getLogger("peewee_migrate").handlers[:]
|
||||
router = Router(migrate_db)
|
||||
router.run()
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ class FrigateWatchdog(threading.Thread):
|
||||
now = datetime.datetime.now().timestamp()
|
||||
|
||||
for name, detector in self.detectors.items():
|
||||
detection_start = detector.detection_start.value # type: ignore[attr-defined]
|
||||
detection_start = detector.detection_start.value
|
||||
# issue https://github.com/python/typeshed/issues/8799
|
||||
# from mypy 0.981 onwards
|
||||
if detection_start > 0.0 and now - detection_start > 10:
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E4", "E7", "E9", "F"]
|
||||
ignore = ["E501","E711","E712","UP031","UP032","UP042","G004"]
|
||||
extend-select = ["I", "UP", "G", "ASYNC210", "B904"]
|
||||
|
||||
Generated
+763
-935
File diff suppressed because it is too large
Load Diff
+51
-51
@@ -23,33 +23,33 @@
|
||||
"dependencies": {
|
||||
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
||||
"@hookform/resolvers": "^5.9.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.23",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.15",
|
||||
"@radix-ui/react-checkbox": "^1.3.11",
|
||||
"@radix-ui/react-collapsible": "^1.1.20",
|
||||
"@radix-ui/react-context-menu": "^2.3.7",
|
||||
"@radix-ui/react-dialog": "^1.1.23",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-hover-card": "^1.1.23",
|
||||
"@radix-ui/react-label": "^2.1.15",
|
||||
"@radix-ui/react-popover": "^1.1.23",
|
||||
"@radix-ui/react-progress": "^1.1.16",
|
||||
"@radix-ui/react-radio-group": "^1.4.7",
|
||||
"@radix-ui/react-scroll-area": "^1.2.18",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-separator": "^1.1.15",
|
||||
"@radix-ui/react-slider": "^1.4.7",
|
||||
"@radix-ui/react-slot": "1.2.4",
|
||||
"@radix-ui/react-switch": "^1.3.7",
|
||||
"@radix-ui/react-tabs": "^1.1.21",
|
||||
"@radix-ui/react-toggle": "^1.1.18",
|
||||
"@radix-ui/react-toggle-group": "^1.1.19",
|
||||
"@radix-ui/react-tooltip": "^1.2.16",
|
||||
"@rjsf/core": "^6.10.0",
|
||||
"@rjsf/shadcn": "^6.10.0",
|
||||
"@rjsf/utils": "^6.10.0",
|
||||
"@rjsf/validator-ajv8": "^6.10.0",
|
||||
"apexcharts": "^7.3.0",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.24",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.16",
|
||||
"@radix-ui/react-checkbox": "^1.3.12",
|
||||
"@radix-ui/react-collapsible": "^1.1.21",
|
||||
"@radix-ui/react-context-menu": "^2.3.8",
|
||||
"@radix-ui/react-dialog": "^1.2.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.25",
|
||||
"@radix-ui/react-hover-card": "^1.1.24",
|
||||
"@radix-ui/react-label": "^2.1.16",
|
||||
"@radix-ui/react-popover": "^1.2.0",
|
||||
"@radix-ui/react-progress": "^1.1.17",
|
||||
"@radix-ui/react-radio-group": "^1.4.8",
|
||||
"@radix-ui/react-scroll-area": "^1.3.0",
|
||||
"@radix-ui/react-select": "^2.3.8",
|
||||
"@radix-ui/react-separator": "^1.1.16",
|
||||
"@radix-ui/react-slider": "^1.5.0",
|
||||
"@radix-ui/react-slot": "1.4.0",
|
||||
"@radix-ui/react-switch": "^1.3.8",
|
||||
"@radix-ui/react-tabs": "^1.1.22",
|
||||
"@radix-ui/react-toggle": "^1.1.19",
|
||||
"@radix-ui/react-toggle-group": "^1.1.20",
|
||||
"@radix-ui/react-tooltip": "^1.3.0",
|
||||
"@rjsf/core": "^6.10.1",
|
||||
"@rjsf/shadcn": "^6.10.1",
|
||||
"@rjsf/utils": "^6.10.1",
|
||||
"@rjsf/validator-ajv8": "^6.10.1",
|
||||
"apexcharts": "^7.8.0",
|
||||
"axios": "^1.20.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -57,31 +57,31 @@
|
||||
"copy-to-clipboard": "^4.0.2",
|
||||
"date-fns": "^4.4.0",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"framer-motion": "^13.3.0",
|
||||
"framer-motion": "^14.0.0",
|
||||
"hls.js": "^1.7.3",
|
||||
"i18next": "^26.4.2",
|
||||
"i18next-http-backend": "^4.0.2",
|
||||
"idb-keyval": "^6.3.0",
|
||||
"js-yaml": "^5.4.2",
|
||||
"konva": "^10.5.0",
|
||||
"js-yaml": "^5.4.3",
|
||||
"konva": "^10.7.1",
|
||||
"lodash": "^4.18.1",
|
||||
"lucide-react": "^1.46.0",
|
||||
"lucide-react": "^1.52.0",
|
||||
"monaco-yaml": "^5.5.1",
|
||||
"next-themes": "^0.4.6",
|
||||
"nosleep.js": "^0.12.0",
|
||||
"react": "^19.3.0",
|
||||
"react-apexcharts": "^2.1.1",
|
||||
"react-day-picker": "^9.14.0",
|
||||
"react-day-picker": "^10.0.2",
|
||||
"react-device-detect": "^2.2.3",
|
||||
"react-dom": "^19.3.0",
|
||||
"react-dropzone": "^20.1.2",
|
||||
"react-grid-layout": "^2.2.4",
|
||||
"react-hook-form": "^7.88.0",
|
||||
"react-i18next": "^17.0.14",
|
||||
"react-grid-layout": "^2.3.0",
|
||||
"react-hook-form": "^7.89.0",
|
||||
"react-i18next": "^17.0.16",
|
||||
"react-icons": "^5.7.0",
|
||||
"react-konva": "^19.2.7",
|
||||
"react-konva": "^19.3.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router-dom": "^6.30.6",
|
||||
"react-router-dom": "^7.18.4",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-zoom-pan-pinch": "3.4.4",
|
||||
"remark-gfm": "^4.0.0",
|
||||
@@ -93,41 +93,41 @@
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"use-long-press": "^3.3.0",
|
||||
"vaul": "^1.1.2",
|
||||
"virtua": "^0.51.3",
|
||||
"virtua": "^0.53.3",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@playwright/test": "^1.63.0",
|
||||
"@playwright/test": "^1.64.0",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/lodash": "^4.17.25",
|
||||
"@types/node": "^26.5.1",
|
||||
"@types/node": "^26.6.4",
|
||||
"@types/react": "^19.3.0",
|
||||
"@types/react-dom": "^19.3.0",
|
||||
"@vitejs/plugin-react": "^6.1.1",
|
||||
"autoprefixer": "^10.6.0",
|
||||
"@vitejs/plugin-react": "^6.1.2",
|
||||
"autoprefixer": "^10.6.1",
|
||||
"esbuild": "^0.28.2",
|
||||
"eslint": "^10.10.0",
|
||||
"eslint": "^10.12.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"eslint-plugin-react-hooks": "^7.1.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.7",
|
||||
"globals": "^17.12.0",
|
||||
"globals": "^17.13.0",
|
||||
"i18next-cli": "^1.5.11",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"patch-package": "^8.0.1",
|
||||
"postcss": "^8.5.12",
|
||||
"prettier": "^3.9.6",
|
||||
"postcss": "^8.5.29",
|
||||
"prettier": "^3.9.9",
|
||||
"prettier-plugin-tailwindcss": "^0.8.1",
|
||||
"tailwindcss": "^3.4.9",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.70.0",
|
||||
"vite": "^8.3.0"
|
||||
"tailwindcss": "^3.4.19",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.71.1",
|
||||
"vite": "^8.3.3"
|
||||
},
|
||||
"overrides": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-popper": "1.2.8",
|
||||
"@radix-ui/react-slot": "1.2.4"
|
||||
"@radix-ui/react-slot": "1.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
diff --git a/node_modules/@radix-ui/react-slot/dist/index.js b/node_modules/@radix-ui/react-slot/dist/index.js
|
||||
index 3691205..3b62ea8 100644
|
||||
--- a/node_modules/@radix-ui/react-slot/dist/index.js
|
||||
+++ b/node_modules/@radix-ui/react-slot/dist/index.js
|
||||
@@ -85,11 +85,12 @@ function createSlotClone(ownerName) {
|
||||
if (isLazyComponent(children) && typeof use === "function") {
|
||||
children = use(children._payload);
|
||||
}
|
||||
+ const childrenRef = React.isValidElement(children) ? getElementRef(children) : null;
|
||||
+ const composedRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, childrenRef);
|
||||
if (React.isValidElement(children)) {
|
||||
- const childrenRef = getElementRef(children);
|
||||
const props2 = mergeProps(slotProps, children.props);
|
||||
if (children.type !== React.Fragment) {
|
||||
- props2.ref = forwardedRef ? (0, import_react_compose_refs.composeRefs)(forwardedRef, childrenRef) : childrenRef;
|
||||
+ props2.ref = forwardedRef ? composedRef : childrenRef;
|
||||
}
|
||||
return React.cloneElement(children, props2);
|
||||
}
|
||||
diff --git a/node_modules/@radix-ui/react-slot/dist/index.mjs b/node_modules/@radix-ui/react-slot/dist/index.mjs
|
||||
index d7ea374..a990150 100644
|
||||
--- a/node_modules/@radix-ui/react-slot/dist/index.mjs
|
||||
+++ b/node_modules/@radix-ui/react-slot/dist/index.mjs
|
||||
@@ -1,6 +1,6 @@
|
||||
// src/slot.tsx
|
||||
import * as React from "react";
|
||||
-import { composeRefs } from "@radix-ui/react-compose-refs";
|
||||
+import { composeRefs, useComposedRefs } from "@radix-ui/react-compose-refs";
|
||||
import { Fragment as Fragment2, jsx } from "react/jsx-runtime";
|
||||
var REACT_LAZY_TYPE = Symbol.for("react.lazy");
|
||||
var use = React[" use ".trim().toString()];
|
||||
@@ -45,11 +45,12 @@ function createSlotClone(ownerName) {
|
||||
if (isLazyComponent(children) && typeof use === "function") {
|
||||
children = use(children._payload);
|
||||
}
|
||||
+ const childrenRef = React.isValidElement(children) ? getElementRef(children) : null;
|
||||
+ const composedRef = useComposedRefs(forwardedRef, childrenRef);
|
||||
if (React.isValidElement(children)) {
|
||||
- const childrenRef = getElementRef(children);
|
||||
const props2 = mergeProps(slotProps, children.props);
|
||||
if (children.type !== React.Fragment) {
|
||||
- props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
|
||||
+ props2.ref = forwardedRef ? composedRef : childrenRef;
|
||||
}
|
||||
return React.cloneElement(children, props2);
|
||||
}
|
||||
+1
-1
@@ -44,7 +44,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<Providers>
|
||||
<BrowserRouter basename={window.baseUrl}>
|
||||
<BrowserRouter basename={window.baseUrl} useTransitions={false}>
|
||||
<Wrapper>
|
||||
{config?.safe_mode ? <SafeAppView /> : <DefaultAppView />}
|
||||
</Wrapper>
|
||||
|
||||
@@ -155,7 +155,7 @@ export function CombinedStorageGraph({
|
||||
formatter: function (val, opts) {
|
||||
const entry = opts ? series[opts.seriesIndex] : undefined;
|
||||
if (entry) {
|
||||
return `${getUnitSize(entry.usage)} (${val.toFixed(2)}%)`;
|
||||
return `${getUnitSize(entry.usage)} (${(val ?? 0).toFixed(2)}%)`;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user