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_one": "{{count}} selected",
|
||||||
"selected_other": "{{count}} selected",
|
"selected_other": "{{count}} selected",
|
||||||
|
"select_all": "All",
|
||||||
"camera": "Camera",
|
"camera": "Camera",
|
||||||
"detected": "detected",
|
"detected": "detected",
|
||||||
"normalActivity": "Normal",
|
"normalActivity": "Normal",
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
},
|
},
|
||||||
"train": {
|
"train": {
|
||||||
"title": "Recent Recognitions",
|
"title": "Recent Recognitions",
|
||||||
|
"titleShort": "Recent",
|
||||||
"aria": "Select recent recognitions",
|
"aria": "Select recent recognitions",
|
||||||
"empty": "There are no recent face recognition attempts"
|
"empty": "There are no recent face recognition attempts"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,11 +22,15 @@ type SearchActionGroupProps = {
|
|||||||
selectedObjects: string[];
|
selectedObjects: string[];
|
||||||
setSelectedObjects: (ids: string[]) => void;
|
setSelectedObjects: (ids: string[]) => void;
|
||||||
pullLatestData: () => void;
|
pullLatestData: () => void;
|
||||||
|
onSelectAllObjects: () => void;
|
||||||
|
totalItems: number;
|
||||||
};
|
};
|
||||||
export default function SearchActionGroup({
|
export default function SearchActionGroup({
|
||||||
selectedObjects,
|
selectedObjects,
|
||||||
setSelectedObjects,
|
setSelectedObjects,
|
||||||
pullLatestData,
|
pullLatestData,
|
||||||
|
onSelectAllObjects,
|
||||||
|
totalItems,
|
||||||
}: SearchActionGroupProps) {
|
}: SearchActionGroupProps) {
|
||||||
const { t } = useTranslation(["components/filter"]);
|
const { t } = useTranslation(["components/filter"]);
|
||||||
const isAdmin = useIsAdmin();
|
const isAdmin = useIsAdmin();
|
||||||
@ -124,6 +128,17 @@ export default function SearchActionGroup({
|
|||||||
>
|
>
|
||||||
{t("button.unselect", { ns: "common" })}
|
{t("button.unselect", { ns: "common" })}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<div className="flex items-center gap-1 md:gap-2">
|
<div className="flex items-center gap-1 md:gap-2">
|
||||||
|
|||||||
@ -52,7 +52,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop, isMobileOnly } from "react-device-detect";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
LuFolderCheck,
|
LuFolderCheck,
|
||||||
@ -370,10 +370,10 @@ export default function FaceLibrary() {
|
|||||||
/>
|
/>
|
||||||
{selectedFaces?.length > 0 ? (
|
{selectedFaces?.length > 0 ? (
|
||||||
<div className="flex items-center justify-center gap-2">
|
<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">
|
<div className="p-1">
|
||||||
{t("selected", {
|
{t("selected", {
|
||||||
ns: "views/event",
|
ns: "views/events",
|
||||||
count: selectedFaces.length,
|
count: selectedFaces.length,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -384,6 +384,24 @@ export default function FaceLibrary() {
|
|||||||
>
|
>
|
||||||
{t("button.unselect", { ns: "common" })}
|
{t("button.unselect", { ns: "common" })}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
className="flex gap-2"
|
className="flex gap-2"
|
||||||
@ -482,6 +500,18 @@ function LibrarySelector({
|
|||||||
[renameFace],
|
[renameFace],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const pageTitle = useMemo(() => {
|
||||||
|
if (pageToggle != "train") {
|
||||||
|
return pageToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMobileOnly) {
|
||||||
|
return t("train.titleShort");
|
||||||
|
}
|
||||||
|
|
||||||
|
return t("train.title");
|
||||||
|
}, [pageToggle, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog
|
<Dialog
|
||||||
@ -532,7 +562,7 @@ function LibrarySelector({
|
|||||||
<DropdownMenu modal={false}>
|
<DropdownMenu modal={false}>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button className="flex justify-between smart-capitalize">
|
<Button className="flex justify-between smart-capitalize">
|
||||||
{pageToggle == "train" ? t("train.title") : pageToggle}
|
{pageTitle}
|
||||||
<span className="ml-2 text-primary-variant">
|
<span className="ml-2 text-primary-variant">
|
||||||
({(pageToggle && faceData?.[pageToggle]?.length) || 0})
|
({(pageToggle && faceData?.[pageToggle]?.length) || 0})
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -421,10 +421,10 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
|||||||
isMobileOnly && "justify-between",
|
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">
|
<div className="p-1">
|
||||||
{t("selected", {
|
{t("selected", {
|
||||||
ns: "views/event",
|
ns: "views/events",
|
||||||
count: selectedImages.length,
|
count: selectedImages.length,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -435,6 +435,26 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) {
|
|||||||
>
|
>
|
||||||
{t("button.unselect", { ns: "common" })}
|
{t("button.unselect", { ns: "common" })}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
className="flex gap-2"
|
className="flex gap-2"
|
||||||
|
|||||||
@ -572,6 +572,8 @@ export default function SearchView({
|
|||||||
selectedObjects={selectedObjects}
|
selectedObjects={selectedObjects}
|
||||||
setSelectedObjects={setSelectedObjects}
|
setSelectedObjects={setSelectedObjects}
|
||||||
pullLatestData={refresh}
|
pullLatestData={refresh}
|
||||||
|
onSelectAllObjects={onSelectAllObjects}
|
||||||
|
totalItems={uniqueResults.length}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user