@principal-ai/principal-view-react 0.14.14 → 0.14.16

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 (75) hide show
  1. package/dist/components/SequenceDiagramRenderer.d.ts +61 -0
  2. package/dist/components/SequenceDiagramRenderer.d.ts.map +1 -0
  3. package/dist/components/SequenceDiagramRenderer.js +184 -0
  4. package/dist/components/SequenceDiagramRenderer.js.map +1 -0
  5. package/dist/components/dashboard/DashboardRenderer.d.ts +9 -0
  6. package/dist/components/dashboard/DashboardRenderer.d.ts.map +1 -0
  7. package/dist/components/dashboard/DashboardRenderer.js +179 -0
  8. package/dist/components/dashboard/DashboardRenderer.js.map +1 -0
  9. package/dist/components/dashboard/MetricPanel.d.ts +9 -0
  10. package/dist/components/dashboard/MetricPanel.d.ts.map +1 -0
  11. package/dist/components/dashboard/MetricPanel.js +103 -0
  12. package/dist/components/dashboard/MetricPanel.js.map +1 -0
  13. package/dist/components/dashboard/MockDataProvider.d.ts +30 -0
  14. package/dist/components/dashboard/MockDataProvider.d.ts.map +1 -0
  15. package/dist/components/dashboard/MockDataProvider.js +270 -0
  16. package/dist/components/dashboard/MockDataProvider.js.map +1 -0
  17. package/dist/components/dashboard/components/BarChart.d.ts +9 -0
  18. package/dist/components/dashboard/components/BarChart.d.ts.map +1 -0
  19. package/dist/components/dashboard/components/BarChart.js +167 -0
  20. package/dist/components/dashboard/components/BarChart.js.map +1 -0
  21. package/dist/components/dashboard/components/LineChart.d.ts +9 -0
  22. package/dist/components/dashboard/components/LineChart.d.ts.map +1 -0
  23. package/dist/components/dashboard/components/LineChart.js +141 -0
  24. package/dist/components/dashboard/components/LineChart.js.map +1 -0
  25. package/dist/components/dashboard/components/MetricCard.d.ts +8 -0
  26. package/dist/components/dashboard/components/MetricCard.d.ts.map +1 -0
  27. package/dist/components/dashboard/components/MetricCard.js +163 -0
  28. package/dist/components/dashboard/components/MetricCard.js.map +1 -0
  29. package/dist/components/dashboard/components/SourceLink.d.ts +8 -0
  30. package/dist/components/dashboard/components/SourceLink.d.ts.map +1 -0
  31. package/dist/components/dashboard/components/SourceLink.js +39 -0
  32. package/dist/components/dashboard/components/SourceLink.js.map +1 -0
  33. package/dist/components/dashboard/components/TimeRangeSelector.d.ts +8 -0
  34. package/dist/components/dashboard/components/TimeRangeSelector.d.ts.map +1 -0
  35. package/dist/components/dashboard/components/TimeRangeSelector.js +167 -0
  36. package/dist/components/dashboard/components/TimeRangeSelector.js.map +1 -0
  37. package/dist/components/dashboard/components/index.d.ts +6 -0
  38. package/dist/components/dashboard/components/index.d.ts.map +1 -0
  39. package/dist/components/dashboard/components/index.js +6 -0
  40. package/dist/components/dashboard/components/index.js.map +1 -0
  41. package/dist/components/dashboard/index.d.ts +6 -0
  42. package/dist/components/dashboard/index.d.ts.map +1 -0
  43. package/dist/components/dashboard/index.js +8 -0
  44. package/dist/components/dashboard/index.js.map +1 -0
  45. package/dist/components/dashboard/types.d.ts +74 -0
  46. package/dist/components/dashboard/types.d.ts.map +1 -0
  47. package/dist/components/dashboard/types.js +8 -0
  48. package/dist/components/dashboard/types.js.map +1 -0
  49. package/dist/hooks/useSequenceLayout.d.ts +148 -0
  50. package/dist/hooks/useSequenceLayout.d.ts.map +1 -0
  51. package/dist/hooks/useSequenceLayout.js +225 -0
  52. package/dist/hooks/useSequenceLayout.js.map +1 -0
  53. package/dist/index.d.ts +6 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +4 -0
  56. package/dist/index.js.map +1 -1
  57. package/package.json +3 -3
  58. package/src/components/SequenceDiagramRenderer.tsx +459 -0
  59. package/src/components/dashboard/DashboardRenderer.tsx +317 -0
  60. package/src/components/dashboard/MetricPanel.tsx +254 -0
  61. package/src/components/dashboard/MockDataProvider.ts +330 -0
  62. package/src/components/dashboard/components/BarChart.tsx +299 -0
  63. package/src/components/dashboard/components/LineChart.tsx +279 -0
  64. package/src/components/dashboard/components/MetricCard.tsx +270 -0
  65. package/src/components/dashboard/components/SourceLink.tsx +63 -0
  66. package/src/components/dashboard/components/TimeRangeSelector.tsx +280 -0
  67. package/src/components/dashboard/components/index.ts +5 -0
  68. package/src/components/dashboard/index.ts +47 -0
  69. package/src/components/dashboard/types.ts +126 -0
  70. package/src/hooks/useSequenceLayout.ts +413 -0
  71. package/src/index.ts +62 -0
  72. package/src/stories/SequenceDiagram.stories.tsx +306 -0
  73. package/src/stories/dashboard/DashboardRenderer.stories.tsx +263 -0
  74. package/src/stories/dashboard/sample-dashboards/activity-feed-analytics.dashboard.json +300 -0
  75. package/src/stories/data/graph-converter-test-execution.json +50 -50
@@ -0,0 +1,280 @@
1
+ /**
2
+ * TimeRangeSelector
3
+ *
4
+ * Dropdown selector for time range and auto-refresh interval.
5
+ */
6
+
7
+ import { useState, useRef, useEffect } from 'react';
8
+ import { useTheme } from '@principal-ade/industry-theme';
9
+ import type { TimeRangeSelectorProps, TimeRangePreset, RefreshInterval } from '../types';
10
+
11
+ const PRESET_LABELS: Record<TimeRangePreset, string> = {
12
+ last_5m: 'Last 5 minutes',
13
+ last_15m: 'Last 15 minutes',
14
+ last_30m: 'Last 30 minutes',
15
+ last_1h: 'Last 1 hour',
16
+ last_3h: 'Last 3 hours',
17
+ last_6h: 'Last 6 hours',
18
+ last_12h: 'Last 12 hours',
19
+ last_24h: 'Last 24 hours',
20
+ last_7d: 'Last 7 days',
21
+ last_30d: 'Last 30 days',
22
+ custom: 'Custom range',
23
+ };
24
+
25
+ const REFRESH_LABELS: Record<RefreshInterval, string> = {
26
+ off: 'Off',
27
+ '10s': '10 seconds',
28
+ '30s': '30 seconds',
29
+ '1m': '1 minute',
30
+ '5m': '5 minutes',
31
+ '10m': '10 minutes',
32
+ };
33
+
34
+ const DEFAULT_PRESETS: TimeRangePreset[] = [
35
+ 'last_1h',
36
+ 'last_3h',
37
+ 'last_6h',
38
+ 'last_12h',
39
+ 'last_24h',
40
+ 'last_7d',
41
+ ];
42
+
43
+ const DEFAULT_REFRESH_INTERVALS: RefreshInterval[] = [
44
+ 'off',
45
+ '30s',
46
+ '1m',
47
+ '5m',
48
+ ];
49
+
50
+ export function TimeRangeSelector({
51
+ timeRange,
52
+ onTimeRangeChange,
53
+ refreshInterval = 'off',
54
+ onRefreshIntervalChange,
55
+ config,
56
+ }: TimeRangeSelectorProps) {
57
+ const { theme } = useTheme();
58
+ const [isOpen, setIsOpen] = useState(false);
59
+ const [activeTab, setActiveTab] = useState<'range' | 'refresh'>('range');
60
+ const dropdownRef = useRef<HTMLDivElement>(null);
61
+
62
+ const presets = config?.presets ?? DEFAULT_PRESETS;
63
+ const refreshIntervals = config?.refreshIntervals ?? DEFAULT_REFRESH_INTERVALS;
64
+
65
+ // Close dropdown when clicking outside
66
+ useEffect(() => {
67
+ const handleClickOutside = (event: MouseEvent) => {
68
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
69
+ setIsOpen(false);
70
+ }
71
+ };
72
+
73
+ document.addEventListener('mousedown', handleClickOutside);
74
+ return () => document.removeEventListener('mousedown', handleClickOutside);
75
+ }, []);
76
+
77
+ const getCurrentLabel = (): string => {
78
+ if (timeRange.preset && timeRange.preset !== 'custom') {
79
+ return PRESET_LABELS[timeRange.preset];
80
+ }
81
+ if (timeRange.start && timeRange.end) {
82
+ const formatDate = (d: Date) => d.toLocaleDateString();
83
+ return `${formatDate(timeRange.start)} - ${formatDate(timeRange.end)}`;
84
+ }
85
+ return 'Select time range';
86
+ };
87
+
88
+ const handlePresetSelect = (preset: TimeRangePreset) => {
89
+ onTimeRangeChange({ preset });
90
+ setIsOpen(false);
91
+ };
92
+
93
+ const handleRefreshSelect = (interval: RefreshInterval) => {
94
+ onRefreshIntervalChange?.(interval);
95
+ setIsOpen(false);
96
+ };
97
+
98
+ const buttonStyle: React.CSSProperties = {
99
+ display: 'flex',
100
+ alignItems: 'center',
101
+ gap: 8,
102
+ padding: '8px 12px',
103
+ backgroundColor: theme.colors.surface || theme.colors.background,
104
+ border: `1px solid ${theme.colors.border}`,
105
+ borderRadius: theme.radii?.[1] || 4,
106
+ fontSize: theme.fontSizes[1],
107
+ fontFamily: theme.fonts.body,
108
+ color: theme.colors.text,
109
+ cursor: 'pointer',
110
+ transition: 'border-color 0.2s',
111
+ };
112
+
113
+ const dropdownStyle: React.CSSProperties = {
114
+ position: 'absolute',
115
+ top: '100%',
116
+ right: 0,
117
+ marginTop: 4,
118
+ minWidth: 200,
119
+ backgroundColor: theme.colors.surface || theme.colors.background,
120
+ border: `1px solid ${theme.colors.border}`,
121
+ borderRadius: theme.radii?.[2] || 8,
122
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
123
+ zIndex: 1000,
124
+ overflow: 'hidden',
125
+ };
126
+
127
+ const tabStyle = (isActive: boolean): React.CSSProperties => ({
128
+ flex: 1,
129
+ padding: '8px 12px',
130
+ backgroundColor: isActive ? theme.colors.surface : 'transparent',
131
+ border: 'none',
132
+ borderBottom: isActive ? `2px solid ${theme.colors.primary || theme.colors.accent}` : '2px solid transparent',
133
+ fontSize: theme.fontSizes[0],
134
+ fontFamily: theme.fonts.body,
135
+ fontWeight: isActive ? theme.fontWeights.medium : theme.fontWeights.body,
136
+ color: isActive ? theme.colors.text : theme.colors.textSecondary,
137
+ cursor: 'pointer',
138
+ });
139
+
140
+ const optionStyle = (isSelected: boolean): React.CSSProperties => ({
141
+ display: 'flex',
142
+ alignItems: 'center',
143
+ justifyContent: 'space-between',
144
+ padding: '8px 12px',
145
+ backgroundColor: isSelected ? (theme.colors.primary || theme.colors.accent) + '15' : 'transparent',
146
+ border: 'none',
147
+ width: '100%',
148
+ textAlign: 'left',
149
+ fontSize: theme.fontSizes[1],
150
+ fontFamily: theme.fonts.body,
151
+ color: theme.colors.text,
152
+ cursor: 'pointer',
153
+ transition: 'background-color 0.15s',
154
+ });
155
+
156
+ return (
157
+ <div ref={dropdownRef} style={{ position: 'relative', display: 'inline-block' }}>
158
+ {/* Main button */}
159
+ <button
160
+ onClick={() => setIsOpen(!isOpen)}
161
+ style={buttonStyle}
162
+ onMouseEnter={(e) => {
163
+ e.currentTarget.style.borderColor = theme.colors.primary || theme.colors.accent;
164
+ }}
165
+ onMouseLeave={(e) => {
166
+ e.currentTarget.style.borderColor = theme.colors.border;
167
+ }}
168
+ >
169
+ {/* Clock icon */}
170
+ <svg width={14} height={14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
171
+ <circle cx="12" cy="12" r="10" />
172
+ <polyline points="12 6 12 12 16 14" />
173
+ </svg>
174
+ <span>{getCurrentLabel()}</span>
175
+ {/* Chevron */}
176
+ <svg
177
+ width={12}
178
+ height={12}
179
+ viewBox="0 0 24 24"
180
+ fill="none"
181
+ stroke="currentColor"
182
+ strokeWidth={2}
183
+ style={{ transform: isOpen ? 'rotate(180deg)' : 'rotate(0)', transition: 'transform 0.2s' }}
184
+ >
185
+ <polyline points="6 9 12 15 18 9" />
186
+ </svg>
187
+ {/* Refresh indicator */}
188
+ {refreshInterval !== 'off' && (
189
+ <span
190
+ style={{
191
+ marginLeft: 4,
192
+ padding: '2px 6px',
193
+ backgroundColor: theme.colors.primary || theme.colors.accent,
194
+ color: theme.colors.background,
195
+ fontSize: theme.fontSizes[0],
196
+ borderRadius: theme.radii?.[1] || 4,
197
+ fontWeight: theme.fontWeights.medium,
198
+ }}
199
+ >
200
+ {refreshInterval}
201
+ </span>
202
+ )}
203
+ </button>
204
+
205
+ {/* Dropdown */}
206
+ {isOpen && (
207
+ <div style={dropdownStyle}>
208
+ {/* Tabs */}
209
+ {onRefreshIntervalChange && (
210
+ <div style={{ display: 'flex', borderBottom: `1px solid ${theme.colors.border}` }}>
211
+ <button style={tabStyle(activeTab === 'range')} onClick={() => setActiveTab('range')}>
212
+ Time Range
213
+ </button>
214
+ <button style={tabStyle(activeTab === 'refresh')} onClick={() => setActiveTab('refresh')}>
215
+ Auto Refresh
216
+ </button>
217
+ </div>
218
+ )}
219
+
220
+ {/* Options */}
221
+ <div style={{ maxHeight: 300, overflowY: 'auto' }}>
222
+ {activeTab === 'range' &&
223
+ presets.map((preset) => (
224
+ <button
225
+ key={preset}
226
+ onClick={() => handlePresetSelect(preset)}
227
+ style={optionStyle(timeRange.preset === preset)}
228
+ onMouseEnter={(e) => {
229
+ if (timeRange.preset !== preset) {
230
+ e.currentTarget.style.backgroundColor = theme.colors.border + '40';
231
+ }
232
+ }}
233
+ onMouseLeave={(e) => {
234
+ e.currentTarget.style.backgroundColor =
235
+ timeRange.preset === preset
236
+ ? (theme.colors.primary || theme.colors.accent) + '15'
237
+ : 'transparent';
238
+ }}
239
+ >
240
+ <span>{PRESET_LABELS[preset]}</span>
241
+ {timeRange.preset === preset && (
242
+ <svg width={14} height={14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
243
+ <polyline points="20 6 9 17 4 12" />
244
+ </svg>
245
+ )}
246
+ </button>
247
+ ))}
248
+
249
+ {activeTab === 'refresh' &&
250
+ refreshIntervals.map((interval) => (
251
+ <button
252
+ key={interval}
253
+ onClick={() => handleRefreshSelect(interval)}
254
+ style={optionStyle(refreshInterval === interval)}
255
+ onMouseEnter={(e) => {
256
+ if (refreshInterval !== interval) {
257
+ e.currentTarget.style.backgroundColor = theme.colors.border + '40';
258
+ }
259
+ }}
260
+ onMouseLeave={(e) => {
261
+ e.currentTarget.style.backgroundColor =
262
+ refreshInterval === interval
263
+ ? (theme.colors.primary || theme.colors.accent) + '15'
264
+ : 'transparent';
265
+ }}
266
+ >
267
+ <span>{REFRESH_LABELS[interval]}</span>
268
+ {refreshInterval === interval && (
269
+ <svg width={14} height={14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
270
+ <polyline points="20 6 9 17 4 12" />
271
+ </svg>
272
+ )}
273
+ </button>
274
+ ))}
275
+ </div>
276
+ </div>
277
+ )}
278
+ </div>
279
+ );
280
+ }
@@ -0,0 +1,5 @@
1
+ export { MetricCard } from './MetricCard';
2
+ export { LineChart } from './LineChart';
3
+ export { BarChart } from './BarChart';
4
+ export { SourceLink } from './SourceLink';
5
+ export { TimeRangeSelector } from './TimeRangeSelector';
@@ -0,0 +1,47 @@
1
+ // Main renderer
2
+ export { DashboardRenderer } from './DashboardRenderer';
3
+ export { MetricPanel } from './MetricPanel';
4
+
5
+ // Individual components
6
+ export { MetricCard, LineChart, BarChart, SourceLink, TimeRangeSelector } from './components';
7
+
8
+ // Data providers
9
+ export { MockDataProvider, createMockDataProvider } from './MockDataProvider';
10
+
11
+ // Types
12
+ export type {
13
+ // Dashboard definition types
14
+ DashboardDefinition,
15
+ MetricDefinition,
16
+ MetricType,
17
+ MetricSource,
18
+ MetricQuery,
19
+ Derivation,
20
+ TimeGroup,
21
+ AlertDefinition,
22
+ MetricDisplay,
23
+ DisplayComponent,
24
+ DashboardLayout,
25
+ DashboardRow,
26
+ PanelPlacement,
27
+ // Time range types
28
+ TimeRangePreset,
29
+ TimeRange,
30
+ RefreshInterval,
31
+ TimeRangeConfig,
32
+ // Mock data types
33
+ MockMetricData,
34
+ TimeSeriesPoint,
35
+ HistogramData,
36
+ // Runtime types
37
+ MetricData,
38
+ DataProvider,
39
+ // Component props
40
+ DashboardRendererProps,
41
+ MetricPanelProps,
42
+ MetricCardProps,
43
+ LineChartProps,
44
+ BarChartProps,
45
+ SourceLinkProps,
46
+ TimeRangeSelectorProps,
47
+ } from './types';
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Dashboard Types for React Components
3
+ *
4
+ * Core definition types are imported from @principal-ai/principal-view-core.
5
+ * This file only contains React-specific component props types.
6
+ */
7
+
8
+ // Re-export all core dashboard types
9
+ export type {
10
+ // Dashboard definition types
11
+ DashboardDefinition,
12
+ MetricDefinition,
13
+ MetricType,
14
+ MetricSource,
15
+ MetricQuery,
16
+ Derivation,
17
+ TimeGroup,
18
+ AlertDefinition,
19
+ MetricDisplay,
20
+ DisplayComponent,
21
+ // Layout types
22
+ DashboardLayout,
23
+ DashboardRow,
24
+ PanelPlacement,
25
+ // Mock data types
26
+ MockMetricData,
27
+ TimeSeriesPoint,
28
+ HistogramData,
29
+ // Time range types
30
+ TimeRangePreset,
31
+ TimeRange,
32
+ RefreshInterval,
33
+ TimeRangeConfig,
34
+ // Runtime types
35
+ MetricData,
36
+ DataProvider,
37
+ } from '@principal-ai/principal-view-core';
38
+
39
+ // Import types needed for component props
40
+ import type {
41
+ DashboardDefinition,
42
+ MetricDefinition,
43
+ MetricSource,
44
+ MetricData,
45
+ TimeSeriesPoint,
46
+ TimeRange,
47
+ RefreshInterval,
48
+ TimeRangeConfig,
49
+ } from '@principal-ai/principal-view-core';
50
+
51
+ // ============================================================================
52
+ // React Component Props Types
53
+ // ============================================================================
54
+
55
+ export interface DashboardRendererProps {
56
+ dashboard: DashboardDefinition;
57
+ dataProvider?: import('@principal-ai/principal-view-core').DataProvider;
58
+
59
+ // Time range controls
60
+ timeRange?: TimeRange;
61
+ onTimeRangeChange?: (range: TimeRange) => void;
62
+ refreshInterval?: RefreshInterval;
63
+ onRefreshIntervalChange?: (interval: RefreshInterval) => void;
64
+ timeRangeConfig?: TimeRangeConfig;
65
+
66
+ // Callbacks
67
+ onMetricClick?: (metricId: string) => void;
68
+ onSourceClick?: (source: MetricSource) => void;
69
+ }
70
+
71
+ export interface MetricPanelProps {
72
+ metric: MetricDefinition;
73
+ data: MetricData;
74
+ onMetricClick?: (metricId: string) => void;
75
+ onSourceClick?: (source: MetricSource) => void;
76
+ }
77
+
78
+ export interface MetricCardProps {
79
+ title: string;
80
+ value: number | string;
81
+ unit?: string;
82
+ description?: string;
83
+ trend?: 'up' | 'down' | 'flat';
84
+ changePercent?: number;
85
+ showTrend?: boolean;
86
+ showSparkline?: boolean;
87
+ sparklineData?: TimeSeriesPoint[];
88
+ thresholds?: { warning?: number; critical?: number };
89
+ size?: 'small' | 'medium' | 'large';
90
+ onClick?: () => void;
91
+ }
92
+
93
+ export interface LineChartProps {
94
+ title: string;
95
+ data: TimeSeriesPoint[];
96
+ xKey?: string;
97
+ yKey?: string;
98
+ series?: string[]; // For multi-series charts
99
+ unit?: string;
100
+ height?: number;
101
+ onClick?: () => void;
102
+ }
103
+
104
+ export interface BarChartProps {
105
+ title: string;
106
+ data: TimeSeriesPoint[];
107
+ xKey?: string;
108
+ series: string[];
109
+ stacked?: boolean;
110
+ unit?: string;
111
+ height?: number;
112
+ onClick?: () => void;
113
+ }
114
+
115
+ export interface SourceLinkProps {
116
+ source: MetricSource;
117
+ onClick?: (source: MetricSource) => void;
118
+ }
119
+
120
+ export interface TimeRangeSelectorProps {
121
+ timeRange: TimeRange;
122
+ onTimeRangeChange: (range: TimeRange) => void;
123
+ refreshInterval?: RefreshInterval;
124
+ onRefreshIntervalChange?: (interval: RefreshInterval) => void;
125
+ config?: TimeRangeConfig;
126
+ }