Miscellaneous Fixes (#21208)

* conditionally display actions for admin role only

* only allow admins to save annotation offset

* Fix classification reset filter

* fix explore context menu from blocking pointer events on the body element after dialog close

applying modal=false to the menu (not to the dialog) to fix this in the same way as elsewhere in the codebase

* add select all link to face library, classification, and explore

* Disable iOS image dragging for classification card

* add proxmox ballooning comment

* lpr docs tweaks

* yaml list

* clarify tls_insecure

* Improve security summary format and usefulness

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
Josh Hawkins
2025-12-11 07:23:34 -07:00
committed by GitHub
co-authored by Nicolas Mowen
parent 9cdc10008d
commit fa6dda6735
18 changed files with 272 additions and 182 deletions
@@ -10,6 +10,7 @@ import { Trans, useTranslation } from "react-i18next";
import { LuInfo } from "react-icons/lu";
import { cn } from "@/lib/utils";
import { isMobile } from "react-device-detect";
import { useIsAdmin } from "@/hooks/use-is-admin";
type Props = {
className?: string;
@@ -17,6 +18,7 @@ type Props = {
export default function AnnotationOffsetSlider({ className }: Props) {
const { annotationOffset, setAnnotationOffset, camera } = useDetailStream();
const isAdmin = useIsAdmin();
const { mutate } = useSWRConfig();
const { t } = useTranslation(["views/explore"]);
const [isSaving, setIsSaving] = useState(false);
@@ -101,11 +103,13 @@ export default function AnnotationOffsetSlider({ className }: Props) {
<Button size="sm" variant="ghost" onClick={reset}>
{t("button.reset", { ns: "common" })}
</Button>
<Button size="sm" onClick={save} disabled={isSaving}>
{isSaving
? t("button.saving", { ns: "common" })
: t("button.save", { ns: "common" })}
</Button>
{isAdmin && (
<Button size="sm" onClick={save} disabled={isSaving}>
{isSaving
? t("button.saving", { ns: "common" })
: t("button.save", { ns: "common" })}
</Button>
)}
</div>
</div>
<div
@@ -24,6 +24,7 @@ import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Trans, useTranslation } from "react-i18next";
import { useDocDomain } from "@/hooks/use-doc-domain";
import { useIsAdmin } from "@/hooks/use-is-admin";
type AnnotationSettingsPaneProps = {
event: Event;
@@ -36,6 +37,7 @@ export function AnnotationSettingsPane({
setAnnotationOffset,
}: AnnotationSettingsPaneProps) {
const { t } = useTranslation(["views/explore"]);
const isAdmin = useIsAdmin();
const { getLocaleDocUrl } = useDocDomain();
const { data: config, mutate: updateConfig } =
@@ -201,22 +203,24 @@ export function AnnotationSettingsPane({
>
{t("button.apply", { ns: "common" })}
</Button>
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
{isAdmin && (
<Button
variant="select"
aria-label={t("button.save", { ns: "common" })}
disabled={isLoading}
className="flex flex-1"
type="submit"
>
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save", { ns: "common" })
)}
</Button>
)}
</div>
</div>
</form>
@@ -15,6 +15,7 @@ import {
import { HiDotsHorizontal } from "react-icons/hi";
import { SearchResult } from "@/types/search";
import { FrigateConfig } from "@/types/frigateConfig";
import { useIsAdmin } from "@/hooks/use-is-admin";
type Props = {
search: SearchResult | Event;
@@ -35,6 +36,7 @@ export default function DetailActionsMenu({
const { t } = useTranslation(["views/explore", "views/faceLibrary"]);
const navigate = useNavigate();
const [isOpen, setIsOpen] = useState(false);
const isAdmin = useIsAdmin();
const clipTimeRange = useMemo(() => {
const startTime = (search.start_time ?? 0) - REVIEW_PADDING;
@@ -130,22 +132,24 @@ export default function DetailActionsMenu({
</DropdownMenuItem>
)}
{config?.semantic_search.enabled && search.data.type == "object" && (
<DropdownMenuItem
onClick={() => {
setIsOpen(false);
setTimeout(() => {
navigate(
`/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>
</DropdownMenuItem>
)}
{isAdmin &&
config?.semantic_search.enabled &&
search.data.type == "object" && (
<DropdownMenuItem
onClick={() => {
setIsOpen(false);
setTimeout(() => {
navigate(
`/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>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenuPortal>
</DropdownMenu>