mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-14 00:56:42 +03:00
add select all link to face library, classification, and explore
This commit is contained in:
parent
44c92e84cd
commit
97ba7a6b78
@ -52,6 +52,7 @@
|
||||
},
|
||||
"selected_one": "{{count}} selected",
|
||||
"selected_other": "{{count}} selected",
|
||||
"select_all": "All",
|
||||
"camera": "Camera",
|
||||
"detected": "detected",
|
||||
"normalActivity": "Normal",
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
},
|
||||
"train": {
|
||||
"title": "Recent Recognitions",
|
||||
"titleShort": "Recent",
|
||||
"aria": "Select recent recognitions",
|
||||
"empty": "There are no recent face recognition attempts"
|
||||
},
|
||||
|
||||
@ -22,11 +22,15 @@ type SearchActionGroupProps = {
|
||||
selectedObjects: string[];
|
||||
setSelectedObjects: (ids: string[]) => void;
|
||||
pullLatestData: () => void;
|
||||
onSelectAllObjects: () => void;
|
||||
totalItems: number;
|
||||
};
|
||||
export default function SearchActionGroup({
|
||||
selectedObjects,
|
||||
setSelectedObjects,
|
||||
pullLatestData,
|
||||
onSelectAllObjects,
|
||||
totalItems,
|
||||
}: SearchActionGroupProps) {
|
||||
const { t } = useTranslation(["components/filter"]);
|
||||
const isAdmin = useIsAdmin();
|
||||
@ -124,6 +128,17 @@ export default function SearchActionGroup({
|
||||
>
|
||||
{t("button.unselect", { ns: "common" })}
|
||||
</div>
|
||||
{selectedObjects.length < totalItems && (
|
||||
<>
|
||||
<div className="p-1">{"|"}</div>
|
||||
<div
|
||||
className="cursor-pointer p-2 text-primary hover:rounded-lg hover:bg-secondary"
|
||||
onClick={onSelectAllObjects}
|
||||
>
|
||||
{t("select_all", { ns: "views/events" })}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<div className="flex items-center gap-1 md:gap-2">
|
||||
|
||||
@ -52,7 +52,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { isDesktop, isMobileOnly } from "react-device-detect";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import {
|
||||
LuFolderCheck,
|
||||
@ -370,10 +370,10 @@ export default function FaceLibrary() {
|
||||
/>
|
||||
{selectedFaces?.length > 0 ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<div className="mx-1 flex w-48 items-center justify-center text-sm text-muted-foreground">
|
||||
<div className="mx-1 flex w-auto items-center justify-center text-sm text-muted-foreground">
|
||||
<div className="p-1">
|
||||
{t("selected", {
|
||||
ns: "views/event",
|
||||
ns: "views/events",
|
||||
count: selectedFaces.length,
|
||||
})}
|
||||
</div>
|
||||
@ -384,6 +384,24 @@ export default function FaceLibrary() {
|
||||
>
|
||||
{t("button.unselect", { ns: "common" })}
|
||||
</div>
|
||||
{selectedFaces.length <
|
||||
(pageToggle === "train"
|
||||
? trainImages.length
|
||||
: faceImages.length) && (
|
||||
<>
|
||||
<div className="p-1">{"|"}</div>
|
||||
<div
|
||||
className="cursor-pointer p-2 text-primary hover:rounded-lg hover:bg-secondary"
|
||||
onClick={() =>
|
||||
setSelectedFaces([
|
||||
...(pageToggle === "train" ? trainImages : faceImages),
|
||||
])
|
||||
}
|
||||
>
|
||||
{t("select_all", { ns: "views/events" })}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
className="flex gap-2"
|
||||
@ -482,6 +500,18 @@ function LibrarySelector({
|
||||
[renameFace],
|
||||
);
|
||||
|
||||
const pageTitle = useMemo(() => {
|
||||
if (pageToggle != "train") {
|
||||
return pageToggle;
|
||||
}
|
||||
|
||||
if (isMobileOnly) {
|
||||
return t("train.titleShort");
|
||||
}
|
||||
|
||||
return t("train.title");
|
||||
}, [pageToggle, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
@ -532,7 +562,7 @@ function LibrarySelector({
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button className="flex justify-between smart-capitalize">
|
||||
{pageToggle == "train" ? t("train.title") : pageToggle}
|
||||
{pageTitle}
|
||||
<span className="ml-2 text-primary-variant">
|
||||
({(pageToggle && faceData?.[pageToggle]?.length) || 0})
|
||||
</span>
|
||||
|
||||
@ -421,10 +421,10 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
||||
isMobileOnly && "justify-between",
|
||||
)}
|
||||
>
|
||||
<div className="flex w-48 items-center justify-center text-sm text-muted-foreground">
|
||||
<div className="flex w-auto items-center justify-center text-sm text-muted-foreground md:w-auto">
|
||||
<div className="p-1">
|
||||
{t("selected", {
|
||||
ns: "views/event",
|
||||
ns: "views/events",
|
||||
count: selectedImages.length,
|
||||
})}
|
||||
</div>
|
||||
@ -435,6 +435,26 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
||||
>
|
||||
{t("button.unselect", { ns: "common" })}
|
||||
</div>
|
||||
{selectedImages.length <
|
||||
(pageToggle === "train"
|
||||
? trainImages?.length || 0
|
||||
: dataset?.[pageToggle]?.length || 0) && (
|
||||
<>
|
||||
<div className="p-1">{"|"}</div>
|
||||
<div
|
||||
className="cursor-pointer p-2 text-primary hover:rounded-lg hover:bg-secondary"
|
||||
onClick={() =>
|
||||
setSelectedImages([
|
||||
...(pageToggle === "train"
|
||||
? trainImages || []
|
||||
: dataset?.[pageToggle] || []),
|
||||
])
|
||||
}
|
||||
>
|
||||
{t("select_all", { ns: "views/events" })}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
className="flex gap-2"
|
||||
|
||||
@ -572,6 +572,8 @@ export default function SearchView({
|
||||
selectedObjects={selectedObjects}
|
||||
setSelectedObjects={setSelectedObjects}
|
||||
pullLatestData={refresh}
|
||||
onSelectAllObjects={onSelectAllObjects}
|
||||
totalItems={uniqueResults.length}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user