mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-30 18:30:34 +03:00
Show the analytics preview in telemetry settings
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Telemetry settings: the analytics preview shows the report Frigate would
|
||||||
|
* send, fetched only when opened.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { test, expect } from "../../fixtures/frigate-test";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const CONFIG_SCHEMA = JSON.parse(
|
||||||
|
readFileSync(
|
||||||
|
resolve(__dirname, "../../fixtures/mock-data/config-schema.json"),
|
||||||
|
"utf-8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const PREVIEW = {
|
||||||
|
schema_version: 1,
|
||||||
|
install_id: "0".repeat(32),
|
||||||
|
install: { version: "0.19.0-test" },
|
||||||
|
};
|
||||||
|
|
||||||
|
test.describe("telemetry settings: analytics preview @medium", () => {
|
||||||
|
test("shows the report on demand", async ({ frigateApp }) => {
|
||||||
|
let requests = 0;
|
||||||
|
const page = frigateApp.page;
|
||||||
|
|
||||||
|
await page.route("**/api/config/schema.json", (route) =>
|
||||||
|
route.fulfill({ json: CONFIG_SCHEMA }),
|
||||||
|
);
|
||||||
|
await page.route("**/api/config/raw_paths", (route) =>
|
||||||
|
route.fulfill({ json: { telemetry: {} } }),
|
||||||
|
);
|
||||||
|
await page.route("**/api/analytics/preview", (route) => {
|
||||||
|
requests += 1;
|
||||||
|
return route.fulfill({ json: PREVIEW });
|
||||||
|
});
|
||||||
|
|
||||||
|
await frigateApp.goto("/settings?page=systemTelemetry");
|
||||||
|
|
||||||
|
const button = page.getByRole("button", { name: "Preview the report" });
|
||||||
|
await expect(button).toBeVisible();
|
||||||
|
expect(requests).toBe(0);
|
||||||
|
|
||||||
|
await button.click();
|
||||||
|
|
||||||
|
await expect(page.getByTestId("analytics-preview")).toContainText(
|
||||||
|
'"schema_version": 1',
|
||||||
|
);
|
||||||
|
expect(requests).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -222,6 +222,10 @@
|
|||||||
"telemetry": {
|
"telemetry": {
|
||||||
"label": "Telemetry",
|
"label": "Telemetry",
|
||||||
"description": "System telemetry and stats options including GPU and network bandwidth monitoring.",
|
"description": "System telemetry and stats options including GPU and network bandwidth monitoring.",
|
||||||
|
"analytics": {
|
||||||
|
"label": "Share anonymous analytics",
|
||||||
|
"description": "Send one anonymous usage report a day to help the Frigate maintainers decide what to support. Nothing is sent until this is on."
|
||||||
|
},
|
||||||
"network_interfaces": {
|
"network_interfaces": {
|
||||||
"label": "Network interfaces",
|
"label": "Network interfaces",
|
||||||
"description": "List of network interface name prefixes to monitor for bandwidth statistics."
|
"description": "List of network interface name prefixes to monitor for bandwidth statistics."
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"analyticsPreview": {
|
||||||
|
"show": "Preview the report",
|
||||||
|
"desc": "Frigate sends this report once a day while sharing is on. It never includes camera names, zones, labels, or addresses.",
|
||||||
|
"error": "Unable to build the preview"
|
||||||
|
},
|
||||||
"documentTitle": {
|
"documentTitle": {
|
||||||
"default": "Settings - Frigate",
|
"default": "Settings - Frigate",
|
||||||
"authentication": "Authentication Settings - Frigate",
|
"authentication": "Authentication Settings - Frigate",
|
||||||
|
|||||||
@@ -45,7 +45,8 @@
|
|||||||
"shm_too_low": "/dev/shm allocation ({{total}} MB) should be increased to at least {{min}} MB",
|
"shm_too_low": "/dev/shm allocation ({{total}} MB) should be increased to at least {{min}} MB",
|
||||||
"failed_login_one": "Failed login attempt for {{user}}",
|
"failed_login_one": "Failed login attempt for {{user}}",
|
||||||
"failed_login_other": "Failed login attempts for {{user}}",
|
"failed_login_other": "Failed login attempts for {{user}}",
|
||||||
"update_available": "Frigate {{version}} is available"
|
"update_available": "Frigate {{version}} is available",
|
||||||
|
"analytics_prompt": "Share anonymous usage statistics to help improve Frigate"
|
||||||
},
|
},
|
||||||
"streamPrefix": "Stream {{index}}: {{message}}",
|
"streamPrefix": "Stream {{index}}: {{message}}",
|
||||||
"streamPrefixRestream": "Stream {{index}} (via go2rtc): {{message}}",
|
"streamPrefixRestream": "Stream {{index}} (via go2rtc): {{message}}",
|
||||||
|
|||||||
@@ -3,9 +3,17 @@ import type { SectionConfigOverrides } from "./types";
|
|||||||
const telemetry: SectionConfigOverrides = {
|
const telemetry: SectionConfigOverrides = {
|
||||||
base: {
|
base: {
|
||||||
sectionDocs: "/configuration/advanced/reference",
|
sectionDocs: "/configuration/advanced/reference",
|
||||||
|
fieldDocs: {
|
||||||
|
analytics: "/configuration/advanced/analytics",
|
||||||
|
},
|
||||||
restartRequired: ["version_check"],
|
restartRequired: ["version_check"],
|
||||||
fieldOrder: ["network_interfaces", "stats", "version_check"],
|
fieldOrder: ["analytics", "network_interfaces", "stats", "version_check"],
|
||||||
advancedFields: [],
|
advancedFields: [],
|
||||||
|
uiSchema: {
|
||||||
|
analytics: {
|
||||||
|
"ui:after": { render: "AnalyticsPreview" },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { LuChevronDown, LuChevronRight } from "react-icons/lu";
|
||||||
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Collapsible,
|
||||||
|
CollapsibleContent,
|
||||||
|
CollapsibleTrigger,
|
||||||
|
} from "@/components/ui/collapsible";
|
||||||
|
|
||||||
|
export default function AnalyticsPreview() {
|
||||||
|
const { t } = useTranslation("views/settings");
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
// built on demand, since building runs every collector on the server
|
||||||
|
const { data, error } = useSWR<Record<string, unknown>>(
|
||||||
|
open ? "analytics/preview" : null,
|
||||||
|
{ revalidateOnFocus: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapsible open={open} onOpenChange={setOpen} className="mt-2">
|
||||||
|
<CollapsibleTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm" className="gap-1">
|
||||||
|
{open ? (
|
||||||
|
<LuChevronDown className="size-4" />
|
||||||
|
) : (
|
||||||
|
<LuChevronRight className="size-4" />
|
||||||
|
)}
|
||||||
|
{t("analyticsPreview.show")}
|
||||||
|
</Button>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
<div className="mt-1 text-xs text-muted-foreground">
|
||||||
|
{t("analyticsPreview.desc")}
|
||||||
|
</div>
|
||||||
|
<CollapsibleContent className="mt-2">
|
||||||
|
{error ? (
|
||||||
|
<div className="text-sm text-danger">
|
||||||
|
{t("analyticsPreview.error")}
|
||||||
|
</div>
|
||||||
|
) : data ? (
|
||||||
|
<pre
|
||||||
|
data-testid="analytics-preview"
|
||||||
|
className="max-h-96 overflow-auto rounded-md bg-secondary p-3 text-xs"
|
||||||
|
>
|
||||||
|
{JSON.stringify(data, null, 2)}
|
||||||
|
</pre>
|
||||||
|
) : (
|
||||||
|
<ActivityIndicator className="size-5" />
|
||||||
|
)}
|
||||||
|
</CollapsibleContent>
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { ComponentType } from "react";
|
import type { ComponentType } from "react";
|
||||||
|
import AnalyticsPreview from "./AnalyticsPreview";
|
||||||
import SemanticSearchReindex from "./SemanticSearchReindex.tsx";
|
import SemanticSearchReindex from "./SemanticSearchReindex.tsx";
|
||||||
import CameraReviewStatusToggles from "./CameraReviewStatusToggles";
|
import CameraReviewStatusToggles from "./CameraReviewStatusToggles";
|
||||||
import ProxyRoleMap from "./ProxyRoleMap";
|
import ProxyRoleMap from "./ProxyRoleMap";
|
||||||
@@ -56,6 +57,9 @@ export const sectionRenderers: SectionRenderers = {
|
|||||||
birdseye: {
|
birdseye: {
|
||||||
BirdseyeCameraReorder,
|
BirdseyeCameraReorder,
|
||||||
},
|
},
|
||||||
|
telemetry: {
|
||||||
|
AnalyticsPreview,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sectionRenderers;
|
export default sectionRenderers;
|
||||||
|
|||||||
@@ -649,6 +649,7 @@ export interface FrigateConfig {
|
|||||||
};
|
};
|
||||||
|
|
||||||
telemetry: {
|
telemetry: {
|
||||||
|
analytics: boolean;
|
||||||
network_interfaces: string[];
|
network_interfaces: string[];
|
||||||
stats: {
|
stats: {
|
||||||
amd_gpu_stats: boolean;
|
amd_gpu_stats: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user