mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-13 02:02:48 +03:00
Compare commits
3
Commits
0c52a3175d
...
79ca18d439
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79ca18d439 | ||
|
|
cabdffea20 | ||
|
|
ba41c90c07 |
@@ -46,9 +46,6 @@ jobs:
|
|||||||
- name: Build web
|
- name: Build web
|
||||||
run: npm run build
|
run: npm run build
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
# - name: Test
|
|
||||||
# run: npm run test
|
|
||||||
# working-directory: ./web
|
|
||||||
|
|
||||||
web_e2e:
|
web_e2e:
|
||||||
name: Web - E2E Tests
|
name: Web - E2E Tests
|
||||||
|
|||||||
@@ -343,13 +343,6 @@ http {
|
|||||||
add_header Cache-Control "public";
|
add_header Cache-Control "public";
|
||||||
}
|
}
|
||||||
|
|
||||||
location /fonts/ {
|
|
||||||
access_log off;
|
|
||||||
expires 1y;
|
|
||||||
include security_headers.conf;
|
|
||||||
add_header Cache-Control "public";
|
|
||||||
}
|
|
||||||
|
|
||||||
location /locales/ {
|
location /locales/ {
|
||||||
access_log off;
|
access_log off;
|
||||||
include security_headers.conf;
|
include security_headers.conf;
|
||||||
|
|||||||
@@ -204,11 +204,20 @@ Light guidelines and advice:
|
|||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
- Add to unit tests and ensure they pass. As much as possible, you should strive to _increase_ test coverage whenever making changes. This will help ensure features do not accidentally become broken in the future.
|
- Ensure the backend [unit tests](#unit-tests) pass. Your PR cannot be merged unless tests pass.
|
||||||
- If you run into error messages like "TypeError: Cannot read properties of undefined (reading 'context')" when running tests, this may be due to these issues (https://github.com/vitest-dev/vitest/issues/1910, https://github.com/vitest-dev/vitest/issues/1652) in vitest, but I haven't been able to resolve them.
|
|
||||||
|
```shell
|
||||||
|
python3 -u -m unittest
|
||||||
|
```
|
||||||
|
|
||||||
|
- Ensure the end-to-end tests pass. They run in Playwright against a production build with mocked API data, so they don't need a running Frigate instance. Add or update tests in `web/e2e/specs/` when you change UI behavior.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
npm run test
|
# First-time setup
|
||||||
|
npx playwright install chromium
|
||||||
|
|
||||||
|
# Build the app and run all tests
|
||||||
|
npm run e2e:build && npm run e2e
|
||||||
```
|
```
|
||||||
|
|
||||||
- Test in different browsers. Firefox, Chrome, and Safari all have different quirks that make them unique targets to interact with.
|
- Test in different browsers. Firefox, Chrome, and Safari all have different quirks that make them unique targets to interact with.
|
||||||
|
|||||||
Generated
+248
-1628
File diff suppressed because it is too large
Load Diff
+12
-25
@@ -12,8 +12,6 @@
|
|||||||
"lint:fix": "eslint --fix .",
|
"lint:fix": "eslint --fix .",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"prettier:write": "prettier -u -w --ignore-path .gitignore \"*.{ts,tsx,js,jsx,css,html}\"",
|
"prettier:write": "prettier -u -w --ignore-path .gitignore \"*.{ts,tsx,js,jsx,css,html}\"",
|
||||||
"test": "vitest",
|
|
||||||
"coverage": "vitest run --coverage",
|
|
||||||
"e2e:build": "tsc && vite build --base=/",
|
"e2e:build": "tsc && vite build --base=/",
|
||||||
"e2e": "playwright test --config e2e/playwright.config.ts",
|
"e2e": "playwright test --config e2e/playwright.config.ts",
|
||||||
"e2e:ui": "playwright test --config e2e/playwright.config.ts --ui",
|
"e2e:ui": "playwright test --config e2e/playwright.config.ts --ui",
|
||||||
@@ -24,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
||||||
"@hookform/resolvers": "^3.10.0",
|
"@hookform/resolvers": "^5.9.1",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.23",
|
"@radix-ui/react-alert-dialog": "^1.1.23",
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.15",
|
"@radix-ui/react-aspect-ratio": "^1.1.15",
|
||||||
"@radix-ui/react-checkbox": "^1.3.11",
|
"@radix-ui/react-checkbox": "^1.3.11",
|
||||||
@@ -57,14 +55,14 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
"copy-to-clipboard": "^4.0.2",
|
"copy-to-clipboard": "^4.0.2",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^4.4.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"framer-motion": "^13.3.0",
|
"framer-motion": "^13.3.0",
|
||||||
"hls.js": "^1.7.3",
|
"hls.js": "^1.7.3",
|
||||||
"i18next": "^24.2.0",
|
"i18next": "^26.4.2",
|
||||||
"i18next-http-backend": "^4.0.2",
|
"i18next-http-backend": "^4.0.2",
|
||||||
"idb-keyval": "^6.3.0",
|
"idb-keyval": "^6.3.0",
|
||||||
"js-yaml": "^4.3.2",
|
"js-yaml": "^5.4.2",
|
||||||
"konva": "^10.5.0",
|
"konva": "^10.5.0",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
"lucide-react": "^1.46.0",
|
"lucide-react": "^1.46.0",
|
||||||
@@ -76,21 +74,19 @@
|
|||||||
"react-day-picker": "^9.14.0",
|
"react-day-picker": "^9.14.0",
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^19.3.0",
|
"react-dom": "^19.3.0",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^20.1.2",
|
||||||
"react-grid-layout": "^2.2.4",
|
"react-grid-layout": "^2.2.4",
|
||||||
"react-hook-form": "^7.88.0",
|
"react-hook-form": "^7.88.0",
|
||||||
"react-i18next": "^15.2.0",
|
"react-i18next": "^17.0.14",
|
||||||
"react-icons": "^5.7.0",
|
"react-icons": "^5.7.0",
|
||||||
"react-konva": "^19.2.7",
|
"react-konva": "^19.2.7",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^6.30.6",
|
"react-router-dom": "^6.30.6",
|
||||||
"react-swipeable": "^7.0.2",
|
"react-swipeable": "^7.0.2",
|
||||||
"react-zoom-pan-pinch": "3.4.4",
|
"react-zoom-pan-pinch": "3.4.4",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"scroll-into-view-if-needed": "^3.1.0",
|
"scroll-into-view-if-needed": "^3.1.0",
|
||||||
"sonner": "^2.0.8",
|
"sonner": "^2.0.8",
|
||||||
"sort-by": "^1.2.0",
|
|
||||||
"strftime": "^0.10.3",
|
|
||||||
"swr": "^2.5.1",
|
"swr": "^2.5.1",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^2.4.0",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
@@ -99,21 +95,17 @@
|
|||||||
"vaul": "^1.1.2",
|
"vaul": "^1.1.2",
|
||||||
"virtua": "^0.51.3",
|
"virtua": "^0.51.3",
|
||||||
"vite-plugin-monaco-editor": "^1.1.0",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.25.76"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@playwright/test": "^1.63.0",
|
"@playwright/test": "^1.63.0",
|
||||||
"@tailwindcss/forms": "^0.5.11",
|
|
||||||
"@testing-library/jest-dom": "^6.6.2",
|
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/lodash": "^4.17.25",
|
"@types/lodash": "^4.17.25",
|
||||||
"@types/node": "^25.9.6",
|
"@types/node": "^26.5.1",
|
||||||
"@types/react": "^19.3.0",
|
"@types/react": "^19.3.0",
|
||||||
"@types/react-dom": "^19.3.0",
|
"@types/react-dom": "^19.3.0",
|
||||||
"@types/strftime": "^0.9.8",
|
|
||||||
"@vitejs/plugin-react": "^6.1.1",
|
"@vitejs/plugin-react": "^6.1.1",
|
||||||
"@vitest/coverage-v8": "^4.1.11",
|
|
||||||
"autoprefixer": "^10.6.0",
|
"autoprefixer": "^10.6.0",
|
||||||
"esbuild": "^0.28.2",
|
"esbuild": "^0.28.2",
|
||||||
"eslint": "^10.10.0",
|
"eslint": "^10.10.0",
|
||||||
@@ -121,22 +113,17 @@
|
|||||||
"eslint-plugin-prettier": "^5.5.6",
|
"eslint-plugin-prettier": "^5.5.6",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"eslint-plugin-react-refresh": "^0.5.7",
|
"eslint-plugin-react-refresh": "^0.5.7",
|
||||||
"fake-indexeddb": "^6.0.0",
|
|
||||||
"globals": "^17.12.0",
|
"globals": "^17.12.0",
|
||||||
"i18next-cli": "^1.5.11",
|
"i18next-cli": "^1.5.11",
|
||||||
"jest-websocket-mock": "^2.5.0",
|
|
||||||
"jsdom": "^24.1.1",
|
|
||||||
"monaco-editor": "^0.52.2",
|
"monaco-editor": "^0.52.2",
|
||||||
"msw": "^2.3.5",
|
|
||||||
"patch-package": "^8.0.1",
|
"patch-package": "^8.0.1",
|
||||||
"postcss": "^8.5.12",
|
"postcss": "^8.5.12",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.9.6",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.8.1",
|
||||||
"tailwindcss": "^3.4.9",
|
"tailwindcss": "^3.4.9",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.70.0",
|
"typescript-eslint": "^8.70.0",
|
||||||
"vite": "^8.3.0",
|
"vite": "^8.3.0"
|
||||||
"vitest": "^4.1.11"
|
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@radix-ui/react-compose-refs": "1.1.2",
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEmbeddingsReindexProgress } from "@/api/ws";
|
|||||||
import {
|
import {
|
||||||
StatusBarMessagesContext,
|
StatusBarMessagesContext,
|
||||||
StatusMessage,
|
StatusMessage,
|
||||||
} from "@/context/statusbar-provider";
|
} from "@/context/statusbar-context";
|
||||||
import useStats, { useAutoFrigateStats } from "@/hooks/use-stats";
|
import useStats, { useAutoFrigateStats } from "@/hooks/use-stats";
|
||||||
import StatusBarNotices from "@/components/health/StatusBarNotices";
|
import StatusBarNotices from "@/components/health/StatusBarNotices";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
|
|||||||
import { CameraConfig } from "@/types/frigateConfig";
|
import { CameraConfig } from "@/types/frigateConfig";
|
||||||
import { useZoneFriendlyName } from "@/hooks/use-zone-friendly-name";
|
import { useZoneFriendlyName } from "@/hooks/use-zone-friendly-name";
|
||||||
|
|
||||||
interface CameraNameLabelProps
|
interface CameraNameLabelProps extends React.ComponentPropsWithoutRef<
|
||||||
extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {
|
typeof LabelPrimitive.Root
|
||||||
|
> {
|
||||||
camera?: string | CameraConfig;
|
camera?: string | CameraConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ZoneNameLabelProps
|
interface ZoneNameLabelProps extends React.ComponentPropsWithoutRef<
|
||||||
extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {
|
typeof LabelPrimitive.Root
|
||||||
|
> {
|
||||||
zone: string;
|
zone: string;
|
||||||
camera?: string;
|
camera?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,8 +163,18 @@ export default function ClassificationModelEditDialog({
|
|||||||
}
|
}
|
||||||
}, [isObjectModel, t]);
|
}, [isObjectModel, t]);
|
||||||
|
|
||||||
const form = useForm<ObjectFormData | StateFormData>({
|
const form = useForm<
|
||||||
resolver: zodResolver(formSchema),
|
ObjectFormData | StateFormData,
|
||||||
|
unknown,
|
||||||
|
ObjectFormData | StateFormData
|
||||||
|
>({
|
||||||
|
resolver: zodResolver(
|
||||||
|
formSchema as z.ZodType<
|
||||||
|
ObjectFormData | StateFormData,
|
||||||
|
z.ZodTypeDef,
|
||||||
|
ObjectFormData | StateFormData
|
||||||
|
>,
|
||||||
|
),
|
||||||
defaultValues: isObjectModel
|
defaultValues: isObjectModel
|
||||||
? ({
|
? ({
|
||||||
enabled: model.enabled,
|
enabled: model.enabled,
|
||||||
|
|||||||
@@ -68,8 +68,7 @@ const review: SectionConfigOverrides = {
|
|||||||
position: "after",
|
position: "after",
|
||||||
condition: (ctx) => {
|
condition: (ctx) => {
|
||||||
const genai = ctx.formData?.genai as
|
const genai = ctx.formData?.genai as
|
||||||
| Record<string, unknown>
|
Record<string, unknown> | undefined;
|
||||||
| undefined;
|
|
||||||
if (genai?.image_source !== "recordings") return false;
|
if (genai?.image_source !== "recordings") return false;
|
||||||
if (ctx.level === "camera" && ctx.fullCameraConfig) {
|
if (ctx.level === "camera" && ctx.fullCameraConfig) {
|
||||||
return ctx.fullCameraConfig.record?.enabled === false;
|
return ctx.fullCameraConfig.record?.enabled === false;
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ export function validateDetectDimensions(
|
|||||||
const height = data.height;
|
const height = data.height;
|
||||||
|
|
||||||
const widthErrors = errors.width as
|
const widthErrors = errors.width as
|
||||||
| { addError?: (message: string) => void }
|
{ addError?: (message: string) => void } | undefined;
|
||||||
| undefined;
|
|
||||||
const heightErrors = errors.height as
|
const heightErrors = errors.height as
|
||||||
| { addError?: (message: string) => void }
|
{ addError?: (message: string) => void } | undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const message = t("detect.dimensionMustBeEven", { ns: "config/validation" });
|
const message = t("detect.dimensionMustBeEven", { ns: "config/validation" });
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ export default function CameraReviewClassification({
|
|||||||
const cameraName = formContext?.cameraName ?? selectedCamera;
|
const cameraName = formContext?.cameraName ?? selectedCamera;
|
||||||
const fullFormData = formContext?.formData as JsonObject | undefined;
|
const fullFormData = formContext?.formData as JsonObject | undefined;
|
||||||
const baselineFormData = formContext?.baselineFormData as
|
const baselineFormData = formContext?.baselineFormData as
|
||||||
| JsonObject
|
JsonObject | undefined;
|
||||||
| undefined;
|
|
||||||
const cameraConfig = formContext?.fullCameraConfig;
|
const cameraConfig = formContext?.fullCameraConfig;
|
||||||
|
|
||||||
const alertsZones = useMemo(
|
const alertsZones = useMemo(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
import { StatusBarMessagesContext } from "@/context/statusbar-context";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -371,9 +371,9 @@ export default function NotificationsSettingsExtras({
|
|||||||
|
|
||||||
const shouldFetchPubKey = Boolean(
|
const shouldFetchPubKey = Boolean(
|
||||||
config &&
|
config &&
|
||||||
(config.notifications?.enabled || anyCameraNotificationsEnabled) &&
|
(config.notifications?.enabled || anyCameraNotificationsEnabled) &&
|
||||||
(watchAllEnabled ||
|
(watchAllEnabled ||
|
||||||
(Array.isArray(watchCameras) && watchCameras.length > 0)),
|
(Array.isArray(watchCameras) && watchCameras.length > 0)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: publicKey } = useSWR(
|
const { data: publicKey } = useSWR(
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import {
|
|||||||
JsonValue,
|
JsonValue,
|
||||||
} from "@/types/configForm";
|
} from "@/types/configForm";
|
||||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
import { StatusBarMessagesContext } from "@/context/statusbar-context";
|
||||||
import {
|
import {
|
||||||
cameraUpdateTopicMap,
|
cameraUpdateTopicMap,
|
||||||
globalCameraDefaultSections,
|
globalCameraDefaultSections,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { FieldPathList, FieldProps } from "@rjsf/utils";
|
import type { FieldPathList, FieldProps } from "@rjsf/utils";
|
||||||
import yaml from "js-yaml";
|
import { dump, load, YAMLException } from "js-yaml";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
@@ -16,7 +16,7 @@ function formatYaml(value: unknown): string {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return yaml.dump(value, { indent: 2, lineWidth: -1 }).trimEnd();
|
return dump(value, { indent: 2, lineWidth: -1 }).trimEnd();
|
||||||
} catch {
|
} catch {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ function parseYaml(text: string): {
|
|||||||
return { value: {}, error: undefined };
|
return { value: {}, error: undefined };
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const parsed = yaml.load(trimmed);
|
const parsed = load(trimmed);
|
||||||
if (
|
if (
|
||||||
typeof parsed !== "object" ||
|
typeof parsed !== "object" ||
|
||||||
parsed === null ||
|
parsed === null ||
|
||||||
@@ -41,7 +41,7 @@ function parseYaml(text: string): {
|
|||||||
}
|
}
|
||||||
return { value: parsed as Record<string, unknown>, error: undefined };
|
return { value: parsed as Record<string, unknown>, error: undefined };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e instanceof yaml.YAMLException ? e.reason : "Invalid YAML";
|
const msg = e instanceof YAMLException ? e.reason : "Invalid YAML";
|
||||||
return { value: undefined, error: msg };
|
return { value: undefined, error: msg };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,8 +217,7 @@ function PlateCombobox({
|
|||||||
export function KnownPlatesField(props: FieldProps) {
|
export function KnownPlatesField(props: FieldProps) {
|
||||||
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const configNamespace =
|
const configNamespace =
|
||||||
formContext?.i18nNamespace ??
|
formContext?.i18nNamespace ??
|
||||||
|
|||||||
@@ -159,8 +159,7 @@ function StreamValueCombobox({
|
|||||||
export function LiveStreamsField(props: FieldProps) {
|
export function LiveStreamsField(props: FieldProps) {
|
||||||
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const configNamespace =
|
const configNamespace =
|
||||||
formContext?.i18nNamespace ??
|
formContext?.i18nNamespace ??
|
||||||
|
|||||||
@@ -96,8 +96,7 @@ const getItemProperties = (
|
|||||||
|
|
||||||
const getSceneOptions = (itemSchema: RJSFSchema | undefined): string[] => {
|
const getSceneOptions = (itemSchema: RJSFSchema | undefined): string[] => {
|
||||||
const scene = getItemProperties(itemSchema).scene as
|
const scene = getItemProperties(itemSchema).scene as
|
||||||
| Record<string, unknown>
|
Record<string, unknown> | undefined;
|
||||||
| undefined;
|
|
||||||
const values = scene?.enum;
|
const values = scene?.enum;
|
||||||
|
|
||||||
return Array.isArray(values)
|
return Array.isArray(values)
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ function getPropertyTitle(itemSchema: RJSFSchema | undefined, key: string) {
|
|||||||
export function ReplaceRulesField(props: FieldProps) {
|
export function ReplaceRulesField(props: FieldProps) {
|
||||||
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
const { schema, formData, onChange, idSchema, disabled, readonly } = props;
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const configNamespace =
|
const configNamespace =
|
||||||
formContext?.i18nNamespace ??
|
formContext?.i18nNamespace ??
|
||||||
|
|||||||
@@ -86,8 +86,7 @@ export function FieldTemplate(props: FieldTemplateProps) {
|
|||||||
const formContext = registry?.formContext as ConfigFormContext | undefined;
|
const formContext = registry?.formContext as ConfigFormContext | undefined;
|
||||||
const i18nNamespace = formContext?.i18nNamespace as string | undefined;
|
const i18nNamespace = formContext?.i18nNamespace as string | undefined;
|
||||||
const sectionI18nPrefix = formContext?.sectionI18nPrefix as
|
const sectionI18nPrefix = formContext?.sectionI18nPrefix as
|
||||||
| string
|
string | undefined;
|
||||||
| undefined;
|
|
||||||
const isCameraLevel = formContext?.level === "camera";
|
const isCameraLevel = formContext?.level === "camera";
|
||||||
const effectiveNamespace = isCameraLevel ? "config/cameras" : i18nNamespace;
|
const effectiveNamespace = isCameraLevel ? "config/cameras" : i18nNamespace;
|
||||||
const { t, i18n } = useTranslation([
|
const { t, i18n } = useTranslation([
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ export function MultiSchemaFieldTemplate<
|
|||||||
const { schema, selector, optionSchemaField, uiSchema } = props;
|
const { schema, selector, optionSchemaField, uiSchema } = props;
|
||||||
|
|
||||||
const uiOptions = uiSchema?.["ui:options"] as
|
const uiOptions = uiSchema?.["ui:options"] as
|
||||||
| UiSchema["ui:options"]
|
UiSchema["ui:options"] | undefined;
|
||||||
| undefined;
|
|
||||||
const suppressMultiSchema = uiOptions?.suppressMultiSchema === true;
|
const suppressMultiSchema = uiOptions?.suppressMultiSchema === true;
|
||||||
|
|
||||||
// Check if this is a simple nullable field that should be handled specially
|
// Check if this is a simple nullable field that should be handled specially
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ export function CameraPathWidget(props: WidgetProps) {
|
|||||||
const [showCredentials, setShowCredentials] = useState(false);
|
const [showCredentials, setShowCredentials] = useState(false);
|
||||||
|
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
const isCameraLevel = formContext?.level === "camera";
|
const isCameraLevel = formContext?.level === "camera";
|
||||||
const cameraName = formContext?.cameraName;
|
const cameraName = formContext?.cameraName;
|
||||||
const inputIndex = useMemo(() => getInputIndexFromWidgetId(id), [id]);
|
const inputIndex = useMemo(() => getInputIndexFromWidgetId(id), [id]);
|
||||||
|
|||||||
@@ -103,8 +103,7 @@ const normalizeManualText = (value: unknown): string => {
|
|||||||
|
|
||||||
export function FfmpegArgsWidget(props: WidgetProps) {
|
export function FfmpegArgsWidget(props: WidgetProps) {
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
const i18nNamespace = formContext?.i18nNamespace as string | undefined;
|
const i18nNamespace = formContext?.i18nNamespace as string | undefined;
|
||||||
const isCameraLevel = formContext?.level === "camera";
|
const isCameraLevel = formContext?.level === "camera";
|
||||||
const effectiveNamespace = isCameraLevel ? "config/cameras" : i18nNamespace;
|
const effectiveNamespace = isCameraLevel ? "config/cameras" : i18nNamespace;
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ import type { GenAIModelsResponse } from "@/types/chat";
|
|||||||
import { getSizedFieldClassName } from "../utils";
|
import { getSizedFieldClassName } from "../utils";
|
||||||
|
|
||||||
type ProbeResponse =
|
type ProbeResponse =
|
||||||
| { success: true; models: string[] }
|
{ success: true; models: string[] } | { success: false; message: string };
|
||||||
| { success: false; message: string };
|
|
||||||
|
|
||||||
type ProbeStatus = "idle" | "probing" | "success" | "error";
|
type ProbeStatus = "idle" | "probing" | "success" | "error";
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ export function OnvifProfileWidget(props: WidgetProps) {
|
|||||||
const { t } = useTranslation(["views/settings"]);
|
const { t } = useTranslation(["views/settings"]);
|
||||||
|
|
||||||
const formContext = props.registry?.formContext as
|
const formContext = props.registry?.formContext as
|
||||||
| ConfigFormContext
|
ConfigFormContext | undefined;
|
||||||
| undefined;
|
|
||||||
const cameraName = formContext?.cameraName;
|
const cameraName = formContext?.cameraName;
|
||||||
const isCameraLevel = formContext?.level === "camera";
|
const isCameraLevel = formContext?.level === "camera";
|
||||||
const hasOnvifHost = !!formContext?.fullCameraConfig?.onvif?.host;
|
const hasOnvifHost = !!formContext?.fullCameraConfig?.onvif?.host;
|
||||||
|
|||||||
@@ -98,8 +98,7 @@ export function SwitchesWidget(props: WidgetProps) {
|
|||||||
const availableEntities = useMemo(() => {
|
const availableEntities = useMemo(() => {
|
||||||
const getEntities =
|
const getEntities =
|
||||||
(props.options?.getEntities as
|
(props.options?.getEntities as
|
||||||
| ((context: FormContext) => string[])
|
((context: FormContext) => string[]) | undefined) || (() => []);
|
||||||
| undefined) || (() => []);
|
|
||||||
if (context) {
|
if (context) {
|
||||||
return getEntities(context);
|
return getEntities(context);
|
||||||
}
|
}
|
||||||
@@ -109,8 +108,8 @@ export function SwitchesWidget(props: WidgetProps) {
|
|||||||
const getDisplayLabel = useMemo(
|
const getDisplayLabel = useMemo(
|
||||||
() =>
|
() =>
|
||||||
(props.options?.getDisplayLabel as
|
(props.options?.getDisplayLabel as
|
||||||
| ((entity: string, context?: FormContext) => string)
|
((entity: string, context?: FormContext) => string) | undefined) ||
|
||||||
| undefined) || ((entity: string) => entity),
|
((entity: string) => entity),
|
||||||
[props.options],
|
[props.options],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import useNavigation from "@/hooks/use-navigation";
|
|||||||
import {
|
import {
|
||||||
StatusBarMessagesContext,
|
StatusBarMessagesContext,
|
||||||
StatusMessage,
|
StatusMessage,
|
||||||
} from "@/context/statusbar-provider";
|
} from "@/context/statusbar-context";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { isMobile } from "react-device-detect";
|
import { isMobile } from "react-device-detect";
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export abstract class PreviewController {
|
||||||
|
public camera = "";
|
||||||
|
|
||||||
|
constructor(camera: string) {
|
||||||
|
this.camera = camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract scrubToTimestamp(time: number): boolean;
|
||||||
|
|
||||||
|
abstract finishedSeeking(): void;
|
||||||
|
|
||||||
|
abstract setNewPreviewStartTime(time: number): void;
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
} from "@/hooks/use-camera-previews";
|
} from "@/hooks/use-camera-previews";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
|
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
|
||||||
|
import { PreviewController } from "./PreviewController";
|
||||||
|
|
||||||
type PreviewPlayerProps = {
|
type PreviewPlayerProps = {
|
||||||
previewRef?: (ref: HTMLDivElement | null) => void;
|
previewRef?: (ref: HTMLDivElement | null) => void;
|
||||||
@@ -102,20 +103,6 @@ export default function PreviewPlayer({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class PreviewController {
|
|
||||||
public camera = "";
|
|
||||||
|
|
||||||
constructor(camera: string) {
|
|
||||||
this.camera = camera;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract scrubToTimestamp(time: number): boolean;
|
|
||||||
|
|
||||||
abstract finishedSeeking(): void;
|
|
||||||
|
|
||||||
abstract setNewPreviewStartTime(time: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type PreviewVideoPlayerProps = {
|
type PreviewVideoPlayerProps = {
|
||||||
visibilityRef?: (ref: HTMLDivElement | null) => void;
|
visibilityRef?: (ref: HTMLDivElement | null) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|||||||
@@ -8,11 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export type DownswitchReason =
|
export type DownswitchReason =
|
||||||
| "stall"
|
"stall" | "bandwidth" | "fatal-error" | "startup" | "codec";
|
||||||
| "bandwidth"
|
|
||||||
| "fatal-error"
|
|
||||||
| "startup"
|
|
||||||
| "codec";
|
|
||||||
|
|
||||||
// stalls just after a seek are expected on any network (the target
|
// stalls just after a seek are expected on any network (the target
|
||||||
// position is rarely buffered), so they get a longer budget and are
|
// position is rarely buffered), so they get a longer budget and are
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Recording } from "@/types/record";
|
import { Recording } from "@/types/record";
|
||||||
import { DynamicPlayback } from "@/types/playback";
|
import { DynamicPlayback } from "@/types/playback";
|
||||||
import { PreviewController } from "../PreviewPlayer";
|
import { PreviewController } from "../PreviewController";
|
||||||
import { TimeRange, TrackingDetailsSequence } from "@/types/timeline";
|
import { TimeRange, TrackingDetailsSequence } from "@/types/timeline";
|
||||||
import {
|
import {
|
||||||
calculateInpointOffset,
|
calculateInpointOffset,
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import {
|
|||||||
RecordingCoverage,
|
RecordingCoverage,
|
||||||
} from "@/types/record";
|
} from "@/types/record";
|
||||||
import { Preview } from "@/types/preview";
|
import { Preview } from "@/types/preview";
|
||||||
import PreviewPlayer, { PreviewController } from "../PreviewPlayer";
|
import PreviewPlayer from "../PreviewPlayer";
|
||||||
|
import { PreviewController } from "../PreviewController";
|
||||||
import { DynamicVideoController } from "./DynamicVideoController";
|
import { DynamicVideoController } from "./DynamicVideoController";
|
||||||
import HlsVideoPlayer, { HlsSource } from "../HlsVideoPlayer";
|
import HlsVideoPlayer, { HlsSource } from "../HlsVideoPlayer";
|
||||||
import { useDetailStream } from "@/context/detail-stream-context";
|
import { useDetailStream } from "@/context/detail-stream-context";
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ import {
|
|||||||
import { buildConfigDataForPath } from "@/utils/configUtil";
|
import { buildConfigDataForPath } from "@/utils/configUtil";
|
||||||
import { useConfigSchema } from "@/hooks/use-config-schema";
|
import { useConfigSchema } from "@/hooks/use-config-schema";
|
||||||
import { useRestart } from "@/api/ws";
|
import { useRestart } from "@/api/ws";
|
||||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
import { StatusBarMessagesContext } from "@/context/statusbar-context";
|
||||||
import RestartDialog from "@/components/overlay/dialog/RestartDialog";
|
import RestartDialog from "@/components/overlay/dialog/RestartDialog";
|
||||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import SaveAllPreviewPopover from "@/components/overlay/detail/SaveAllPreviewPopover";
|
import SaveAllPreviewPopover from "@/components/overlay/detail/SaveAllPreviewPopover";
|
||||||
|
|||||||
@@ -316,7 +316,11 @@ export default function ZoneEditPane({
|
|||||||
return profileZone ?? cam.zones[polygon.name];
|
return profileZone ?? cam.zones[polygon.name];
|
||||||
}, [polygon, config, editingProfile]);
|
}, [polygon, config, editingProfile]);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<
|
||||||
|
z.input<typeof formSchema>,
|
||||||
|
unknown,
|
||||||
|
z.output<typeof formSchema>
|
||||||
|
>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -601,7 +605,7 @@ export default function ZoneEditPane({
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
function onSubmit(values: z.infer<typeof formSchema>) {
|
function onSubmit(values: z.output<typeof formSchema>) {
|
||||||
if (activePolygonIndex === undefined || !values || !polygons) {
|
if (activePolygonIndex === undefined || !values || !polygons) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
|
||||||
|
|
||||||
const AspectRatio = AspectRatioPrimitive.Root
|
const AspectRatio = AspectRatioPrimitive.Root;
|
||||||
|
|
||||||
export { AspectRatio }
|
export { AspectRatio };
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ const badgeVariants = cva(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export interface BadgeProps
|
export interface BadgeProps
|
||||||
extends React.HTMLAttributes<HTMLDivElement>,
|
extends
|
||||||
|
React.HTMLAttributes<HTMLDivElement>,
|
||||||
VariantProps<typeof badgeVariants> {}
|
VariantProps<typeof badgeVariants> {}
|
||||||
|
|
||||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ const buttonVariants = cva(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends
|
||||||
|
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean;
|
asChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
||||||
import { Check } from "lucide-react"
|
import { Check } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Checkbox = React.forwardRef<
|
const Checkbox = React.forwardRef<
|
||||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||||
@@ -11,8 +11,8 @@ const Checkbox = React.forwardRef<
|
|||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -22,7 +22,7 @@ const Checkbox = React.forwardRef<
|
|||||||
<Check className="h-4 w-4" />
|
<Check className="h-4 w-4" />
|
||||||
</CheckboxPrimitive.Indicator>
|
</CheckboxPrimitive.Indicator>
|
||||||
</CheckboxPrimitive.Root>
|
</CheckboxPrimitive.Root>
|
||||||
))
|
));
|
||||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Checkbox }
|
export { Checkbox };
|
||||||
|
|||||||
@@ -99,7 +99,11 @@ export default function AnimatedCircularProgressBar({
|
|||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
data-current-value={currentPercent}
|
data-current-value={currentPercent}
|
||||||
className="duration-[var(--transition-length)] delay-[var(--delay)] absolute inset-0 m-auto size-fit ease-linear animate-in fade-in"
|
className="absolute inset-0 m-auto size-fit ease-linear animate-in fade-in"
|
||||||
|
style={{
|
||||||
|
animationDuration: "var(--transition-length)",
|
||||||
|
animationDelay: "var(--delay)",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{currentPercent}%
|
{currentPercent}%
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
|
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const ContextMenu = ContextMenuPrimitive.Root
|
const ContextMenu = ContextMenuPrimitive.Root;
|
||||||
|
|
||||||
const ContextMenuTrigger = ContextMenuPrimitive.Trigger
|
const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
||||||
|
|
||||||
const ContextMenuGroup = ContextMenuPrimitive.Group
|
const ContextMenuGroup = ContextMenuPrimitive.Group;
|
||||||
|
|
||||||
const ContextMenuPortal = ContextMenuPrimitive.Portal
|
const ContextMenuPortal = ContextMenuPrimitive.Portal;
|
||||||
|
|
||||||
const ContextMenuSub = ContextMenuPrimitive.Sub
|
const ContextMenuSub = ContextMenuPrimitive.Sub;
|
||||||
|
|
||||||
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
|
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
|
||||||
|
|
||||||
const ContextMenuSubTrigger = React.forwardRef<
|
const ContextMenuSubTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
|
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
|
||||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, children, ...props }, ref) => (
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
<ContextMenuPrimitive.SubTrigger
|
<ContextMenuPrimitive.SubTrigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<ChevronRight className="ml-auto h-4 w-4" />
|
<ChevronRight className="ml-auto h-4 w-4" />
|
||||||
</ContextMenuPrimitive.SubTrigger>
|
</ContextMenuPrimitive.SubTrigger>
|
||||||
))
|
));
|
||||||
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
|
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
|
||||||
|
|
||||||
const ContextMenuSubContent = React.forwardRef<
|
const ContextMenuSubContent = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
|
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
|
||||||
@@ -45,12 +45,12 @@ const ContextMenuSubContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
|
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
|
||||||
|
|
||||||
const ContextMenuContent = React.forwardRef<
|
const ContextMenuContent = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
||||||
@@ -61,31 +61,31 @@ const ContextMenuContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</ContextMenuPrimitive.Portal>
|
</ContextMenuPrimitive.Portal>
|
||||||
))
|
));
|
||||||
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
|
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
const ContextMenuItem = React.forwardRef<
|
const ContextMenuItem = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<ContextMenuPrimitive.Item
|
<ContextMenuPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
|
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
|
||||||
|
|
||||||
const ContextMenuCheckboxItem = React.forwardRef<
|
const ContextMenuCheckboxItem = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
|
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
|
||||||
@@ -94,8 +94,8 @@ const ContextMenuCheckboxItem = React.forwardRef<
|
|||||||
<ContextMenuPrimitive.CheckboxItem
|
<ContextMenuPrimitive.CheckboxItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -107,9 +107,9 @@ const ContextMenuCheckboxItem = React.forwardRef<
|
|||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</ContextMenuPrimitive.CheckboxItem>
|
</ContextMenuPrimitive.CheckboxItem>
|
||||||
))
|
));
|
||||||
ContextMenuCheckboxItem.displayName =
|
ContextMenuCheckboxItem.displayName =
|
||||||
ContextMenuPrimitive.CheckboxItem.displayName
|
ContextMenuPrimitive.CheckboxItem.displayName;
|
||||||
|
|
||||||
const ContextMenuRadioItem = React.forwardRef<
|
const ContextMenuRadioItem = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
|
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
|
||||||
@@ -118,8 +118,8 @@ const ContextMenuRadioItem = React.forwardRef<
|
|||||||
<ContextMenuPrimitive.RadioItem
|
<ContextMenuPrimitive.RadioItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -130,13 +130,13 @@ const ContextMenuRadioItem = React.forwardRef<
|
|||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</ContextMenuPrimitive.RadioItem>
|
</ContextMenuPrimitive.RadioItem>
|
||||||
))
|
));
|
||||||
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
|
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
|
||||||
|
|
||||||
const ContextMenuLabel = React.forwardRef<
|
const ContextMenuLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.Label>,
|
React.ElementRef<typeof ContextMenuPrimitive.Label>,
|
||||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
|
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<ContextMenuPrimitive.Label
|
<ContextMenuPrimitive.Label
|
||||||
@@ -144,12 +144,12 @@ const ContextMenuLabel = React.forwardRef<
|
|||||||
className={cn(
|
className={cn(
|
||||||
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
|
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
|
||||||
|
|
||||||
const ContextMenuSeparator = React.forwardRef<
|
const ContextMenuSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
|
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
|
||||||
@@ -160,8 +160,8 @@ const ContextMenuSeparator = React.forwardRef<
|
|||||||
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
|
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
|
||||||
|
|
||||||
const ContextMenuShortcut = ({
|
const ContextMenuShortcut = ({
|
||||||
className,
|
className,
|
||||||
@@ -171,13 +171,13 @@ const ContextMenuShortcut = ({
|
|||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
ContextMenuShortcut.displayName = "ContextMenuShortcut"
|
ContextMenuShortcut.displayName = "ContextMenuShortcut";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
@@ -195,4 +195,4 @@ export {
|
|||||||
ContextMenuSubContent,
|
ContextMenuSubContent,
|
||||||
ContextMenuSubTrigger,
|
ContextMenuSubTrigger,
|
||||||
ContextMenuRadioGroup,
|
ContextMenuRadioGroup,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||||
|
|
||||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||||
|
|
||||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||||
|
|
||||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||||
|
|
||||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||||
|
|
||||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||||
|
|
||||||
const DropdownMenuSubTrigger = React.forwardRef<
|
const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, children, ...props }, ref) => (
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-accent focus:bg-accent",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<ChevronRight className="ml-auto h-4 w-4" />
|
<ChevronRight className="ml-auto h-4 w-4" />
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
))
|
));
|
||||||
DropdownMenuSubTrigger.displayName =
|
DropdownMenuSubTrigger.displayName =
|
||||||
DropdownMenuPrimitive.SubTrigger.displayName
|
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||||
|
|
||||||
const DropdownMenuSubContent = React.forwardRef<
|
const DropdownMenuSubContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||||
@@ -46,13 +46,13 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSubContent.displayName =
|
DropdownMenuSubContent.displayName =
|
||||||
DropdownMenuPrimitive.SubContent.displayName
|
DropdownMenuPrimitive.SubContent.displayName;
|
||||||
|
|
||||||
const DropdownMenuContent = React.forwardRef<
|
const DropdownMenuContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||||
@@ -66,31 +66,31 @@ const DropdownMenuContent = React.forwardRef<
|
|||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuPrimitive.Portal>
|
</DropdownMenuPrimitive.Portal>
|
||||||
))
|
));
|
||||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DropdownMenuItem = React.forwardRef<
|
const DropdownMenuItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||||
|
|
||||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||||
@@ -99,8 +99,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.CheckboxItem
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -112,9 +112,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.CheckboxItem>
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
))
|
));
|
||||||
DropdownMenuCheckboxItem.displayName =
|
DropdownMenuCheckboxItem.displayName =
|
||||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuRadioItem = React.forwardRef<
|
const DropdownMenuRadioItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||||
@@ -123,8 +123,8 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.RadioItem
|
<DropdownMenuPrimitive.RadioItem
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -135,13 +135,13 @@ const DropdownMenuRadioItem = React.forwardRef<
|
|||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.RadioItem>
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
))
|
));
|
||||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuLabel = React.forwardRef<
|
const DropdownMenuLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Label
|
<DropdownMenuPrimitive.Label
|
||||||
@@ -149,12 +149,12 @@ const DropdownMenuLabel = React.forwardRef<
|
|||||||
className={cn(
|
className={cn(
|
||||||
"px-2 py-1.5 text-sm font-semibold",
|
"px-2 py-1.5 text-sm font-semibold",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||||
|
|
||||||
const DropdownMenuSeparator = React.forwardRef<
|
const DropdownMenuSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||||
@@ -165,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
|
|||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||||
|
|
||||||
const DropdownMenuShortcut = ({
|
const DropdownMenuShortcut = ({
|
||||||
className,
|
className,
|
||||||
@@ -177,9 +177,9 @@ const DropdownMenuShortcut = ({
|
|||||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -197,4 +197,4 @@ export {
|
|||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuRadioGroup,
|
DropdownMenuRadioGroup,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
|
import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const HoverCard = HoverCardPrimitive.Root
|
const HoverCard = HoverCardPrimitive.Root;
|
||||||
|
|
||||||
const HoverCardTrigger = HoverCardPrimitive.Trigger
|
const HoverCardTrigger = HoverCardPrimitive.Trigger;
|
||||||
|
|
||||||
const HoverCardContent = React.forwardRef<
|
const HoverCardContent = React.forwardRef<
|
||||||
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
||||||
@@ -17,11 +17,11 @@ const HoverCardContent = React.forwardRef<
|
|||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
|
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface InputProps
|
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, ...props }, ref) => {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||||
)
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
@@ -18,7 +18,7 @@ const Label = React.forwardRef<
|
|||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Label.displayName = LabelPrimitive.Root.displayName
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Label }
|
export { Label };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Progress = React.forwardRef<
|
const Progress = React.forwardRef<
|
||||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||||
@@ -11,7 +11,7 @@ const Progress = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
|
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -20,7 +20,7 @@ const Progress = React.forwardRef<
|
|||||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||||
/>
|
/>
|
||||||
</ProgressPrimitive.Root>
|
</ProgressPrimitive.Root>
|
||||||
))
|
));
|
||||||
Progress.displayName = ProgressPrimitive.Root.displayName
|
Progress.displayName = ProgressPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Progress }
|
export { Progress };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
||||||
import { Circle } from "lucide-react"
|
import { Circle } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const RadioGroup = React.forwardRef<
|
const RadioGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||||
@@ -14,9 +14,9 @@ const RadioGroup = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
||||||
|
|
||||||
const RadioGroupItem = React.forwardRef<
|
const RadioGroupItem = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||||
@@ -27,7 +27,7 @@ const RadioGroupItem = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@@ -35,8 +35,8 @@ const RadioGroupItem = React.forwardRef<
|
|||||||
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
||||||
</RadioGroupPrimitive.Indicator>
|
</RadioGroupPrimitive.Indicator>
|
||||||
</RadioGroupPrimitive.Item>
|
</RadioGroupPrimitive.Item>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
||||||
|
|
||||||
export { RadioGroup, RadioGroupItem }
|
export { RadioGroup, RadioGroupItem };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const ScrollArea = React.forwardRef<
|
const ScrollArea = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
@@ -18,8 +18,8 @@ const ScrollArea = React.forwardRef<
|
|||||||
<ScrollBar />
|
<ScrollBar />
|
||||||
<ScrollAreaPrimitive.Corner />
|
<ScrollAreaPrimitive.Corner />
|
||||||
</ScrollAreaPrimitive.Root>
|
</ScrollAreaPrimitive.Root>
|
||||||
))
|
));
|
||||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||||
|
|
||||||
const ScrollBar = React.forwardRef<
|
const ScrollBar = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||||
@@ -34,13 +34,13 @@ const ScrollBar = React.forwardRef<
|
|||||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||||
orientation === "horizontal" &&
|
orientation === "horizontal" &&
|
||||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
))
|
));
|
||||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||||
|
|
||||||
export { ScrollArea, ScrollBar }
|
export { ScrollArea, ScrollBar };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Separator = React.forwardRef<
|
const Separator = React.forwardRef<
|
||||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||||
@@ -9,7 +9,7 @@ const Separator = React.forwardRef<
|
|||||||
>(
|
>(
|
||||||
(
|
(
|
||||||
{ className, orientation = "horizontal", decorative = true, ...props },
|
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||||
ref
|
ref,
|
||||||
) => (
|
) => (
|
||||||
<SeparatorPrimitive.Root
|
<SeparatorPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@@ -18,12 +18,12 @@ const Separator = React.forwardRef<
|
|||||||
className={cn(
|
className={cn(
|
||||||
"shrink-0 bg-border",
|
"shrink-0 bg-border",
|
||||||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
)
|
);
|
||||||
Separator.displayName = SeparatorPrimitive.Root.displayName
|
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Separator }
|
export { Separator };
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ const sheetVariants = cva(
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface SheetContentProps
|
interface SheetContentProps
|
||||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
extends
|
||||||
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||||
VariantProps<typeof sheetVariants> {}
|
VariantProps<typeof sheetVariants> {}
|
||||||
|
|
||||||
const SheetContent = React.forwardRef<
|
const SheetContent = React.forwardRef<
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Skeleton({
|
function Skeleton({
|
||||||
className,
|
className,
|
||||||
@@ -9,7 +9,7 @@ function Skeleton({
|
|||||||
className={cn("animate-pulse rounded-md bg-muted", className)}
|
className={cn("animate-pulse rounded-md bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Skeleton }
|
export { Skeleton };
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const Switch = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<SwitchPrimitives.Root
|
<SwitchPrimitives.Root
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-selected data-[state=unchecked]:bg-input",
|
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors data-[state=checked]:bg-selected data-[state=unchecked]:bg-input focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Table = React.forwardRef<
|
const Table = React.forwardRef<
|
||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
@@ -13,16 +13,16 @@ const Table = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
Table.displayName = "Table"
|
Table.displayName = "Table";
|
||||||
|
|
||||||
const TableHeader = React.forwardRef<
|
const TableHeader = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
React.HTMLAttributes<HTMLTableSectionElement>
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||||
))
|
));
|
||||||
TableHeader.displayName = "TableHeader"
|
TableHeader.displayName = "TableHeader";
|
||||||
|
|
||||||
const TableBody = React.forwardRef<
|
const TableBody = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
@@ -33,8 +33,8 @@ const TableBody = React.forwardRef<
|
|||||||
className={cn("[&_tr:last-child]:border-0", className)}
|
className={cn("[&_tr:last-child]:border-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableBody.displayName = "TableBody"
|
TableBody.displayName = "TableBody";
|
||||||
|
|
||||||
const TableFooter = React.forwardRef<
|
const TableFooter = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
@@ -44,12 +44,12 @@ const TableFooter = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableFooter.displayName = "TableFooter"
|
TableFooter.displayName = "TableFooter";
|
||||||
|
|
||||||
const TableRow = React.forwardRef<
|
const TableRow = React.forwardRef<
|
||||||
HTMLTableRowElement,
|
HTMLTableRowElement,
|
||||||
@@ -58,13 +58,13 @@ const TableRow = React.forwardRef<
|
|||||||
<tr
|
<tr
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
"border-b transition-colors data-[state=selected]:bg-muted hover:bg-muted/50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableRow.displayName = "TableRow"
|
TableRow.displayName = "TableRow";
|
||||||
|
|
||||||
const TableHead = React.forwardRef<
|
const TableHead = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
@@ -74,12 +74,12 @@ const TableHead = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableHead.displayName = "TableHead"
|
TableHead.displayName = "TableHead";
|
||||||
|
|
||||||
const TableCell = React.forwardRef<
|
const TableCell = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
@@ -90,8 +90,8 @@ const TableCell = React.forwardRef<
|
|||||||
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCell.displayName = "TableCell"
|
TableCell.displayName = "TableCell";
|
||||||
|
|
||||||
const TableCaption = React.forwardRef<
|
const TableCaption = React.forwardRef<
|
||||||
HTMLTableCaptionElement,
|
HTMLTableCaptionElement,
|
||||||
@@ -102,8 +102,8 @@ const TableCaption = React.forwardRef<
|
|||||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCaption.displayName = "TableCaption"
|
TableCaption.displayName = "TableCaption";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Table,
|
Table,
|
||||||
@@ -114,4 +114,4 @@ export {
|
|||||||
TableRow,
|
TableRow,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableCaption,
|
TableCaption,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Tabs = TabsPrimitive.Root
|
const Tabs = TabsPrimitive.Root;
|
||||||
|
|
||||||
const TabsList = React.forwardRef<
|
const TabsList = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.List>,
|
React.ElementRef<typeof TabsPrimitive.List>,
|
||||||
@@ -13,12 +13,12 @@ const TabsList = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsList.displayName = TabsPrimitive.List.displayName
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||||
|
|
||||||
const TabsTrigger = React.forwardRef<
|
const TabsTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
@@ -27,13 +27,13 @@ const TabsTrigger = React.forwardRef<
|
|||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const TabsContent = React.forwardRef<
|
const TabsContent = React.forwardRef<
|
||||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||||
@@ -43,11 +43,11 @@ const TabsContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TabsContent.displayName = TabsPrimitive.Content.displayName
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type TextElements =
|
type TextElements =
|
||||||
| "p"
|
"p" | "blockquote" | "code" | "lead" | "large" | "small" | "muted";
|
||||||
| "blockquote"
|
|
||||||
| "code"
|
|
||||||
| "lead"
|
|
||||||
| "large"
|
|
||||||
| "small"
|
|
||||||
| "muted";
|
|
||||||
|
|
||||||
const Text = ({
|
const Text = ({
|
||||||
children,
|
children,
|
||||||
@@ -36,7 +30,7 @@ const Text = ({
|
|||||||
<code
|
<code
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold",
|
"relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface TextareaProps
|
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
||||||
|
|
||||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
({ className, ...props }, ref) => {
|
({ className, ...props }, ref) => {
|
||||||
@@ -11,14 +10,14 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
Textarea.displayName = "Textarea"
|
Textarea.displayName = "Textarea";
|
||||||
|
|
||||||
export { Textarea }
|
export { Textarea };
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
|
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
||||||
import { VariantProps } from "class-variance-authority"
|
import { VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
import { toggleVariants } from "@/components/ui/toggle"
|
import { toggleVariants } from "@/components/ui/toggle";
|
||||||
|
|
||||||
const ToggleGroupContext = React.createContext<
|
const ToggleGroupContext = React.createContext<
|
||||||
VariantProps<typeof toggleVariants>
|
VariantProps<typeof toggleVariants>
|
||||||
>({
|
>({
|
||||||
size: "default",
|
size: "default",
|
||||||
variant: "default",
|
variant: "default",
|
||||||
})
|
});
|
||||||
|
|
||||||
const ToggleGroup = React.forwardRef<
|
const ToggleGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
||||||
@@ -26,16 +26,16 @@ const ToggleGroup = React.forwardRef<
|
|||||||
{children}
|
{children}
|
||||||
</ToggleGroupContext>
|
</ToggleGroupContext>
|
||||||
</ToggleGroupPrimitive.Root>
|
</ToggleGroupPrimitive.Root>
|
||||||
))
|
));
|
||||||
|
|
||||||
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
|
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
|
||||||
|
|
||||||
const ToggleGroupItem = React.forwardRef<
|
const ToggleGroupItem = React.forwardRef<
|
||||||
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
||||||
VariantProps<typeof toggleVariants>
|
VariantProps<typeof toggleVariants>
|
||||||
>(({ className, children, variant, size, ...props }, ref) => {
|
>(({ className, children, variant, size, ...props }, ref) => {
|
||||||
const context = React.useContext(ToggleGroupContext)
|
const context = React.useContext(ToggleGroupContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToggleGroupPrimitive.Item
|
<ToggleGroupPrimitive.Item
|
||||||
@@ -45,15 +45,15 @@ const ToggleGroupItem = React.forwardRef<
|
|||||||
variant: context.variant || variant,
|
variant: context.variant || variant,
|
||||||
size: context.size || size,
|
size: context.size || size,
|
||||||
}),
|
}),
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ToggleGroupPrimitive.Item>
|
</ToggleGroupPrimitive.Item>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
|
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
|
||||||
|
|
||||||
export { ToggleGroup, ToggleGroupItem }
|
export { ToggleGroup, ToggleGroupItem };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const toggleVariants = cva(
|
const toggleVariants = cva(
|
||||||
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
||||||
@@ -23,8 +23,8 @@ const toggleVariants = cva(
|
|||||||
variant: "default",
|
variant: "default",
|
||||||
size: "default",
|
size: "default",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
const Toggle = React.forwardRef<
|
const Toggle = React.forwardRef<
|
||||||
React.ElementRef<typeof TogglePrimitive.Root>,
|
React.ElementRef<typeof TogglePrimitive.Root>,
|
||||||
@@ -36,8 +36,8 @@ const Toggle = React.forwardRef<
|
|||||||
className={cn(toggleVariants({ variant, size, className }))}
|
className={cn(toggleVariants({ variant, size, className }))}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
|
|
||||||
Toggle.displayName = TogglePrimitive.Root.displayName
|
Toggle.displayName = TogglePrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Toggle, toggleVariants }
|
export { Toggle, toggleVariants };
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const TooltipProvider = TooltipPrimitive.Provider
|
const TooltipProvider = TooltipPrimitive.Provider;
|
||||||
|
|
||||||
const Tooltip = TooltipPrimitive.Root
|
const Tooltip = TooltipPrimitive.Root;
|
||||||
|
|
||||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
||||||
|
|
||||||
const TooltipContent = React.forwardRef<
|
const TooltipContent = React.forwardRef<
|
||||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||||
@@ -18,11 +18,11 @@ const TooltipContent = React.forwardRef<
|
|||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
export interface AuthState {
|
||||||
|
user: { username: string; role: string | null } | null;
|
||||||
|
allowedCameras: string[];
|
||||||
|
isLoading: boolean;
|
||||||
|
isAuthenticated: boolean; // true if auth is required
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthContextType {
|
||||||
|
auth: AuthState;
|
||||||
|
login: (user: AuthState["user"]) => void;
|
||||||
|
logout: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AuthContext = createContext<AuthContextType>({
|
||||||
|
auth: {
|
||||||
|
user: null,
|
||||||
|
allowedCameras: [],
|
||||||
|
isLoading: true,
|
||||||
|
isAuthenticated: false,
|
||||||
|
},
|
||||||
|
login: () => {},
|
||||||
|
logout: () => {},
|
||||||
|
});
|
||||||
@@ -1,30 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { createContext, useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import { AuthContext, AuthState } from "./auth-context";
|
||||||
interface AuthState {
|
|
||||||
user: { username: string; role: string | null } | null;
|
|
||||||
allowedCameras: string[];
|
|
||||||
isLoading: boolean;
|
|
||||||
isAuthenticated: boolean; // true if auth is required
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AuthContextType {
|
|
||||||
auth: AuthState;
|
|
||||||
login: (user: AuthState["user"]) => void;
|
|
||||||
logout: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AuthContext = createContext<AuthContextType>({
|
|
||||||
auth: {
|
|
||||||
user: null,
|
|
||||||
allowedCameras: [],
|
|
||||||
isLoading: true,
|
|
||||||
isAuthenticated: false,
|
|
||||||
},
|
|
||||||
login: () => {},
|
|
||||||
logout: () => {},
|
|
||||||
});
|
|
||||||
|
|
||||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||||
const [auth, setAuth] = useState<AuthState>({
|
const [auth, setAuth] = useState<AuthState>({
|
||||||
@@ -6,7 +6,7 @@ import { TooltipProvider } from "@/components/ui/tooltip";
|
|||||||
import { StatusBarMessagesProvider } from "@/context/statusbar-provider";
|
import { StatusBarMessagesProvider } from "@/context/statusbar-provider";
|
||||||
import { LanguageProvider } from "./language-provider";
|
import { LanguageProvider } from "./language-provider";
|
||||||
import { StreamingSettingsProvider } from "./streaming-settings-provider";
|
import { StreamingSettingsProvider } from "./streaming-settings-provider";
|
||||||
import { AuthProvider } from "./auth-context";
|
import { AuthProvider } from "./auth-provider";
|
||||||
|
|
||||||
type TProvidersProps = {
|
type TProvidersProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
export type StatusMessage = {
|
||||||
|
id: string;
|
||||||
|
text: string;
|
||||||
|
color?: string;
|
||||||
|
link?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StatusMessagesState = {
|
||||||
|
[key: string]: StatusMessage[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StatusBarMessagesContextValue = {
|
||||||
|
messages: StatusMessagesState;
|
||||||
|
addMessage: (
|
||||||
|
key: string,
|
||||||
|
message: string,
|
||||||
|
color?: string,
|
||||||
|
messageId?: string,
|
||||||
|
link?: string,
|
||||||
|
) => string | undefined;
|
||||||
|
removeMessage: (key: string, messageId: string) => void;
|
||||||
|
clearMessages: (key: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StatusBarMessagesContext =
|
||||||
|
createContext<StatusBarMessagesContextValue | null>(null);
|
||||||
@@ -1,42 +1,13 @@
|
|||||||
|
import { useState, ReactNode, useCallback, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
createContext,
|
StatusBarMessagesContext,
|
||||||
useState,
|
StatusMessagesState,
|
||||||
ReactNode,
|
} from "@/context/statusbar-context";
|
||||||
useCallback,
|
|
||||||
useMemo,
|
|
||||||
} from "react";
|
|
||||||
|
|
||||||
export type StatusMessage = {
|
|
||||||
id: string;
|
|
||||||
text: string;
|
|
||||||
color?: string;
|
|
||||||
link?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type StatusMessagesState = {
|
|
||||||
[key: string]: StatusMessage[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type StatusBarMessagesProviderProps = {
|
type StatusBarMessagesProviderProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StatusBarMessagesContextValue = {
|
|
||||||
messages: StatusMessagesState;
|
|
||||||
addMessage: (
|
|
||||||
key: string,
|
|
||||||
message: string,
|
|
||||||
color?: string,
|
|
||||||
messageId?: string,
|
|
||||||
link?: string,
|
|
||||||
) => string | undefined;
|
|
||||||
removeMessage: (key: string, messageId: string) => void;
|
|
||||||
clearMessages: (key: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const StatusBarMessagesContext =
|
|
||||||
createContext<StatusBarMessagesContextValue | null>(null);
|
|
||||||
|
|
||||||
export function StatusBarMessagesProvider({
|
export function StatusBarMessagesProvider({
|
||||||
children,
|
children,
|
||||||
}: StatusBarMessagesProviderProps) {
|
}: StatusBarMessagesProviderProps) {
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ function getDefaultFilter(
|
|||||||
if (!schema) return undefined;
|
if (!schema) return undefined;
|
||||||
const sectionSchema = extractSectionSchema(schema, sectionPath, "camera");
|
const sectionSchema = extractSectionSchema(schema, sectionPath, "camera");
|
||||||
const filtersSchema = sectionSchema?.properties?.filters as
|
const filtersSchema = sectionSchema?.properties?.filters as
|
||||||
| RJSFSchema
|
RJSFSchema | undefined;
|
||||||
| undefined;
|
|
||||||
if (!filtersSchema) return undefined;
|
if (!filtersSchema) return undefined;
|
||||||
|
|
||||||
// An optional map (`dict[str, X] | None`, as `audio.filters` is declared)
|
// An optional map (`dict[str, X] | None`, as `audio.filters` is declared)
|
||||||
@@ -965,8 +964,7 @@ export function useProfileSectionDeltas(
|
|||||||
|
|
||||||
const profileSection = (
|
const profileSection = (
|
||||||
cameraConfig.profiles?.[profileName] as
|
cameraConfig.profiles?.[profileName] as
|
||||||
| Record<string, unknown>
|
Record<string, unknown> | undefined
|
||||||
| undefined
|
|
||||||
)?.[sectionPath];
|
)?.[sectionPath];
|
||||||
if (profileSection == null) return [];
|
if (profileSection == null) return [];
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ export default function useStats(stats: FrigateStats | undefined) {
|
|||||||
const { payload: replayJob } = useJobStatus("debug_replay", isAdmin);
|
const { payload: replayJob } = useJobStatus("debug_replay", isAdmin);
|
||||||
const replayActive = Boolean(
|
const replayActive = Boolean(
|
||||||
isAdmin &&
|
isAdmin &&
|
||||||
replayJob &&
|
replayJob &&
|
||||||
(replayJob.status === "queued" ||
|
(replayJob.status === "queued" ||
|
||||||
replayJob.status === "running" ||
|
replayJob.status === "running" ||
|
||||||
replayJob.status === "success"),
|
replayJob.status === "success"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const memoizedStats = useDeepMemo(stats);
|
const memoizedStats = useDeepMemo(stats);
|
||||||
|
|||||||
+18
-18
@@ -48,126 +48,126 @@ html {
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Thin.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Thin.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-ThinItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-ThinItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-ExtraLight.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-ExtraLight.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-ExtraLightItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-ExtraLightItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Light.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Light.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-LightItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-LightItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Regular.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Regular.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Italic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Italic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Medium.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Medium.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-MediumItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-MediumItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-SemiBold.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-SemiBold.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-SemiBoldItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-SemiBoldItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Bold.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Bold.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-BoldItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-BoldItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-ExtraBold.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-ExtraBold.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-ExtraBoldItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-ExtraBoldItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-Black.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-Black.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Inter";
|
font-family: "Inter";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url("../fonts/Inter-BlackItalic.woff2") format("woff2");
|
src: url("./assets/fonts/Inter-BlackItalic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-resizable-handle {
|
.react-resizable-handle {
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ function normalizeNullableSchema(schema: RJSFSchema): RJSFSchema {
|
|||||||
anyOf.length === stringBranches.length + (hasNull ? 1 : 0)
|
anyOf.length === stringBranches.length + (hasNull ? 1 : 0)
|
||||||
) {
|
) {
|
||||||
const enumValues = (enumBranch as Record<string, unknown>).enum as
|
const enumValues = (enumBranch as Record<string, unknown>).enum as
|
||||||
| unknown[]
|
unknown[] | undefined;
|
||||||
| undefined;
|
|
||||||
const { anyOf: _anyOf, oneOf: _oneOf, ...rest } = schemaObj;
|
const { anyOf: _anyOf, oneOf: _oneOf, ...rest } = schemaObj;
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
@@ -751,8 +750,7 @@ export function applySchemaDefaults(
|
|||||||
let properties = schemaObj.properties;
|
let properties = schemaObj.properties;
|
||||||
if (!isSchemaObject(properties)) {
|
if (!isSchemaObject(properties)) {
|
||||||
const branches = (schemaObj.anyOf ?? schemaObj.oneOf) as
|
const branches = (schemaObj.anyOf ?? schemaObj.oneOf) as
|
||||||
| unknown[]
|
unknown[] | undefined;
|
||||||
| undefined;
|
|
||||||
if (Array.isArray(branches)) {
|
if (Array.isArray(branches)) {
|
||||||
const objectBranch = branches.find(
|
const objectBranch = branches.find(
|
||||||
(s) =>
|
(s) =>
|
||||||
|
|||||||
@@ -748,14 +748,12 @@ export default function Settings() {
|
|||||||
|
|
||||||
if (level === "camera") {
|
if (level === "camera") {
|
||||||
return CAMERA_SECTION_MAPPING[actualSection] as
|
return CAMERA_SECTION_MAPPING[actualSection] as
|
||||||
| SettingsType
|
SettingsType | undefined;
|
||||||
| undefined;
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
(GLOBAL_SECTION_MAPPING[actualSection] as SettingsType | undefined) ??
|
(GLOBAL_SECTION_MAPPING[actualSection] as SettingsType | undefined) ??
|
||||||
(ENRICHMENTS_SECTION_MAPPING[actualSection] as
|
(ENRICHMENTS_SECTION_MAPPING[actualSection] as
|
||||||
| SettingsType
|
SettingsType | undefined) ??
|
||||||
| undefined) ??
|
|
||||||
(SYSTEM_SECTION_MAPPING[actualSection] as SettingsType | undefined)
|
(SYSTEM_SECTION_MAPPING[actualSection] as SettingsType | undefined)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ export interface Event {
|
|||||||
path_data: [number[], number][];
|
path_data: [number[], number][];
|
||||||
// Allow arbitrary keys for attributes (e.g., model_name, model_name_score)
|
// Allow arbitrary keys for attributes (e.g., model_name, model_name_score)
|
||||||
[key: string]:
|
[key: string]:
|
||||||
| number
|
number | number[] | string | [number[], number][] | undefined;
|
||||||
| number[]
|
|
||||||
| string
|
|
||||||
| [number[], number][]
|
|
||||||
| undefined;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ export interface BirdseyeConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type BirdseyeMode =
|
export type BirdseyeMode =
|
||||||
| "continuous"
|
"continuous" | "motion" | "all_objects" | "alerts" | "detections";
|
||||||
| "motion"
|
|
||||||
| "all_objects"
|
|
||||||
| "alerts"
|
|
||||||
| "detections";
|
|
||||||
|
|
||||||
export interface FaceRecognitionConfig {
|
export interface FaceRecognitionConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
type PtzFeature =
|
type PtzFeature =
|
||||||
| "pt"
|
"pt" | "zoom" | "pt-r" | "zoom-r" | "zoom-a" | "pt-r-fov" | "focus";
|
||||||
| "zoom"
|
|
||||||
| "pt-r"
|
|
||||||
| "zoom-r"
|
|
||||||
| "zoom-a"
|
|
||||||
| "pt-r-fov"
|
|
||||||
| "focus";
|
|
||||||
|
|
||||||
export type OnvifProfile = {
|
export type OnvifProfile = {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -25,11 +25,7 @@ export const DEFAULT_SEARCH_FILTERS: SearchFilters[] = [
|
|||||||
export type SearchSource = "similarity" | "thumbnail" | "description";
|
export type SearchSource = "similarity" | "thumbnail" | "description";
|
||||||
|
|
||||||
export type SearchSortType =
|
export type SearchSortType =
|
||||||
| "date_asc"
|
"date_asc" | "date_desc" | "score_asc" | "score_desc" | "relevance";
|
||||||
| "date_desc"
|
|
||||||
| "score_asc"
|
|
||||||
| "score_desc"
|
|
||||||
| "relevance";
|
|
||||||
|
|
||||||
export type EventType = "object" | "audio" | "manual";
|
export type EventType = "object" | "audio" | "manual";
|
||||||
|
|
||||||
|
|||||||
@@ -163,11 +163,7 @@ export type Ffprobe = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type KeyframeSeverity =
|
export type KeyframeSeverity =
|
||||||
| "ok"
|
"ok" | "warning" | "error" | "unknown" | "record_disabled";
|
||||||
| "warning"
|
|
||||||
| "error"
|
|
||||||
| "unknown"
|
|
||||||
| "record_disabled";
|
|
||||||
|
|
||||||
export type KeyframeGapPattern = "fixed" | "variable";
|
export type KeyframeGapPattern = "fixed" | "variable";
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -102,10 +102,7 @@ export type EmbeddingsReindexProgressType = {
|
|||||||
export type ToggleableSetting = "ON" | "OFF";
|
export type ToggleableSetting = "ON" | "OFF";
|
||||||
|
|
||||||
export type TrackedObjectUpdateType =
|
export type TrackedObjectUpdateType =
|
||||||
| "description"
|
"description" | "lpr" | "transcription" | "face";
|
||||||
| "lpr"
|
|
||||||
| "transcription"
|
|
||||||
| "face";
|
|
||||||
|
|
||||||
export type TrackedObjectUpdateReturnType = {
|
export type TrackedObjectUpdateReturnType = {
|
||||||
type: TrackedObjectUpdateType;
|
type: TrackedObjectUpdateType;
|
||||||
|
|||||||
@@ -605,8 +605,7 @@ export function buildClonedCameraPayloads({
|
|||||||
// deleting a key not in the YAML. Cloned above so this won't mutate the cache.
|
// deleting a key not in the YAML. Cloned above so this won't mutate the cache.
|
||||||
const syntheticCameraObj = syntheticTargetCamera as unknown as JsonObject;
|
const syntheticCameraObj = syntheticTargetCamera as unknown as JsonObject;
|
||||||
const baseConfigObj = syntheticCameraObj.base_config as
|
const baseConfigObj = syntheticCameraObj.base_config as
|
||||||
| Record<string, JsonObject>
|
Record<string, JsonObject> | undefined;
|
||||||
| undefined;
|
|
||||||
for (const section of Object.keys(FILTER_SECTION_DEFS)) {
|
for (const section of Object.keys(FILTER_SECTION_DEFS)) {
|
||||||
const syntheticSection = syntheticCameraObj[section];
|
const syntheticSection = syntheticCameraObj[section];
|
||||||
if (syntheticSection && typeof syntheticSection === "object") {
|
if (syntheticSection && typeof syntheticSection === "object") {
|
||||||
|
|||||||
@@ -192,9 +192,9 @@ export function evaluateConfigHealth(
|
|||||||
t,
|
t,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (!(
|
||||||
!(inherited && firedGlobally.has(`${section}:${message.key}`))
|
inherited && firedGlobally.has(`${section}:${message.key}`)
|
||||||
) {
|
)) {
|
||||||
problems.push(problem);
|
problems.push(problem);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,21 +1,8 @@
|
|||||||
export type FfmpegVideoOption = "copy" | "h264" | "h265" | "exclude";
|
export type FfmpegVideoOption = "copy" | "h264" | "h265" | "exclude";
|
||||||
export type FfmpegAudioOption =
|
export type FfmpegAudioOption =
|
||||||
| "copy"
|
"copy" | "aac" | "opus" | "pcmu" | "pcma" | "pcm" | "mp3" | "exclude";
|
||||||
| "aac"
|
|
||||||
| "opus"
|
|
||||||
| "pcmu"
|
|
||||||
| "pcma"
|
|
||||||
| "pcm"
|
|
||||||
| "mp3"
|
|
||||||
| "exclude";
|
|
||||||
export type FfmpegHardwareOption =
|
export type FfmpegHardwareOption =
|
||||||
| "none"
|
"none" | "auto" | "vaapi" | "cuda" | "v4l2m2m" | "dxva2" | "videotoolbox";
|
||||||
| "auto"
|
|
||||||
| "vaapi"
|
|
||||||
| "cuda"
|
|
||||||
| "v4l2m2m"
|
|
||||||
| "dxva2"
|
|
||||||
| "videotoolbox";
|
|
||||||
|
|
||||||
export type ParsedFfmpegUrl = {
|
export type ParsedFfmpegUrl = {
|
||||||
isFfmpeg: boolean;
|
isFfmpeg: boolean;
|
||||||
|
|||||||
@@ -256,12 +256,7 @@ export function detectionRows({
|
|||||||
// ------------------------------------------------------------------ hwaccel
|
// ------------------------------------------------------------------ hwaccel
|
||||||
|
|
||||||
export type HwaccelFamilyKey =
|
export type HwaccelFamilyKey =
|
||||||
| "nvidia"
|
"nvidia" | "vaapi" | "intel-qsv" | "rkmpp" | "jetson" | "rpi";
|
||||||
| "vaapi"
|
|
||||||
| "intel-qsv"
|
|
||||||
| "rkmpp"
|
|
||||||
| "jetson"
|
|
||||||
| "rpi";
|
|
||||||
|
|
||||||
export type HwaccelClass =
|
export type HwaccelClass =
|
||||||
| { kind: "none" }
|
| { kind: "none" }
|
||||||
|
|||||||
@@ -276,14 +276,10 @@ export function downloadJson(payload: unknown, fileName: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ParseError =
|
export type ParseError =
|
||||||
| "invalid_json"
|
"invalid_json" | "wrong_type" | "unsupported_version" | "invalid_schema";
|
||||||
| "wrong_type"
|
|
||||||
| "unsupported_version"
|
|
||||||
| "invalid_schema";
|
|
||||||
|
|
||||||
export type ParseResult =
|
export type ParseResult =
|
||||||
| { ok: true; file: UiSettingsFile }
|
{ ok: true; file: UiSettingsFile } | { ok: false; error: ParseError };
|
||||||
| { ok: false; error: ParseError };
|
|
||||||
|
|
||||||
export function parseUiSettingsFile(text: string): ParseResult {
|
export function parseUiSettingsFile(text: string): ParseResult {
|
||||||
let raw: unknown;
|
let raw: unknown;
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import PreviewPlayer, {
|
import PreviewPlayer from "@/components/player/PreviewPlayer";
|
||||||
PreviewController,
|
import { PreviewController } from "@/components/player/PreviewController";
|
||||||
} from "@/components/player/PreviewPlayer";
|
|
||||||
import SummaryTimeline from "@/components/timeline/SummaryTimeline";
|
import SummaryTimeline from "@/components/timeline/SummaryTimeline";
|
||||||
import { RecordingStartingPoint } from "@/types/record";
|
import { RecordingStartingPoint } from "@/types/record";
|
||||||
import VideoControls from "@/components/player/VideoControls";
|
import VideoControls from "@/components/player/VideoControls";
|
||||||
|
|||||||
@@ -720,10 +720,10 @@ export default function MotionSearchView({
|
|||||||
|
|
||||||
const canStartSearch = Boolean(
|
const canStartSearch = Boolean(
|
||||||
selectedCamera &&
|
selectedCamera &&
|
||||||
searchRange &&
|
searchRange &&
|
||||||
searchRange.before >= searchRange.after &&
|
searchRange.before >= searchRange.after &&
|
||||||
polygonPoints.length >= 3 &&
|
polygonPoints.length >= 3 &&
|
||||||
!isDrawingROI,
|
!isDrawingROI,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cancelMotionSearchJob = useCallback(
|
const cancelMotionSearchJob = useCallback(
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import ReviewFilterGroup from "@/components/filter/ReviewFilterGroup";
|
|||||||
import DebugReplayDialog from "@/components/overlay/DebugReplayDialog";
|
import DebugReplayDialog from "@/components/overlay/DebugReplayDialog";
|
||||||
import ExportDialog from "@/components/overlay/ExportDialog";
|
import ExportDialog from "@/components/overlay/ExportDialog";
|
||||||
import ActionsDropdown from "@/components/overlay/ActionsDropdown";
|
import ActionsDropdown from "@/components/overlay/ActionsDropdown";
|
||||||
import PreviewPlayer, {
|
import PreviewPlayer from "@/components/player/PreviewPlayer";
|
||||||
PreviewController,
|
import { PreviewController } from "@/components/player/PreviewController";
|
||||||
} from "@/components/player/PreviewPlayer";
|
|
||||||
import { DynamicVideoController } from "@/components/player/dynamic/DynamicVideoController";
|
import { DynamicVideoController } from "@/components/player/dynamic/DynamicVideoController";
|
||||||
import DynamicVideoPlayer from "@/components/player/dynamic/DynamicVideoPlayer";
|
import DynamicVideoPlayer from "@/components/player/dynamic/DynamicVideoPlayer";
|
||||||
import QualitySelector from "@/components/player/QualitySelector";
|
import QualitySelector from "@/components/player/QualitySelector";
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ import {
|
|||||||
import type { ProfileState } from "@/types/profile";
|
import type { ProfileState } from "@/types/profile";
|
||||||
import { getProfileColor } from "@/utils/profileColors";
|
import { getProfileColor } from "@/utils/profileColors";
|
||||||
import { isReplayCamera } from "@/utils/cameraUtil";
|
import { isReplayCamera } from "@/utils/cameraUtil";
|
||||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
import { StatusBarMessagesContext } from "@/context/statusbar-context";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user