mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +03:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d8234fa27 | ||
|
|
ad76c28a66 | ||
|
|
131d07e649 | ||
|
|
776bb79f0b | ||
|
|
aedfaa3641 | ||
|
|
83ac42cbdc | ||
|
|
a5ce8d0d77 | ||
|
|
0ee2e404da |
@@ -33,9 +33,9 @@ runs:
|
|||||||
with:
|
with:
|
||||||
string: ${{ github.repository }}
|
string: ${{ github.repository }}
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
|
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
|
||||||
with:
|
with:
|
||||||
|
|||||||
+22
-15
@@ -19,7 +19,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
amd64_build:
|
amd64_build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: AMD64 Build
|
name: AMD64 Build
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
tags: ${{ steps.setup.outputs.image-name }}-amd64
|
tags: ${{ steps.setup.outputs.image-name }}-amd64
|
||||||
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
|
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
|
||||||
arm64_build:
|
arm64_build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ARM Build
|
name: ARM Build
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -66,8 +66,9 @@ jobs:
|
|||||||
${{ steps.setup.outputs.image-name }}-standard-arm64
|
${{ steps.setup.outputs.image-name }}-standard-arm64
|
||||||
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
|
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
|
||||||
- name: Build and push RPi build
|
- name: Build and push RPi build
|
||||||
uses: docker/bake-action@v4
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: rpi
|
targets: rpi
|
||||||
files: docker/rpi/rpi.hcl
|
files: docker/rpi/rpi.hcl
|
||||||
@@ -76,7 +77,7 @@ jobs:
|
|||||||
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
|
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
|
||||||
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64,mode=max
|
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64,mode=max
|
||||||
jetson_jp4_build:
|
jetson_jp4_build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Jetson Jetpack 4
|
name: Jetson Jetpack 4
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -94,8 +95,9 @@ jobs:
|
|||||||
BASE_IMAGE: timongentzsch/l4t-ubuntu20-opencv:latest
|
BASE_IMAGE: timongentzsch/l4t-ubuntu20-opencv:latest
|
||||||
SLIM_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
|
SLIM_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
|
||||||
TRT_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
|
TRT_BASE: timongentzsch/l4t-ubuntu20-opencv:latest
|
||||||
uses: docker/bake-action@v4
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: tensorrt
|
targets: tensorrt
|
||||||
files: docker/tensorrt/trt.hcl
|
files: docker/tensorrt/trt.hcl
|
||||||
@@ -104,7 +106,7 @@ jobs:
|
|||||||
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4
|
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4
|
||||||
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4,mode=max
|
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp4,mode=max
|
||||||
jetson_jp5_build:
|
jetson_jp5_build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Jetson Jetpack 5
|
name: Jetson Jetpack 5
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -122,8 +124,9 @@ jobs:
|
|||||||
BASE_IMAGE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
BASE_IMAGE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
||||||
SLIM_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
SLIM_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
||||||
TRT_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
TRT_BASE: nvcr.io/nvidia/l4t-tensorrt:r8.5.2-runtime
|
||||||
uses: docker/bake-action@v4
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: tensorrt
|
targets: tensorrt
|
||||||
files: docker/tensorrt/trt.hcl
|
files: docker/tensorrt/trt.hcl
|
||||||
@@ -132,7 +135,7 @@ jobs:
|
|||||||
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5
|
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5
|
||||||
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5,mode=max
|
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp5,mode=max
|
||||||
amd64_extra_builds:
|
amd64_extra_builds:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: AMD64 Extra Build
|
name: AMD64 Extra Build
|
||||||
needs:
|
needs:
|
||||||
- amd64_build
|
- amd64_build
|
||||||
@@ -149,8 +152,9 @@ jobs:
|
|||||||
- name: Build and push TensorRT (x86 GPU)
|
- name: Build and push TensorRT (x86 GPU)
|
||||||
env:
|
env:
|
||||||
COMPUTE_LEVEL: "50 60 70 80 90"
|
COMPUTE_LEVEL: "50 60 70 80 90"
|
||||||
uses: docker/bake-action@v4
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: tensorrt
|
targets: tensorrt
|
||||||
files: docker/tensorrt/trt.hcl
|
files: docker/tensorrt/trt.hcl
|
||||||
@@ -159,7 +163,7 @@ jobs:
|
|||||||
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
|
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
|
||||||
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64,mode=max
|
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64,mode=max
|
||||||
arm64_extra_builds:
|
arm64_extra_builds:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ARM Extra Build
|
name: ARM Extra Build
|
||||||
needs:
|
needs:
|
||||||
- arm64_build
|
- arm64_build
|
||||||
@@ -174,8 +178,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push Rockchip build
|
- name: Build and push Rockchip build
|
||||||
uses: docker/bake-action@v3
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: rk
|
targets: rk
|
||||||
files: docker/rockchip/rk.hcl
|
files: docker/rockchip/rk.hcl
|
||||||
@@ -183,7 +188,7 @@ jobs:
|
|||||||
rk.tags=${{ steps.setup.outputs.image-name }}-rk
|
rk.tags=${{ steps.setup.outputs.image-name }}-rk
|
||||||
*.cache-from=type=gha
|
*.cache-from=type=gha
|
||||||
combined_extra_builds:
|
combined_extra_builds:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Combined Extra Builds
|
name: Combined Extra Builds
|
||||||
needs:
|
needs:
|
||||||
- amd64_build
|
- amd64_build
|
||||||
@@ -199,8 +204,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push Hailo-8l build
|
- name: Build and push Hailo-8l build
|
||||||
uses: docker/bake-action@v4
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: h8l
|
targets: h8l
|
||||||
files: docker/hailo8l/h8l.hcl
|
files: docker/hailo8l/h8l.hcl
|
||||||
@@ -212,8 +218,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
AMDGPU: gfx
|
AMDGPU: gfx
|
||||||
HSA_OVERRIDE: 0
|
HSA_OVERRIDE: 0
|
||||||
uses: docker/bake-action@v3
|
uses: docker/bake-action@v6
|
||||||
with:
|
with:
|
||||||
|
source: .
|
||||||
push: true
|
push: true
|
||||||
targets: rocm
|
targets: rocm
|
||||||
files: docker/rocm/rocm.hcl
|
files: docker/rocm/rocm.hcl
|
||||||
@@ -223,7 +230,7 @@ jobs:
|
|||||||
# The majority of users running arm64 are rpi users, so the rpi
|
# The majority of users running arm64 are rpi users, so the rpi
|
||||||
# build should be the primary arm64 image
|
# build should be the primary arm64 image
|
||||||
assemble_default_build:
|
assemble_default_build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Assemble and push default build
|
name: Assemble and push default build
|
||||||
needs:
|
needs:
|
||||||
- amd64_build
|
- amd64_build
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ ENV TRANSFORMERS_NO_ADVISORY_WARNINGS=1
|
|||||||
ENV OPENCV_FFMPEG_LOGLEVEL=8
|
ENV OPENCV_FFMPEG_LOGLEVEL=8
|
||||||
|
|
||||||
ENV PATH="/usr/local/go2rtc/bin:/usr/local/tempio/bin:/usr/local/nginx/sbin:${PATH}"
|
ENV PATH="/usr/local/go2rtc/bin:/usr/local/tempio/bin:/usr/local/nginx/sbin:${PATH}"
|
||||||
ENV LIBAVFORMAT_VERSION_MAJOR=60
|
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN --mount=type=bind,source=docker/main/install_deps.sh,target=/deps/install_deps.sh \
|
RUN --mount=type=bind,source=docker/main/install_deps.sh,target=/deps/install_deps.sh \
|
||||||
|
|||||||
@@ -42,8 +42,14 @@ function migrate_db_path() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_libva_version() {
|
||||||
|
local ffmpeg_path=$(python3 /usr/local/ffmpeg/get_ffmpeg_path.py)
|
||||||
|
export LIBAVFORMAT_VERSION_MAJOR=$($ffmpeg_path -version | grep -Po "libavformat\W+\K\d+")
|
||||||
|
}
|
||||||
|
|
||||||
echo "[INFO] Preparing Frigate..."
|
echo "[INFO] Preparing Frigate..."
|
||||||
migrate_db_path
|
migrate_db_path
|
||||||
|
set_libva_version
|
||||||
echo "[INFO] Starting Frigate..."
|
echo "[INFO] Starting Frigate..."
|
||||||
|
|
||||||
cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate"
|
cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate"
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ function get_ip_and_port_from_supervisor() {
|
|||||||
export FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL="${ip_address}:${webrtc_port}"
|
export FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL="${ip_address}:${webrtc_port}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_libva_version() {
|
||||||
|
local ffmpeg_path=$(python3 /usr/local/ffmpeg/get_ffmpeg_path.py)
|
||||||
|
export LIBAVFORMAT_VERSION_MAJOR=$($ffmpeg_path -version | grep -Po "libavformat\W+\K\d+")
|
||||||
|
}
|
||||||
|
|
||||||
if [[ -f "/dev/shm/go2rtc.yaml" ]]; then
|
if [[ -f "/dev/shm/go2rtc.yaml" ]]; then
|
||||||
echo "[INFO] Removing stale config from last run..."
|
echo "[INFO] Removing stale config from last run..."
|
||||||
rm /dev/shm/go2rtc.yaml
|
rm /dev/shm/go2rtc.yaml
|
||||||
@@ -61,6 +66,8 @@ else
|
|||||||
echo "[WARNING] Unable to remove existing go2rtc config. Changes made to your frigate config file may not be recognized. Please remove the /dev/shm/go2rtc.yaml from your docker host manually."
|
echo "[WARNING] Unable to remove existing go2rtc config. Changes made to your frigate config file may not be recognized. Please remove the /dev/shm/go2rtc.yaml from your docker host manually."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set_libva_version
|
||||||
|
|
||||||
readonly config_path="/config"
|
readonly config_path="/config"
|
||||||
|
|
||||||
if [[ -x "${config_path}/go2rtc" ]]; then
|
if [[ -x "${config_path}/go2rtc" ]]; then
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
sys.path.insert(0, "/opt/frigate")
|
||||||
|
from frigate.const import (
|
||||||
|
DEFAULT_FFMPEG_VERSION,
|
||||||
|
INCLUDED_FFMPEG_VERSIONS,
|
||||||
|
)
|
||||||
|
|
||||||
|
sys.path.remove("/opt/frigate")
|
||||||
|
|
||||||
|
yaml = YAML()
|
||||||
|
|
||||||
|
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
|
||||||
|
|
||||||
|
# Check if we can use .yaml instead of .yml
|
||||||
|
config_file_yaml = config_file.replace(".yml", ".yaml")
|
||||||
|
if os.path.isfile(config_file_yaml):
|
||||||
|
config_file = config_file_yaml
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(config_file) as f:
|
||||||
|
raw_config = f.read()
|
||||||
|
|
||||||
|
if config_file.endswith((".yaml", ".yml")):
|
||||||
|
config: dict[str, any] = yaml.load(raw_config)
|
||||||
|
elif config_file.endswith(".json"):
|
||||||
|
config: dict[str, any] = json.loads(raw_config)
|
||||||
|
except FileNotFoundError:
|
||||||
|
config: dict[str, any] = {}
|
||||||
|
|
||||||
|
path = config.get("ffmpeg", {}).get("path", "default")
|
||||||
|
if path == "default":
|
||||||
|
if shutil.which("ffmpeg") is None:
|
||||||
|
print(f"/usr/lib/ffmpeg/{DEFAULT_FFMPEG_VERSION}/bin/ffmpeg")
|
||||||
|
else:
|
||||||
|
print("ffmpeg")
|
||||||
|
elif path in INCLUDED_FFMPEG_VERSIONS:
|
||||||
|
print(f"/usr/lib/ffmpeg/{path}/bin/ffmpeg")
|
||||||
|
else:
|
||||||
|
print(f"{path}/bin/ffmpeg")
|
||||||
@@ -12,7 +12,5 @@ RUN rm -rf /usr/lib/btbn-ffmpeg/
|
|||||||
RUN --mount=type=bind,source=docker/rpi/install_deps.sh,target=/deps/install_deps.sh \
|
RUN --mount=type=bind,source=docker/rpi/install_deps.sh,target=/deps/install_deps.sh \
|
||||||
/deps/install_deps.sh
|
/deps/install_deps.sh
|
||||||
|
|
||||||
ENV LIBAVFORMAT_VERSION_MAJOR=58
|
|
||||||
|
|
||||||
WORKDIR /opt/frigate/
|
WORKDIR /opt/frigate/
|
||||||
COPY --from=rootfs / /
|
COPY --from=rootfs / /
|
||||||
|
|||||||
@@ -121,22 +121,29 @@ class RecordingCleanup(threading.Thread):
|
|||||||
review_start = 0
|
review_start = 0
|
||||||
deleted_recordings = set()
|
deleted_recordings = set()
|
||||||
kept_recordings: list[tuple[float, float]] = []
|
kept_recordings: list[tuple[float, float]] = []
|
||||||
|
recording: Recordings
|
||||||
for recording in recordings:
|
for recording in recordings:
|
||||||
keep = False
|
keep = False
|
||||||
mode = None
|
mode = None
|
||||||
# Now look for a reason to keep this recording segment
|
# Now look for a reason to keep this recording segment
|
||||||
for idx in range(review_start, len(reviews)):
|
for idx in range(review_start, len(reviews)):
|
||||||
review: ReviewSegment = reviews[idx]
|
review: ReviewSegment = reviews[idx]
|
||||||
|
severity = review.severity
|
||||||
|
pre_capture = config.record.get_review_pre_capture(severity)
|
||||||
|
post_capture = config.record.get_review_post_capture(severity)
|
||||||
|
|
||||||
# if the review starts in the future, stop checking reviews
|
# if the review starts in the future, stop checking reviews
|
||||||
# and let this recording segment expire
|
# and let this recording segment expire
|
||||||
if review.start_time > recording.end_time:
|
if review.start_time - pre_capture > recording.end_time:
|
||||||
keep = False
|
keep = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# if the review is in progress or ends after the recording starts, keep it
|
# if the review is in progress or ends after the recording starts, keep it
|
||||||
# and stop looking at reviews
|
# and stop looking at reviews
|
||||||
if review.end_time is None or review.end_time >= recording.start_time:
|
if (
|
||||||
|
review.end_time is None
|
||||||
|
or review.end_time + post_capture >= recording.start_time
|
||||||
|
):
|
||||||
keep = True
|
keep = True
|
||||||
mode = (
|
mode = (
|
||||||
config.record.alerts.retain.mode
|
config.record.alerts.retain.mode
|
||||||
@@ -149,7 +156,7 @@ class RecordingCleanup(threading.Thread):
|
|||||||
# this review and check the next review for an overlap.
|
# this review and check the next review for an overlap.
|
||||||
# since the review and recordings are sorted, we can skip review
|
# since the review and recordings are sorted, we can skip review
|
||||||
# that end before the previous recording segment started on future segments
|
# that end before the previous recording segment started on future segments
|
||||||
if review.end_time < recording.start_time:
|
if review.end_time + post_capture < recording.start_time:
|
||||||
review_start = idx
|
review_start = idx
|
||||||
|
|
||||||
# Delete recordings outside of the retention window or based on the retention mode
|
# Delete recordings outside of the retention window or based on the retention mode
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ type SearchDetailDialogProps = {
|
|||||||
setSearch: (search: SearchResult | undefined) => void;
|
setSearch: (search: SearchResult | undefined) => void;
|
||||||
setSearchPage: (page: SearchTab) => void;
|
setSearchPage: (page: SearchTab) => void;
|
||||||
setSimilarity?: () => void;
|
setSimilarity?: () => void;
|
||||||
|
setInputFocused: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
};
|
};
|
||||||
export default function SearchDetailDialog({
|
export default function SearchDetailDialog({
|
||||||
search,
|
search,
|
||||||
@@ -92,6 +93,7 @@ export default function SearchDetailDialog({
|
|||||||
setSearch,
|
setSearch,
|
||||||
setSearchPage,
|
setSearchPage,
|
||||||
setSimilarity,
|
setSimilarity,
|
||||||
|
setInputFocused,
|
||||||
}: SearchDetailDialogProps) {
|
}: SearchDetailDialogProps) {
|
||||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
@@ -232,6 +234,7 @@ export default function SearchDetailDialog({
|
|||||||
config={config}
|
config={config}
|
||||||
setSearch={setSearch}
|
setSearch={setSearch}
|
||||||
setSimilarity={setSimilarity}
|
setSimilarity={setSimilarity}
|
||||||
|
setInputFocused={setInputFocused}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{page == "snapshot" && (
|
{page == "snapshot" && (
|
||||||
@@ -266,12 +269,14 @@ type ObjectDetailsTabProps = {
|
|||||||
config?: FrigateConfig;
|
config?: FrigateConfig;
|
||||||
setSearch: (search: SearchResult | undefined) => void;
|
setSearch: (search: SearchResult | undefined) => void;
|
||||||
setSimilarity?: () => void;
|
setSimilarity?: () => void;
|
||||||
|
setInputFocused: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
};
|
};
|
||||||
function ObjectDetailsTab({
|
function ObjectDetailsTab({
|
||||||
search,
|
search,
|
||||||
config,
|
config,
|
||||||
setSearch,
|
setSearch,
|
||||||
setSimilarity,
|
setSimilarity,
|
||||||
|
setInputFocused,
|
||||||
}: ObjectDetailsTabProps) {
|
}: ObjectDetailsTabProps) {
|
||||||
const apiHost = useApiHost();
|
const apiHost = useApiHost();
|
||||||
|
|
||||||
@@ -283,6 +288,14 @@ function ObjectDetailsTab({
|
|||||||
|
|
||||||
const [desc, setDesc] = useState(search?.data.description);
|
const [desc, setDesc] = useState(search?.data.description);
|
||||||
|
|
||||||
|
const handleDescriptionFocus = useCallback(() => {
|
||||||
|
setInputFocused(true);
|
||||||
|
}, [setInputFocused]);
|
||||||
|
|
||||||
|
const handleDescriptionBlur = useCallback(() => {
|
||||||
|
setInputFocused(false);
|
||||||
|
}, [setInputFocused]);
|
||||||
|
|
||||||
// we have to make sure the current selected search item stays in sync
|
// we have to make sure the current selected search item stays in sync
|
||||||
useEffect(() => setDesc(search?.data.description ?? ""), [search]);
|
useEffect(() => setDesc(search?.data.description ?? ""), [search]);
|
||||||
|
|
||||||
@@ -499,6 +512,8 @@ function ObjectDetailsTab({
|
|||||||
placeholder="Description of the tracked object"
|
placeholder="Description of the tracked object"
|
||||||
value={desc}
|
value={desc}
|
||||||
onChange={(e) => setDesc(e.target.value)}
|
onChange={(e) => setDesc(e.target.value)}
|
||||||
|
onFocus={handleDescriptionFocus}
|
||||||
|
onBlur={handleDescriptionBlur}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ export default function SearchView({
|
|||||||
setSimilarity={
|
setSimilarity={
|
||||||
searchDetail && (() => setSimilaritySearch(searchDetail))
|
searchDetail && (() => setSimilaritySearch(searchDetail))
|
||||||
}
|
}
|
||||||
|
setInputFocused={setInputFocused}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user