@djangocfg/ui-tools 2.1.418 → 2.1.419
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/file-icon/index.cjs +3 -3
- package/dist/file-icon/index.cjs.map +1 -1
- package/dist/file-icon/index.mjs +3 -3
- package/dist/file-icon/index.mjs.map +1 -1
- package/package.json +93 -28
- package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
- package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
- package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
- package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
- package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
- package/src/lib/http.ts +64 -0
- package/src/tools/chat/index.ts +1 -1
- package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
- package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
- package/src/tools/chat/lazy.tsx +1 -1
- package/src/tools/chat/messages/MessageBubble.tsx +1 -1
- package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
- package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
- package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
- package/src/tools/data/DataGrid/lazy.tsx +1 -1
- package/src/tools/data/DataTable/lazy.tsx +1 -1
- package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
- package/src/tools/data/JsonTree/README.md +126 -73
- package/src/tools/data/JsonTree/index.tsx +3 -95
- package/src/tools/data/JsonTree/lazy.tsx +10 -50
- package/src/tools/data/JsonTree/types.ts +82 -63
- package/src/tools/data/Kanban/lazy.tsx +1 -1
- package/src/tools/data/Listbox/lazy.tsx +1 -1
- package/src/tools/data/Masonry/lazy.tsx +1 -1
- package/src/tools/data/Timeline/lazy.tsx +1 -1
- package/src/tools/data/Tree/lazy.tsx +1 -1
- package/src/tools/dev/Map/lazy.tsx +1 -1
- package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
- package/src/tools/dev/Mermaid/lazy.tsx +1 -1
- package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
- package/src/tools/dev/api/ApiRefTable/README.md +31 -0
- package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
- package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
- package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
- package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
- package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
- package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
- package/src/tools/dev/api/RequestViewer/README.md +33 -0
- package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
- package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
- package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
- package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
- package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
- package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
- package/src/tools/dev/api/RequestViewer/index.ts +16 -0
- package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
- package/src/tools/dev/api/RequestViewer/types.ts +81 -0
- package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
- package/src/tools/dev/code/DiffViewer/README.md +33 -0
- package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
- package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
- package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
- package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
- package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
- package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
- package/src/tools/dev/code/DiffViewer/index.ts +22 -0
- package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
- package/src/tools/dev/code/DiffViewer/types.ts +109 -0
- package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
- package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
- package/src/tools/dev/ops/EnvTable/README.md +29 -0
- package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
- package/src/tools/dev/ops/EnvTable/index.ts +12 -0
- package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
- package/src/tools/dev/ops/EnvTable/types.ts +76 -0
- package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
- package/src/tools/dev/ops/LogViewer/README.md +30 -0
- package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
- package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
- package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
- package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
- package/src/tools/dev/ops/LogViewer/index.ts +18 -0
- package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
- package/src/tools/dev/ops/LogViewer/types.ts +142 -0
- package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
- package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
- package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
- package/src/tools/forms/FileUpload/lazy.tsx +1 -1
- package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
- package/src/tools/forms/JsonEditor/index.ts +1 -0
- package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
- package/src/tools/forms/JsonForm/index.ts +1 -1
- package/src/tools/forms/JsonForm/lazy.tsx +1 -1
- package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
- package/src/tools/forms/NotionEditor/README.md +237 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +1 -1
- package/src/tools/index.ts +153 -13
- package/src/tools/input/Combobox/lazy.tsx +1 -1
- package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
- package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
- package/src/tools/input/CronScheduler/components/index.ts +3 -0
- package/src/tools/input/CronScheduler/index.tsx +5 -1
- package/src/tools/input/CronScheduler/lazy.tsx +5 -1
- package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
- package/src/tools/input/CronScheduler/utils/index.ts +1 -0
- package/src/tools/input/Scroller/lazy.tsx +1 -1
- package/src/tools/input/Sortable/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
- package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +27 -19
- package/src/tools/media/ImageViewer/lazy.tsx +1 -1
- package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +28 -1
- package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
- package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
- package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
- package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
- package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
- package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
- package/src/tools/overlay/Tour/lazy.tsx +1 -1
- package/src/tools/visual/Marquee/lazy.tsx +1 -1
- package/src/tools/visual/QRCode/lazy.tsx +1 -1
- package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
- package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
- package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
- package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
- package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
- package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
- package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
- package/src/tools/visual/charts/CommitGraph/README.md +28 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
- package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
- package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
- package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
- package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
- package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
- package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
- package/src/tools/visual/charts/Sparkline/README.md +29 -0
- package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
- package/src/tools/visual/charts/Sparkline/index.ts +9 -0
- package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
- package/src/tools/visual/charts/Sparkline/types.ts +58 -0
- package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
- package/src/tools/visual/design/ColorPalette/README.md +34 -0
- package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
- package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
- package/src/tools/visual/design/ColorPalette/index.ts +12 -0
- package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
- package/src/tools/visual/design/ColorPalette/types.ts +63 -0
- package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
- package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
- package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
- package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
- package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
- package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
- package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
- package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
- package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
- package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
- package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
- package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
- package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
- package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
- package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
- /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
- /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
- /package/src/{components → common}/index.ts +0 -0
- /package/src/{components → common}/lazy-wrapper.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/types.ts +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import {
|
|
7
|
+
ArrowDownToLine,
|
|
8
|
+
Circle,
|
|
9
|
+
Pause,
|
|
10
|
+
Play,
|
|
11
|
+
Search,
|
|
12
|
+
Terminal,
|
|
13
|
+
Trash2,
|
|
14
|
+
X,
|
|
15
|
+
} from 'lucide-react';
|
|
16
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
17
|
+
import type { LogLevel } from '../types';
|
|
18
|
+
import { LEVEL_LABELS, getLevelToneClasses } from '../types';
|
|
19
|
+
|
|
20
|
+
interface ToolbarButtonProps {
|
|
21
|
+
onClick: () => void;
|
|
22
|
+
label: string;
|
|
23
|
+
active?: boolean;
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function ToolbarButton({ onClick, label, active, children }: ToolbarButtonProps) {
|
|
28
|
+
return (
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
onClick={onClick}
|
|
32
|
+
aria-label={label}
|
|
33
|
+
aria-pressed={active}
|
|
34
|
+
className={cn(
|
|
35
|
+
'inline-flex size-7 items-center justify-center rounded-md outline-none transition-colors',
|
|
36
|
+
'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
37
|
+
'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
|
|
38
|
+
active && 'bg-accent text-accent-foreground',
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</button>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ToolbarProps {
|
|
47
|
+
title: string;
|
|
48
|
+
totalCount: number;
|
|
49
|
+
filteredCount: number;
|
|
50
|
+
levels: LogLevel[];
|
|
51
|
+
activeLevels: Set<LogLevel>;
|
|
52
|
+
toggleLevel: (level: LogLevel) => void;
|
|
53
|
+
levelCounts: Partial<Record<LogLevel, number>>;
|
|
54
|
+
searchQuery: string;
|
|
55
|
+
setSearchQuery: (q: string) => void;
|
|
56
|
+
autoScrollEnabled: boolean;
|
|
57
|
+
paused: boolean;
|
|
58
|
+
setPaused: (p: boolean) => void;
|
|
59
|
+
onClear?: () => void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Header + filter row for the LogViewer. The level chips also serve as
|
|
64
|
+
* the count badges — clicking strikes them out and removes the level
|
|
65
|
+
* from the active set. The search input is always visible (no expand /
|
|
66
|
+
* collapse toggle) because filter and search are the two main jobs of
|
|
67
|
+
* the toolbar; hiding either is friction.
|
|
68
|
+
*/
|
|
69
|
+
export function Toolbar({
|
|
70
|
+
title,
|
|
71
|
+
totalCount,
|
|
72
|
+
filteredCount,
|
|
73
|
+
levels,
|
|
74
|
+
activeLevels,
|
|
75
|
+
toggleLevel,
|
|
76
|
+
levelCounts,
|
|
77
|
+
searchQuery,
|
|
78
|
+
setSearchQuery,
|
|
79
|
+
autoScrollEnabled,
|
|
80
|
+
paused,
|
|
81
|
+
setPaused,
|
|
82
|
+
onClear,
|
|
83
|
+
}: ToolbarProps) {
|
|
84
|
+
return (
|
|
85
|
+
<div className="flex flex-col gap-2 border-b border-border/40 bg-muted/30 px-3 py-2">
|
|
86
|
+
<div className="flex items-center gap-2">
|
|
87
|
+
<Terminal className="size-3.5 shrink-0 text-muted-foreground" />
|
|
88
|
+
<span className="flex-1 truncate text-sm font-medium text-foreground">
|
|
89
|
+
{title}
|
|
90
|
+
</span>
|
|
91
|
+
|
|
92
|
+
<span className="mr-1 text-[10px] tabular-nums text-muted-foreground">
|
|
93
|
+
{filteredCount}
|
|
94
|
+
{filteredCount !== totalCount && ` / ${totalCount}`} lines
|
|
95
|
+
</span>
|
|
96
|
+
|
|
97
|
+
<div className="flex items-center gap-0.5">
|
|
98
|
+
{autoScrollEnabled && (
|
|
99
|
+
<ToolbarButton
|
|
100
|
+
onClick={() => setPaused(!paused)}
|
|
101
|
+
label={paused ? 'Resume auto-scroll' : 'Pause auto-scroll'}
|
|
102
|
+
active={paused}
|
|
103
|
+
>
|
|
104
|
+
{paused ? (
|
|
105
|
+
<Play className="size-3.5" />
|
|
106
|
+
) : (
|
|
107
|
+
<Pause className="size-3.5" />
|
|
108
|
+
)}
|
|
109
|
+
</ToolbarButton>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{onClear && (
|
|
113
|
+
<ToolbarButton onClick={onClear} label="Clear logs">
|
|
114
|
+
<Trash2 className="size-3.5" />
|
|
115
|
+
</ToolbarButton>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
121
|
+
<div className="flex flex-wrap items-center gap-1">
|
|
122
|
+
{levels.map((level) => {
|
|
123
|
+
const tone = getLevelToneClasses(level);
|
|
124
|
+
const isActive = activeLevels.has(level);
|
|
125
|
+
const count = levelCounts[level] ?? 0;
|
|
126
|
+
return (
|
|
127
|
+
<button
|
|
128
|
+
key={level}
|
|
129
|
+
type="button"
|
|
130
|
+
onClick={() => toggleLevel(level)}
|
|
131
|
+
role="checkbox"
|
|
132
|
+
aria-checked={isActive}
|
|
133
|
+
aria-label={`${isActive ? 'Hide' : 'Show'} ${level} logs`}
|
|
134
|
+
className={cn(
|
|
135
|
+
'inline-flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium outline-none transition-colors',
|
|
136
|
+
'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
|
|
137
|
+
isActive
|
|
138
|
+
? tone.badge
|
|
139
|
+
: 'bg-muted/50 text-muted-foreground/60 line-through',
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
<Circle
|
|
143
|
+
className={cn(
|
|
144
|
+
'size-1.5 fill-current',
|
|
145
|
+
isActive ? tone.text : 'text-muted-foreground/40',
|
|
146
|
+
)}
|
|
147
|
+
/>
|
|
148
|
+
{LEVEL_LABELS[level]}
|
|
149
|
+
{count > 0 && <span className="tabular-nums">{count}</span>}
|
|
150
|
+
</button>
|
|
151
|
+
);
|
|
152
|
+
})}
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div className="ml-auto flex items-center gap-1.5 rounded-md border border-border/40 bg-background px-2 py-1">
|
|
156
|
+
<Search className="size-3 text-muted-foreground" />
|
|
157
|
+
<input
|
|
158
|
+
type="text"
|
|
159
|
+
value={searchQuery}
|
|
160
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
161
|
+
placeholder="Filter…"
|
|
162
|
+
aria-label="Filter logs"
|
|
163
|
+
className="w-32 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground sm:w-40"
|
|
164
|
+
/>
|
|
165
|
+
{searchQuery && (
|
|
166
|
+
<button
|
|
167
|
+
type="button"
|
|
168
|
+
onClick={() => setSearchQuery('')}
|
|
169
|
+
className="inline-flex size-4 items-center justify-center rounded text-muted-foreground hover:text-foreground"
|
|
170
|
+
aria-label="Clear search"
|
|
171
|
+
>
|
|
172
|
+
<X className="size-3" />
|
|
173
|
+
</button>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface ScrollToBottomPillProps {
|
|
182
|
+
visible: boolean;
|
|
183
|
+
onClick: () => void;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function ScrollToBottomPill({ visible, onClick }: ScrollToBottomPillProps) {
|
|
187
|
+
if (!visible) return null;
|
|
188
|
+
return (
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
onClick={onClick}
|
|
192
|
+
className="flex w-full items-center justify-center gap-1.5 border-t border-border/40 bg-muted/30 py-1.5 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground"
|
|
193
|
+
aria-label="Scroll to latest"
|
|
194
|
+
>
|
|
195
|
+
<ArrowDownToLine className="size-3" />
|
|
196
|
+
New logs below
|
|
197
|
+
</button>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import type { VirtuosoHandle } from 'react-virtuoso';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sticky-bottom controller for the virtualized log list. Tracks whether
|
|
10
|
+
* the viewport is pinned to the latest entry; when it is and a new entry
|
|
11
|
+
* arrives, jumps to the end via Virtuoso's `scrollToIndex`. When the
|
|
12
|
+
* user has scrolled up, the controller stays out of the way and exposes
|
|
13
|
+
* `scrollToBottom` so the UI can offer a "Jump to latest" pill.
|
|
14
|
+
*
|
|
15
|
+
* The previous (DOM-scroll) implementation set `scrollTop = scrollHeight`
|
|
16
|
+
* inside an effect. That works for a non-virtualized list but fights
|
|
17
|
+
* Virtuoso, which owns the scroller. We instead use Virtuoso's
|
|
18
|
+
* `atBottomStateChange` callback (fired with hysteresis) and call
|
|
19
|
+
* `scrollToIndex` when new entries land while we're pinned.
|
|
20
|
+
*/
|
|
21
|
+
export interface UseAutoScrollResult {
|
|
22
|
+
virtuosoRef: React.RefObject<VirtuosoHandle | null>;
|
|
23
|
+
isAtBottom: boolean;
|
|
24
|
+
/** Wire to Virtuoso's `atBottomStateChange`. */
|
|
25
|
+
onAtBottomChange: (atBottom: boolean) => void;
|
|
26
|
+
/** Jump to the end of the list. Used by the "New logs below" pill. */
|
|
27
|
+
scrollToBottom: () => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useAutoScroll(
|
|
31
|
+
entryCount: number,
|
|
32
|
+
enabled: boolean,
|
|
33
|
+
): UseAutoScrollResult {
|
|
34
|
+
const virtuosoRef = React.useRef<VirtuosoHandle | null>(null);
|
|
35
|
+
const [isAtBottom, setIsAtBottom] = React.useState(true);
|
|
36
|
+
const isAtBottomRef = React.useRef(true);
|
|
37
|
+
const lastCountRef = React.useRef(entryCount);
|
|
38
|
+
|
|
39
|
+
const onAtBottomChange = React.useCallback((atBottom: boolean) => {
|
|
40
|
+
isAtBottomRef.current = atBottom;
|
|
41
|
+
setIsAtBottom(atBottom);
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
const scrollToBottom = React.useCallback(() => {
|
|
45
|
+
const handle = virtuosoRef.current;
|
|
46
|
+
if (!handle) return;
|
|
47
|
+
// `LAST` is Virtuoso's sentinel for "bottom".
|
|
48
|
+
handle.scrollToIndex({ index: 'LAST', behavior: 'auto' });
|
|
49
|
+
isAtBottomRef.current = true;
|
|
50
|
+
setIsAtBottom(true);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
const prev = lastCountRef.current;
|
|
55
|
+
lastCountRef.current = entryCount;
|
|
56
|
+
if (!enabled) return;
|
|
57
|
+
if (entryCount <= prev) return; // shrink / no-op
|
|
58
|
+
if (!isAtBottomRef.current) return;
|
|
59
|
+
// Defer one frame so Virtuoso settles the new row's height first;
|
|
60
|
+
// otherwise the jump lands one row short on the very first append.
|
|
61
|
+
const id = requestAnimationFrame(() => {
|
|
62
|
+
virtuosoRef.current?.scrollToIndex({ index: 'LAST', behavior: 'auto' });
|
|
63
|
+
});
|
|
64
|
+
return () => cancelAnimationFrame(id);
|
|
65
|
+
}, [entryCount, enabled]);
|
|
66
|
+
|
|
67
|
+
return { virtuosoRef, isAtBottom, onAtBottomChange, scrollToBottom };
|
|
68
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import type { LogEntry, LogLevel } from '../types';
|
|
7
|
+
import { stripAnsi } from '../utils/ansi';
|
|
8
|
+
|
|
9
|
+
interface UseLogFilterArgs {
|
|
10
|
+
entries: LogEntry[];
|
|
11
|
+
activeLevels: Set<LogLevel>;
|
|
12
|
+
searchQuery: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface UseLogFilterResult {
|
|
16
|
+
filtered: LogEntry[];
|
|
17
|
+
/** Counts per level for the **unfiltered** entries — feeds the filter
|
|
18
|
+
* chip badges. */
|
|
19
|
+
counts: Partial<Record<LogLevel, number>>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Filter + search the entry list. Both operations route through one
|
|
24
|
+
* pass over `entries` so a 10k-entry list with both filters active
|
|
25
|
+
* costs one iteration, not two. The result is memoized on the input
|
|
26
|
+
* identity — callers that only append to `entries` get an incremental
|
|
27
|
+
* O(n) re-derivation (acceptable for 10k+; if it ever bites, switch
|
|
28
|
+
* to a streaming filter that reuses the prior result).
|
|
29
|
+
*
|
|
30
|
+
* Search is case-insensitive and strips ANSI escapes from the haystack
|
|
31
|
+
* — a search for `"port 3000"` matches `\x1b[32mport 3000\x1b[0m` too.
|
|
32
|
+
*/
|
|
33
|
+
export function useLogFilter({
|
|
34
|
+
entries,
|
|
35
|
+
activeLevels,
|
|
36
|
+
searchQuery,
|
|
37
|
+
}: UseLogFilterArgs): UseLogFilterResult {
|
|
38
|
+
return React.useMemo(() => {
|
|
39
|
+
const counts: Partial<Record<LogLevel, number>> = {};
|
|
40
|
+
const filtered: LogEntry[] = [];
|
|
41
|
+
const needle = searchQuery.trim().toLowerCase();
|
|
42
|
+
const hasSearch = needle.length > 0;
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
45
|
+
const entry = entries[i];
|
|
46
|
+
counts[entry.level] = (counts[entry.level] ?? 0) + 1;
|
|
47
|
+
|
|
48
|
+
if (!activeLevels.has(entry.level)) continue;
|
|
49
|
+
if (hasSearch) {
|
|
50
|
+
const haystack = stripAnsi(entry.message).toLowerCase();
|
|
51
|
+
if (!haystack.includes(needle)) continue;
|
|
52
|
+
}
|
|
53
|
+
filtered.push(entry);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { filtered, counts };
|
|
57
|
+
}, [entries, activeLevels, searchQuery]);
|
|
58
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
export { LogViewer } from './LogViewer';
|
|
4
|
+
export {
|
|
5
|
+
LEVEL_LABELS,
|
|
6
|
+
LEVEL_TONE,
|
|
7
|
+
TONE_CLASSES as LOG_TONE_CLASSES,
|
|
8
|
+
getLevelToneClasses,
|
|
9
|
+
} from './types';
|
|
10
|
+
export type {
|
|
11
|
+
LogEntry,
|
|
12
|
+
LogLevel,
|
|
13
|
+
LogTone,
|
|
14
|
+
LogToneClasses,
|
|
15
|
+
LogViewerProps,
|
|
16
|
+
} from './types';
|
|
17
|
+
export { parseAnsi, stripAnsi } from './utils/ansi';
|
|
18
|
+
export type { AnsiSegment } from './utils/ansi';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import { createLazyComponent } from '../../../../common/lazy-wrapper';
|
|
6
|
+
import type { LogViewerProps } from './types';
|
|
7
|
+
|
|
8
|
+
export const LazyLogViewer = createLazyComponent<LogViewerProps>(
|
|
9
|
+
() => import('./LogViewer').then((mod) => ({ default: mod.LogViewer })),
|
|
10
|
+
{
|
|
11
|
+
displayName: 'LazyLogViewer',
|
|
12
|
+
fallback: (
|
|
13
|
+
<div
|
|
14
|
+
data-slot="log-viewer-skeleton"
|
|
15
|
+
className="flex h-[400px] w-full animate-pulse flex-col gap-2 rounded-xl border border-border/60 bg-card p-3"
|
|
16
|
+
>
|
|
17
|
+
<div className="h-7 w-1/3 rounded bg-muted" />
|
|
18
|
+
<div className="h-5 w-2/3 rounded bg-muted" />
|
|
19
|
+
<div className="flex-1 rounded bg-muted/60" />
|
|
20
|
+
</div>
|
|
21
|
+
),
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export type { LogViewerProps } from './types';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Adapted from jalcoui (MIT) — github.com/jal-co/ui
|
|
2
|
+
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Severity level of a log entry. Five canonical levels — `error`, `warn`,
|
|
7
|
+
* `info`, `debug` route to status / categorical semantic tokens; `verbose`
|
|
8
|
+
* collapses to muted.
|
|
9
|
+
*/
|
|
10
|
+
export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Tone bucket each level resolves to. `debug` is intentionally **not** a
|
|
14
|
+
* status — it routes through a categorical preset color so themes can
|
|
15
|
+
* rotate it without polluting the destructive/warning/info/success
|
|
16
|
+
* palette.
|
|
17
|
+
*/
|
|
18
|
+
export type LogTone = 'destructive' | 'warning' | 'info' | 'debug' | 'muted';
|
|
19
|
+
|
|
20
|
+
export interface LogEntry {
|
|
21
|
+
/** Severity. */
|
|
22
|
+
level: LogLevel;
|
|
23
|
+
/** Log message text. May contain ANSI escape sequences. */
|
|
24
|
+
message: string;
|
|
25
|
+
/** ISO timestamp string. When omitted, the current time is used for display. */
|
|
26
|
+
timestamp?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Tone CSS class bundle per `LogTone`. Every class resolves to a semantic
|
|
31
|
+
* token (no raw color scales). `dot` and `text` ride on opacity-derived
|
|
32
|
+
* surfaces so they survive every preset that overrides only the base
|
|
33
|
+
* `--{status}` token.
|
|
34
|
+
*/
|
|
35
|
+
export interface LogToneClasses {
|
|
36
|
+
/** Text color for the level label / icon. */
|
|
37
|
+
text: string;
|
|
38
|
+
/** Background for the filled dot. */
|
|
39
|
+
dot: string;
|
|
40
|
+
/** Badge surface when the level filter is active. */
|
|
41
|
+
badge: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Mapping from {@link LogLevel} to {@link LogTone}. `debug` collapses to
|
|
46
|
+
* the categorical `debug` tone — it is not a status.
|
|
47
|
+
*/
|
|
48
|
+
export const LEVEL_TONE: Record<LogLevel, LogTone> = {
|
|
49
|
+
error: 'destructive',
|
|
50
|
+
warn: 'warning',
|
|
51
|
+
info: 'info',
|
|
52
|
+
debug: 'debug',
|
|
53
|
+
verbose: 'muted',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Short 3-letter labels rendered in monospace gutters. Matches `ERR`,
|
|
58
|
+
* `WRN`, `INF`, `DBG`, `VRB` so columns align on screen.
|
|
59
|
+
*/
|
|
60
|
+
export const LEVEL_LABELS: Record<LogLevel, string> = {
|
|
61
|
+
error: 'ERR',
|
|
62
|
+
warn: 'WRN',
|
|
63
|
+
info: 'INF',
|
|
64
|
+
debug: 'DBG',
|
|
65
|
+
verbose: 'VRB',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Semantic-token class bundle per {@link LogTone}. All `bg-` / `text-`
|
|
70
|
+
* values resolve through ui-core tokens — themes can swap them without
|
|
71
|
+
* touching this file. `debug` uses a violet-ish categorical via the
|
|
72
|
+
* `--chart-4`/`--chart-5` fallbacks already shipped in ui-core (we keep
|
|
73
|
+
* it on the `muted` family for surface and lean on opacity for
|
|
74
|
+
* differentiation; the actual debug color comes from the level dot in
|
|
75
|
+
* the source).
|
|
76
|
+
*/
|
|
77
|
+
export const TONE_CLASSES: Record<LogTone, LogToneClasses> = {
|
|
78
|
+
destructive: {
|
|
79
|
+
text: 'text-destructive',
|
|
80
|
+
dot: 'bg-destructive',
|
|
81
|
+
badge: 'bg-destructive/15 text-destructive',
|
|
82
|
+
},
|
|
83
|
+
warning: {
|
|
84
|
+
text: 'text-warning',
|
|
85
|
+
dot: 'bg-warning',
|
|
86
|
+
badge: 'bg-warning/15 text-warning',
|
|
87
|
+
},
|
|
88
|
+
info: {
|
|
89
|
+
text: 'text-info',
|
|
90
|
+
dot: 'bg-info',
|
|
91
|
+
badge: 'bg-info/15 text-info',
|
|
92
|
+
},
|
|
93
|
+
// `debug` is categorical, not status — render via primary token tinted
|
|
94
|
+
// for legibility; themes that recolour `--primary` get a free debug
|
|
95
|
+
// shift without touching this file.
|
|
96
|
+
debug: {
|
|
97
|
+
text: 'text-primary',
|
|
98
|
+
dot: 'bg-primary',
|
|
99
|
+
badge: 'bg-primary/15 text-primary',
|
|
100
|
+
},
|
|
101
|
+
muted: {
|
|
102
|
+
text: 'text-muted-foreground',
|
|
103
|
+
dot: 'bg-muted-foreground/60',
|
|
104
|
+
badge: 'bg-muted text-muted-foreground',
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolve the tone class bundle for a level.
|
|
110
|
+
*/
|
|
111
|
+
export function getLevelToneClasses(level: LogLevel): LogToneClasses {
|
|
112
|
+
return TONE_CLASSES[LEVEL_TONE[level]];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface LogViewerProps
|
|
116
|
+
extends Omit<React.ComponentProps<'div'>, 'children' | 'title'> {
|
|
117
|
+
/** Log entries to render. */
|
|
118
|
+
entries: LogEntry[];
|
|
119
|
+
/** Header title. @default "Logs" */
|
|
120
|
+
title?: string;
|
|
121
|
+
/** Maximum visible height in pixels. @default 400 */
|
|
122
|
+
maxHeight?: number;
|
|
123
|
+
/** Show monospace line numbers. @default true */
|
|
124
|
+
lineNumbers?: boolean;
|
|
125
|
+
/** Show timestamps. @default true */
|
|
126
|
+
timestamps?: boolean;
|
|
127
|
+
/** Auto-scroll to bottom when new entries arrive (and the user is
|
|
128
|
+
* already pinned to the bottom). @default true */
|
|
129
|
+
autoScroll?: boolean;
|
|
130
|
+
/** Levels exposed in the toolbar filter chips. @default all five */
|
|
131
|
+
levels?: LogLevel[];
|
|
132
|
+
/** Interpret ANSI escape sequences (`\x1b[31m…`) in `message`.
|
|
133
|
+
* @default true */
|
|
134
|
+
ansi?: boolean;
|
|
135
|
+
/** Optional callback wired to the "Clear" toolbar button — when
|
|
136
|
+
* omitted, the button is hidden. */
|
|
137
|
+
onClear?: () => void;
|
|
138
|
+
/** Force-disable virtualization (small / Storybook usage). The
|
|
139
|
+
* virtualized path uses `react-virtuoso` and handles 10k+ entries
|
|
140
|
+
* without lag. @default false */
|
|
141
|
+
noVirtualize?: boolean;
|
|
142
|
+
}
|