@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.
- package/index.html +22 -0
- package/package.json +69 -0
- package/public/brand/logo-dark.svg +16 -0
- package/public/brand/logo-horizontal-dark.svg +21 -0
- package/public/brand/logo-horizontal-light.svg +21 -0
- package/public/brand/logo-light.svg +16 -0
- package/public/brand/logo-wide-dark.svg +24 -0
- package/public/brand/logo-wide-light.svg +24 -0
- package/public/favicon.svg +8 -0
- package/public/vendor/react-jsx-runtime.mjs +24 -0
- package/public/vendor/react.mjs +16 -0
- package/src/App.tsx +71 -0
- package/src/components/addons/AddonCard.tsx +339 -0
- package/src/components/addons/AddonUploadZone.tsx +307 -0
- package/src/components/addons/CapabilityBadge.tsx +55 -0
- package/src/components/addons/CapabilityMap.tsx +133 -0
- package/src/components/addons/UpdatesList.tsx +119 -0
- package/src/components/agents/AgentCard.tsx +281 -0
- package/src/components/agents/AgentLogs.tsx +231 -0
- package/src/components/agents/ProcessList.tsx +127 -0
- package/src/components/agents/ProcessTree.tsx +369 -0
- package/src/components/agents/TaskList.tsx +68 -0
- package/src/components/cameras/CameraCard.tsx +60 -0
- package/src/components/cameras/LiveEventsPanel.tsx +91 -0
- package/src/components/cameras/ProviderSection.tsx +50 -0
- package/src/components/cameras/StreamArea.tsx +107 -0
- package/src/components/cameras/tabs/AddonsTab.tsx +113 -0
- package/src/components/cameras/tabs/CameraEventsTab.tsx +129 -0
- package/src/components/cameras/tabs/PipelineTab.tsx +118 -0
- package/src/components/cameras/tabs/StreamsTab.tsx +114 -0
- package/src/components/dashboard/BlockPicker.tsx +54 -0
- package/src/components/dashboard/BlockWrapper.tsx +97 -0
- package/src/components/dashboard/DashboardGrid.tsx +160 -0
- package/src/components/dashboard/block-registry.ts +15 -0
- package/src/components/dashboard/blocks/PipelineStagesBlock.tsx +39 -0
- package/src/components/dashboard/blocks/StorageBlock.tsx +66 -0
- package/src/components/dashboard/blocks/SystemStatusBlock.tsx +67 -0
- package/src/components/dashboard/blocks/index.ts +32 -0
- package/src/components/device/DeviceHeader.tsx +116 -0
- package/src/components/device/FloatingPanel.tsx +132 -0
- package/src/components/device/FloatingPanelManager.tsx +167 -0
- package/src/components/device/PanelContent.tsx +196 -0
- package/src/components/device/QuickConfigWizard.tsx +507 -0
- package/src/components/device/tabs/DetectionConfigTab.tsx +96 -0
- package/src/components/device/tabs/EventsTab.tsx +19 -0
- package/src/components/device/tabs/LogsTab.tsx +22 -0
- package/src/components/device/tabs/OverviewTab.tsx +104 -0
- package/src/components/device/tabs/ProviderSettingsTab.tsx +34 -0
- package/src/components/device/tabs/RecordingTab.tsx +47 -0
- package/src/components/device/tabs/ReplTab.tsx +153 -0
- package/src/components/device/tabs/TrackTrailTab.tsx +49 -0
- package/src/components/device/tabs/ZonesTab.tsx +98 -0
- package/src/components/device/zone-editor/ZoneCanvas.tsx +354 -0
- package/src/components/device/zone-editor/ZoneForm.tsx +128 -0
- package/src/components/device/zone-editor/ZoneList.tsx +150 -0
- package/src/components/form-builder/FormBuilder.tsx +135 -0
- package/src/components/form-builder/FormField.tsx +732 -0
- package/src/components/form-builder/ModelSelector.tsx +239 -0
- package/src/components/integrations/AddDeviceDialog.tsx +205 -0
- package/src/components/integrations/CompactDeviceCard.tsx +35 -0
- package/src/components/integrations/DeviceCard.tsx +29 -0
- package/src/components/integrations/DeviceDiscoveryStep.tsx +105 -0
- package/src/components/integrations/DeviceGrid.tsx +79 -0
- package/src/components/integrations/DeviceGroupHeader.tsx +17 -0
- package/src/components/integrations/DiscoveredDeviceCard.tsx +26 -0
- package/src/components/integrations/IntegrationCard.tsx +40 -0
- package/src/components/integrations/IntegrationWizard.tsx +171 -0
- package/src/components/integrations/ProviderConfigForm.tsx +89 -0
- package/src/components/integrations/ProviderPicker.tsx +91 -0
- package/src/components/integrations/SnapshotPopover.tsx +68 -0
- package/src/components/metrics/AgentLoad.tsx +113 -0
- package/src/components/metrics/IntegrationUsage.tsx +90 -0
- package/src/components/metrics/PipelineStatus.tsx +105 -0
- package/src/components/metrics/ProcessResources.tsx +139 -0
- package/src/components/pipeline/PhaseSettings.tsx +131 -0
- package/src/components/shared/CapabilityBadges.tsx +30 -0
- package/src/components/shared/ProviderIcon.tsx +42 -0
- package/src/components/shared/StatusBadge.tsx +23 -0
- package/src/components/shared/WebRtcPlayer.tsx +211 -0
- package/src/components/timeline/EventMarker.tsx +32 -0
- package/src/components/timeline/TimelineBar.tsx +131 -0
- package/src/components/ui/ConfirmDialog.tsx +115 -0
- package/src/components/ui/ToastContainer.tsx +92 -0
- package/src/contexts/auth-context.tsx +91 -0
- package/src/hooks/useBackendClient.ts +6 -0
- package/src/hooks/useTheme.ts +1 -0
- package/src/i18n/en.json +164 -0
- package/src/i18n/index.ts +29 -0
- package/src/i18n/it.json +164 -0
- package/src/index.css +63 -0
- package/src/layouts/AddonPageLoader.tsx +120 -0
- package/src/layouts/AppLayout.tsx +238 -0
- package/src/layouts/ProtectedRoute.tsx +25 -0
- package/src/lib/addon-page-context.ts +29 -0
- package/src/lib/backend.ts +16 -0
- package/src/main.tsx +21 -0
- package/src/pages/AccessDenied.tsx +22 -0
- package/src/pages/Cameras.tsx +127 -0
- package/src/pages/Dashboard.tsx +6 -0
- package/src/pages/DeviceDetail.tsx +175 -0
- package/src/pages/IntegrationDetail.tsx +224 -0
- package/src/pages/Integrations.tsx +330 -0
- package/src/pages/Login.tsx +106 -0
- package/src/pages/Metrics.tsx +18 -0
- package/src/pages/PipelineConfig.tsx +282 -0
- package/src/pages/Showroom.tsx +351 -0
- package/src/pages/Timeline.tsx +269 -0
- package/src/pages/system/Addons.tsx +525 -0
- package/src/pages/system/Agents.tsx +362 -0
- package/src/pages/system/Logs.tsx +131 -0
- package/src/pages/system/Models.tsx +102 -0
- package/src/pages/system/Processes.tsx +129 -0
- package/src/pages/system/Repl.tsx +148 -0
- package/src/pages/system/Settings.tsx +168 -0
- package/src/pages/system/Users.tsx +174 -0
- package/src/server/addon.ts +54 -0
- package/src/types/config-ui.ts +210 -0
- package/src/types/dashboard.ts +39 -0
- package/tsconfig.json +29 -0
- package/tsconfig.server.json +16 -0
- package/tsup.config.ts +20 -0
- 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
|
+
}
|