mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-09 23:15:28 +03:00
Compare commits
No commits in common. "7b6d0c5e4258dc62f7e81b973fcfe2ee32265a5e" and "59f570f4360b10389c2bfe3e7ce0bdfd472714bf" have entirely different histories.
7b6d0c5e42
...
59f570f436
3
.github/workflows/pull_request.yml
vendored
3
.github/workflows/pull_request.yml
vendored
@ -27,9 +27,6 @@ jobs:
|
|||||||
- name: Lint
|
- name: Lint
|
||||||
run: npm run lint
|
run: npm run lint
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
- name: Check i18n keys
|
|
||||||
run: npm run i18n:extract:ci
|
|
||||||
working-directory: ./web
|
|
||||||
|
|
||||||
web_test:
|
web_test:
|
||||||
name: Web - Test
|
name: Web - Test
|
||||||
|
|||||||
@ -59,14 +59,12 @@ ARG ROCM
|
|||||||
# Copy HIP headers required for MIOpen JIT (BuildHip) / HIPRTC at runtime
|
# Copy HIP headers required for MIOpen JIT (BuildHip) / HIPRTC at runtime
|
||||||
COPY --from=rocm /opt/rocm-${ROCM}/include/ /opt/rocm-${ROCM}/include/
|
COPY --from=rocm /opt/rocm-${ROCM}/include/ /opt/rocm-${ROCM}/include/
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/bin/rocminfo /opt/rocm-$ROCM/bin/migraphx-driver /opt/rocm-$ROCM/bin/
|
COPY --from=rocm /opt/rocm-$ROCM/bin/rocminfo /opt/rocm-$ROCM/bin/migraphx-driver /opt/rocm-$ROCM/bin/
|
||||||
# Copy MIOpen database files for gfx10xx, gfx11xx, and gfx12xx only (RDNA2/RDNA3/RDNA4)
|
# Copy MIOpen database files for gfx10xx and gfx11xx only (RDNA2/RDNA3)
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*gfx10* /opt/rocm-$ROCM/share/miopen/db/
|
COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*gfx10* /opt/rocm-$ROCM/share/miopen/db/
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*gfx11* /opt/rocm-$ROCM/share/miopen/db/
|
COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*gfx11* /opt/rocm-$ROCM/share/miopen/db/
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*gfx12* /opt/rocm-$ROCM/share/miopen/db/
|
# Copy rocBLAS library files for gfx10xx and gfx11xx only
|
||||||
# Copy rocBLAS library files for gfx10xx, gfx11xx, and gfx12xx only
|
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*gfx10* /opt/rocm-$ROCM/lib/rocblas/library/
|
COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*gfx10* /opt/rocm-$ROCM/lib/rocblas/library/
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*gfx11* /opt/rocm-$ROCM/lib/rocblas/library/
|
COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*gfx11* /opt/rocm-$ROCM/lib/rocblas/library/
|
||||||
COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*gfx12* /opt/rocm-$ROCM/lib/rocblas/library/
|
|
||||||
COPY --from=rocm /opt/rocm-dist/ /
|
COPY --from=rocm /opt/rocm-dist/ /
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
import { defineConfig, type Plugin } from "i18next-cli";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugin to remove false positive keys generated by dynamic namespace patterns
|
|
||||||
* like useTranslation([i18nLibrary]) and t("key", { ns: configNamespace }).
|
|
||||||
* These keys already exist in their correct runtime namespaces.
|
|
||||||
*/
|
|
||||||
function ignoreDynamicNamespaceKeys(): Plugin {
|
|
||||||
// Keys that the extractor misattributes to the wrong namespace
|
|
||||||
// because it can't resolve dynamic ns values at build time.
|
|
||||||
const falsePositiveKeys = new Set([
|
|
||||||
// From useTranslation([i18nLibrary]) in ClassificationCard.tsx
|
|
||||||
// Already in views/classificationModel and views/faceLibrary
|
|
||||||
"details.unknown",
|
|
||||||
"details.none",
|
|
||||||
// From t("key", { ns: configNamespace }) in DetectorHardwareField.tsx
|
|
||||||
// Already in config/global
|
|
||||||
"detectors.type.label",
|
|
||||||
// From t(`${prefix}`) template literals producing empty/partial keys
|
|
||||||
"",
|
|
||||||
"_one",
|
|
||||||
"_other",
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: "ignore-dynamic-namespace-keys",
|
|
||||||
onEnd: async (keys) => {
|
|
||||||
for (const key of keys.keys()) {
|
|
||||||
// Each map key is "ns:actualKey" format
|
|
||||||
const separatorIndex = key.indexOf(":");
|
|
||||||
const actualKey =
|
|
||||||
separatorIndex >= 0 ? key.slice(separatorIndex + 1) : key;
|
|
||||||
if (falsePositiveKeys.has(actualKey)) {
|
|
||||||
keys.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
locales: ["en"],
|
|
||||||
extract: {
|
|
||||||
input: ["src/**/*.{ts,tsx}"],
|
|
||||||
output: "public/locales/{{language}}/{{namespace}}.json",
|
|
||||||
defaultNS: "common",
|
|
||||||
removeUnusedKeys: false,
|
|
||||||
sort: false,
|
|
||||||
},
|
|
||||||
plugins: [ignoreDynamicNamespaceKeys()],
|
|
||||||
});
|
|
||||||
1446
web/package-lock.json
generated
1446
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,14 +12,11 @@
|
|||||||
"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",
|
"test": "vitest",
|
||||||
"coverage": "vitest run --coverage",
|
"coverage": "vitest run --coverage"
|
||||||
"i18n:extract": "i18next-cli extract",
|
|
||||||
"i18n:extract:ci": "i18next-cli extract --ci",
|
|
||||||
"i18n:status": "i18next-cli status"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
||||||
"@hookform/resolvers": "^3.10.0",
|
"@hookform/resolvers": "^3.9.0",
|
||||||
"@melloware/react-logviewer": "^6.1.2",
|
"@melloware/react-logviewer": "^6.1.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
||||||
@ -43,38 +40,38 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.2",
|
"@radix-ui/react-toggle": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@rjsf/core": "^6.4.1",
|
"@rjsf/core": "^6.3.1",
|
||||||
"@rjsf/shadcn": "^6.4.1",
|
"@rjsf/shadcn": "^6.3.1",
|
||||||
"@rjsf/utils": "^6.4.1",
|
"@rjsf/utils": "^6.3.1",
|
||||||
"@rjsf/validator-ajv8": "^6.4.1",
|
"@rjsf/validator-ajv8": "^6.3.1",
|
||||||
"apexcharts": "^3.52.0",
|
"apexcharts": "^3.52.0",
|
||||||
"axios": "^1.13.6",
|
"axios": "^1.7.7",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
"copy-to-clipboard": "^3.3.3",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"framer-motion": "^12.38.0",
|
"framer-motion": "^12.35.0",
|
||||||
"hls.js": "^1.6.15",
|
"hls.js": "^1.5.20",
|
||||||
"i18next": "^24.2.0",
|
"i18next": "^24.2.0",
|
||||||
"i18next-http-backend": "^3.0.1",
|
"i18next-http-backend": "^3.0.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"konva": "^10.2.3",
|
"konva": "^9.3.18",
|
||||||
"lodash": "^4.17.23",
|
"lodash": "^4.17.23",
|
||||||
"lucide-react": "^0.577.0",
|
"lucide-react": "^0.477.0",
|
||||||
"monaco-yaml": "^5.4.1",
|
"monaco-yaml": "^5.3.1",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"nosleep.js": "^0.12.0",
|
"nosleep.js": "^0.12.0",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-apexcharts": "^1.4.1",
|
"react-apexcharts": "^1.4.1",
|
||||||
"react-day-picker": "^9.14.0",
|
"react-day-picker": "^9.7.0",
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-grid-layout": "^2.2.2",
|
"react-grid-layout": "^2.2.2",
|
||||||
"react-hook-form": "^7.72.0",
|
"react-hook-form": "^7.52.1",
|
||||||
"react-i18next": "^15.2.0",
|
"react-i18next": "^15.2.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-konva": "^19.2.3",
|
"react-konva": "^19.2.3",
|
||||||
@ -87,7 +84,7 @@
|
|||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"sort-by": "^1.2.0",
|
"sort-by": "^1.2.0",
|
||||||
"strftime": "^0.10.3",
|
"strftime": "^0.10.3",
|
||||||
"swr": "^2.4.1",
|
"swr": "^2.3.2",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^2.4.0",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
@ -117,13 +114,12 @@
|
|||||||
"eslint-plugin-react-refresh": "^0.4.8",
|
"eslint-plugin-react-refresh": "^0.4.8",
|
||||||
"eslint-plugin-vitest-globals": "^1.5.0",
|
"eslint-plugin-vitest-globals": "^1.5.0",
|
||||||
"fake-indexeddb": "^6.0.0",
|
"fake-indexeddb": "^6.0.0",
|
||||||
"i18next-cli": "^1.5.11",
|
|
||||||
"jest-websocket-mock": "^2.5.0",
|
"jest-websocket-mock": "^2.5.0",
|
||||||
"jsdom": "^24.1.1",
|
"jsdom": "^24.1.1",
|
||||||
"monaco-editor": "^0.52.2",
|
"monaco-editor": "^0.52.0",
|
||||||
"msw": "^2.3.5",
|
"msw": "^2.3.5",
|
||||||
"patch-package": "^8.0.1",
|
"patch-package": "^8.0.1",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.4.47",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
"tailwindcss": "^3.4.9",
|
"tailwindcss": "^3.4.9",
|
||||||
|
|||||||
@ -161,8 +161,7 @@
|
|||||||
"resetToDefault": "Reset to Default",
|
"resetToDefault": "Reset to Default",
|
||||||
"saveAll": "Save All",
|
"saveAll": "Save All",
|
||||||
"savingAll": "Saving All…",
|
"savingAll": "Saving All…",
|
||||||
"undoAll": "Undo All",
|
"undoAll": "Undo All"
|
||||||
"retry": "Retry"
|
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"system": "System",
|
"system": "System",
|
||||||
@ -276,8 +275,7 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"title": "Failed to save config changes: {{errorMessage}}",
|
"title": "Failed to save config changes: {{errorMessage}}",
|
||||||
"noMessage": "Failed to save config changes"
|
"noMessage": "Failed to save config changes"
|
||||||
},
|
}
|
||||||
"success": "Successfully saved config changes."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"role": {
|
"role": {
|
||||||
@ -312,7 +310,5 @@
|
|||||||
"readTheDocumentation": "Read the documentation",
|
"readTheDocumentation": "Read the documentation",
|
||||||
"information": {
|
"information": {
|
||||||
"pixels": "{{area}}px"
|
"pixels": "{{area}}px"
|
||||||
},
|
}
|
||||||
"no_items": "No items",
|
|
||||||
"validation_errors": "Validation Errors"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,6 @@
|
|||||||
"zones": "Zones",
|
"zones": "Zones",
|
||||||
"mask": "Mask",
|
"mask": "Mask",
|
||||||
"motion": "Motion",
|
"motion": "Motion",
|
||||||
"regions": "Regions",
|
"regions": "Regions"
|
||||||
"paths": "Paths"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,17 +23,15 @@
|
|||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"success": {
|
"success": {
|
||||||
|
"deletedCategory": "Deleted Class",
|
||||||
|
"deletedImage": "Deleted Images",
|
||||||
"deletedModel_one": "Successfully deleted {{count}} model",
|
"deletedModel_one": "Successfully deleted {{count}} model",
|
||||||
"deletedModel_other": "Successfully deleted {{count}} models",
|
"deletedModel_other": "Successfully deleted {{count}} models",
|
||||||
"categorizedImage": "Successfully Classified Image",
|
"categorizedImage": "Successfully Classified Image",
|
||||||
"trainedModel": "Successfully trained model.",
|
"trainedModel": "Successfully trained model.",
|
||||||
"trainingModel": "Successfully started model training.",
|
"trainingModel": "Successfully started model training.",
|
||||||
"updatedModel": "Successfully updated model configuration",
|
"updatedModel": "Successfully updated model configuration",
|
||||||
"renamedCategory": "Successfully renamed class to {{name}}",
|
"renamedCategory": "Successfully renamed class to {{name}}"
|
||||||
"deletedCategory_one": "Deleted {{count}} class",
|
|
||||||
"deletedCategory_other": "Deleted {{count}} classes",
|
|
||||||
"deletedImage_one": "Deleted {{count}} image",
|
|
||||||
"deletedImage_other": "Deleted {{count}} images"
|
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"deleteImageFailed": "Failed to delete: {{errorMessage}}",
|
"deleteImageFailed": "Failed to delete: {{errorMessage}}",
|
||||||
|
|||||||
@ -15,10 +15,8 @@
|
|||||||
"description": "Review items can only be created for a camera when recordings are enabled for that camera."
|
"description": "Review items can only be created for a camera when recordings are enabled for that camera."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": "Timeline",
|
||||||
"label": "Timeline",
|
"timeline.aria": "Select timeline",
|
||||||
"aria": "Select timeline"
|
|
||||||
},
|
|
||||||
"zoomIn": "Zoom In",
|
"zoomIn": "Zoom In",
|
||||||
"zoomOut": "Zoom Out",
|
"zoomOut": "Zoom Out",
|
||||||
"events": {
|
"events": {
|
||||||
|
|||||||
@ -169,8 +169,7 @@
|
|||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"label": "Title"
|
"label": "Title"
|
||||||
},
|
}
|
||||||
"scoreInfo": "Score Information"
|
|
||||||
},
|
},
|
||||||
"itemMenu": {
|
"itemMenu": {
|
||||||
"downloadVideo": {
|
"downloadVideo": {
|
||||||
@ -221,18 +220,12 @@
|
|||||||
"debugReplay": {
|
"debugReplay": {
|
||||||
"label": "Debug replay",
|
"label": "Debug replay",
|
||||||
"aria": "View this tracked object in the debug replay view"
|
"aria": "View this tracked object in the debug replay view"
|
||||||
},
|
|
||||||
"more": {
|
|
||||||
"aria": "More"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"confirmDelete": {
|
"confirmDelete": {
|
||||||
"title": "Confirm Delete",
|
"title": "Confirm Delete",
|
||||||
"desc": "Deleting this tracked object removes the snapshot, any saved embeddings, and any associated tracking details entries. Recorded footage of this tracked object in History view will <em>NOT</em> be deleted.<br /><br />Are you sure you want to proceed?"
|
"desc": "Deleting this tracked object removes the snapshot, any saved embeddings, and any associated tracking details entries. Recorded footage of this tracked object in History view will <em>NOT</em> be deleted.<br /><br />Are you sure you want to proceed?"
|
||||||
},
|
|
||||||
"toast": {
|
|
||||||
"error": "Error deleting this tracked object: {{errorMessage}}"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"noTrackedObjects": "No Tracked Objects Found",
|
"noTrackedObjects": "No Tracked Objects Found",
|
||||||
@ -255,8 +248,5 @@
|
|||||||
},
|
},
|
||||||
"concerns": {
|
"concerns": {
|
||||||
"label": "Concerns"
|
"label": "Concerns"
|
||||||
},
|
|
||||||
"objectLifecycle": {
|
|
||||||
"noImageFound": "No image found for this tracked object."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,8 @@
|
|||||||
"cases": "Cases",
|
"cases": "Cases",
|
||||||
"uncategorizedExports": "Uncategorized Exports"
|
"uncategorizedExports": "Uncategorized Exports"
|
||||||
},
|
},
|
||||||
"deleteExport": {
|
"deleteExport": "Delete Export",
|
||||||
"label": "Delete Export",
|
"deleteExport.desc": "Are you sure you want to delete {{exportName}}?",
|
||||||
"desc": "Are you sure you want to delete {{exportName}}?"
|
|
||||||
},
|
|
||||||
"editExport": {
|
"editExport": {
|
||||||
"title": "Rename Export",
|
"title": "Rename Export",
|
||||||
"desc": "Enter a new name for this export.",
|
"desc": "Enter a new name for this export.",
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"documentTitle": {
|
"documentTitle": "Live - Frigate",
|
||||||
"default": "Live - Frigate",
|
"documentTitle.withCamera": "{{camera}} - Live - Frigate",
|
||||||
"withCamera": "{{camera}} - Live - Frigate"
|
|
||||||
},
|
|
||||||
"lowBandwidthMode": "Low-bandwidth Mode",
|
"lowBandwidthMode": "Low-bandwidth Mode",
|
||||||
"twoWayTalk": {
|
"twoWayTalk": {
|
||||||
"enable": "Enable Two Way Talk",
|
"enable": "Enable Two Way Talk",
|
||||||
|
|||||||
@ -515,6 +515,7 @@
|
|||||||
"reviewClassification": {
|
"reviewClassification": {
|
||||||
"title": "Review Classification",
|
"title": "Review Classification",
|
||||||
"desc": "Frigate categorizes review items as Alerts and Detections. By default, all <em>person</em> and <em>car</em> objects are considered Alerts. You can refine categorization of your review items by configuring required zones for them.",
|
"desc": "Frigate categorizes review items as Alerts and Detections. By default, all <em>person</em> and <em>car</em> objects are considered Alerts. You can refine categorization of your review items by configuring required zones for them.",
|
||||||
|
|
||||||
"noDefinedZones": "No zones are defined for this camera.",
|
"noDefinedZones": "No zones are defined for this camera.",
|
||||||
"objectAlertsTips": "All {{alertsLabels}} objects on {{cameraName}} will be shown as Alerts.",
|
"objectAlertsTips": "All {{alertsLabels}} objects on {{cameraName}} will be shown as Alerts.",
|
||||||
"zoneObjectAlertsTips": "All {{alertsLabels}} objects detected in {{zone}} on {{cameraName}} will be shown as Alerts.",
|
"zoneObjectAlertsTips": "All {{alertsLabels}} objects detected in {{zone}} on {{cameraName}} will be shown as Alerts.",
|
||||||
@ -552,17 +553,6 @@
|
|||||||
"motionMaskLabel": "Motion Mask {{number}}",
|
"motionMaskLabel": "Motion Mask {{number}}",
|
||||||
"objectMaskLabel": "Object Mask {{number}}",
|
"objectMaskLabel": "Object Mask {{number}}",
|
||||||
"form": {
|
"form": {
|
||||||
"id": {
|
|
||||||
"error": {
|
|
||||||
"mustNotBeEmpty": "ID must not be empty.",
|
|
||||||
"alreadyExists": "A mask with this ID already exists for this camera."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"error": {
|
|
||||||
"mustNotBeEmpty": "Name must not be empty."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"zoneName": {
|
"zoneName": {
|
||||||
"error": {
|
"error": {
|
||||||
"mustBeAtLeastTwoCharacters": "Zone name must be at least 2 characters.",
|
"mustBeAtLeastTwoCharacters": "Zone name must be at least 2 characters.",
|
||||||
@ -1296,8 +1286,7 @@
|
|||||||
},
|
},
|
||||||
"camera": {
|
"camera": {
|
||||||
"title": "Camera Settings",
|
"title": "Camera Settings",
|
||||||
"description": "These settings apply only to this camera and override the global settings.",
|
"description": "These settings apply only to this camera and override the global settings."
|
||||||
"noCameras": "No cameras available"
|
|
||||||
},
|
},
|
||||||
"advancedSettingsCount": "Advanced Settings ({{count}})",
|
"advancedSettingsCount": "Advanced Settings ({{count}})",
|
||||||
"advancedCount": "Advanced ({{count}})",
|
"advancedCount": "Advanced ({{count}})",
|
||||||
|
|||||||
@ -35,8 +35,7 @@
|
|||||||
"cameras_count_other": "{{count}} Cameras"
|
"cameras_count_other": "{{count}} Cameras"
|
||||||
},
|
},
|
||||||
"empty": "No messages captured yet",
|
"empty": "No messages captured yet",
|
||||||
"count_one": "{{count}} message",
|
"count": "{{count}} messages",
|
||||||
"count_other": "{{count}} messages",
|
|
||||||
"expanded": {
|
"expanded": {
|
||||||
"payload": "Payload"
|
"payload": "Payload"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ export default function DeleteRoleDialog({
|
|||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
<p>
|
<p>
|
||||||
<Trans
|
<Trans
|
||||||
ns="views/settings"
|
ns={"views/settings"}
|
||||||
values={{ role }}
|
values={{ role }}
|
||||||
components={{ strong: <span className="font-medium" /> }}
|
components={{ strong: <span className="font-medium" /> }}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export default function DeleteTriggerDialog({
|
|||||||
<DialogTitle>{t("triggers.dialog.deleteTrigger.title")}</DialogTitle>
|
<DialogTitle>{t("triggers.dialog.deleteTrigger.title")}</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
<Trans
|
<Trans
|
||||||
ns="views/settings"
|
ns={"views/settings"}
|
||||||
values={{ triggerName }}
|
values={{ triggerName }}
|
||||||
components={{ strong: <span className="font-medium" /> }}
|
components={{ strong: <span className="font-medium" /> }}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -90,7 +90,7 @@ export default function EditRoleCamerasDialog({
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
<Trans
|
<Trans
|
||||||
ns="views/settings"
|
ns={"views/settings"}
|
||||||
values={{ role }}
|
values={{ role }}
|
||||||
components={{ strong: <span className="font-medium" /> }}
|
components={{ strong: <span className="font-medium" /> }}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export default function MobileTimelineDrawer({
|
|||||||
setDrawer(false);
|
setDrawer(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("timeline.label")}
|
{t("timeline")}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`mx-4 w-full py-2 text-center smart-capitalize ${selected == "events" ? "rounded-lg bg-secondary" : ""}`}
|
className={`mx-4 w-full py-2 text-center smart-capitalize ${selected == "events" ? "rounded-lg bg-secondary" : ""}`}
|
||||||
|
|||||||
@ -494,7 +494,7 @@ export default function CameraEditForm({
|
|||||||
<CardContent className="space-y-4 p-4">
|
<CardContent className="space-y-4 p-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="font-medium">
|
<h4 className="font-medium">
|
||||||
{t("cameraWizard.step3.streamTitle", {
|
{t("cameraWizard.step2.streamTitle", {
|
||||||
number: index + 1,
|
number: index + 1,
|
||||||
})}
|
})}
|
||||||
</h4>
|
</h4>
|
||||||
|
|||||||
@ -338,8 +338,8 @@ export default function CameraWizardDialog({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.success(
|
toast.success(
|
||||||
t("cameraWizard.save.success", {
|
t("camera.cameraConfig.toast.success", {
|
||||||
cameraName: friendlyName || finalCameraName,
|
cameraName: wizardData.cameraName,
|
||||||
}),
|
}),
|
||||||
{ position: "top-center" },
|
{ position: "top-center" },
|
||||||
);
|
);
|
||||||
|
|||||||
@ -785,7 +785,7 @@ export default function ZoneEditPane({
|
|||||||
</div>
|
</div>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t("masksAndZones.zones.speedEstimation.desc")}
|
{t("masksAndZones.zones.speedEstimation.desc")}
|
||||||
<span className="mt-2 flex items-center text-primary">
|
<div className="mt-2 flex items-center text-primary">
|
||||||
<Link
|
<Link
|
||||||
to={getLocaleDocUrl(
|
to={getLocaleDocUrl(
|
||||||
"configuration/zones#speed-estimation",
|
"configuration/zones#speed-estimation",
|
||||||
@ -797,7 +797,7 @@ export default function ZoneEditPane({
|
|||||||
{t("readTheDocumentation", { ns: "common" })}
|
{t("readTheDocumentation", { ns: "common" })}
|
||||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</div>
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@ -220,7 +220,7 @@ function Exports() {
|
|||||||
>
|
>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>{t("deleteExport.label")}</AlertDialogTitle>
|
<AlertDialogTitle>{t("deleteExport")}</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
{t("deleteExport.desc", { exportName: deleteClip?.exportName })}
|
{t("deleteExport.desc", { exportName: deleteClip?.exportName })}
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
|
|||||||
@ -81,7 +81,7 @@ function Live() {
|
|||||||
camera: `${cameraGroup[0].toUpperCase()}${cameraGroup.substring(1)}`,
|
camera: `${cameraGroup[0].toUpperCase()}${cameraGroup.substring(1)}`,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
document.title = t("documentTitle.default", { ns: "views/live" });
|
document.title = t("documentTitle", { ns: "views/live" });
|
||||||
}
|
}
|
||||||
}, [cameraGroup, selectedCameraName, t]);
|
}, [cameraGroup, selectedCameraName, t]);
|
||||||
|
|
||||||
|
|||||||
@ -1397,12 +1397,10 @@ export default function Settings() {
|
|||||||
: "bg-selected";
|
: "bg-selected";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full min-w-0 items-center justify-between pr-4 md:pr-0">
|
<div className="flex w-full items-center justify-between pr-4 md:pr-0">
|
||||||
<div className="min-w-0 flex-1 whitespace-normal break-words">
|
<div>{t("menu." + key)}</div>
|
||||||
{t("menu." + key)}
|
|
||||||
</div>
|
|
||||||
{(showOverrideDot || showUnsavedDot) && (
|
{(showOverrideDot || showUnsavedDot) && (
|
||||||
<div className="ml-2 flex shrink-0 items-center gap-2">
|
<div className="ml-2 flex items-center gap-2">
|
||||||
{showOverrideDot && (
|
{showOverrideDot && (
|
||||||
<span
|
<span
|
||||||
className={cn("inline-block size-2 rounded-full", dotColor)}
|
className={cn("inline-block size-2 rounded-full", dotColor)}
|
||||||
@ -1749,7 +1747,7 @@ export default function Settings() {
|
|||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
className="ml-0 h-auto min-h-8 py-1.5"
|
className="ml-0"
|
||||||
isActive={pageToggle === filteredItems[0].key}
|
isActive={pageToggle === filteredItems[0].key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (
|
if (
|
||||||
@ -1790,7 +1788,6 @@ export default function Settings() {
|
|||||||
{filteredItems.map((item) => (
|
{filteredItems.map((item) => (
|
||||||
<SidebarMenuSubItem key={item.key}>
|
<SidebarMenuSubItem key={item.key}>
|
||||||
<SidebarMenuSubButton
|
<SidebarMenuSubButton
|
||||||
className="h-auto w-full py-1.5"
|
|
||||||
isActive={pageToggle === item.key}
|
isActive={pageToggle === item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { TFunction } from "i18next";
|
|
||||||
|
|
||||||
export const calculatePasswordStrength = (password: string): number => {
|
export const calculatePasswordStrength = (password: string): number => {
|
||||||
if (!password) return 0;
|
if (!password) return 0;
|
||||||
|
|
||||||
@ -18,18 +16,13 @@ export const getPasswordRequirements = (password: string) => ({
|
|||||||
|
|
||||||
export const getPasswordStrengthLabel = (
|
export const getPasswordStrengthLabel = (
|
||||||
password: string,
|
password: string,
|
||||||
t: TFunction,
|
t: (key: string) => string,
|
||||||
): string => {
|
): string => {
|
||||||
const strength = calculatePasswordStrength(password);
|
const strength = calculatePasswordStrength(password);
|
||||||
|
|
||||||
if (!password) return "";
|
if (!password) return "";
|
||||||
if (strength < 1)
|
if (strength < 1) return t("users.dialog.form.password.strength.weak");
|
||||||
return t("users.dialog.form.password.strength.weak", {
|
return t("users.dialog.form.password.strength.veryStrong");
|
||||||
ns: "views/settings",
|
|
||||||
});
|
|
||||||
return t("users.dialog.form.password.strength.veryStrong", {
|
|
||||||
ns: "views/settings",
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPasswordStrengthColor = (password: string): string => {
|
export const getPasswordStrengthColor = (password: string): string => {
|
||||||
|
|||||||
@ -700,7 +700,7 @@ export function RecordingView({
|
|||||||
value="timeline"
|
value="timeline"
|
||||||
aria-label={t("timeline.aria")}
|
aria-label={t("timeline.aria")}
|
||||||
>
|
>
|
||||||
<div className="">{t("timeline.label")}</div>
|
<div className="">{t("timeline")}</div>
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
<ToggleGroupItem
|
<ToggleGroupItem
|
||||||
className={`${timelineType == "events" ? "" : "text-muted-foreground"}`}
|
className={`${timelineType == "events" ? "" : "text-muted-foreground"}`}
|
||||||
|
|||||||
@ -618,7 +618,7 @@ export default function ProfilesView({
|
|||||||
ns: "views/settings",
|
ns: "views/settings",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<DialogFooter className="gap-2 md:gap-0">
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user