@flanksource/clicky-ui 0.2.19 → 0.2.20
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/dist/ai.cjs +26 -0
- package/dist/ai.cjs.map +1 -0
- package/dist/ai.d.ts +2 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +26 -0
- package/dist/ai.js.map +1 -0
- package/dist/chat.cjs +7 -0
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.js +7 -0
- package/dist/chat.js.map +1 -1
- package/dist/components/FilterBar.cjs +49 -18
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts +0 -2
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +50 -19
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/SearchInput.cjs +63 -0
- package/dist/components/SearchInput.cjs.map +1 -0
- package/dist/components/SearchInput.d.ts +31 -0
- package/dist/components/SearchInput.d.ts.map +1 -0
- package/dist/components/SearchInput.js +63 -0
- package/dist/components/SearchInput.js.map +1 -0
- package/dist/components/SegmentedControl.cjs +88 -0
- package/dist/components/SegmentedControl.cjs.map +1 -0
- package/dist/components/SegmentedControl.d.ts +38 -0
- package/dist/components/SegmentedControl.d.ts.map +1 -0
- package/dist/components/SegmentedControl.js +88 -0
- package/dist/components/SegmentedControl.js.map +1 -0
- package/dist/components/Switch.cjs +51 -0
- package/dist/components/Switch.cjs.map +1 -0
- package/dist/components/Switch.d.ts +23 -0
- package/dist/components/Switch.d.ts.map +1 -0
- package/dist/components/Switch.js +51 -0
- package/dist/components/Switch.js.map +1 -0
- package/dist/components/TimeRange.cjs +53 -45
- package/dist/components/TimeRange.cjs.map +1 -1
- package/dist/components/TimeRange.d.ts.map +1 -1
- package/dist/components/TimeRange.js +53 -45
- package/dist/components/TimeRange.js.map +1 -1
- package/dist/components/TreePickerField.cjs +5 -1
- package/dist/components/TreePickerField.cjs.map +1 -1
- package/dist/components/TreePickerField.d.ts.map +1 -1
- package/dist/components/TreePickerField.js +5 -1
- package/dist/components/TreePickerField.js.map +1 -1
- package/dist/components/filter-bar-utils.cjs +5 -0
- package/dist/components/filter-bar-utils.cjs.map +1 -1
- package/dist/components/filter-bar-utils.d.ts +2 -0
- package/dist/components/filter-bar-utils.d.ts.map +1 -1
- package/dist/components/filter-bar-utils.js +5 -0
- package/dist/components/filter-bar-utils.js.map +1 -1
- package/dist/components/json-schema-form-fields.cjs +8 -2
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +8 -2
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +1 -1
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.js +1 -1
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components.cjs +15 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +8 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +15 -1
- package/dist/components.js.map +1 -1
- package/dist/data/Clicky.cjs +33 -44
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.d.ts +0 -9
- package/dist/data/Clicky.d.ts.map +1 -1
- package/dist/data/Clicky.js +31 -42
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/DataTable.cjs +73 -50
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +4 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +73 -50
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/Icon.cjs +2 -5
- package/dist/data/Icon.cjs.map +1 -1
- package/dist/data/Icon.d.ts +1 -21
- package/dist/data/Icon.d.ts.map +1 -1
- package/dist/data/Icon.js +3 -6
- package/dist/data/Icon.js.map +1 -1
- package/dist/data/MatrixTable.cjs +4 -4
- package/dist/data/MatrixTable.cjs.map +1 -1
- package/dist/data/MatrixTable.js +4 -4
- package/dist/data/MatrixTable.js.map +1 -1
- package/dist/data/RadialGauge.cjs +76 -0
- package/dist/data/RadialGauge.cjs.map +1 -0
- package/dist/data/RadialGauge.d.ts +24 -0
- package/dist/data/RadialGauge.d.ts.map +1 -0
- package/dist/data/RadialGauge.js +76 -0
- package/dist/data/RadialGauge.js.map +1 -0
- package/dist/data/StatusBreakdown.cjs +0 -4
- package/dist/data/StatusBreakdown.cjs.map +1 -1
- package/dist/data/StatusBreakdown.d.ts +0 -2
- package/dist/data/StatusBreakdown.d.ts.map +1 -1
- package/dist/data/StatusBreakdown.js +1 -5
- package/dist/data/StatusBreakdown.js.map +1 -1
- package/dist/data/Timeline.cjs +61 -0
- package/dist/data/Timeline.cjs.map +1 -0
- package/dist/data/Timeline.d.ts +36 -0
- package/dist/data/Timeline.d.ts.map +1 -0
- package/dist/data/Timeline.js +61 -0
- package/dist/data/Timeline.js.map +1 -0
- package/dist/data/TimeseriesCoreBars.cjs +2 -25
- package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts +0 -19
- package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
- package/dist/data/TimeseriesCoreBars.js +2 -25
- package/dist/data/TimeseriesCoreBars.js.map +1 -1
- package/dist/data/TimeseriesCoreBars.model.cjs +27 -0
- package/dist/data/TimeseriesCoreBars.model.cjs.map +1 -0
- package/dist/data/TimeseriesCoreBars.model.d.ts +20 -0
- package/dist/data/TimeseriesCoreBars.model.d.ts.map +1 -0
- package/dist/data/TimeseriesCoreBars.model.js +27 -0
- package/dist/data/TimeseriesCoreBars.model.js.map +1 -0
- package/dist/data/TimeseriesPanel.axes.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.axes.d.ts +1 -1
- package/dist/data/TimeseriesPanel.axes.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.axes.js.map +1 -1
- package/dist/data/TimeseriesPanel.cjs +4 -54
- package/dist/data/TimeseriesPanel.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.d.ts +2 -138
- package/dist/data/TimeseriesPanel.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.js +2 -52
- package/dist/data/TimeseriesPanel.js.map +1 -1
- package/dist/data/TimeseriesPanel.model.cjs +53 -0
- package/dist/data/TimeseriesPanel.model.cjs.map +1 -0
- package/dist/data/TimeseriesPanel.model.d.ts +88 -0
- package/dist/data/TimeseriesPanel.model.d.ts.map +1 -0
- package/dist/data/TimeseriesPanel.model.js +53 -0
- package/dist/data/TimeseriesPanel.model.js.map +1 -0
- package/dist/data/Tree.cjs +1 -1
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.js +1 -1
- package/dist/data/Tree.js.map +1 -1
- package/dist/data/ai/ChatFab.cjs +29 -0
- package/dist/data/ai/ChatFab.cjs.map +1 -0
- package/dist/data/ai/ChatFab.d.ts +12 -0
- package/dist/data/ai/ChatFab.d.ts.map +1 -0
- package/dist/data/ai/ChatFab.js +29 -0
- package/dist/data/ai/ChatFab.js.map +1 -0
- package/dist/data/ai/ChatWindow.cjs +178 -0
- package/dist/data/ai/ChatWindow.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.d.ts +38 -0
- package/dist/data/ai/ChatWindow.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.js +156 -0
- package/dist/data/ai/ChatWindow.js.map +1 -0
- package/dist/data/ai/ChatWindowManager.cjs +139 -0
- package/dist/data/ai/ChatWindowManager.cjs.map +1 -0
- package/dist/data/ai/ChatWindowManager.d.ts +12 -0
- package/dist/data/ai/ChatWindowManager.d.ts.map +1 -0
- package/dist/data/ai/ChatWindowManager.js +139 -0
- package/dist/data/ai/ChatWindowManager.js.map +1 -0
- package/dist/data/ai/ContextBadges.cjs +74 -0
- package/dist/data/ai/ContextBadges.cjs.map +1 -0
- package/dist/data/ai/ContextBadges.d.ts +16 -0
- package/dist/data/ai/ContextBadges.d.ts.map +1 -0
- package/dist/data/ai/ContextBadges.js +74 -0
- package/dist/data/ai/ContextBadges.js.map +1 -0
- package/dist/data/ai/ThreadPicker.cjs +148 -0
- package/dist/data/ai/ThreadPicker.cjs.map +1 -0
- package/dist/data/ai/ThreadPicker.d.ts +37 -0
- package/dist/data/ai/ThreadPicker.d.ts.map +1 -0
- package/dist/data/ai/ThreadPicker.js +148 -0
- package/dist/data/ai/ThreadPicker.js.map +1 -0
- package/dist/data/ai/ToolPreferences.cjs +80 -0
- package/dist/data/ai/ToolPreferences.cjs.map +1 -0
- package/dist/data/ai/ToolPreferences.d.ts +19 -0
- package/dist/data/ai/ToolPreferences.d.ts.map +1 -0
- package/dist/data/ai/ToolPreferences.js +80 -0
- package/dist/data/ai/ToolPreferences.js.map +1 -0
- package/dist/data/ai/chat-window-context.cjs +78 -0
- package/dist/data/ai/chat-window-context.cjs.map +1 -0
- package/dist/data/ai/chat-window-context.d.ts +57 -0
- package/dist/data/ai/chat-window-context.d.ts.map +1 -0
- package/dist/data/ai/chat-window-context.js +78 -0
- package/dist/data/ai/chat-window-context.js.map +1 -0
- package/dist/data/ai/context.cjs +43 -0
- package/dist/data/ai/context.cjs.map +1 -0
- package/dist/data/ai/context.d.ts +35 -0
- package/dist/data/ai/context.d.ts.map +1 -0
- package/dist/data/ai/context.js +43 -0
- package/dist/data/ai/context.js.map +1 -0
- package/dist/data/ai/index.d.ts +10 -0
- package/dist/data/ai/index.d.ts.map +1 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs +15 -0
- package/dist/data/cache-browser/CacheDetailPanel.cjs.map +1 -1
- package/dist/data/cache-browser/CacheDetailPanel.d.ts.map +1 -1
- package/dist/data/cache-browser/CacheDetailPanel.js +15 -0
- package/dist/data/cache-browser/CacheDetailPanel.js.map +1 -1
- package/dist/data/cache-browser/cache-browser.fixtures.d.ts +10 -0
- package/dist/data/cache-browser/cache-browser.fixtures.d.ts.map +1 -0
- package/dist/data/cache-browser/download.cjs +13 -0
- package/dist/data/cache-browser/download.cjs.map +1 -0
- package/dist/data/cache-browser/download.d.ts +3 -0
- package/dist/data/cache-browser/download.d.ts.map +1 -0
- package/dist/data/cache-browser/download.js +13 -0
- package/dist/data/cache-browser/download.js.map +1 -0
- package/dist/data/chat/Chat.cjs +40 -2
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts +5 -2
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.cjs +86 -0
- package/dist/data/chat/Chat.fixtures.cjs.map +1 -0
- package/dist/data/chat/Chat.fixtures.d.ts +4 -0
- package/dist/data/chat/Chat.fixtures.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.js +86 -0
- package/dist/data/chat/Chat.fixtures.js.map +1 -0
- package/dist/data/chat/Chat.js +41 -3
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/ContextUsage.cjs +99 -0
- package/dist/data/chat/ContextUsage.cjs.map +1 -0
- package/dist/data/chat/ContextUsage.d.ts +19 -0
- package/dist/data/chat/ContextUsage.d.ts.map +1 -0
- package/dist/data/chat/ContextUsage.js +99 -0
- package/dist/data/chat/ContextUsage.js.map +1 -0
- package/dist/data/chat/ModelSelector.cjs +28 -14
- package/dist/data/chat/ModelSelector.cjs.map +1 -1
- package/dist/data/chat/ModelSelector.d.ts +5 -4
- package/dist/data/chat/ModelSelector.d.ts.map +1 -1
- package/dist/data/chat/ModelSelector.js +28 -14
- package/dist/data/chat/ModelSelector.js.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.cjs +21 -1
- package/dist/data/chat/clickyOperationsToTools.cjs.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts +5 -4
- package/dist/data/chat/clickyOperationsToTools.d.ts.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.js +21 -1
- package/dist/data/chat/clickyOperationsToTools.js.map +1 -1
- package/dist/data/chat/index.d.ts +4 -1
- package/dist/data/chat/index.d.ts.map +1 -1
- package/dist/data/chat/provider-icons.cjs +15 -0
- package/dist/data/chat/provider-icons.cjs.map +1 -0
- package/dist/data/chat/provider-icons.d.ts +7 -0
- package/dist/data/chat/provider-icons.d.ts.map +1 -0
- package/dist/data/chat/provider-icons.js +15 -0
- package/dist/data/chat/provider-icons.js.map +1 -0
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +41 -9
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/clicky-parse.cjs +42 -0
- package/dist/data/clicky-parse.cjs.map +1 -0
- package/dist/data/clicky-parse.d.ts +11 -0
- package/dist/data/clicky-parse.d.ts.map +1 -0
- package/dist/data/clicky-parse.js +42 -0
- package/dist/data/clicky-parse.js.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.cjs +0 -4
- package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.d.ts +1 -11
- package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.js +1 -5
- package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.utils.cjs +7 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.cjs.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.d.ts +12 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.d.ts.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.js +7 -0
- package/dist/data/diagnostics/FrameSourceWindow.utils.js.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.cjs +2 -1
- package/dist/data/diagnostics/JvmStackTrace.cjs.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.js +2 -1
- package/dist/data/diagnostics/JvmStackTrace.js.map +1 -1
- package/dist/data/icon-fallback.cjs +12 -0
- package/dist/data/icon-fallback.cjs.map +1 -0
- package/dist/data/icon-fallback.d.ts +19 -0
- package/dist/data/icon-fallback.d.ts.map +1 -0
- package/dist/data/icon-fallback.js +12 -0
- package/dist/data/icon-fallback.js.map +1 -0
- package/dist/data/status-breakdown-utils.cjs +7 -0
- package/dist/data/status-breakdown-utils.cjs.map +1 -0
- package/dist/data/status-breakdown-utils.d.ts +4 -0
- package/dist/data/status-breakdown-utils.d.ts.map +1 -0
- package/dist/data/status-breakdown-utils.js +7 -0
- package/dist/data/status-breakdown-utils.js.map +1 -0
- package/dist/data/test-runner/TestRunSummary.cjs +36 -0
- package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
- package/dist/data/test-runner/TestRunSummary.d.ts +7 -1
- package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunSummary.js +36 -0
- package/dist/data/test-runner/TestRunSummary.js.map +1 -1
- package/dist/data/test-runner/TestRunner.cjs +5 -3
- package/dist/data/test-runner/TestRunner.cjs.map +1 -1
- package/dist/data/test-runner/TestRunner.d.ts +13 -1
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.js +5 -3
- package/dist/data/test-runner/TestRunner.js.map +1 -1
- package/dist/data/version-info.cjs +2 -2
- package/dist/data/version-info.js +2 -2
- package/dist/data.cjs +19 -6
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +13 -5
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +18 -5
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +51 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +50 -6
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.cjs +179 -29
- package/dist/layout/AppShell.cjs.map +1 -1
- package/dist/layout/AppShell.d.ts +5 -5
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/AppShell.js +179 -29
- package/dist/layout/AppShell.js.map +1 -1
- package/dist/layout/AppSidebar.cjs +239 -0
- package/dist/layout/AppSidebar.cjs.map +1 -0
- package/dist/layout/AppSidebar.d.ts +62 -0
- package/dist/layout/AppSidebar.d.ts.map +1 -0
- package/dist/layout/AppSidebar.js +239 -0
- package/dist/layout/AppSidebar.js.map +1 -0
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/Modal.cjs +4 -2
- package/dist/overlay/Modal.cjs.map +1 -1
- package/dist/overlay/Modal.d.ts +1 -1
- package/dist/overlay/Modal.d.ts.map +1 -1
- package/dist/overlay/Modal.js +4 -2
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/overlay/Toast.cjs +89 -0
- package/dist/overlay/Toast.cjs.map +1 -0
- package/dist/overlay/Toast.d.ts +14 -0
- package/dist/overlay/Toast.d.ts.map +1 -0
- package/dist/overlay/Toast.js +89 -0
- package/dist/overlay/Toast.js.map +1 -0
- package/dist/overlay/toast-context.cjs +12 -0
- package/dist/overlay/toast-context.cjs.map +1 -0
- package/dist/overlay/toast-context.d.ts +24 -0
- package/dist/overlay/toast-context.d.ts.map +1 -0
- package/dist/overlay/toast-context.js +12 -0
- package/dist/overlay/toast-context.js.map +1 -0
- package/dist/rpc/AcceptPicker.cjs +81 -58
- package/dist/rpc/AcceptPicker.cjs.map +1 -1
- package/dist/rpc/AcceptPicker.d.ts.map +1 -1
- package/dist/rpc/AcceptPicker.js +81 -58
- package/dist/rpc/AcceptPicker.js.map +1 -1
- package/dist/rpc/CommandForm.cjs +5 -35
- package/dist/rpc/CommandForm.cjs.map +1 -1
- package/dist/rpc/CommandForm.d.ts +0 -3
- package/dist/rpc/CommandForm.d.ts.map +1 -1
- package/dist/rpc/CommandForm.js +2 -32
- package/dist/rpc/CommandForm.js.map +1 -1
- package/dist/rpc/CommandOutput.cjs +2 -1
- package/dist/rpc/CommandOutput.cjs.map +1 -1
- package/dist/rpc/CommandOutput.d.ts.map +1 -1
- package/dist/rpc/CommandOutput.js +2 -1
- package/dist/rpc/CommandOutput.js.map +1 -1
- package/dist/rpc/EntityExplorerApp.cjs +28 -83
- package/dist/rpc/EntityExplorerApp.cjs.map +1 -1
- package/dist/rpc/EntityExplorerApp.d.ts +1 -4
- package/dist/rpc/EntityExplorerApp.d.ts.map +1 -1
- package/dist/rpc/EntityExplorerApp.js +13 -68
- package/dist/rpc/EntityExplorerApp.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +2 -2
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +1 -1
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +1 -1
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationCommandPage.cjs +6 -4
- package/dist/rpc/OperationCommandPage.cjs.map +1 -1
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
- package/dist/rpc/OperationCommandPage.js +3 -1
- package/dist/rpc/OperationCommandPage.js.map +1 -1
- package/dist/rpc/RouterProvider.cjs +10 -0
- package/dist/rpc/RouterProvider.cjs.map +1 -0
- package/dist/rpc/RouterProvider.d.ts +10 -0
- package/dist/rpc/RouterProvider.d.ts.map +1 -0
- package/dist/rpc/RouterProvider.js +10 -0
- package/dist/rpc/RouterProvider.js.map +1 -0
- package/dist/rpc/apiClient.cjs +4 -4
- package/dist/rpc/apiClient.cjs.map +1 -1
- package/dist/rpc/apiClient.js +4 -4
- package/dist/rpc/apiClient.js.map +1 -1
- package/dist/rpc/command-form-utils.cjs +43 -0
- package/dist/rpc/command-form-utils.cjs.map +1 -0
- package/dist/rpc/command-form-utils.d.ts +5 -0
- package/dist/rpc/command-form-utils.d.ts.map +1 -0
- package/dist/rpc/command-form-utils.js +43 -0
- package/dist/rpc/command-form-utils.js.map +1 -0
- package/dist/rpc/commandHref.cjs +62 -0
- package/dist/rpc/commandHref.cjs.map +1 -0
- package/dist/rpc/commandHref.d.ts +7 -0
- package/dist/rpc/commandHref.d.ts.map +1 -0
- package/dist/rpc/commandHref.js +62 -0
- package/dist/rpc/commandHref.js.map +1 -0
- package/dist/rpc/formMetadata.cjs +1 -1
- package/dist/rpc/formMetadata.cjs.map +1 -1
- package/dist/rpc/formMetadata.js +1 -1
- package/dist/rpc/formMetadata.js.map +1 -1
- package/dist/rpc/router.cjs +83 -0
- package/dist/rpc/router.cjs.map +1 -0
- package/dist/rpc/router.d.ts +24 -0
- package/dist/rpc/router.d.ts.map +1 -0
- package/dist/rpc/router.js +83 -0
- package/dist/rpc/router.js.map +1 -0
- package/dist/rpc/rpc-story-fixtures/orders.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/orders.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/services.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/services.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/surface-fixture.d.ts +24 -0
- package/dist/rpc/rpc-story-fixtures/surface-fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story-fixtures/widgets.fixture.d.ts +3 -0
- package/dist/rpc/rpc-story-fixtures/widgets.fixture.d.ts.map +1 -0
- package/dist/rpc/rpc-story.fixtures.d.ts +16 -0
- package/dist/rpc/rpc-story.fixtures.d.ts.map +1 -0
- package/dist/rpc.cjs +17 -0
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.ts +5 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +18 -1
- package/dist/rpc.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +11 -1
|
@@ -4,9 +4,6 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
4
4
|
require("react");
|
|
5
5
|
const utils = require("../lib/utils.cjs");
|
|
6
6
|
const button = require("../components/button.cjs");
|
|
7
|
-
function segment(key, label, count, className) {
|
|
8
|
-
return { key, label, count: Math.max(0, count || 0), className };
|
|
9
|
-
}
|
|
10
7
|
const defaultRenderLink = ({ to, className, title, children }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: to, className, title, children });
|
|
11
8
|
function StackedStatusBar({
|
|
12
9
|
segments,
|
|
@@ -76,5 +73,4 @@ function StatusRows({
|
|
|
76
73
|
}
|
|
77
74
|
exports.StackedStatusBar = StackedStatusBar;
|
|
78
75
|
exports.StatusRows = StatusRows;
|
|
79
|
-
exports.segment = segment;
|
|
80
76
|
//# sourceMappingURL=StatusBreakdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBreakdown.cjs","sources":["../../src/data/StatusBreakdown.tsx"],"sourcesContent":["import { type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/button\";\n\n// A status-breakdown family: one StatusSegment list rendered either as a single\n// horizontal StackedStatusBar (scan a mix at a glance) or as vertical StatusRows\n// (each status on its own line with a proportional bar, optional drill-down link\n// and retry). Shared by monitor/intake/cycle breakdowns and any panel that shows\n// a count mix.\n\nexport interface StatusSegment {\n key: string;\n label: string;\n count: number;\n /** Tailwind background class for the swatch/bar fill, e.g. \"bg-green-500\". */\n className: string;\n /**\n * When set, the row links here (the breakdown points each status at its\n * filtered records/members view). Rendered via the `renderLink` prop so the\n * component stays router-agnostic.\n */\n href?: string;\n}\n\n/**
|
|
1
|
+
{"version":3,"file":"StatusBreakdown.cjs","sources":["../../src/data/StatusBreakdown.tsx"],"sourcesContent":["import { type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/button\";\n\n// A status-breakdown family: one StatusSegment list rendered either as a single\n// horizontal StackedStatusBar (scan a mix at a glance) or as vertical StatusRows\n// (each status on its own line with a proportional bar, optional drill-down link\n// and retry). Shared by monitor/intake/cycle breakdowns and any panel that shows\n// a count mix.\n\nexport interface StatusSegment {\n key: string;\n label: string;\n count: number;\n /** Tailwind background class for the swatch/bar fill, e.g. \"bg-green-500\". */\n className: string;\n /**\n * When set, the row links here (the breakdown points each status at its\n * filtered records/members view). Rendered via the `renderLink` prop so the\n * component stays router-agnostic.\n */\n href?: string;\n}\n\n/** Render-prop for a status row's link, so callers supply their router's Link (or a plain <a>). */\nexport type StatusRenderLink = (args: {\n to: string;\n className?: string;\n title?: string;\n children: ReactNode;\n}) => ReactElement;\n\nconst defaultRenderLink: StatusRenderLink = ({ to, className, title, children }) => (\n <a href={to} className={className} title={title}>\n {children}\n </a>\n);\n\n// StackedStatusBar renders the segments as a single horizontal multi-color bar —\n// segments share one track sized proportionally to the visible-segment total.\nexport function StackedStatusBar({\n segments,\n ariaLabel,\n}: {\n segments: StatusSegment[];\n ariaLabel?: string;\n}) {\n const visible = segments.filter((s) => s.count > 0);\n const total = visible.reduce((sum, s) => sum + s.count, 0);\n if (visible.length === 0 || total <= 0) {\n return <div className=\"rounded border border-dashed p-3 text-xs text-muted-foreground\">No status data</div>;\n }\n return (\n <div className=\"flex h-2 overflow-hidden rounded bg-muted\" aria-label={ariaLabel}>\n {visible.map((s) => (\n <div\n key={s.key}\n className={s.className}\n title={`${s.label}: ${s.count}`}\n style={{ width: `${Math.max(1, (s.count / total) * 100)}%` }}\n />\n ))}\n </div>\n );\n}\n\n// StatusRows renders each status as its own row — a colored swatch + label, the\n// count, and a horizontal bar sized proportionally to the visible-segment total.\n// The vertical counterpart to StackedStatusBar. An optional onRetry surfaces a\n// Retry button per row; callers that omit it get no button. When a segment\n// carries an href the whole row links there via renderLink (defaults to a plain\n// <a>); the Retry button stops propagation so it stays independently clickable.\nexport function StatusRows({\n segments,\n ariaLabel,\n onRetry,\n retryingKey,\n isRetryable,\n renderLink = defaultRenderLink,\n}: {\n segments: StatusSegment[];\n ariaLabel?: string;\n onRetry?: (segment: StatusSegment) => void;\n retryingKey?: string;\n isRetryable?: (segment: StatusSegment) => boolean;\n renderLink?: StatusRenderLink;\n}) {\n const visible = segments.filter((s) => s.count > 0);\n const total = visible.reduce((sum, s) => sum + s.count, 0);\n if (visible.length === 0 || total <= 0) {\n return <div className=\"rounded border border-dashed p-3 text-xs text-muted-foreground\">No status data</div>;\n }\n return (\n <div className=\"space-y-2\" aria-label={ariaLabel}>\n {visible.map((s) => {\n const retryable = !!onRetry && (isRetryable?.(s) ?? false);\n const meta = (\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <span className={cn(\"h-2.5 w-2.5 shrink-0 rounded-sm\", s.className)} aria-hidden=\"true\" />\n <span className=\"truncate text-xs\">{s.label}</span>\n <span className=\"ml-auto shrink-0 font-mono text-xs text-muted-foreground\">{s.count}</span>\n </div>\n );\n return (\n <div key={s.key} className=\"flex items-center gap-3\">\n {s.href\n ? renderLink({\n to: s.href,\n className: \"flex min-w-0 flex-1 rounded hover:bg-accent/40\",\n title: `View ${s.label} records`,\n children: meta,\n })\n : meta}\n <div className=\"h-2 w-32 shrink-0 overflow-hidden rounded bg-muted sm:w-48\">\n <div className={cn(\"h-full\", s.className)} style={{ width: `${Math.max(1, (s.count / total) * 100)}%` }} />\n </div>\n {retryable ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-6 shrink-0 px-2 text-[11px]\"\n disabled={retryingKey === s.key}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onRetry?.(s);\n }}\n >\n {retryingKey === s.key ? \"Retrying…\" : \"Retry\"}\n </Button>\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"],"names":["jsx","jsxs","cn","Button"],"mappings":"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"}
|
|
@@ -12,8 +12,6 @@ export interface StatusSegment {
|
|
|
12
12
|
*/
|
|
13
13
|
href?: string;
|
|
14
14
|
}
|
|
15
|
-
/** Builds a StatusSegment, clamping the count to a non-negative integer. */
|
|
16
|
-
export declare function segment(key: string, label: string, count: number, className: string): StatusSegment;
|
|
17
15
|
/** Render-prop for a status row's link, so callers supply their router's Link (or a plain <a>). */
|
|
18
16
|
export type StatusRenderLink = (args: {
|
|
19
17
|
to: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBreakdown.d.ts","sourceRoot":"","sources":["../../src/data/StatusBreakdown.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAU1D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,
|
|
1
|
+
{"version":3,"file":"StatusBreakdown.d.ts","sourceRoot":"","sources":["../../src/data/StatusBreakdown.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAU1D,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mGAAmG;AACnG,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC;CACrB,KAAK,YAAY,CAAC;AAUnB,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAkBA;AAQD,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,SAAS,EACT,OAAO,EACP,WAAW,EACX,WAAW,EACX,UAA8B,GAC/B,EAAE;IACD,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;IAClD,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,2CAmDA"}
|
|
@@ -2,9 +2,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { Button } from "../components/button.js";
|
|
5
|
-
function segment(key, label, count, className) {
|
|
6
|
-
return { key, label, count: Math.max(0, count || 0), className };
|
|
7
|
-
}
|
|
8
5
|
const defaultRenderLink = ({ to, className, title, children }) => /* @__PURE__ */ jsx("a", { href: to, className, title, children });
|
|
9
6
|
function StackedStatusBar({
|
|
10
7
|
segments,
|
|
@@ -74,7 +71,6 @@ function StatusRows({
|
|
|
74
71
|
}
|
|
75
72
|
export {
|
|
76
73
|
StackedStatusBar,
|
|
77
|
-
StatusRows
|
|
78
|
-
segment
|
|
74
|
+
StatusRows
|
|
79
75
|
};
|
|
80
76
|
//# sourceMappingURL=StatusBreakdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBreakdown.js","sources":["../../src/data/StatusBreakdown.tsx"],"sourcesContent":["import { type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/button\";\n\n// A status-breakdown family: one StatusSegment list rendered either as a single\n// horizontal StackedStatusBar (scan a mix at a glance) or as vertical StatusRows\n// (each status on its own line with a proportional bar, optional drill-down link\n// and retry). Shared by monitor/intake/cycle breakdowns and any panel that shows\n// a count mix.\n\nexport interface StatusSegment {\n key: string;\n label: string;\n count: number;\n /** Tailwind background class for the swatch/bar fill, e.g. \"bg-green-500\". */\n className: string;\n /**\n * When set, the row links here (the breakdown points each status at its\n * filtered records/members view). Rendered via the `renderLink` prop so the\n * component stays router-agnostic.\n */\n href?: string;\n}\n\n/**
|
|
1
|
+
{"version":3,"file":"StatusBreakdown.js","sources":["../../src/data/StatusBreakdown.tsx"],"sourcesContent":["import { type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../components/button\";\n\n// A status-breakdown family: one StatusSegment list rendered either as a single\n// horizontal StackedStatusBar (scan a mix at a glance) or as vertical StatusRows\n// (each status on its own line with a proportional bar, optional drill-down link\n// and retry). Shared by monitor/intake/cycle breakdowns and any panel that shows\n// a count mix.\n\nexport interface StatusSegment {\n key: string;\n label: string;\n count: number;\n /** Tailwind background class for the swatch/bar fill, e.g. \"bg-green-500\". */\n className: string;\n /**\n * When set, the row links here (the breakdown points each status at its\n * filtered records/members view). Rendered via the `renderLink` prop so the\n * component stays router-agnostic.\n */\n href?: string;\n}\n\n/** Render-prop for a status row's link, so callers supply their router's Link (or a plain <a>). */\nexport type StatusRenderLink = (args: {\n to: string;\n className?: string;\n title?: string;\n children: ReactNode;\n}) => ReactElement;\n\nconst defaultRenderLink: StatusRenderLink = ({ to, className, title, children }) => (\n <a href={to} className={className} title={title}>\n {children}\n </a>\n);\n\n// StackedStatusBar renders the segments as a single horizontal multi-color bar —\n// segments share one track sized proportionally to the visible-segment total.\nexport function StackedStatusBar({\n segments,\n ariaLabel,\n}: {\n segments: StatusSegment[];\n ariaLabel?: string;\n}) {\n const visible = segments.filter((s) => s.count > 0);\n const total = visible.reduce((sum, s) => sum + s.count, 0);\n if (visible.length === 0 || total <= 0) {\n return <div className=\"rounded border border-dashed p-3 text-xs text-muted-foreground\">No status data</div>;\n }\n return (\n <div className=\"flex h-2 overflow-hidden rounded bg-muted\" aria-label={ariaLabel}>\n {visible.map((s) => (\n <div\n key={s.key}\n className={s.className}\n title={`${s.label}: ${s.count}`}\n style={{ width: `${Math.max(1, (s.count / total) * 100)}%` }}\n />\n ))}\n </div>\n );\n}\n\n// StatusRows renders each status as its own row — a colored swatch + label, the\n// count, and a horizontal bar sized proportionally to the visible-segment total.\n// The vertical counterpart to StackedStatusBar. An optional onRetry surfaces a\n// Retry button per row; callers that omit it get no button. When a segment\n// carries an href the whole row links there via renderLink (defaults to a plain\n// <a>); the Retry button stops propagation so it stays independently clickable.\nexport function StatusRows({\n segments,\n ariaLabel,\n onRetry,\n retryingKey,\n isRetryable,\n renderLink = defaultRenderLink,\n}: {\n segments: StatusSegment[];\n ariaLabel?: string;\n onRetry?: (segment: StatusSegment) => void;\n retryingKey?: string;\n isRetryable?: (segment: StatusSegment) => boolean;\n renderLink?: StatusRenderLink;\n}) {\n const visible = segments.filter((s) => s.count > 0);\n const total = visible.reduce((sum, s) => sum + s.count, 0);\n if (visible.length === 0 || total <= 0) {\n return <div className=\"rounded border border-dashed p-3 text-xs text-muted-foreground\">No status data</div>;\n }\n return (\n <div className=\"space-y-2\" aria-label={ariaLabel}>\n {visible.map((s) => {\n const retryable = !!onRetry && (isRetryable?.(s) ?? false);\n const meta = (\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <span className={cn(\"h-2.5 w-2.5 shrink-0 rounded-sm\", s.className)} aria-hidden=\"true\" />\n <span className=\"truncate text-xs\">{s.label}</span>\n <span className=\"ml-auto shrink-0 font-mono text-xs text-muted-foreground\">{s.count}</span>\n </div>\n );\n return (\n <div key={s.key} className=\"flex items-center gap-3\">\n {s.href\n ? renderLink({\n to: s.href,\n className: \"flex min-w-0 flex-1 rounded hover:bg-accent/40\",\n title: `View ${s.label} records`,\n children: meta,\n })\n : meta}\n <div className=\"h-2 w-32 shrink-0 overflow-hidden rounded bg-muted sm:w-48\">\n <div className={cn(\"h-full\", s.className)} style={{ width: `${Math.max(1, (s.count / total) * 100)}%` }} />\n </div>\n {retryable ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-6 shrink-0 px-2 text-[11px]\"\n disabled={retryingKey === s.key}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onRetry?.(s);\n }}\n >\n {retryingKey === s.key ? \"Retrying…\" : \"Retry\"}\n </Button>\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;AAgCA,MAAM,oBAAsC,CAAC,EAAE,IAAI,WAAW,OAAO,SAAA,MACnE,oBAAC,KAAA,EAAE,MAAM,IAAI,WAAsB,OAChC,SAAA,CACH;AAKK,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GAGG;AACD,QAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;AAClD,QAAM,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACzD,MAAI,QAAQ,WAAW,KAAK,SAAS,GAAG;AACtC,WAAO,oBAAC,OAAA,EAAI,WAAU,kEAAiE,UAAA,kBAAc;AAAA,EACvG;AACA,SACE,oBAAC,SAAI,WAAU,6CAA4C,cAAY,WACpE,UAAA,QAAQ,IAAI,CAAC,MACZ;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,WAAW,EAAE;AAAA,MACb,OAAO,GAAG,EAAE,KAAK,KAAK,EAAE,KAAK;AAAA,MAC7B,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,GAAI,EAAE,QAAQ,QAAS,GAAG,CAAC,IAAA;AAAA,IAAI;AAAA,IAHtD,EAAE;AAAA,EAAA,CAKV,GACH;AAEJ;AAQO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAOG;AACD,QAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;AAClD,QAAM,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACzD,MAAI,QAAQ,WAAW,KAAK,SAAS,GAAG;AACtC,WAAO,oBAAC,OAAA,EAAI,WAAU,kEAAiE,UAAA,kBAAc;AAAA,EACvG;AACA,SACE,oBAAC,SAAI,WAAU,aAAY,cAAY,WACpC,UAAA,QAAQ,IAAI,CAAC,MAAM;AAClB,UAAM,YAAY,CAAC,CAAC,aAAY,2CAAc,OAAM;AACpD,UAAM,OACJ,qBAAC,OAAA,EAAI,WAAU,0CACb,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAW,GAAG,mCAAmC,EAAE,SAAS,GAAG,eAAY,QAAO;AAAA,MACxF,oBAAC,QAAA,EAAK,WAAU,oBAAoB,YAAE,OAAM;AAAA,MAC5C,oBAAC,QAAA,EAAK,WAAU,4DAA4D,YAAE,MAAA,CAAM;AAAA,IAAA,GACtF;AAEF,WACE,qBAAC,OAAA,EAAgB,WAAU,2BACxB,UAAA;AAAA,MAAA,EAAE,OACC,WAAW;AAAA,QACT,IAAI,EAAE;AAAA,QACN,WAAW;AAAA,QACX,OAAO,QAAQ,EAAE,KAAK;AAAA,QACtB,UAAU;AAAA,MAAA,CACX,IACD;AAAA,MACJ,oBAAC,OAAA,EAAI,WAAU,8DACb,UAAA,oBAAC,OAAA,EAAI,WAAW,GAAG,UAAU,EAAE,SAAS,GAAG,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,GAAI,EAAE,QAAQ,QAAS,GAAG,CAAC,IAAA,EAAI,CAAG,EAAA,CAC3G;AAAA,MACC,YACC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,WAAU;AAAA,UACV,UAAU,gBAAgB,EAAE;AAAA,UAC5B,SAAS,CAAC,MAAM;AACd,cAAE,eAAA;AACF,cAAE,gBAAA;AACF,+CAAU;AAAA,UACZ;AAAA,UAEC,UAAA,gBAAgB,EAAE,MAAM,cAAc;AAAA,QAAA;AAAA,MAAA,IAEvC;AAAA,IAAA,EAAA,GA3BI,EAAE,GA4BZ;AAAA,EAEJ,CAAC,EAAA,CACH;AAEJ;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const utils = require("../lib/utils.cjs");
|
|
5
|
+
const Icon = require("./Icon.cjs");
|
|
6
|
+
const DISC_TONE = {
|
|
7
|
+
success: "bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300",
|
|
8
|
+
danger: "bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300",
|
|
9
|
+
warning: "bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300",
|
|
10
|
+
info: "bg-sky-100 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300",
|
|
11
|
+
neutral: "bg-muted text-muted-foreground"
|
|
12
|
+
};
|
|
13
|
+
function Timeline({ items, className }) {
|
|
14
|
+
return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: utils.cn("relative", className), children: items.map((item, index) => {
|
|
15
|
+
const last = index === items.length - 1;
|
|
16
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative flex gap-density-3 pb-density-4 last:pb-0", children: [
|
|
17
|
+
!last && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18
|
+
"span",
|
|
19
|
+
{
|
|
20
|
+
"aria-hidden": true,
|
|
21
|
+
className: "absolute bottom-0 left-[10px] top-[22px] w-px bg-border"
|
|
22
|
+
}
|
|
23
|
+
),
|
|
24
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25
|
+
"span",
|
|
26
|
+
{
|
|
27
|
+
className: utils.cn(
|
|
28
|
+
"relative z-[1] flex h-[21px] w-[21px] shrink-0 items-center justify-center rounded-full",
|
|
29
|
+
DISC_TONE[item.tone ?? "neutral"]
|
|
30
|
+
),
|
|
31
|
+
children: item.icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32
|
+
Icon.Icon,
|
|
33
|
+
{
|
|
34
|
+
...typeof item.icon === "string" ? { name: item.icon } : { icon: item.icon },
|
|
35
|
+
className: "h-3 w-3"
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 pt-px", children: [
|
|
41
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
|
|
42
|
+
item.actor && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: item.actor }),
|
|
43
|
+
item.action && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
44
|
+
" ",
|
|
45
|
+
item.action
|
|
46
|
+
] }),
|
|
47
|
+
item.timestamp && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1.5 text-xs text-muted-foreground", children: [
|
|
48
|
+
"· ",
|
|
49
|
+
item.timestamp
|
|
50
|
+
] })
|
|
51
|
+
] }),
|
|
52
|
+
item.body != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 overflow-hidden rounded-md border border-border bg-secondary", children: [
|
|
53
|
+
item.bodyHeader != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-density-3 py-1.5 text-xs", children: item.bodyHeader }),
|
|
54
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-density-3 py-density-2 text-sm leading-relaxed text-foreground", children: item.body })
|
|
55
|
+
] })
|
|
56
|
+
] })
|
|
57
|
+
] }, item.id);
|
|
58
|
+
}) });
|
|
59
|
+
}
|
|
60
|
+
exports.Timeline = Timeline;
|
|
61
|
+
//# sourceMappingURL=Timeline.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timeline.cjs","sources":["../../src/data/Timeline.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { BadgeTone } from \"./Badge\";\n\nexport type TimelineItem = {\n /** Stable key. */\n id: string | number;\n /** Icon shown in the tone-colored disc. */\n icon?: string | StaticIconComponent;\n /** Semantic color of the disc. Defaults to `neutral`. */\n tone?: BadgeTone;\n /** Actor (rendered bold), e.g. a username. */\n actor?: ReactNode;\n /** What happened, e.g. \"approved these changes\". */\n action?: ReactNode;\n /** Relative time, e.g. \"1d ago\". */\n timestamp?: ReactNode;\n /** Optional expanded body (Gavel's threaded comment bubble). */\n body?: ReactNode;\n /** Optional header for the body bubble, e.g. a file anchor + status `Badge`. */\n bodyHeader?: ReactNode;\n};\n\nexport type TimelineProps = {\n /** Events rendered top to bottom, connected by a rail. */\n items: TimelineItem[];\n /** Classes applied to the list. */\n className?: string;\n};\n\nconst DISC_TONE: Record<BadgeTone, string> = {\n success: \"bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300\",\n danger: \"bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300\",\n warning: \"bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300\",\n info: \"bg-sky-100 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300\",\n neutral: \"bg-muted text-muted-foreground\",\n};\n\n/**\n * Vertical activity feed (the Gavel `TimelineCard`): each event has a\n * tone-colored icon disc joined by a connector rail, an actor/action/time\n * line, and an optional body bubble for threaded detail. Domain-agnostic —\n * callers compose `bodyHeader` (e.g. a file anchor + status `Badge`) and\n * `body` themselves.\n */\nexport function Timeline({ items, className }: TimelineProps) {\n return (\n <ol className={cn(\"relative\", className)}>\n {items.map((item, index) => {\n const last = index === items.length - 1;\n return (\n <li key={item.id} className=\"relative flex gap-density-3 pb-density-4 last:pb-0\">\n {!last && (\n <span\n aria-hidden\n className=\"absolute bottom-0 left-[10px] top-[22px] w-px bg-border\"\n />\n )}\n <span\n className={cn(\n \"relative z-[1] flex h-[21px] w-[21px] shrink-0 items-center justify-center rounded-full\",\n DISC_TONE[item.tone ?? \"neutral\"],\n )}\n >\n {item.icon && (\n <Icon\n {...(typeof item.icon === \"string\" ? { name: item.icon } : { icon: item.icon })}\n className=\"h-3 w-3\"\n />\n )}\n </span>\n <div className=\"min-w-0 flex-1 pt-px\">\n <div className=\"text-sm\">\n {item.actor && <span className=\"font-semibold text-foreground\">{item.actor}</span>}\n {item.action && <span className=\"text-muted-foreground\"> {item.action}</span>}\n {item.timestamp && (\n <span className=\"ml-1.5 text-xs text-muted-foreground\">· {item.timestamp}</span>\n )}\n </div>\n {item.body != null && (\n <div className=\"mt-1.5 overflow-hidden rounded-md border border-border bg-secondary\">\n {item.bodyHeader != null && (\n <div className=\"border-b border-border px-density-3 py-1.5 text-xs\">\n {item.bodyHeader}\n </div>\n )}\n <div className=\"px-density-3 py-density-2 text-sm leading-relaxed text-foreground\">\n {item.body}\n </div>\n </div>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"names":["jsx","cn","jsxs","Icon"],"mappings":";;;;;AA+BA,MAAM,YAAuC;AAAA,EAC3C,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX;AASO,SAAS,SAAS,EAAE,OAAO,aAA4B;AAC5D,SACEA,2BAAAA,IAAC,MAAA,EAAG,WAAWC,MAAAA,GAAG,YAAY,SAAS,GACpC,UAAA,MAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,UAAM,OAAO,UAAU,MAAM,SAAS;AACtC,WACEC,2BAAAA,KAAC,MAAA,EAAiB,WAAU,sDACzB,UAAA;AAAA,MAAA,CAAC,QACAF,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAW;AAAA,UACX,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,MAGdA,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAWC,MAAAA;AAAAA,YACT;AAAA,YACA,UAAU,KAAK,QAAQ,SAAS;AAAA,UAAA;AAAA,UAGjC,eAAK,QACJD,2BAAAA;AAAAA,YAACG,KAAAA;AAAAA,YAAA;AAAA,cACE,GAAI,OAAO,KAAK,SAAS,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,MAAM,KAAK,KAAA;AAAA,cACxE,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,MAGJD,2BAAAA,KAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,QAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,WACZ,UAAA;AAAA,UAAA,KAAK,SAASF,2BAAAA,IAAC,QAAA,EAAK,WAAU,iCAAiC,eAAK,OAAM;AAAA,UAC1E,KAAK,UAAUE,gCAAC,QAAA,EAAK,WAAU,yBAAwB,UAAA;AAAA,YAAA;AAAA,YAAE,KAAK;AAAA,UAAA,GAAO;AAAA,UACrE,KAAK,aACJA,gCAAC,QAAA,EAAK,WAAU,wCAAuC,UAAA;AAAA,YAAA;AAAA,YAAG,KAAK;AAAA,UAAA,EAAA,CAAU;AAAA,QAAA,GAE7E;AAAA,QACC,KAAK,QAAQ,QACZA,2BAAAA,KAAC,OAAA,EAAI,WAAU,uEACZ,UAAA;AAAA,UAAA,KAAK,cAAc,QAClBF,2BAAAA,IAAC,SAAI,WAAU,sDACZ,eAAK,WAAA,CACR;AAAA,UAEFA,2BAAAA,IAAC,OAAA,EAAI,WAAU,qEACZ,eAAK,KAAA,CACR;AAAA,QAAA,EAAA,CACF;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA,EAAA,GAxCO,KAAK,EAyCd;AAAA,EAEJ,CAAC,EAAA,CACH;AAEJ;;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StaticIconComponent } from './Icon';
|
|
3
|
+
import { BadgeTone } from './Badge';
|
|
4
|
+
export type TimelineItem = {
|
|
5
|
+
/** Stable key. */
|
|
6
|
+
id: string | number;
|
|
7
|
+
/** Icon shown in the tone-colored disc. */
|
|
8
|
+
icon?: string | StaticIconComponent;
|
|
9
|
+
/** Semantic color of the disc. Defaults to `neutral`. */
|
|
10
|
+
tone?: BadgeTone;
|
|
11
|
+
/** Actor (rendered bold), e.g. a username. */
|
|
12
|
+
actor?: ReactNode;
|
|
13
|
+
/** What happened, e.g. "approved these changes". */
|
|
14
|
+
action?: ReactNode;
|
|
15
|
+
/** Relative time, e.g. "1d ago". */
|
|
16
|
+
timestamp?: ReactNode;
|
|
17
|
+
/** Optional expanded body (Gavel's threaded comment bubble). */
|
|
18
|
+
body?: ReactNode;
|
|
19
|
+
/** Optional header for the body bubble, e.g. a file anchor + status `Badge`. */
|
|
20
|
+
bodyHeader?: ReactNode;
|
|
21
|
+
};
|
|
22
|
+
export type TimelineProps = {
|
|
23
|
+
/** Events rendered top to bottom, connected by a rail. */
|
|
24
|
+
items: TimelineItem[];
|
|
25
|
+
/** Classes applied to the list. */
|
|
26
|
+
className?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Vertical activity feed (the Gavel `TimelineCard`): each event has a
|
|
30
|
+
* tone-colored icon disc joined by a connector rail, an actor/action/time
|
|
31
|
+
* line, and an optional body bubble for threaded detail. Domain-agnostic —
|
|
32
|
+
* callers compose `bodyHeader` (e.g. a file anchor + status `Badge`) and
|
|
33
|
+
* `body` themselves.
|
|
34
|
+
*/
|
|
35
|
+
export declare function Timeline({ items, className }: TimelineProps): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
//# sourceMappingURL=Timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../src/data/Timeline.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB,kBAAkB;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,yDAAyD;IACzD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gEAAgE;IAChE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,gFAAgF;IAChF,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,0DAA0D;IAC1D,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAUF;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,aAAa,2CAoD3D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Icon } from "./Icon.js";
|
|
4
|
+
const DISC_TONE = {
|
|
5
|
+
success: "bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300",
|
|
6
|
+
danger: "bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300",
|
|
7
|
+
warning: "bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300",
|
|
8
|
+
info: "bg-sky-100 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300",
|
|
9
|
+
neutral: "bg-muted text-muted-foreground"
|
|
10
|
+
};
|
|
11
|
+
function Timeline({ items, className }) {
|
|
12
|
+
return /* @__PURE__ */ jsx("ol", { className: cn("relative", className), children: items.map((item, index) => {
|
|
13
|
+
const last = index === items.length - 1;
|
|
14
|
+
return /* @__PURE__ */ jsxs("li", { className: "relative flex gap-density-3 pb-density-4 last:pb-0", children: [
|
|
15
|
+
!last && /* @__PURE__ */ jsx(
|
|
16
|
+
"span",
|
|
17
|
+
{
|
|
18
|
+
"aria-hidden": true,
|
|
19
|
+
className: "absolute bottom-0 left-[10px] top-[22px] w-px bg-border"
|
|
20
|
+
}
|
|
21
|
+
),
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
"span",
|
|
24
|
+
{
|
|
25
|
+
className: cn(
|
|
26
|
+
"relative z-[1] flex h-[21px] w-[21px] shrink-0 items-center justify-center rounded-full",
|
|
27
|
+
DISC_TONE[item.tone ?? "neutral"]
|
|
28
|
+
),
|
|
29
|
+
children: item.icon && /* @__PURE__ */ jsx(
|
|
30
|
+
Icon,
|
|
31
|
+
{
|
|
32
|
+
...typeof item.icon === "string" ? { name: item.icon } : { icon: item.icon },
|
|
33
|
+
className: "h-3 w-3"
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 pt-px", children: [
|
|
39
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
|
|
40
|
+
item.actor && /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: item.actor }),
|
|
41
|
+
item.action && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
42
|
+
" ",
|
|
43
|
+
item.action
|
|
44
|
+
] }),
|
|
45
|
+
item.timestamp && /* @__PURE__ */ jsxs("span", { className: "ml-1.5 text-xs text-muted-foreground", children: [
|
|
46
|
+
"· ",
|
|
47
|
+
item.timestamp
|
|
48
|
+
] })
|
|
49
|
+
] }),
|
|
50
|
+
item.body != null && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 overflow-hidden rounded-md border border-border bg-secondary", children: [
|
|
51
|
+
item.bodyHeader != null && /* @__PURE__ */ jsx("div", { className: "border-b border-border px-density-3 py-1.5 text-xs", children: item.bodyHeader }),
|
|
52
|
+
/* @__PURE__ */ jsx("div", { className: "px-density-3 py-density-2 text-sm leading-relaxed text-foreground", children: item.body })
|
|
53
|
+
] })
|
|
54
|
+
] })
|
|
55
|
+
] }, item.id);
|
|
56
|
+
}) });
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
Timeline
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=Timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timeline.js","sources":["../../src/data/Timeline.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { BadgeTone } from \"./Badge\";\n\nexport type TimelineItem = {\n /** Stable key. */\n id: string | number;\n /** Icon shown in the tone-colored disc. */\n icon?: string | StaticIconComponent;\n /** Semantic color of the disc. Defaults to `neutral`. */\n tone?: BadgeTone;\n /** Actor (rendered bold), e.g. a username. */\n actor?: ReactNode;\n /** What happened, e.g. \"approved these changes\". */\n action?: ReactNode;\n /** Relative time, e.g. \"1d ago\". */\n timestamp?: ReactNode;\n /** Optional expanded body (Gavel's threaded comment bubble). */\n body?: ReactNode;\n /** Optional header for the body bubble, e.g. a file anchor + status `Badge`. */\n bodyHeader?: ReactNode;\n};\n\nexport type TimelineProps = {\n /** Events rendered top to bottom, connected by a rail. */\n items: TimelineItem[];\n /** Classes applied to the list. */\n className?: string;\n};\n\nconst DISC_TONE: Record<BadgeTone, string> = {\n success: \"bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300\",\n danger: \"bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300\",\n warning: \"bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300\",\n info: \"bg-sky-100 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300\",\n neutral: \"bg-muted text-muted-foreground\",\n};\n\n/**\n * Vertical activity feed (the Gavel `TimelineCard`): each event has a\n * tone-colored icon disc joined by a connector rail, an actor/action/time\n * line, and an optional body bubble for threaded detail. Domain-agnostic —\n * callers compose `bodyHeader` (e.g. a file anchor + status `Badge`) and\n * `body` themselves.\n */\nexport function Timeline({ items, className }: TimelineProps) {\n return (\n <ol className={cn(\"relative\", className)}>\n {items.map((item, index) => {\n const last = index === items.length - 1;\n return (\n <li key={item.id} className=\"relative flex gap-density-3 pb-density-4 last:pb-0\">\n {!last && (\n <span\n aria-hidden\n className=\"absolute bottom-0 left-[10px] top-[22px] w-px bg-border\"\n />\n )}\n <span\n className={cn(\n \"relative z-[1] flex h-[21px] w-[21px] shrink-0 items-center justify-center rounded-full\",\n DISC_TONE[item.tone ?? \"neutral\"],\n )}\n >\n {item.icon && (\n <Icon\n {...(typeof item.icon === \"string\" ? { name: item.icon } : { icon: item.icon })}\n className=\"h-3 w-3\"\n />\n )}\n </span>\n <div className=\"min-w-0 flex-1 pt-px\">\n <div className=\"text-sm\">\n {item.actor && <span className=\"font-semibold text-foreground\">{item.actor}</span>}\n {item.action && <span className=\"text-muted-foreground\"> {item.action}</span>}\n {item.timestamp && (\n <span className=\"ml-1.5 text-xs text-muted-foreground\">· {item.timestamp}</span>\n )}\n </div>\n {item.body != null && (\n <div className=\"mt-1.5 overflow-hidden rounded-md border border-border bg-secondary\">\n {item.bodyHeader != null && (\n <div className=\"border-b border-border px-density-3 py-1.5 text-xs\">\n {item.bodyHeader}\n </div>\n )}\n <div className=\"px-density-3 py-density-2 text-sm leading-relaxed text-foreground\">\n {item.body}\n </div>\n </div>\n )}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"names":[],"mappings":";;;AA+BA,MAAM,YAAuC;AAAA,EAC3C,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX;AASO,SAAS,SAAS,EAAE,OAAO,aAA4B;AAC5D,SACE,oBAAC,MAAA,EAAG,WAAW,GAAG,YAAY,SAAS,GACpC,UAAA,MAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,UAAM,OAAO,UAAU,MAAM,SAAS;AACtC,WACE,qBAAC,MAAA,EAAiB,WAAU,sDACzB,UAAA;AAAA,MAAA,CAAC,QACA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAW;AAAA,UACX,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,MAGd;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,UAAU,KAAK,QAAQ,SAAS;AAAA,UAAA;AAAA,UAGjC,eAAK,QACJ;AAAA,YAAC;AAAA,YAAA;AAAA,cACE,GAAI,OAAO,KAAK,SAAS,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,MAAM,KAAK,KAAA;AAAA,cACxE,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,MAGJ,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,WACZ,UAAA;AAAA,UAAA,KAAK,SAAS,oBAAC,QAAA,EAAK,WAAU,iCAAiC,eAAK,OAAM;AAAA,UAC1E,KAAK,UAAU,qBAAC,QAAA,EAAK,WAAU,yBAAwB,UAAA;AAAA,YAAA;AAAA,YAAE,KAAK;AAAA,UAAA,GAAO;AAAA,UACrE,KAAK,aACJ,qBAAC,QAAA,EAAK,WAAU,wCAAuC,UAAA;AAAA,YAAA;AAAA,YAAG,KAAK;AAAA,UAAA,EAAA,CAAU;AAAA,QAAA,GAE7E;AAAA,QACC,KAAK,QAAQ,QACZ,qBAAC,OAAA,EAAI,WAAU,uEACZ,UAAA;AAAA,UAAA,KAAK,cAAc,QAClB,oBAAC,SAAI,WAAU,sDACZ,eAAK,WAAA,CACR;AAAA,UAEF,oBAAC,OAAA,EAAI,WAAU,qEACZ,eAAK,KAAA,CACR;AAAA,QAAA,EAAA,CACF;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA,EAAA,GAxCO,KAAK,EAyCd;AAAA,EAEJ,CAAC,EAAA,CACH;AAEJ;"}
|
|
@@ -5,6 +5,7 @@ const reactQuery = require("@tanstack/react-query");
|
|
|
5
5
|
const react = require("react");
|
|
6
6
|
const utils = require("../lib/utils.cjs");
|
|
7
7
|
const Icon = require("./Icon.cjs");
|
|
8
|
+
const TimeseriesCoreBars_model = require("./TimeseriesCoreBars.model.cjs");
|
|
8
9
|
const defaultFetcher = async (url) => {
|
|
9
10
|
const res = await fetch(url);
|
|
10
11
|
if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);
|
|
@@ -21,29 +22,6 @@ function toneClass(pct, [warn, danger]) {
|
|
|
21
22
|
if (pct >= warn) return "bg-amber-500";
|
|
22
23
|
return "bg-emerald-500";
|
|
23
24
|
}
|
|
24
|
-
const clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
25
|
-
function deriveCoreBars(usageMilli, limitMilli) {
|
|
26
|
-
const hasUsage = usageMilli !== void 0;
|
|
27
|
-
const usageCores = (usageMilli ?? 0) / 1e3;
|
|
28
|
-
const hasLimit = limitMilli !== void 0 && limitMilli > 0;
|
|
29
|
-
const limitCores = hasLimit ? limitMilli / 1e3 : void 0;
|
|
30
|
-
const coreCount = Math.max(
|
|
31
|
-
1,
|
|
32
|
-
Math.ceil(hasLimit ? limitCores : usageCores)
|
|
33
|
-
);
|
|
34
|
-
const pct = hasLimit ? Math.min(100, Math.round(usageCores / limitCores * 100)) : 0;
|
|
35
|
-
const bars = Array.from({ length: coreCount }, (_, i) => ({
|
|
36
|
-
fill: clamp01(usageCores - i)
|
|
37
|
-
}));
|
|
38
|
-
return {
|
|
39
|
-
hasUsage,
|
|
40
|
-
usageCores,
|
|
41
|
-
coreCount,
|
|
42
|
-
pct,
|
|
43
|
-
bars,
|
|
44
|
-
...limitCores !== void 0 && { limitCores }
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
25
|
function CoreBarsIcon({ icon }) {
|
|
48
26
|
if (typeof icon === "string") {
|
|
49
27
|
return /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: icon, width: 14, height: 14, className: "text-muted-foreground" });
|
|
@@ -96,7 +74,7 @@ function TimeseriesCoreBars({
|
|
|
96
74
|
const rawMax = latestValue((_b = results[1]) == null ? void 0 : _b.data);
|
|
97
75
|
limit = rawMax === void 0 ? void 0 : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;
|
|
98
76
|
}
|
|
99
|
-
const model = deriveCoreBars(usage, limit);
|
|
77
|
+
const model = TimeseriesCoreBars_model.deriveCoreBars(usage, limit);
|
|
100
78
|
const tone = toneClass(model.pct, thresholds);
|
|
101
79
|
const caption = model.hasUsage ? `${formatCores(model.usageCores)} / ${model.limitCores !== void 0 ? formatCores(model.limitCores) : "?"} cores` : "—";
|
|
102
80
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex flex-col items-center gap-1", className), children: [
|
|
@@ -128,5 +106,4 @@ function TimeseriesCoreBars({
|
|
|
128
106
|
] });
|
|
129
107
|
}
|
|
130
108
|
exports.TimeseriesCoreBars = TimeseriesCoreBars;
|
|
131
|
-
exports.deriveCoreBars = deriveCoreBars;
|
|
132
109
|
//# sourceMappingURL=TimeseriesCoreBars.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeseriesCoreBars.cjs","sources":["../../src/data/TimeseriesCoreBars.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\nimport type { TimeseriesResponse } from \"./TimeseriesPanel\";\n\nexport interface TimeseriesCoreBarsProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value (CPU millicores) fills the bars. */\n value: GaugeSeries;\n /**\n * The CPU capacity. Either a `.limit`-style metric series (its latest value in\n * millicores) or a fixed number of millicores. Determines the number of bars\n * (one per core). When omitted or 0, the bar count falls back to the ceiling of\n * the usage in cores so an unbounded reading still renders.\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Look-back window passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nexport interface CoreBar {\n /** Fraction of this core that is in use, in [0, 1]. */\n fill: number;\n}\n\nexport interface CoreBarsModel {\n /** Whether a usage reading was available. */\n hasUsage: boolean;\n /** Usage expressed in cores (millicores / 1000). */\n usageCores: number;\n /** Capacity in cores; undefined when no limit was resolved. */\n limitCores?: number;\n /** Number of bars rendered (one per core). */\n coreCount: number;\n /** Utilisation percentage of capacity; 0 when unbounded. */\n pct: number;\n /** Per-core fill fractions, left to right. */\n bars: CoreBar[];\n}\n\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n));\n\n// deriveCoreBars turns the latest usage/limit millicore readings into a per-core\n// bar model: one bar per core (ceil of the limit), filled left to right by usage\n// so the bar straddling the usage boundary is partially filled and the remainder\n// stays empty. When the limit is missing or 0 the bar count falls back to the\n// ceiling of the usage so an unbounded reading still renders sensibly.\nexport function deriveCoreBars(\n usageMilli: number | undefined,\n limitMilli: number | undefined,\n): CoreBarsModel {\n const hasUsage = usageMilli !== undefined;\n const usageCores = (usageMilli ?? 0) / 1000;\n const hasLimit = limitMilli !== undefined && limitMilli > 0;\n const limitCores = hasLimit ? (limitMilli as number) / 1000 : undefined;\n\n const coreCount = Math.max(\n 1,\n Math.ceil(hasLimit ? (limitCores as number) : usageCores),\n );\n const pct = hasLimit\n ? Math.min(100, Math.round((usageCores / (limitCores as number)) * 100))\n : 0;\n\n const bars: CoreBar[] = Array.from({ length: coreCount }, (_, i) => ({\n fill: clamp01(usageCores - i),\n }));\n\n // limitCores is an optional field under exactOptionalPropertyTypes — only set\n // the key when a limit resolved, rather than assigning an explicit undefined.\n return {\n hasUsage,\n usageCores,\n coreCount,\n pct,\n bars,\n ...(limitCores !== undefined && { limitCores }),\n };\n}\n\nfunction CoreBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\nfunction formatCores(cores: number): string {\n return Number.isInteger(cores) ? String(cores) : cores.toFixed(1);\n}\n\n/**\n * TimeseriesCoreBars renders CPU utilisation as a row of vertical bars — one bar\n * per core (the ceiling of the CPU limit) — filled left to right by the latest\n * usage. The bar that straddles the usage boundary is partially filled (\"blocked\n * out\") to show the fractional core in use, and the trailing bars stay empty to\n * show headroom. Both usage and limit are read live from the timeseries store,\n * mirroring TimeseriesGauge's data plumbing; the bar colour crosses warning and\n * danger thresholds. A \"<used> / <cores>\" caption sits below with the icon+title.\n */\nexport function TimeseriesCoreBars({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n range = \"1h\",\n refreshMs = 5000,\n thresholds = [75, 90],\n fetcher = defaultFetcher,\n className,\n}: TimeseriesCoreBarsProps) {\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const usage = rawValue === undefined ? undefined : value.transform ? value.transform(rawValue) : rawValue;\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const model = deriveCoreBars(usage, limit);\n const tone = toneClass(model.pct, thresholds);\n const caption = model.hasUsage\n ? `${formatCores(model.usageCores)} / ${model.limitCores !== undefined ? formatCores(model.limitCores) : \"?\"} cores`\n : \"—\";\n\n return (\n <div className={cn(\"flex flex-col items-center gap-1\", className)}>\n <div className=\"flex h-10 items-end gap-0.5\">\n {model.bars.map((bar, i) => {\n const corePct = Math.round(bar.fill * 100);\n return (\n <div\n key={i}\n className=\"relative h-full w-2 overflow-hidden rounded-sm bg-muted\"\n title={`core ${i + 1}: ${corePct}%`}\n aria-label={`core ${i + 1}: ${corePct}%`}\n data-fill={bar.fill}\n >\n <div\n className={cn(\"absolute inset-x-0 bottom-0 transition-all duration-300\", tone)}\n style={{ height: `${corePct}%` }}\n />\n </div>\n );\n })}\n </div>\n <span className=\"text-xs font-semibold text-foreground\">{caption}</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <CoreBarsIcon icon={icon} /> : null}\n <span>{title}</span>\n </div>\n </div>\n );\n}\n"],"names":["jsx","Icon","useMemo","useQueries","cn","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimeseriesCoreBars.cjs","sources":["../../src/data/TimeseriesCoreBars.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\nimport type { TimeseriesResponse } from \"./TimeseriesPanel\";\nimport { deriveCoreBars } from \"./TimeseriesCoreBars.model\";\n\nexport interface TimeseriesCoreBarsProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value (CPU millicores) fills the bars. */\n value: GaugeSeries;\n /**\n * The CPU capacity. Either a `.limit`-style metric series (its latest value in\n * millicores) or a fixed number of millicores. Determines the number of bars\n * (one per core). When omitted or 0, the bar count falls back to the ceiling of\n * the usage in cores so an unbounded reading still renders.\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Look-back window passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nfunction CoreBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\nfunction formatCores(cores: number): string {\n return Number.isInteger(cores) ? String(cores) : cores.toFixed(1);\n}\n\n/**\n * TimeseriesCoreBars renders CPU utilisation as a row of vertical bars — one bar\n * per core (the ceiling of the CPU limit) — filled left to right by the latest\n * usage. The bar that straddles the usage boundary is partially filled (\"blocked\n * out\") to show the fractional core in use, and the trailing bars stay empty to\n * show headroom. Both usage and limit are read live from the timeseries store,\n * mirroring TimeseriesGauge's data plumbing; the bar colour crosses warning and\n * danger thresholds. A \"<used> / <cores>\" caption sits below with the icon+title.\n */\nexport function TimeseriesCoreBars({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n range = \"1h\",\n refreshMs = 5000,\n thresholds = [75, 90],\n fetcher = defaultFetcher,\n className,\n}: TimeseriesCoreBarsProps) {\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const usage = rawValue === undefined ? undefined : value.transform ? value.transform(rawValue) : rawValue;\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const model = deriveCoreBars(usage, limit);\n const tone = toneClass(model.pct, thresholds);\n const caption = model.hasUsage\n ? `${formatCores(model.usageCores)} / ${model.limitCores !== undefined ? formatCores(model.limitCores) : \"?\"} cores`\n : \"—\";\n\n return (\n <div className={cn(\"flex flex-col items-center gap-1\", className)}>\n <div className=\"flex h-10 items-end gap-0.5\">\n {model.bars.map((bar, i) => {\n const corePct = Math.round(bar.fill * 100);\n return (\n <div\n key={i}\n className=\"relative h-full w-2 overflow-hidden rounded-sm bg-muted\"\n title={`core ${i + 1}: ${corePct}%`}\n aria-label={`core ${i + 1}: ${corePct}%`}\n data-fill={bar.fill}\n >\n <div\n className={cn(\"absolute inset-x-0 bottom-0 transition-all duration-300\", tone)}\n style={{ height: `${corePct}%` }}\n />\n </div>\n );\n })}\n </div>\n <span className=\"text-xs font-semibold text-foreground\">{caption}</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <CoreBarsIcon icon={icon} /> : null}\n <span>{title}</span>\n </div>\n </div>\n );\n}\n"],"names":["jsx","Icon","useMemo","useQueries","deriveCoreBars","cn","jsxs"],"mappings":"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"}
|
|
@@ -29,25 +29,6 @@ export interface TimeseriesCoreBarsProps {
|
|
|
29
29
|
fetcher?: (url: string) => Promise<TimeseriesResponse>;
|
|
30
30
|
className?: string;
|
|
31
31
|
}
|
|
32
|
-
export interface CoreBar {
|
|
33
|
-
/** Fraction of this core that is in use, in [0, 1]. */
|
|
34
|
-
fill: number;
|
|
35
|
-
}
|
|
36
|
-
export interface CoreBarsModel {
|
|
37
|
-
/** Whether a usage reading was available. */
|
|
38
|
-
hasUsage: boolean;
|
|
39
|
-
/** Usage expressed in cores (millicores / 1000). */
|
|
40
|
-
usageCores: number;
|
|
41
|
-
/** Capacity in cores; undefined when no limit was resolved. */
|
|
42
|
-
limitCores?: number;
|
|
43
|
-
/** Number of bars rendered (one per core). */
|
|
44
|
-
coreCount: number;
|
|
45
|
-
/** Utilisation percentage of capacity; 0 when unbounded. */
|
|
46
|
-
pct: number;
|
|
47
|
-
/** Per-core fill fractions, left to right. */
|
|
48
|
-
bars: CoreBar[];
|
|
49
|
-
}
|
|
50
|
-
export declare function deriveCoreBars(usageMilli: number | undefined, limitMilli: number | undefined): CoreBarsModel;
|
|
51
32
|
/**
|
|
52
33
|
* TimeseriesCoreBars renders CPU utilisation as a row of vertical bars — one bar
|
|
53
34
|
* per core (the ceiling of the CPU limit) — filled left to right by the latest
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeseriesCoreBars.d.ts","sourceRoot":"","sources":["../../src/data/TimeseriesCoreBars.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeseriesCoreBars.d.ts","sourceRoot":"","sources":["../../src/data/TimeseriesCoreBars.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,KAAK,EAAE,WAAW,CAAC;IACnB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,8EAA8E;IAC9E,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAY,EACZ,KAAK,EACL,GAAG,EACH,KAAK,EACL,IAAI,EACJ,KAAY,EACZ,SAAgB,EAChB,UAAqB,EACrB,OAAwB,EACxB,SAAS,GACV,EAAE,uBAAuB,2CAqEzB"}
|
|
@@ -3,6 +3,7 @@ import { useQueries } from "@tanstack/react-query";
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
5
|
import { Icon } from "./Icon.js";
|
|
6
|
+
import { deriveCoreBars } from "./TimeseriesCoreBars.model.js";
|
|
6
7
|
const defaultFetcher = async (url) => {
|
|
7
8
|
const res = await fetch(url);
|
|
8
9
|
if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);
|
|
@@ -19,29 +20,6 @@ function toneClass(pct, [warn, danger]) {
|
|
|
19
20
|
if (pct >= warn) return "bg-amber-500";
|
|
20
21
|
return "bg-emerald-500";
|
|
21
22
|
}
|
|
22
|
-
const clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
23
|
-
function deriveCoreBars(usageMilli, limitMilli) {
|
|
24
|
-
const hasUsage = usageMilli !== void 0;
|
|
25
|
-
const usageCores = (usageMilli ?? 0) / 1e3;
|
|
26
|
-
const hasLimit = limitMilli !== void 0 && limitMilli > 0;
|
|
27
|
-
const limitCores = hasLimit ? limitMilli / 1e3 : void 0;
|
|
28
|
-
const coreCount = Math.max(
|
|
29
|
-
1,
|
|
30
|
-
Math.ceil(hasLimit ? limitCores : usageCores)
|
|
31
|
-
);
|
|
32
|
-
const pct = hasLimit ? Math.min(100, Math.round(usageCores / limitCores * 100)) : 0;
|
|
33
|
-
const bars = Array.from({ length: coreCount }, (_, i) => ({
|
|
34
|
-
fill: clamp01(usageCores - i)
|
|
35
|
-
}));
|
|
36
|
-
return {
|
|
37
|
-
hasUsage,
|
|
38
|
-
usageCores,
|
|
39
|
-
coreCount,
|
|
40
|
-
pct,
|
|
41
|
-
bars,
|
|
42
|
-
...limitCores !== void 0 && { limitCores }
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
23
|
function CoreBarsIcon({ icon }) {
|
|
46
24
|
if (typeof icon === "string") {
|
|
47
25
|
return /* @__PURE__ */ jsx(Icon, { name: icon, width: 14, height: 14, className: "text-muted-foreground" });
|
|
@@ -126,7 +104,6 @@ function TimeseriesCoreBars({
|
|
|
126
104
|
] });
|
|
127
105
|
}
|
|
128
106
|
export {
|
|
129
|
-
TimeseriesCoreBars
|
|
130
|
-
deriveCoreBars
|
|
107
|
+
TimeseriesCoreBars
|
|
131
108
|
};
|
|
132
109
|
//# sourceMappingURL=TimeseriesCoreBars.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeseriesCoreBars.js","sources":["../../src/data/TimeseriesCoreBars.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\nimport type { TimeseriesResponse } from \"./TimeseriesPanel\";\n\nexport interface TimeseriesCoreBarsProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value (CPU millicores) fills the bars. */\n value: GaugeSeries;\n /**\n * The CPU capacity. Either a `.limit`-style metric series (its latest value in\n * millicores) or a fixed number of millicores. Determines the number of bars\n * (one per core). When omitted or 0, the bar count falls back to the ceiling of\n * the usage in cores so an unbounded reading still renders.\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Look-back window passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nexport interface CoreBar {\n /** Fraction of this core that is in use, in [0, 1]. */\n fill: number;\n}\n\nexport interface CoreBarsModel {\n /** Whether a usage reading was available. */\n hasUsage: boolean;\n /** Usage expressed in cores (millicores / 1000). */\n usageCores: number;\n /** Capacity in cores; undefined when no limit was resolved. */\n limitCores?: number;\n /** Number of bars rendered (one per core). */\n coreCount: number;\n /** Utilisation percentage of capacity; 0 when unbounded. */\n pct: number;\n /** Per-core fill fractions, left to right. */\n bars: CoreBar[];\n}\n\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n));\n\n// deriveCoreBars turns the latest usage/limit millicore readings into a per-core\n// bar model: one bar per core (ceil of the limit), filled left to right by usage\n// so the bar straddling the usage boundary is partially filled and the remainder\n// stays empty. When the limit is missing or 0 the bar count falls back to the\n// ceiling of the usage so an unbounded reading still renders sensibly.\nexport function deriveCoreBars(\n usageMilli: number | undefined,\n limitMilli: number | undefined,\n): CoreBarsModel {\n const hasUsage = usageMilli !== undefined;\n const usageCores = (usageMilli ?? 0) / 1000;\n const hasLimit = limitMilli !== undefined && limitMilli > 0;\n const limitCores = hasLimit ? (limitMilli as number) / 1000 : undefined;\n\n const coreCount = Math.max(\n 1,\n Math.ceil(hasLimit ? (limitCores as number) : usageCores),\n );\n const pct = hasLimit\n ? Math.min(100, Math.round((usageCores / (limitCores as number)) * 100))\n : 0;\n\n const bars: CoreBar[] = Array.from({ length: coreCount }, (_, i) => ({\n fill: clamp01(usageCores - i),\n }));\n\n // limitCores is an optional field under exactOptionalPropertyTypes — only set\n // the key when a limit resolved, rather than assigning an explicit undefined.\n return {\n hasUsage,\n usageCores,\n coreCount,\n pct,\n bars,\n ...(limitCores !== undefined && { limitCores }),\n };\n}\n\nfunction CoreBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\nfunction formatCores(cores: number): string {\n return Number.isInteger(cores) ? String(cores) : cores.toFixed(1);\n}\n\n/**\n * TimeseriesCoreBars renders CPU utilisation as a row of vertical bars — one bar\n * per core (the ceiling of the CPU limit) — filled left to right by the latest\n * usage. The bar that straddles the usage boundary is partially filled (\"blocked\n * out\") to show the fractional core in use, and the trailing bars stay empty to\n * show headroom. Both usage and limit are read live from the timeseries store,\n * mirroring TimeseriesGauge's data plumbing; the bar colour crosses warning and\n * danger thresholds. A \"<used> / <cores>\" caption sits below with the icon+title.\n */\nexport function TimeseriesCoreBars({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n range = \"1h\",\n refreshMs = 5000,\n thresholds = [75, 90],\n fetcher = defaultFetcher,\n className,\n}: TimeseriesCoreBarsProps) {\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const usage = rawValue === undefined ? undefined : value.transform ? value.transform(rawValue) : rawValue;\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const model = deriveCoreBars(usage, limit);\n const tone = toneClass(model.pct, thresholds);\n const caption = model.hasUsage\n ? `${formatCores(model.usageCores)} / ${model.limitCores !== undefined ? formatCores(model.limitCores) : \"?\"} cores`\n : \"—\";\n\n return (\n <div className={cn(\"flex flex-col items-center gap-1\", className)}>\n <div className=\"flex h-10 items-end gap-0.5\">\n {model.bars.map((bar, i) => {\n const corePct = Math.round(bar.fill * 100);\n return (\n <div\n key={i}\n className=\"relative h-full w-2 overflow-hidden rounded-sm bg-muted\"\n title={`core ${i + 1}: ${corePct}%`}\n aria-label={`core ${i + 1}: ${corePct}%`}\n data-fill={bar.fill}\n >\n <div\n className={cn(\"absolute inset-x-0 bottom-0 transition-all duration-300\", tone)}\n style={{ height: `${corePct}%` }}\n />\n </div>\n );\n })}\n </div>\n <span className=\"text-xs font-semibold text-foreground\">{caption}</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <CoreBarsIcon icon={icon} /> : null}\n <span>{title}</span>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimeseriesCoreBars.js","sources":["../../src/data/TimeseriesCoreBars.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\nimport type { TimeseriesResponse } from \"./TimeseriesPanel\";\nimport { deriveCoreBars } from \"./TimeseriesCoreBars.model\";\n\nexport interface TimeseriesCoreBarsProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value (CPU millicores) fills the bars. */\n value: GaugeSeries;\n /**\n * The CPU capacity. Either a `.limit`-style metric series (its latest value in\n * millicores) or a fixed number of millicores. Determines the number of bars\n * (one per core). When omitted or 0, the bar count falls back to the ceiling of\n * the usage in cores so an unbounded reading still renders.\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Look-back window passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nfunction CoreBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\nfunction formatCores(cores: number): string {\n return Number.isInteger(cores) ? String(cores) : cores.toFixed(1);\n}\n\n/**\n * TimeseriesCoreBars renders CPU utilisation as a row of vertical bars — one bar\n * per core (the ceiling of the CPU limit) — filled left to right by the latest\n * usage. The bar that straddles the usage boundary is partially filled (\"blocked\n * out\") to show the fractional core in use, and the trailing bars stay empty to\n * show headroom. Both usage and limit are read live from the timeseries store,\n * mirroring TimeseriesGauge's data plumbing; the bar colour crosses warning and\n * danger thresholds. A \"<used> / <cores>\" caption sits below with the icon+title.\n */\nexport function TimeseriesCoreBars({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n range = \"1h\",\n refreshMs = 5000,\n thresholds = [75, 90],\n fetcher = defaultFetcher,\n className,\n}: TimeseriesCoreBarsProps) {\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const usage = rawValue === undefined ? undefined : value.transform ? value.transform(rawValue) : rawValue;\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const model = deriveCoreBars(usage, limit);\n const tone = toneClass(model.pct, thresholds);\n const caption = model.hasUsage\n ? `${formatCores(model.usageCores)} / ${model.limitCores !== undefined ? formatCores(model.limitCores) : \"?\"} cores`\n : \"—\";\n\n return (\n <div className={cn(\"flex flex-col items-center gap-1\", className)}>\n <div className=\"flex h-10 items-end gap-0.5\">\n {model.bars.map((bar, i) => {\n const corePct = Math.round(bar.fill * 100);\n return (\n <div\n key={i}\n className=\"relative h-full w-2 overflow-hidden rounded-sm bg-muted\"\n title={`core ${i + 1}: ${corePct}%`}\n aria-label={`core ${i + 1}: ${corePct}%`}\n data-fill={bar.fill}\n >\n <div\n className={cn(\"absolute inset-x-0 bottom-0 transition-all duration-300\", tone)}\n style={{ height: `${corePct}%` }}\n />\n </div>\n );\n })}\n </div>\n <span className=\"text-xs font-semibold text-foreground\">{caption}</span>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <CoreBarsIcon icon={icon} /> : null}\n <span>{title}</span>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
4
|
+
function deriveCoreBars(usageMilli, limitMilli) {
|
|
5
|
+
const hasUsage = usageMilli !== void 0;
|
|
6
|
+
const usageCores = (usageMilli ?? 0) / 1e3;
|
|
7
|
+
const hasLimit = limitMilli !== void 0 && limitMilli > 0;
|
|
8
|
+
const limitCores = hasLimit ? limitMilli / 1e3 : void 0;
|
|
9
|
+
const coreCount = Math.max(
|
|
10
|
+
1,
|
|
11
|
+
Math.ceil(hasLimit ? limitCores : usageCores)
|
|
12
|
+
);
|
|
13
|
+
const pct = hasLimit ? Math.min(100, Math.round(usageCores / limitCores * 100)) : 0;
|
|
14
|
+
const bars = Array.from({ length: coreCount }, (_, i) => ({
|
|
15
|
+
fill: clamp01(usageCores - i)
|
|
16
|
+
}));
|
|
17
|
+
return {
|
|
18
|
+
hasUsage,
|
|
19
|
+
usageCores,
|
|
20
|
+
coreCount,
|
|
21
|
+
pct,
|
|
22
|
+
bars,
|
|
23
|
+
...limitCores !== void 0 && { limitCores }
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.deriveCoreBars = deriveCoreBars;
|
|
27
|
+
//# sourceMappingURL=TimeseriesCoreBars.model.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeseriesCoreBars.model.cjs","sources":["../../src/data/TimeseriesCoreBars.model.ts"],"sourcesContent":["export interface CoreBar {\n /** Fraction of this core that is in use, in [0, 1]. */\n fill: number;\n}\n\nexport interface CoreBarsModel {\n /** Whether a usage reading was available. */\n hasUsage: boolean;\n /** Usage expressed in cores (millicores / 1000). */\n usageCores: number;\n /** Capacity in cores; undefined when no limit was resolved. */\n limitCores?: number;\n /** Number of bars rendered (one per core). */\n coreCount: number;\n /** Utilisation percentage of capacity; 0 when unbounded. */\n pct: number;\n /** Per-core fill fractions, left to right. */\n bars: CoreBar[];\n}\n\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n));\n\n// deriveCoreBars turns the latest usage/limit millicore readings into a per-core\n// bar model: one bar per core (ceil of the limit), filled left to right by usage\n// so the bar straddling the usage boundary is partially filled and the remainder\n// stays empty. When the limit is missing or 0 the bar count falls back to the\n// ceiling of the usage so an unbounded reading still renders sensibly.\nexport function deriveCoreBars(\n usageMilli: number | undefined,\n limitMilli: number | undefined,\n): CoreBarsModel {\n const hasUsage = usageMilli !== undefined;\n const usageCores = (usageMilli ?? 0) / 1000;\n const hasLimit = limitMilli !== undefined && limitMilli > 0;\n const limitCores = hasLimit ? (limitMilli as number) / 1000 : undefined;\n\n const coreCount = Math.max(\n 1,\n Math.ceil(hasLimit ? (limitCores as number) : usageCores),\n );\n const pct = hasLimit\n ? Math.min(100, Math.round((usageCores / (limitCores as number)) * 100))\n : 0;\n\n const bars: CoreBar[] = Array.from({ length: coreCount }, (_, i) => ({\n fill: clamp01(usageCores - i),\n }));\n\n return {\n hasUsage,\n usageCores,\n coreCount,\n pct,\n bars,\n ...(limitCores !== undefined && { limitCores }),\n };\n}\n"],"names":[],"mappings":";;AAoBA,MAAM,UAAU,CAAC,MAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AAO1D,SAAS,eACd,YACA,YACe;AACf,QAAM,WAAW,eAAe;AAChC,QAAM,cAAc,cAAc,KAAK;AACvC,QAAM,WAAW,eAAe,UAAa,aAAa;AAC1D,QAAM,aAAa,WAAY,aAAwB,MAAO;AAE9D,QAAM,YAAY,KAAK;AAAA,IACrB;AAAA,IACA,KAAK,KAAK,WAAY,aAAwB,UAAU;AAAA,EAAA;AAE1D,QAAM,MAAM,WACR,KAAK,IAAI,KAAK,KAAK,MAAO,aAAc,aAAyB,GAAG,CAAC,IACrE;AAEJ,QAAM,OAAkB,MAAM,KAAK,EAAE,QAAQ,UAAA,GAAa,CAAC,GAAG,OAAO;AAAA,IACnE,MAAM,QAAQ,aAAa,CAAC;AAAA,EAAA,EAC5B;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,eAAe,UAAa,EAAE,WAAA;AAAA,EAAW;AAEjD;;"}
|