@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
@@ -0,0 +1,135 @@
1
+ import { useState } from 'react'
2
+ import type { ConfigUISchema, ConfigSection } from '../../types/config-ui'
3
+ import { FormField } from './FormField'
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Translation support
7
+ // ---------------------------------------------------------------------------
8
+
9
+ /**
10
+ * Optional function that resolves an i18n key to a translated string.
11
+ * When provided, labels and descriptions that look like i18n keys
12
+ * (contain at least one dot, e.g. 'addon.settings.title') are passed
13
+ * through this function. Plain text labels are returned as-is.
14
+ */
15
+ export type TranslationFn = (key: string) => string
16
+
17
+ /** Returns true if the string looks like an i18n key (contains a dot separator) */
18
+ function isI18nKey(value: string): boolean {
19
+ return /^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+$/.test(value)
20
+ }
21
+
22
+ /** Resolve a label/description through the translation function if applicable */
23
+ export function resolveLabel(value: string | undefined, t?: TranslationFn): string | undefined {
24
+ if (value === undefined) return undefined
25
+ if (t && isI18nKey(value)) return t(value)
26
+ return value
27
+ }
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Props
31
+ // ---------------------------------------------------------------------------
32
+
33
+ interface FormBuilderProps {
34
+ schema: ConfigUISchema
35
+ values: Record<string, unknown>
36
+ onChange: (values: Record<string, unknown>) => void
37
+ disabled?: boolean
38
+ /** Optional translation function for resolving i18n keys in labels and descriptions */
39
+ translationFn?: TranslationFn
40
+ }
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Section renderer
44
+ // ---------------------------------------------------------------------------
45
+
46
+ function SectionCard({
47
+ section,
48
+ values,
49
+ onChange,
50
+ disabled,
51
+ translationFn,
52
+ }: {
53
+ section: ConfigSection
54
+ values: Record<string, unknown>
55
+ onChange: (key: string, value: unknown) => void
56
+ disabled?: boolean
57
+ translationFn?: TranslationFn
58
+ }) {
59
+ const [collapsed, setCollapsed] = useState(section.defaultCollapsed ?? false)
60
+ const isAccordion = section.style === 'accordion'
61
+
62
+ const columns = section.columns ?? 2
63
+ const gridClass =
64
+ columns === 1
65
+ ? 'grid-cols-1'
66
+ : columns === 3
67
+ ? 'grid-cols-3'
68
+ : columns === 4
69
+ ? 'grid-cols-4'
70
+ : 'grid-cols-2'
71
+
72
+ return (
73
+ <div className="rounded-lg border border-border bg-surface p-4">
74
+ <div
75
+ className={[
76
+ 'flex items-center justify-between mb-3',
77
+ isAccordion ? 'cursor-pointer' : '',
78
+ ].join(' ')}
79
+ onClick={isAccordion ? () => setCollapsed((c) => !c) : undefined}
80
+ >
81
+ <div>
82
+ <h3 className="text-xs font-semibold text-foreground-subtle uppercase tracking-wider">
83
+ {resolveLabel(section.title, translationFn)}
84
+ </h3>
85
+ {section.description && (
86
+ <p className="text-[10px] text-foreground-subtle mt-0.5">{resolveLabel(section.description, translationFn)}</p>
87
+ )}
88
+ </div>
89
+ {isAccordion && (
90
+ <span className="text-foreground-subtle text-xs ml-2">{collapsed ? '▸' : '▾'}</span>
91
+ )}
92
+ </div>
93
+
94
+ {!collapsed && (
95
+ <div className={`grid ${gridClass} gap-x-4 gap-y-3`}>
96
+ {section.fields.map((field) => (
97
+ <FormField
98
+ key={field.key}
99
+ field={field}
100
+ values={values}
101
+ onChange={onChange}
102
+ disabled={disabled}
103
+ translationFn={translationFn}
104
+ />
105
+ ))}
106
+ </div>
107
+ )}
108
+ </div>
109
+ )
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // FormBuilder
114
+ // ---------------------------------------------------------------------------
115
+
116
+ export function FormBuilder({ schema, values, onChange, disabled, translationFn }: FormBuilderProps) {
117
+ const handleFieldChange = (key: string, value: unknown) => {
118
+ onChange({ ...values, [key]: value })
119
+ }
120
+
121
+ return (
122
+ <div className="space-y-4">
123
+ {schema.sections.map((section) => (
124
+ <SectionCard
125
+ key={section.id}
126
+ section={section}
127
+ values={values}
128
+ onChange={handleFieldChange}
129
+ disabled={disabled}
130
+ translationFn={translationFn}
131
+ />
132
+ ))}
133
+ </div>
134
+ )
135
+ }