mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-11 04:40:42 -06:00
conditionally display actions for admin role only
This commit is contained in:
parent
9cdc10008d
commit
8d5349ca85
@ -19,6 +19,7 @@ import {
|
|||||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { useIsAdmin } from "@/hooks/use-is-admin";
|
||||||
|
|
||||||
type ReviewActionGroupProps = {
|
type ReviewActionGroupProps = {
|
||||||
selectedReviews: ReviewSegment[];
|
selectedReviews: ReviewSegment[];
|
||||||
@ -33,6 +34,7 @@ export default function ReviewActionGroup({
|
|||||||
pullLatestData,
|
pullLatestData,
|
||||||
}: ReviewActionGroupProps) {
|
}: ReviewActionGroupProps) {
|
||||||
const { t } = useTranslation(["components/dialog"]);
|
const { t } = useTranslation(["components/dialog"]);
|
||||||
|
const isAdmin = useIsAdmin();
|
||||||
const onClearSelected = useCallback(() => {
|
const onClearSelected = useCallback(() => {
|
||||||
setSelectedReviews([]);
|
setSelectedReviews([]);
|
||||||
}, [setSelectedReviews]);
|
}, [setSelectedReviews]);
|
||||||
@ -185,21 +187,23 @@ export default function ReviewActionGroup({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{isAdmin && (
|
||||||
className="flex items-center gap-2 p-2"
|
<Button
|
||||||
aria-label={t("button.delete", { ns: "common" })}
|
className="flex items-center gap-2 p-2"
|
||||||
size="sm"
|
aria-label={t("button.delete", { ns: "common" })}
|
||||||
onClick={handleDelete}
|
size="sm"
|
||||||
>
|
onClick={handleDelete}
|
||||||
<HiTrash className="text-secondary-foreground" />
|
>
|
||||||
{isDesktop && (
|
<HiTrash className="text-secondary-foreground" />
|
||||||
<div className="text-primary">
|
{isDesktop && (
|
||||||
{bypassDialog
|
<div className="text-primary">
|
||||||
? t("recording.button.deleteNow")
|
{bypassDialog
|
||||||
: t("button.delete", { ns: "common" })}
|
? t("recording.button.deleteNow")
|
||||||
</div>
|
: t("button.delete", { ns: "common" })}
|
||||||
)}
|
</div>
|
||||||
</Button>
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import { useIsAdmin } from "@/hooks/use-is-admin";
|
||||||
|
|
||||||
type SearchActionGroupProps = {
|
type SearchActionGroupProps = {
|
||||||
selectedObjects: string[];
|
selectedObjects: string[];
|
||||||
@ -28,6 +29,7 @@ export default function SearchActionGroup({
|
|||||||
pullLatestData,
|
pullLatestData,
|
||||||
}: SearchActionGroupProps) {
|
}: SearchActionGroupProps) {
|
||||||
const { t } = useTranslation(["components/filter"]);
|
const { t } = useTranslation(["components/filter"]);
|
||||||
|
const isAdmin = useIsAdmin();
|
||||||
const onClearSelected = useCallback(() => {
|
const onClearSelected = useCallback(() => {
|
||||||
setSelectedObjects([]);
|
setSelectedObjects([]);
|
||||||
}, [setSelectedObjects]);
|
}, [setSelectedObjects]);
|
||||||
@ -123,23 +125,25 @@ export default function SearchActionGroup({
|
|||||||
{t("button.unselect", { ns: "common" })}
|
{t("button.unselect", { ns: "common" })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1 md:gap-2">
|
{isAdmin && (
|
||||||
<Button
|
<div className="flex items-center gap-1 md:gap-2">
|
||||||
className="flex items-center gap-2 p-2"
|
<Button
|
||||||
aria-label={t("button.delete", { ns: "common" })}
|
className="flex items-center gap-2 p-2"
|
||||||
size="sm"
|
aria-label={t("button.delete", { ns: "common" })}
|
||||||
onClick={handleDelete}
|
size="sm"
|
||||||
>
|
onClick={handleDelete}
|
||||||
<HiTrash className="text-secondary-foreground" />
|
>
|
||||||
{isDesktop && (
|
<HiTrash className="text-secondary-foreground" />
|
||||||
<div className="text-primary">
|
{isDesktop && (
|
||||||
{bypassDialog
|
<div className="text-primary">
|
||||||
? t("button.deleteNow", { ns: "common" })
|
{bypassDialog
|
||||||
: t("button.delete", { ns: "common" })}
|
? t("button.deleteNow", { ns: "common" })
|
||||||
</div>
|
: t("button.delete", { ns: "common" })}
|
||||||
)}
|
</div>
|
||||||
</Button>
|
)}
|
||||||
</div>
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import BlurredIconButton from "../button/BlurredIconButton";
|
import BlurredIconButton from "../button/BlurredIconButton";
|
||||||
|
import { useIsAdmin } from "@/hooks/use-is-admin";
|
||||||
|
|
||||||
type SearchResultActionsProps = {
|
type SearchResultActionsProps = {
|
||||||
searchResult: SearchResult;
|
searchResult: SearchResult;
|
||||||
@ -52,6 +53,7 @@ export default function SearchResultActions({
|
|||||||
children,
|
children,
|
||||||
}: SearchResultActionsProps) {
|
}: SearchResultActionsProps) {
|
||||||
const { t } = useTranslation(["views/explore"]);
|
const { t } = useTranslation(["views/explore"]);
|
||||||
|
const isAdmin = useIsAdmin();
|
||||||
|
|
||||||
const { data: config } = useSWR<FrigateConfig>("config");
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
|
|
||||||
@ -137,7 +139,8 @@ export default function SearchResultActions({
|
|||||||
<span>{t("itemMenu.findSimilar.label")}</span>
|
<span>{t("itemMenu.findSimilar.label")}</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{config?.semantic_search?.enabled &&
|
{isAdmin &&
|
||||||
|
config?.semantic_search?.enabled &&
|
||||||
searchResult.data.type == "object" && (
|
searchResult.data.type == "object" && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
aria-label={t("itemMenu.addTrigger.aria")}
|
aria-label={t("itemMenu.addTrigger.aria")}
|
||||||
@ -146,12 +149,14 @@ export default function SearchResultActions({
|
|||||||
<span>{t("itemMenu.addTrigger.label")}</span>
|
<span>{t("itemMenu.addTrigger.label")}</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
<MenuItem
|
{isAdmin && (
|
||||||
aria-label={t("itemMenu.deleteTrackedObject.label")}
|
<MenuItem
|
||||||
onClick={() => setDeleteDialogOpen(true)}
|
aria-label={t("itemMenu.deleteTrackedObject.label")}
|
||||||
>
|
onClick={() => setDeleteDialogOpen(true)}
|
||||||
<span>{t("button.delete", { ns: "common" })}</span>
|
>
|
||||||
</MenuItem>
|
<span>{t("button.delete", { ns: "common" })}</span>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
import { HiDotsHorizontal } from "react-icons/hi";
|
import { HiDotsHorizontal } from "react-icons/hi";
|
||||||
import { SearchResult } from "@/types/search";
|
import { SearchResult } from "@/types/search";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
|
import { useIsAdmin } from "@/hooks/use-is-admin";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
search: SearchResult | Event;
|
search: SearchResult | Event;
|
||||||
@ -35,6 +36,7 @@ export default function DetailActionsMenu({
|
|||||||
const { t } = useTranslation(["views/explore", "views/faceLibrary"]);
|
const { t } = useTranslation(["views/explore", "views/faceLibrary"]);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const isAdmin = useIsAdmin();
|
||||||
|
|
||||||
const clipTimeRange = useMemo(() => {
|
const clipTimeRange = useMemo(() => {
|
||||||
const startTime = (search.start_time ?? 0) - REVIEW_PADDING;
|
const startTime = (search.start_time ?? 0) - REVIEW_PADDING;
|
||||||
@ -130,22 +132,24 @@ export default function DetailActionsMenu({
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{config?.semantic_search.enabled && search.data.type == "object" && (
|
{isAdmin &&
|
||||||
<DropdownMenuItem
|
config?.semantic_search.enabled &&
|
||||||
onClick={() => {
|
search.data.type == "object" && (
|
||||||
setIsOpen(false);
|
<DropdownMenuItem
|
||||||
setTimeout(() => {
|
onClick={() => {
|
||||||
navigate(
|
setIsOpen(false);
|
||||||
`/settings?page=triggers&camera=${search.camera}&event_id=${search.id}`,
|
setTimeout(() => {
|
||||||
);
|
navigate(
|
||||||
}, 0);
|
`/settings?page=triggers&camera=${search.camera}&event_id=${search.id}`,
|
||||||
}}
|
);
|
||||||
>
|
}, 0);
|
||||||
<div className="flex cursor-pointer items-center gap-2">
|
}}
|
||||||
<span>{t("itemMenu.addTrigger.label")}</span>
|
>
|
||||||
</div>
|
<div className="flex cursor-pointer items-center gap-2">
|
||||||
</DropdownMenuItem>
|
<span>{t("itemMenu.addTrigger.label")}</span>
|
||||||
)}
|
</div>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenuPortal>
|
</DropdownMenuPortal>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user