@superdangerous/app-framework 4.9.2 → 4.15.0

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 (54) hide show
  1. package/README.md +8 -2
  2. package/dist/api/logsRouter.d.ts +4 -1
  3. package/dist/api/logsRouter.d.ts.map +1 -1
  4. package/dist/api/logsRouter.js +100 -118
  5. package/dist/api/logsRouter.js.map +1 -1
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/middleware/validation.d.ts +48 -43
  11. package/dist/middleware/validation.d.ts.map +1 -1
  12. package/dist/middleware/validation.js +48 -43
  13. package/dist/middleware/validation.js.map +1 -1
  14. package/dist/services/emailService.d.ts +146 -0
  15. package/dist/services/emailService.d.ts.map +1 -0
  16. package/dist/services/emailService.js +649 -0
  17. package/dist/services/emailService.js.map +1 -0
  18. package/dist/services/index.d.ts +2 -0
  19. package/dist/services/index.d.ts.map +1 -1
  20. package/dist/services/index.js +2 -0
  21. package/dist/services/index.js.map +1 -1
  22. package/dist/services/websocketServer.d.ts +7 -4
  23. package/dist/services/websocketServer.d.ts.map +1 -1
  24. package/dist/services/websocketServer.js +22 -16
  25. package/dist/services/websocketServer.js.map +1 -1
  26. package/dist/types/index.d.ts +7 -8
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/package.json +11 -2
  29. package/src/api/logsRouter.ts +119 -138
  30. package/src/index.ts +14 -0
  31. package/src/middleware/validation.ts +82 -90
  32. package/src/services/emailService.ts +812 -0
  33. package/src/services/index.ts +14 -0
  34. package/src/services/websocketServer.ts +37 -23
  35. package/src/types/index.ts +7 -8
  36. package/ui/data-table/components/BatchActionsBar.tsx +53 -0
  37. package/ui/data-table/components/ColumnVisibility.tsx +111 -0
  38. package/ui/data-table/components/DataTablePage.tsx +238 -0
  39. package/ui/data-table/components/Pagination.tsx +203 -0
  40. package/ui/data-table/components/PaginationControls.tsx +122 -0
  41. package/ui/data-table/components/TableFilters.tsx +139 -0
  42. package/ui/data-table/components/index.ts +27 -0
  43. package/ui/data-table/hooks/index.ts +17 -0
  44. package/ui/data-table/hooks/useColumnOrder.ts +233 -0
  45. package/ui/data-table/hooks/useColumnVisibility.ts +128 -0
  46. package/ui/data-table/hooks/usePagination.ts +160 -0
  47. package/ui/data-table/hooks/useResizableColumns.ts +280 -0
  48. package/ui/data-table/index.ts +74 -0
  49. package/ui/dist/index.d.mts +207 -5
  50. package/ui/dist/index.d.ts +207 -5
  51. package/ui/dist/index.js +36 -43
  52. package/ui/dist/index.js.map +1 -1
  53. package/ui/dist/index.mjs +36 -43
  54. package/ui/dist/index.mjs.map +1 -1
@@ -0,0 +1,280 @@
1
+ import { useState, useCallback, useEffect, useRef } from 'react';
2
+
3
+ interface ColumnConfig {
4
+ key: string;
5
+ minWidth?: number;
6
+ maxWidth?: number;
7
+ defaultWidth?: number;
8
+ }
9
+
10
+ interface UseResizableColumnsOptions {
11
+ tableId: string;
12
+ columns: ColumnConfig[];
13
+ storageKey?: string;
14
+ }
15
+
16
+ interface ResizableColumnState {
17
+ widths: Record<string, number>;
18
+ isResizing: boolean;
19
+ resizingColumn: string | null;
20
+ }
21
+
22
+ export interface ResizableColumnResult {
23
+ widths: Record<string, number>;
24
+ isResizing: boolean;
25
+ totalWidth: number;
26
+ getResizeHandleProps: (columnKey: string) => {
27
+ onPointerDown: (e: React.PointerEvent) => void;
28
+ onMouseDown: (e: React.MouseEvent) => void;
29
+ draggable: boolean;
30
+ onDragStart: (e: React.DragEvent) => void;
31
+ className: string;
32
+ 'data-resizing': boolean;
33
+ };
34
+ getColumnStyle: (columnKey: string) => React.CSSProperties;
35
+ getTableStyle: () => React.CSSProperties;
36
+ resetToDefaults: () => void;
37
+ }
38
+
39
+ const DEFAULT_MIN_WIDTH = 50;
40
+ const DEFAULT_WIDTH = 150;
41
+ const DRAG_THRESHOLD = 3; // Minimum pixels before resize activates
42
+
43
+ export function useResizableColumns({
44
+ tableId,
45
+ columns,
46
+ storageKey,
47
+ }: UseResizableColumnsOptions): ResizableColumnResult {
48
+ const effectiveStorageKey = storageKey || `table-columns-${tableId}`;
49
+
50
+ // Get default widths from column config
51
+ const getDefaultWidths = useCallback(() => {
52
+ return columns.reduce((acc, col) => {
53
+ acc[col.key] = col.defaultWidth || DEFAULT_WIDTH;
54
+ return acc;
55
+ }, {} as Record<string, number>);
56
+ }, [columns]);
57
+
58
+ // Initialize widths from localStorage or defaults
59
+ const [state, setState] = useState<ResizableColumnState>(() => {
60
+ try {
61
+ const stored = localStorage.getItem(effectiveStorageKey);
62
+ if (stored) {
63
+ const parsed = JSON.parse(stored);
64
+ // Merge with defaults in case new columns were added
65
+ const defaults = getDefaultWidths();
66
+ return {
67
+ widths: { ...defaults, ...parsed },
68
+ isResizing: false,
69
+ resizingColumn: null,
70
+ };
71
+ }
72
+ } catch {
73
+ // Ignore localStorage errors
74
+ }
75
+ return {
76
+ widths: getDefaultWidths(),
77
+ isResizing: false,
78
+ resizingColumn: null,
79
+ };
80
+ });
81
+
82
+ // Refs for resize handling - these are stable across renders
83
+ const startXRef = useRef<number>(0);
84
+ const startWidthRef = useRef<number>(0);
85
+ const activeColumnRef = useRef<string | null>(null);
86
+ const hasDraggedRef = useRef<boolean>(false);
87
+ const columnsRef = useRef(columns);
88
+
89
+ // Keep columnsRef up to date
90
+ useEffect(() => {
91
+ columnsRef.current = columns;
92
+ }, [columns]);
93
+
94
+ // Get column config by key - uses ref for stable reference
95
+ const getColumnConfig = useCallback(
96
+ (key: string) => columnsRef.current.find((c) => c.key === key),
97
+ []
98
+ );
99
+
100
+ // Persist widths to localStorage
101
+ useEffect(() => {
102
+ try {
103
+ localStorage.setItem(effectiveStorageKey, JSON.stringify(state.widths));
104
+ } catch {
105
+ // Ignore localStorage errors
106
+ }
107
+ }, [state.widths, effectiveStorageKey]);
108
+
109
+ // Stable event handlers using refs - these don't change between renders
110
+ const handlersRef = useRef<{
111
+ onPointerMove: (e: PointerEvent) => void;
112
+ onPointerUp: (e: PointerEvent) => void;
113
+ } | null>(null);
114
+
115
+ // Initialize handlers once
116
+ if (!handlersRef.current) {
117
+ handlersRef.current = {
118
+ onPointerMove: (e: PointerEvent) => {
119
+ if (!activeColumnRef.current) return;
120
+
121
+ const diff = e.clientX - startXRef.current;
122
+
123
+ // Check if we've exceeded the drag threshold
124
+ if (!hasDraggedRef.current) {
125
+ if (Math.abs(diff) < DRAG_THRESHOLD) {
126
+ return; // Not yet dragging
127
+ }
128
+ // Now we're actually dragging - set the resizing state
129
+ hasDraggedRef.current = true;
130
+ setState((prev) => ({
131
+ ...prev,
132
+ isResizing: true,
133
+ resizingColumn: activeColumnRef.current,
134
+ }));
135
+ document.body.style.cursor = 'col-resize';
136
+ document.body.style.userSelect = 'none';
137
+ }
138
+
139
+ const config = getColumnConfig(activeColumnRef.current);
140
+ const minWidth = config?.minWidth || DEFAULT_MIN_WIDTH;
141
+ const maxWidth = config?.maxWidth;
142
+
143
+ let newWidth = Math.max(minWidth, startWidthRef.current + diff);
144
+ if (maxWidth) {
145
+ newWidth = Math.min(maxWidth, newWidth);
146
+ }
147
+
148
+ setState((prev) => ({
149
+ ...prev,
150
+ widths: {
151
+ ...prev.widths,
152
+ [activeColumnRef.current!]: newWidth,
153
+ },
154
+ }));
155
+ },
156
+
157
+ onPointerUp: () => {
158
+ activeColumnRef.current = null;
159
+ hasDraggedRef.current = false;
160
+ setState((prev) => ({
161
+ ...prev,
162
+ isResizing: false,
163
+ resizingColumn: null,
164
+ }));
165
+
166
+ // Remove listeners using the same stable references
167
+ document.removeEventListener('pointermove', handlersRef.current!.onPointerMove);
168
+ document.removeEventListener('pointerup', handlersRef.current!.onPointerUp);
169
+ document.removeEventListener('pointercancel', handlersRef.current!.onPointerUp);
170
+
171
+ // Remove cursor override
172
+ document.body.style.cursor = '';
173
+ document.body.style.userSelect = '';
174
+ },
175
+ };
176
+ }
177
+
178
+ // Cleanup on unmount
179
+ useEffect(() => {
180
+ return () => {
181
+ if (handlersRef.current) {
182
+ document.removeEventListener('pointermove', handlersRef.current.onPointerMove);
183
+ document.removeEventListener('pointerup', handlersRef.current.onPointerUp);
184
+ document.removeEventListener('pointercancel', handlersRef.current.onPointerUp);
185
+ }
186
+ document.body.style.cursor = '';
187
+ document.body.style.userSelect = '';
188
+ };
189
+ }, []);
190
+
191
+ // Ref to access current widths without causing re-renders
192
+ const widthsRef = useRef(state.widths);
193
+ useEffect(() => {
194
+ widthsRef.current = state.widths;
195
+ }, [state.widths]);
196
+
197
+ // Start resize - uses stable handler refs
198
+ const startResize = useCallback(
199
+ (columnKey: string, clientX: number) => {
200
+ startXRef.current = clientX;
201
+ startWidthRef.current = widthsRef.current[columnKey] || DEFAULT_WIDTH;
202
+ activeColumnRef.current = columnKey;
203
+ hasDraggedRef.current = false;
204
+
205
+ // Add listeners using stable references - use pointer events consistently
206
+ document.addEventListener('pointermove', handlersRef.current!.onPointerMove);
207
+ document.addEventListener('pointerup', handlersRef.current!.onPointerUp);
208
+ document.addEventListener('pointercancel', handlersRef.current!.onPointerUp);
209
+ },
210
+ []
211
+ );
212
+
213
+ // Get resize handle props for a column
214
+ const getResizeHandleProps = useCallback(
215
+ (columnKey: string) => ({
216
+ onPointerDown: (e: React.PointerEvent) => {
217
+ e.preventDefault();
218
+ e.stopPropagation();
219
+ startResize(columnKey, e.clientX);
220
+ },
221
+ // Prevent other events from interfering
222
+ onMouseDown: (e: React.MouseEvent) => {
223
+ e.preventDefault();
224
+ e.stopPropagation();
225
+ },
226
+ draggable: false,
227
+ onDragStart: (e: React.DragEvent) => {
228
+ e.preventDefault();
229
+ e.stopPropagation();
230
+ },
231
+ className: 'resize-handle',
232
+ 'data-resizing': state.resizingColumn === columnKey,
233
+ }),
234
+ [startResize, state.resizingColumn]
235
+ );
236
+
237
+ // Get column style with width
238
+ const getColumnStyle = useCallback(
239
+ (columnKey: string): React.CSSProperties => {
240
+ const currentWidth = state.widths[columnKey] || DEFAULT_WIDTH;
241
+ return {
242
+ width: currentWidth,
243
+ minWidth: currentWidth,
244
+ position: 'relative',
245
+ };
246
+ },
247
+ [state.widths]
248
+ );
249
+
250
+ // Calculate total table width from all columns
251
+ const totalWidth = columns.reduce((sum, col) => {
252
+ return sum + (state.widths[col.key] || col.defaultWidth || DEFAULT_WIDTH);
253
+ }, 0);
254
+
255
+ // Get table style
256
+ const getTableStyle = useCallback(
257
+ (): React.CSSProperties => ({
258
+ minWidth: totalWidth,
259
+ }),
260
+ [totalWidth]
261
+ );
262
+
263
+ // Reset all columns to default widths
264
+ const resetToDefaults = useCallback(() => {
265
+ setState((prev) => ({
266
+ ...prev,
267
+ widths: getDefaultWidths(),
268
+ }));
269
+ }, [getDefaultWidths]);
270
+
271
+ return {
272
+ widths: state.widths,
273
+ isResizing: state.isResizing,
274
+ totalWidth,
275
+ getResizeHandleProps,
276
+ getColumnStyle,
277
+ getTableStyle,
278
+ resetToDefaults,
279
+ };
280
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @superdangerous/app-framework/data-table
3
+ *
4
+ * A comprehensive data table module providing hooks and components
5
+ * for building enterprise-grade data tables with:
6
+ *
7
+ * - Pagination with localStorage persistence
8
+ * - Column visibility toggling with locked columns
9
+ * - Column resizing with drag handles
10
+ * - Column reordering with drag-and-drop
11
+ * - Batch selection and actions
12
+ * - Search and filter controls
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * import {
17
+ * usePagination,
18
+ * useColumnVisibility,
19
+ * DataTablePage,
20
+ * BatchActionsBar
21
+ * } from '@superdangerous/app-framework/data-table';
22
+ *
23
+ * function MyTable() {
24
+ * const pagination = usePagination({ data: items, storageKey: 'my-table' });
25
+ * const columnVisibility = useColumnVisibility({ columns, storageKey: 'my-table-cols' });
26
+ *
27
+ * return (
28
+ * <DataTablePage
29
+ * title="Items"
30
+ * pagination={pagination}
31
+ * // ...
32
+ * >
33
+ * <table>...</table>
34
+ * </DataTablePage>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+
40
+ // Hooks
41
+ export {
42
+ usePagination,
43
+ useColumnVisibility,
44
+ useResizableColumns,
45
+ useColumnOrder,
46
+ useColumnDragDrop,
47
+ } from './hooks';
48
+
49
+ export type {
50
+ ColumnConfig,
51
+ ColumnVisibilityState,
52
+ ResizableColumnResult,
53
+ ColumnOrderConfig,
54
+ DragState,
55
+ } from './hooks';
56
+
57
+ // Components
58
+ export {
59
+ DataTablePage,
60
+ PaginationControls,
61
+ Pagination,
62
+ BatchActionsBar,
63
+ ColumnVisibility,
64
+ TableFilters,
65
+ } from './components';
66
+
67
+ export type {
68
+ DataTablePageProps,
69
+ FilterOption,
70
+ PaginationControlsProps,
71
+ BatchActionsBarProps,
72
+ TableFiltersProps,
73
+ TableFilterOption,
74
+ } from './components';
@@ -1,6 +1,6 @@
1
1
  import * as class_variance_authority_types from 'class-variance-authority/types';
2
2
  import * as React$1 from 'react';
3
- import React__default, { ReactNode } from 'react';
3
+ import React__default, { ReactNode, MouseEvent } from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
@@ -195,10 +195,20 @@ declare function ProtectedRoute({ children, loginPath, authEndpoint, loadingComp
195
195
 
196
196
  interface LogsPageProps {
197
197
  apiUrl?: string;
198
- title?: string;
199
- description?: string;
200
198
  }
201
- declare function LogsPage({ apiUrl, title, description }: LogsPageProps): react_jsx_runtime.JSX.Element;
199
+ /**
200
+ * A complete logs page component with file list and live log viewer
201
+ *
202
+ * @example
203
+ * ```tsx
204
+ * import { LogsPage } from '@superdangerous/app-framework/ui';
205
+ *
206
+ * function App() {
207
+ * return <LogsPage apiUrl="/api/logs" />;
208
+ * }
209
+ * ```
210
+ */
211
+ declare function LogsPage({ apiUrl }: LogsPageProps): react_jsx_runtime.JSX.Element;
202
212
 
203
213
  interface SettingDefinition$1 {
204
214
  key: string;
@@ -403,6 +413,176 @@ declare function MarkdownScrollArea({ content, className, height, ...props }: Ma
403
413
  height?: string;
404
414
  }): react_jsx_runtime.JSX.Element;
405
415
 
416
+ interface TruncatedTextProps {
417
+ children: ReactNode;
418
+ className?: string;
419
+ maxWidth?: string | number;
420
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left';
421
+ }
422
+ declare function TruncatedText({ children, className, maxWidth, tooltipSide, }: TruncatedTextProps): react_jsx_runtime.JSX.Element;
423
+
424
+ declare const TAG_COLORS: {
425
+ hex: string;
426
+ name: string;
427
+ }[];
428
+ interface ColorPaletteProps {
429
+ value: string;
430
+ onChange: (color: string) => void;
431
+ columns?: number;
432
+ className?: string;
433
+ }
434
+ declare function ColorPalette({ value, onChange, columns, className }: ColorPaletteProps): react_jsx_runtime.JSX.Element;
435
+ declare function getRandomTagColor(): string;
436
+ declare function getNextTagColor(currentColor: string): string;
437
+ declare function getNextAvailableColor(usedColors: string[]): string;
438
+
439
+ type ConfirmDialogVariant = 'default' | 'destructive' | 'warning' | 'success';
440
+ interface ConfirmDialogProps {
441
+ open: boolean;
442
+ onOpenChange: (open: boolean) => void;
443
+ title: string;
444
+ description: string;
445
+ confirmLabel?: string;
446
+ cancelLabel?: string;
447
+ variant?: ConfirmDialogVariant;
448
+ icon?: LucideIcon;
449
+ onConfirm: () => void;
450
+ onCancel?: () => void;
451
+ loading?: boolean;
452
+ }
453
+ declare function ConfirmDialog({ open, onOpenChange, title, description, confirmLabel, cancelLabel, variant, icon, onConfirm, onCancel, loading, }: ConfirmDialogProps): react_jsx_runtime.JSX.Element;
454
+ /**
455
+ * Hook to manage confirm dialog state
456
+ */
457
+ declare function useConfirmDialog(): {
458
+ confirm: (options: {
459
+ title: string;
460
+ description: string;
461
+ confirmLabel?: string;
462
+ cancelLabel?: string;
463
+ variant?: ConfirmDialogVariant;
464
+ }) => Promise<boolean>;
465
+ dialogProps: {
466
+ onOpenChange: (open: boolean) => void;
467
+ onCancel: () => void;
468
+ open: boolean;
469
+ title: string;
470
+ description: string;
471
+ confirmLabel?: string;
472
+ cancelLabel?: string;
473
+ variant?: ConfirmDialogVariant;
474
+ onConfirm: () => void;
475
+ };
476
+ ConfirmDialog: typeof ConfirmDialog;
477
+ };
478
+
479
+ interface ResizableDialogRenderProps {
480
+ isFullscreen: boolean;
481
+ }
482
+ interface ResizableDialogProps {
483
+ open: boolean;
484
+ onOpenChange: (open: boolean) => void;
485
+ title?: React.ReactNode;
486
+ children: React.ReactNode | ((props: ResizableDialogRenderProps) => React.ReactNode);
487
+ footer?: React.ReactNode;
488
+ defaultWidth?: number;
489
+ defaultHeight?: number;
490
+ minWidth?: number;
491
+ minHeight?: number;
492
+ className?: string;
493
+ onFullscreenChange?: (isFullscreen: boolean) => void;
494
+ }
495
+ declare function ResizableDialog({ open, onOpenChange, title, children, footer, defaultWidth, defaultHeight, minWidth, minHeight, className, onFullscreenChange, }: ResizableDialogProps): react_jsx_runtime.JSX.Element;
496
+
497
+ interface ContextMenuPosition {
498
+ x: number;
499
+ y: number;
500
+ }
501
+ interface ContextMenuProps {
502
+ position: ContextMenuPosition;
503
+ onClose: () => void;
504
+ children: ReactNode;
505
+ className?: string;
506
+ }
507
+ /**
508
+ * Base context menu container with positioning, close-on-outside-click,
509
+ * and close-on-scroll behavior. Automatically adjusts position to stay within viewport.
510
+ */
511
+ declare function ContextMenu({ position, onClose, children, className }: ContextMenuProps): react_jsx_runtime.JSX.Element;
512
+
513
+ interface ContextMenuItemProps {
514
+ onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
515
+ onMouseEnter?: () => void;
516
+ icon?: ReactNode;
517
+ children: ReactNode;
518
+ /** Use 'default' for standard items, or specify a color variant */
519
+ variant?: 'default' | 'success' | 'warning' | 'destructive' | 'purple';
520
+ disabled?: boolean;
521
+ className?: string;
522
+ }
523
+ /**
524
+ * A single menu item for the context menu.
525
+ */
526
+ declare function ContextMenuItem({ onClick, onMouseEnter, icon, children, variant, disabled, className, }: ContextMenuItemProps): react_jsx_runtime.JSX.Element;
527
+ /**
528
+ * Horizontal separator for context menu sections.
529
+ */
530
+ declare function ContextMenuSeparator(): react_jsx_runtime.JSX.Element;
531
+
532
+ interface ContextMenuSubmenuProps {
533
+ label: string;
534
+ icon?: ReactNode;
535
+ children: ReactNode;
536
+ /** Callback when this submenu opens (useful for closing other submenus) */
537
+ onOpen?: () => void;
538
+ /** External control for open state */
539
+ isOpen?: boolean;
540
+ /** External control for setting open state */
541
+ onOpenChange?: (open: boolean) => void;
542
+ className?: string;
543
+ }
544
+ /**
545
+ * A hoverable submenu that opens to the right of the trigger.
546
+ * Can be controlled externally or manage its own state.
547
+ */
548
+ declare function ContextMenuSubmenu({ label, icon, children, onOpen, isOpen: externalIsOpen, onOpenChange, className, }: ContextMenuSubmenuProps): react_jsx_runtime.JSX.Element;
549
+
550
+ interface CodeViewerProps {
551
+ code: string;
552
+ language?: string;
553
+ filename?: string;
554
+ lineStart?: number;
555
+ highlightLines?: number[];
556
+ className?: string;
557
+ showLineNumbers?: boolean;
558
+ showFilename?: boolean;
559
+ autoScrollToHighlight?: boolean;
560
+ }
561
+ /**
562
+ * Code viewer with syntax highlighting, line numbers, and highlighted line support.
563
+ *
564
+ * @example
565
+ * ```tsx
566
+ * <CodeViewer
567
+ * code={sourceCode}
568
+ * filename="example.ts"
569
+ * highlightLines={[5, 6, 7]}
570
+ * lineStart={10}
571
+ * />
572
+ * ```
573
+ */
574
+ declare function CodeViewer({ code, language, filename, lineStart, highlightLines, className, showLineNumbers, showFilename, autoScrollToHighlight, }: CodeViewerProps): react_jsx_runtime.JSX.Element;
575
+
576
+ /**
577
+ * Compact version for inline code snippets without line numbers.
578
+ */
579
+ declare function CodeSnippet({ code, language, filename, className, }: {
580
+ code: string;
581
+ language?: string;
582
+ filename?: string;
583
+ className?: string;
584
+ }): react_jsx_runtime.JSX.Element;
585
+
406
586
  /**
407
587
  * Date formatting utilities for displaying relative time
408
588
  */
@@ -432,6 +612,28 @@ declare function formatDuration(seconds: number): string;
432
612
  */
433
613
  declare function formatShortRelativeTime(date: Date | string | number): string;
434
614
 
615
+ /**
616
+ * Number and byte formatting utilities
617
+ */
618
+ /**
619
+ * Formats bytes to human-readable size
620
+ * @param bytes - Number of bytes
621
+ * @returns Formatted string (e.g., "1.50 KB", "2.30 MB")
622
+ */
623
+ declare function formatBytes(bytes: number): string;
624
+ /**
625
+ * Formats large numbers with K/M suffixes
626
+ * @param num - Number to format
627
+ * @returns Formatted string (e.g., "1.5K", "2.3M")
628
+ */
629
+ declare function formatNumber(num: number): string;
630
+ /**
631
+ * Formats duration in milliseconds to human-readable format
632
+ * @param ms - Duration in milliseconds
633
+ * @returns Formatted duration string (e.g., "2h 15m", "45s")
634
+ */
635
+ declare function formatDurationMs(ms: number): string;
636
+
435
637
  declare function getTagColor(tag: string): {
436
638
  bg: string;
437
639
  text: string;
@@ -1218,4 +1420,4 @@ declare const statusStyles: {
1218
1420
  };
1219
1421
  };
1220
1422
 
1221
- export { ActivityLED, type ActivityLEDProps, Alert, AlertDescription, AlertTitle, type ApiReadinessOptions, type ApiReadinessResult, AppLayout, type AppLayoutProps, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, type CardProps, CardSkeleton, CardTitle, Checkbox, CompactStat, type CompactStatProps, CompactThemeToggle, ConnectionIndicator, ConnectionLostOverlay, ConnectionOverlay, ConnectionStatus$1 as ConnectionStatus, ConnectionStatusBanner, DashboardStats, type DashboardStatsProps, type DataColumn, DeviceIcon, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DogEarBadge, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStates, type FormState, HelpTooltip, Input, type InputProps, Label, LoadingState, type LogEntry, type LogFile, LogStats, type LogStatsProps, LogViewer, type LogViewerProps, LoginPage, LogsPage, type LogsPageProps, MarkdownCard, MarkdownScrollArea, MarkdownViewer, type NavItem, NetworkInterfaceSelect, NoSearchResults, NoSimulatorsRunning, NoTemplatesFound, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, RealtimeDataTable, type RealtimeDataTableProps, RestartBanner, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SettingDefinition$1 as SettingDefinition, type SettingsCategory$1 as SettingsCategory, SettingsFramework, SettingsPage, type SettingsPageProps, SidebarLayout, type SidebarLayoutProps, Slider, type SocketIOActions, type SocketIOConfig, type SocketIOState, Sparkline, type SparklineProps, type StatCard, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TestModeIndicator, Textarea, type TextareaProps, type Theme, type ThemeConfig, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UpdateNotification, type UseFormStateOptions, activityStyles, apiRequest, authHandler, badgeVariants, buttonStyles, buttonVariants, cardStyles, checkApiReadiness, cn, createSettingsCategory, defaultSettingsCategories, emptyStateStyles, formatDateTime, formatDuration, formatRelativeTime, formatShortRelativeTime, getCSSVariables, getTagClassName, getTagColor, socketManager, statusStyles, theme, timeAgo, useApiReadiness, useConnectionStatus, useDebounce, useFormState, useSocketIO, useTheme, waitForApiReady };
1423
+ export { ActivityLED, type ActivityLEDProps, Alert, AlertDescription, AlertTitle, type ApiReadinessOptions, type ApiReadinessResult, AppLayout, type AppLayoutProps, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, type CardProps, CardSkeleton, CardTitle, Checkbox, CodeSnippet, CodeViewer, type CodeViewerProps, ColorPalette, CompactStat, type CompactStatProps, CompactThemeToggle, ConfirmDialog, type ConfirmDialogVariant, ConnectionIndicator, ConnectionLostOverlay, ConnectionOverlay, ConnectionStatus$1 as ConnectionStatus, ConnectionStatusBanner, ContextMenu, ContextMenuItem, type ContextMenuItemProps, type ContextMenuPosition, type ContextMenuProps, ContextMenuSeparator, ContextMenuSubmenu, type ContextMenuSubmenuProps, DashboardStats, type DashboardStatsProps, type DataColumn, DeviceIcon, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DogEarBadge, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStates, type FormState, HelpTooltip, Input, type InputProps, Label, LoadingState, type LogEntry, type LogFile, LogStats, type LogStatsProps, LogViewer, type LogViewerProps, LoginPage, LogsPage, type LogsPageProps, MarkdownCard, MarkdownScrollArea, MarkdownViewer, type NavItem, NetworkInterfaceSelect, NoSearchResults, NoSimulatorsRunning, NoTemplatesFound, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, RealtimeDataTable, type RealtimeDataTableProps, ResizableDialog, RestartBanner, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SettingDefinition$1 as SettingDefinition, type SettingsCategory$1 as SettingsCategory, SettingsFramework, SettingsPage, type SettingsPageProps, SidebarLayout, type SidebarLayoutProps, Slider, type SocketIOActions, type SocketIOConfig, type SocketIOState, Sparkline, type SparklineProps, type StatCard, Switch, TAG_COLORS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TestModeIndicator, Textarea, type TextareaProps, type Theme, type ThemeConfig, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruncatedText, UpdateNotification, type UseFormStateOptions, activityStyles, apiRequest, authHandler, badgeVariants, buttonStyles, buttonVariants, cardStyles, checkApiReadiness, cn, createSettingsCategory, defaultSettingsCategories, emptyStateStyles, formatBytes, formatDateTime, formatDuration, formatDurationMs, formatNumber, formatRelativeTime, formatShortRelativeTime, getCSSVariables, getNextAvailableColor, getNextTagColor, getRandomTagColor, getTagClassName, getTagColor, socketManager, statusStyles, theme, timeAgo, useApiReadiness, useConfirmDialog, useConnectionStatus, useDebounce, useFormState, useSocketIO, useTheme, waitForApiReady };