@camstack/addon-admin-ui 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/index.html +22 -0
  2. package/package.json +69 -0
  3. package/public/brand/logo-dark.svg +16 -0
  4. package/public/brand/logo-horizontal-dark.svg +21 -0
  5. package/public/brand/logo-horizontal-light.svg +21 -0
  6. package/public/brand/logo-light.svg +16 -0
  7. package/public/brand/logo-wide-dark.svg +24 -0
  8. package/public/brand/logo-wide-light.svg +24 -0
  9. package/public/favicon.svg +8 -0
  10. package/public/vendor/react-jsx-runtime.mjs +24 -0
  11. package/public/vendor/react.mjs +16 -0
  12. package/src/App.tsx +71 -0
  13. package/src/components/addons/AddonCard.tsx +339 -0
  14. package/src/components/addons/AddonUploadZone.tsx +307 -0
  15. package/src/components/addons/CapabilityBadge.tsx +55 -0
  16. package/src/components/addons/CapabilityMap.tsx +133 -0
  17. package/src/components/addons/UpdatesList.tsx +119 -0
  18. package/src/components/agents/AgentCard.tsx +281 -0
  19. package/src/components/agents/AgentLogs.tsx +231 -0
  20. package/src/components/agents/ProcessList.tsx +127 -0
  21. package/src/components/agents/ProcessTree.tsx +369 -0
  22. package/src/components/agents/TaskList.tsx +68 -0
  23. package/src/components/cameras/CameraCard.tsx +60 -0
  24. package/src/components/cameras/LiveEventsPanel.tsx +91 -0
  25. package/src/components/cameras/ProviderSection.tsx +50 -0
  26. package/src/components/cameras/StreamArea.tsx +107 -0
  27. package/src/components/cameras/tabs/AddonsTab.tsx +113 -0
  28. package/src/components/cameras/tabs/CameraEventsTab.tsx +129 -0
  29. package/src/components/cameras/tabs/PipelineTab.tsx +118 -0
  30. package/src/components/cameras/tabs/StreamsTab.tsx +114 -0
  31. package/src/components/dashboard/BlockPicker.tsx +54 -0
  32. package/src/components/dashboard/BlockWrapper.tsx +97 -0
  33. package/src/components/dashboard/DashboardGrid.tsx +160 -0
  34. package/src/components/dashboard/block-registry.ts +15 -0
  35. package/src/components/dashboard/blocks/PipelineStagesBlock.tsx +39 -0
  36. package/src/components/dashboard/blocks/StorageBlock.tsx +66 -0
  37. package/src/components/dashboard/blocks/SystemStatusBlock.tsx +67 -0
  38. package/src/components/dashboard/blocks/index.ts +32 -0
  39. package/src/components/device/DeviceHeader.tsx +116 -0
  40. package/src/components/device/FloatingPanel.tsx +132 -0
  41. package/src/components/device/FloatingPanelManager.tsx +167 -0
  42. package/src/components/device/PanelContent.tsx +196 -0
  43. package/src/components/device/QuickConfigWizard.tsx +507 -0
  44. package/src/components/device/tabs/DetectionConfigTab.tsx +96 -0
  45. package/src/components/device/tabs/EventsTab.tsx +19 -0
  46. package/src/components/device/tabs/LogsTab.tsx +22 -0
  47. package/src/components/device/tabs/OverviewTab.tsx +104 -0
  48. package/src/components/device/tabs/ProviderSettingsTab.tsx +34 -0
  49. package/src/components/device/tabs/RecordingTab.tsx +47 -0
  50. package/src/components/device/tabs/ReplTab.tsx +153 -0
  51. package/src/components/device/tabs/TrackTrailTab.tsx +49 -0
  52. package/src/components/device/tabs/ZonesTab.tsx +98 -0
  53. package/src/components/device/zone-editor/ZoneCanvas.tsx +354 -0
  54. package/src/components/device/zone-editor/ZoneForm.tsx +128 -0
  55. package/src/components/device/zone-editor/ZoneList.tsx +150 -0
  56. package/src/components/form-builder/FormBuilder.tsx +135 -0
  57. package/src/components/form-builder/FormField.tsx +732 -0
  58. package/src/components/form-builder/ModelSelector.tsx +239 -0
  59. package/src/components/integrations/AddDeviceDialog.tsx +205 -0
  60. package/src/components/integrations/CompactDeviceCard.tsx +35 -0
  61. package/src/components/integrations/DeviceCard.tsx +29 -0
  62. package/src/components/integrations/DeviceDiscoveryStep.tsx +105 -0
  63. package/src/components/integrations/DeviceGrid.tsx +79 -0
  64. package/src/components/integrations/DeviceGroupHeader.tsx +17 -0
  65. package/src/components/integrations/DiscoveredDeviceCard.tsx +26 -0
  66. package/src/components/integrations/IntegrationCard.tsx +40 -0
  67. package/src/components/integrations/IntegrationWizard.tsx +171 -0
  68. package/src/components/integrations/ProviderConfigForm.tsx +89 -0
  69. package/src/components/integrations/ProviderPicker.tsx +91 -0
  70. package/src/components/integrations/SnapshotPopover.tsx +68 -0
  71. package/src/components/metrics/AgentLoad.tsx +113 -0
  72. package/src/components/metrics/IntegrationUsage.tsx +90 -0
  73. package/src/components/metrics/PipelineStatus.tsx +105 -0
  74. package/src/components/metrics/ProcessResources.tsx +139 -0
  75. package/src/components/pipeline/PhaseSettings.tsx +131 -0
  76. package/src/components/shared/CapabilityBadges.tsx +30 -0
  77. package/src/components/shared/ProviderIcon.tsx +42 -0
  78. package/src/components/shared/StatusBadge.tsx +23 -0
  79. package/src/components/shared/WebRtcPlayer.tsx +211 -0
  80. package/src/components/timeline/EventMarker.tsx +32 -0
  81. package/src/components/timeline/TimelineBar.tsx +131 -0
  82. package/src/components/ui/ConfirmDialog.tsx +115 -0
  83. package/src/components/ui/ToastContainer.tsx +92 -0
  84. package/src/contexts/auth-context.tsx +91 -0
  85. package/src/hooks/useBackendClient.ts +6 -0
  86. package/src/hooks/useTheme.ts +1 -0
  87. package/src/i18n/en.json +164 -0
  88. package/src/i18n/index.ts +29 -0
  89. package/src/i18n/it.json +164 -0
  90. package/src/index.css +63 -0
  91. package/src/layouts/AddonPageLoader.tsx +120 -0
  92. package/src/layouts/AppLayout.tsx +238 -0
  93. package/src/layouts/ProtectedRoute.tsx +25 -0
  94. package/src/lib/addon-page-context.ts +29 -0
  95. package/src/lib/backend.ts +16 -0
  96. package/src/main.tsx +21 -0
  97. package/src/pages/AccessDenied.tsx +22 -0
  98. package/src/pages/Cameras.tsx +127 -0
  99. package/src/pages/Dashboard.tsx +6 -0
  100. package/src/pages/DeviceDetail.tsx +175 -0
  101. package/src/pages/IntegrationDetail.tsx +224 -0
  102. package/src/pages/Integrations.tsx +330 -0
  103. package/src/pages/Login.tsx +106 -0
  104. package/src/pages/Metrics.tsx +18 -0
  105. package/src/pages/PipelineConfig.tsx +282 -0
  106. package/src/pages/Showroom.tsx +351 -0
  107. package/src/pages/Timeline.tsx +269 -0
  108. package/src/pages/system/Addons.tsx +525 -0
  109. package/src/pages/system/Agents.tsx +362 -0
  110. package/src/pages/system/Logs.tsx +131 -0
  111. package/src/pages/system/Models.tsx +102 -0
  112. package/src/pages/system/Processes.tsx +129 -0
  113. package/src/pages/system/Repl.tsx +148 -0
  114. package/src/pages/system/Settings.tsx +168 -0
  115. package/src/pages/system/Users.tsx +174 -0
  116. package/src/server/addon.ts +54 -0
  117. package/src/types/config-ui.ts +210 -0
  118. package/src/types/dashboard.ts +39 -0
  119. package/tsconfig.json +29 -0
  120. package/tsconfig.server.json +16 -0
  121. package/tsup.config.ts +20 -0
  122. package/vite.config.ts +68 -0
package/index.html ADDED
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>CamStack Admin</title>
7
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
+ <!-- Import map: allows addon page bundles to import 'react' and get the host instance -->
9
+ <script type="importmap">
10
+ {
11
+ "imports": {
12
+ "react": "/vendor/react.mjs",
13
+ "react/jsx-runtime": "/vendor/react-jsx-runtime.mjs"
14
+ }
15
+ }
16
+ </script>
17
+ </head>
18
+ <body>
19
+ <div id="root"></div>
20
+ <script type="module" src="/src/main.tsx"></script>
21
+ </body>
22
+ </html>
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@camstack/addon-admin-ui",
3
+ "version": "0.1.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "CamStack Admin UI — Vite frontend build and server-side addon",
7
+ "exports": {
8
+ "./server/addon": {
9
+ "types": "./dist/server/addon.d.ts",
10
+ "import": "./dist/server/addon.js",
11
+ "require": "./dist/server/addon.cjs"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "camstack": {
16
+ "addons": [
17
+ {
18
+ "id": "admin-ui",
19
+ "entry": "./dist/server/addon.js",
20
+ "slot": null,
21
+ "capabilities": [
22
+ {
23
+ "name": "admin-ui",
24
+ "mode": "singleton"
25
+ }
26
+ ]
27
+ }
28
+ ]
29
+ },
30
+ "scripts": {
31
+ "dev": "vite --port 3001",
32
+ "build": "tsc --noEmit && vite build && tsup",
33
+ "build:addon": "tsup",
34
+ "preview": "vite preview",
35
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json"
36
+ },
37
+ "dependencies": {
38
+ "@camstack/sdk": "*",
39
+ "@camstack/ui-library": "*",
40
+ "@tanstack/react-query": "^5.90.0",
41
+ "clsx": "^2.1.1",
42
+ "i18next": "^25.10.3",
43
+ "konva": "^10.2.3",
44
+ "lucide-react": "^0.511.0",
45
+ "react": "^19.1.0",
46
+ "react-dom": "^19.1.0",
47
+ "react-grid-layout": "^2.2.2",
48
+ "react-i18next": "^16.6.0",
49
+ "react-konva": "^19.2.3",
50
+ "react-router-dom": "^7.13.0",
51
+ "tailwind-merge": "^3.3.0"
52
+ },
53
+ "peerDependencies": {
54
+ "@camstack/types": "^0.1.0"
55
+ },
56
+ "devDependencies": {
57
+ "@camstack/types": "*",
58
+ "@tailwindcss/vite": "^4.2.0",
59
+ "@types/node": "^22",
60
+ "@types/react": "^19.1.0",
61
+ "@types/react-dom": "^19.1.0",
62
+ "@types/react-grid-layout": "^1.3.6",
63
+ "@vitejs/plugin-react": "^4.5.0",
64
+ "tailwindcss": "^4.2.0",
65
+ "tsup": "^8.0.0",
66
+ "typescript": "^5.7.0",
67
+ "vite": "^6.3.0"
68
+ }
69
+ }
@@ -0,0 +1,16 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 48" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 2) scale(0.68)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#292524"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#44403c"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#f59e42"/>
7
+ <circle cx="32" cy="18" r="8" fill="#0c0a09" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#0c0a09" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#fafaf9" opacity="0.8"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="52" y="31" font-family="system-ui, -apple-system, sans-serif" font-size="26" font-weight="700" letter-spacing="-0.5" fill="#fafaf9">
14
+ Cam<tspan fill="#f59e42">Stack</tspan>
15
+ </text>
16
+ </svg>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 56" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 2) scale(0.8)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#292524"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#44403c"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#f59e42"/>
7
+ <circle cx="32" cy="18" r="8" fill="#0c0a09" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#0c0a09" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#fafaf9" opacity="0.8"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="62" y="30" font-family="system-ui, -apple-system, sans-serif" font-size="24" font-weight="700" letter-spacing="-0.5" fill="#fafaf9">
14
+ Cam<tspan fill="#f59e42">Stack</tspan>
15
+ </text>
16
+
17
+ <!-- Admin subtitle -->
18
+ <text x="63" y="44" font-family="system-ui, -apple-system, sans-serif" font-size="10" font-weight="600" letter-spacing="3" text-transform="uppercase" fill="#78716c">
19
+ ADMIN
20
+ </text>
21
+ </svg>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 56" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 2) scale(0.8)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#d6d3d1"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#a8a29e"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#e67e22"/>
7
+ <circle cx="32" cy="18" r="8" fill="#fafaf9" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#fafaf9" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#1c1917" opacity="0.7"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="62" y="30" font-family="system-ui, -apple-system, sans-serif" font-size="24" font-weight="700" letter-spacing="-0.5" fill="#1c1917">
14
+ Cam<tspan fill="#e67e22">Stack</tspan>
15
+ </text>
16
+
17
+ <!-- Admin subtitle -->
18
+ <text x="63" y="44" font-family="system-ui, -apple-system, sans-serif" font-size="10" font-weight="600" letter-spacing="3" fill="#78716c">
19
+ ADMIN
20
+ </text>
21
+ </svg>
@@ -0,0 +1,16 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 48" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 2) scale(0.68)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#d6d3d1"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#a8a29e"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#e67e22"/>
7
+ <circle cx="32" cy="18" r="8" fill="#fafaf9" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#fafaf9" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#1c1917" opacity="0.7"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="52" y="31" font-family="system-ui, -apple-system, sans-serif" font-size="26" font-weight="700" letter-spacing="-0.5" fill="#1c1917">
14
+ Cam<tspan fill="#e67e22">Stack</tspan>
15
+ </text>
16
+ </svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 48" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 1) scale(0.7)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#292524"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#44403c"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#f59e42"/>
7
+ <circle cx="32" cy="18" r="8" fill="#0c0a09" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#0c0a09" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#fafaf9" opacity="0.8"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="54" y="32" font-family="system-ui, -apple-system, sans-serif" font-size="28" font-weight="700" letter-spacing="-0.5" fill="#fafaf9">
14
+ Cam<tspan fill="#f59e42">Stack</tspan>
15
+ </text>
16
+
17
+ <!-- Separator dot -->
18
+ <circle cx="210" cy="26" r="2" fill="#44403c"/>
19
+
20
+ <!-- Tagline -->
21
+ <text x="220" y="31" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" letter-spacing="0.5" fill="#78716c">
22
+ Surveillance
23
+ </text>
24
+ </svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 48" fill="none">
2
+ <!-- Stacked lens icon -->
3
+ <g transform="translate(4, 1) scale(0.7)">
4
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#d6d3d1"/>
5
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#a8a29e"/>
6
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#e67e22"/>
7
+ <circle cx="32" cy="18" r="8" fill="#fafaf9" opacity="0.3"/>
8
+ <circle cx="32" cy="18" r="5" fill="#fafaf9" opacity="0.2"/>
9
+ <circle cx="32" cy="18" r="2.5" fill="#1c1917" opacity="0.7"/>
10
+ </g>
11
+
12
+ <!-- CamStack wordmark -->
13
+ <text x="54" y="32" font-family="system-ui, -apple-system, sans-serif" font-size="28" font-weight="700" letter-spacing="-0.5" fill="#1c1917">
14
+ Cam<tspan fill="#e67e22">Stack</tspan>
15
+ </text>
16
+
17
+ <!-- Separator dot -->
18
+ <circle cx="210" cy="26" r="2" fill="#d6d3d1"/>
19
+
20
+ <!-- Tagline -->
21
+ <text x="220" y="31" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" letter-spacing="0.5" fill="#78716c">
22
+ Surveillance
23
+ </text>
24
+ </svg>
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
+ <rect x="8" y="28" width="48" height="28" rx="6" fill="#292524"/>
3
+ <rect x="12" y="16" width="40" height="28" rx="6" fill="#44403c"/>
4
+ <rect x="16" y="4" width="32" height="28" rx="6" fill="#f59e42"/>
5
+ <circle cx="32" cy="18" r="8" fill="#0c0a09" opacity="0.3"/>
6
+ <circle cx="32" cy="18" r="5" fill="#0c0a09" opacity="0.2"/>
7
+ <circle cx="32" cy="18" r="2.5" fill="#fafaf9" opacity="0.8"/>
8
+ </svg>
@@ -0,0 +1,24 @@
1
+ // JSX runtime proxy — delegates to the host React's jsx-runtime
2
+ // This ensures addon pages share the same React instance as the admin UI.
3
+
4
+ import React from './react.mjs'
5
+
6
+ export const Fragment = React.Fragment
7
+
8
+ export function jsx(type, props, key) {
9
+ const { children, ...rest } = props || {}
10
+ if (key !== undefined) rest.key = key
11
+ if (children !== undefined) {
12
+ if (Array.isArray(children)) {
13
+ return React.createElement(type, rest, ...children)
14
+ }
15
+ return React.createElement(type, rest, children)
16
+ }
17
+ return React.createElement(type, rest)
18
+ }
19
+
20
+ export const jsxs = jsx
21
+
22
+ export function jsxDEV(type, props, key) {
23
+ return jsx(type, props, key)
24
+ }
@@ -0,0 +1,16 @@
1
+ // Re-export React from the global instance set by the admin UI bundle.
2
+ // This file is served statically and referenced by the import map so that
3
+ // addon page bundles can `import { useState } from 'react'` and get the
4
+ // same React instance used by the host application.
5
+
6
+ const React = window.__camstackReact
7
+ export const {
8
+ Children, Component, Fragment, Profiler, PureComponent, StrictMode, Suspense,
9
+ cloneElement, createContext, createElement, createFactory, createRef,
10
+ forwardRef, isValidElement, lazy, memo, startTransition,
11
+ unstable_act, useCallback, useContext, useDebugValue, useDeferredValue,
12
+ useEffect, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect,
13
+ useMemo, useReducer, useRef, useState, useSyncExternalStore, useTransition,
14
+ version,
15
+ } = React
16
+ export default React
package/src/App.tsx ADDED
@@ -0,0 +1,71 @@
1
+ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
2
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
3
+ import { ThemeProvider } from '@camstack/ui'
4
+ import { AuthProvider } from './contexts/auth-context'
5
+ import { ProtectedRoute } from './layouts/ProtectedRoute'
6
+ import { AppLayout } from './layouts/AppLayout'
7
+ import { LoginPage } from './pages/Login'
8
+ import { AccessDeniedPage } from './pages/AccessDenied'
9
+ import { DashboardPage } from './pages/Dashboard'
10
+ import { CamerasPage } from './pages/Cameras'
11
+ import { IntegrationsPage } from './pages/Integrations'
12
+ import { IntegrationDetailPage } from './pages/IntegrationDetail'
13
+ import { TimelinePage } from './pages/Timeline'
14
+ import { PipelineConfigPage } from './pages/PipelineConfig'
15
+ import { DeviceDetailPage } from './pages/DeviceDetail'
16
+ import { AddonsPage } from './pages/system/Addons'
17
+ import { AgentsPage } from './pages/system/Agents'
18
+ import { LogsPage } from './pages/system/Logs'
19
+ import { UsersPage } from './pages/system/Users'
20
+ import { SettingsPage } from './pages/system/Settings'
21
+ import { ShowroomPage } from './pages/Showroom'
22
+ import { AddonPageLoader } from './layouts/AddonPageLoader'
23
+ import { ConfirmDialogProvider } from './components/ui/ConfirmDialog'
24
+ import { ToastContainer } from './components/ui/ToastContainer'
25
+
26
+ const queryClient = new QueryClient({
27
+ defaultOptions: {
28
+ queries: {
29
+ staleTime: 30_000,
30
+ retry: false,
31
+ refetchOnWindowFocus: false,
32
+ },
33
+ },
34
+ })
35
+
36
+ export function App() {
37
+ return (
38
+ <ThemeProvider defaultMode="dark">
39
+ <QueryClientProvider client={queryClient}>
40
+ <ConfirmDialogProvider>
41
+ <AuthProvider>
42
+ <BrowserRouter>
43
+ <Routes>
44
+ <Route path="/login" element={<LoginPage />} />
45
+ <Route path="/access-denied" element={<AccessDeniedPage />} />
46
+ <Route path="/showroom" element={<ShowroomPage />} />
47
+ <Route element={<ProtectedRoute><AppLayout /></ProtectedRoute>}>
48
+ <Route index element={<Navigate to="/dashboard" replace />} />
49
+ <Route path="/dashboard" element={<DashboardPage />} />
50
+ <Route path="/cameras" element={<CamerasPage />} />
51
+ <Route path="/integrations" element={<IntegrationsPage />} />
52
+ <Route path="/integrations/:integrationId" element={<IntegrationDetailPage />} />
53
+ <Route path="/timeline" element={<TimelinePage />} />
54
+ <Route path="/pipeline" element={<PipelineConfigPage />} />
55
+ <Route path="/devices/:deviceId" element={<DeviceDetailPage />} />
56
+ <Route path="/system/agents" element={<ProtectedRoute requiredRole="admin"><AgentsPage /></ProtectedRoute>} />
57
+ <Route path="/system/logs" element={<ProtectedRoute requiredRole="admin"><LogsPage /></ProtectedRoute>} />
58
+ <Route path="/system/users" element={<ProtectedRoute requiredRole="admin"><UsersPage /></ProtectedRoute>} />
59
+ <Route path="/system/settings" element={<ProtectedRoute requiredRole="admin"><SettingsPage /></ProtectedRoute>} />
60
+ <Route path="/system/addons" element={<ProtectedRoute requiredRole="admin"><AddonsPage /></ProtectedRoute>} />
61
+ <Route path="/addon/:pagePath" element={<ProtectedRoute requiredRole="admin"><AddonPageLoader /></ProtectedRoute>} />
62
+ </Route>
63
+ </Routes>
64
+ </BrowserRouter>
65
+ <ToastContainer />
66
+ </AuthProvider>
67
+ </ConfirmDialogProvider>
68
+ </QueryClientProvider>
69
+ </ThemeProvider>
70
+ )
71
+ }