@brainfish-ai/devdoc 0.1.42 → 0.1.44
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/cli/commands/create.js +2 -2
- package/dist/cli/commands/dev.js +19 -10
- package/package.json +3 -2
- package/renderer/app/api/assets/[...path]/route.js +108 -0
- package/renderer/app/api/assets/route.js +114 -0
- package/renderer/app/api/assets/upload/route.js +163 -0
- package/renderer/app/api/auth-schemes/route.js +58 -0
- package/renderer/app/api/chat/route.js +759 -0
- package/renderer/app/api/codegen/route.js +52 -0
- package/renderer/app/api/collections/route.js +706 -0
- package/renderer/app/api/debug/route.js +47 -0
- package/renderer/app/api/deploy/route.js +199 -0
- package/renderer/app/api/device/route.js +36 -0
- package/renderer/app/api/docs/route.js +205 -0
- package/renderer/app/api/domains/add/route.js +121 -0
- package/renderer/app/api/domains/lookup/route.js +43 -0
- package/renderer/app/api/domains/remove/route.js +89 -0
- package/renderer/app/api/domains/status/route.js +140 -0
- package/renderer/app/api/domains/verify/route.js +168 -0
- package/renderer/app/api/keys/regenerate/route.js +71 -0
- package/renderer/app/api/local-assets/[...path]/route.js +108 -0
- package/renderer/app/api/openapi-spec/route.js +73 -0
- package/renderer/app/api/projects/[slug]/route.js +129 -0
- package/renderer/app/api/projects/[slug]/stats/route.js +80 -0
- package/renderer/app/api/projects/register/route.js +176 -0
- package/renderer/app/api/proxy/route.js +139 -0
- package/renderer/app/api/proxy-stream/route.js +156 -0
- package/renderer/app/api/redirects/route.js +35 -0
- package/renderer/app/api/schema/route.js +85 -0
- package/renderer/app/api/subdomains/check/route.js +158 -0
- package/renderer/app/api/suggestions/route.js +195 -0
- package/renderer/app/globals.css +69 -0
- package/renderer/app/layout.js +47 -0
- package/renderer/app/llms-full.txt/route.js +266 -0
- package/renderer/app/llms.txt/route.js +228 -0
- package/renderer/app/page.js +12 -0
- package/renderer/app/robots.txt/route.js +66 -0
- package/renderer/app/sitemap.xml/route.js +155 -0
- package/renderer/components/docs/index.js +8 -0
- package/renderer/components/docs/mdx/accordion.js +113 -0
- package/renderer/components/docs/mdx/badge.js +72 -0
- package/renderer/components/docs/mdx/callouts.js +137 -0
- package/renderer/components/docs/mdx/cards.js +175 -0
- package/renderer/components/docs/mdx/changelog.js +100 -0
- package/renderer/components/docs/mdx/code-block.js +147 -0
- package/renderer/components/docs/mdx/code-group.js +287 -0
- package/renderer/components/docs/mdx/file-embeds.js +82 -0
- package/renderer/components/docs/mdx/frame.js +59 -0
- package/renderer/components/docs/mdx/highlight.js +90 -0
- package/renderer/components/docs/mdx/iframe.js +69 -0
- package/renderer/components/docs/mdx/image.js +135 -0
- package/renderer/components/docs/mdx/index.js +134 -0
- package/renderer/components/docs/mdx/landing.js +317 -0
- package/renderer/components/docs/mdx/mermaid.js +212 -0
- package/renderer/components/docs/mdx/param-field.js +112 -0
- package/renderer/components/docs/mdx/steps.js +74 -0
- package/renderer/components/docs/mdx/tabs.js +50 -0
- package/renderer/components/docs/mdx-renderer.js +77 -0
- package/renderer/components/docs/navigation/breadcrumbs.js +64 -0
- package/renderer/components/docs/navigation/index.js +6 -0
- package/renderer/components/docs/navigation/page-nav.js +57 -0
- package/renderer/components/docs/navigation/sidebar.js +375 -0
- package/renderer/components/docs/navigation/toc.js +89 -0
- package/renderer/components/docs/notice.js +77 -0
- package/renderer/components/docs-header.js +202 -0
- package/renderer/components/docs-viewer/agent/agent-chat.js +1831 -0
- package/renderer/components/docs-viewer/agent/agent-popup-button.js +99 -0
- package/renderer/components/docs-viewer/agent/cards/debug-context-card.js +107 -0
- package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.js +57 -0
- package/renderer/components/docs-viewer/agent/cards/index.js +45 -0
- package/renderer/components/docs-viewer/agent/cards/response-options-card.js +154 -0
- package/renderer/components/docs-viewer/agent/cards/types.js +22 -0
- package/renderer/components/docs-viewer/agent/chat-message.js +2 -0
- package/renderer/components/docs-viewer/agent/index.js +7 -0
- package/renderer/components/docs-viewer/agent/messages/assistant-message.js +108 -0
- package/renderer/components/docs-viewer/agent/messages/chat-message.js +34 -0
- package/renderer/components/docs-viewer/agent/messages/index.js +6 -0
- package/renderer/components/docs-viewer/agent/messages/tool-call-display.js +1065 -0
- package/renderer/components/docs-viewer/agent/messages/types.js +2 -0
- package/renderer/components/docs-viewer/agent/messages/typing-indicator.js +26 -0
- package/renderer/components/docs-viewer/agent/messages/user-message.js +37 -0
- package/renderer/components/docs-viewer/code-editor/{index.tsx → index.js} +1 -1
- package/renderer/components/docs-viewer/code-editor/notes-mode.js +1338 -0
- package/renderer/components/docs-viewer/content/changelog-page.js +297 -0
- package/renderer/components/docs-viewer/content/content-router.js +182 -0
- package/renderer/components/docs-viewer/content/doc-page.js +290 -0
- package/renderer/components/docs-viewer/content/documentation-viewer.js +14 -0
- package/renderer/components/docs-viewer/content/index.js +31 -0
- package/renderer/components/docs-viewer/content/not-found-page.js +300 -0
- package/renderer/components/docs-viewer/content/request-details.js +528 -0
- package/renderer/components/docs-viewer/content/sections/auth.js +108 -0
- package/renderer/components/docs-viewer/content/sections/body.js +80 -0
- package/renderer/components/docs-viewer/content/sections/headers.js +64 -0
- package/renderer/components/docs-viewer/content/sections/overview.js +56 -0
- package/renderer/components/docs-viewer/content/sections/parameters.js +64 -0
- package/renderer/components/docs-viewer/content/sections/responses.js +91 -0
- package/renderer/components/docs-viewer/global-auth-modal.js +427 -0
- package/renderer/components/docs-viewer/index.js +1448 -0
- package/renderer/components/docs-viewer/playground/auth-editor.js +418 -0
- package/renderer/components/docs-viewer/playground/body-editor.js +240 -0
- package/renderer/components/docs-viewer/playground/code-editor.js +135 -0
- package/renderer/components/docs-viewer/playground/code-snippet.js +393 -0
- package/renderer/components/docs-viewer/playground/graphql-playground.js +936 -0
- package/renderer/components/docs-viewer/playground/index.js +682 -0
- package/renderer/components/docs-viewer/playground/key-value-editor.js +317 -0
- package/renderer/components/docs-viewer/playground/method-selector.js +65 -0
- package/renderer/components/docs-viewer/playground/request-builder.js +181 -0
- package/renderer/components/docs-viewer/playground/request-tabs.js +240 -0
- package/renderer/components/docs-viewer/playground/response-cards/idle-card.js +42 -0
- package/renderer/components/docs-viewer/playground/response-cards/index.js +72 -0
- package/renderer/components/docs-viewer/playground/response-cards/loading-card.js +24 -0
- package/renderer/components/docs-viewer/playground/response-cards/network-error-card.js +28 -0
- package/renderer/components/docs-viewer/playground/response-cards/response-body-card.js +308 -0
- package/renderer/components/docs-viewer/playground/response-cards/types.js +9 -0
- package/renderer/components/docs-viewer/playground/response-viewer.js +18 -0
- package/renderer/components/docs-viewer/search/index.js +2 -0
- package/renderer/components/docs-viewer/search/search-dialog.js +367 -0
- package/renderer/components/docs-viewer/search/use-search.js +89 -0
- package/renderer/components/docs-viewer/shared/markdown-renderer.js +423 -0
- package/renderer/components/docs-viewer/shared/method-badge.js +23 -0
- package/renderer/components/docs-viewer/shared/schema-viewer.js +321 -0
- package/renderer/components/docs-viewer/sidebar/collection-tree.js +222 -0
- package/renderer/components/docs-viewer/sidebar/endpoint-options.js +512 -0
- package/renderer/components/docs-viewer/sidebar/index.js +196 -0
- package/renderer/components/docs-viewer/sidebar/right-sidebar.js +159 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-group.js +87 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-item.js +172 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-section.js +31 -0
- package/renderer/components/theme-provider.js +10 -0
- package/renderer/components/theme-toggle.js +86 -0
- package/renderer/components/ui/badge.js +29 -0
- package/renderer/components/ui/button.js +40 -0
- package/renderer/components/ui/dialog.js +50 -0
- package/renderer/components/ui/dropdown-menu.js +143 -0
- package/renderer/components/ui/input.js +12 -0
- package/renderer/components/ui/label.js +13 -0
- package/renderer/components/ui/navigation-menu.js +83 -0
- package/renderer/components/ui/select.js +116 -0
- package/renderer/components/ui/spinner.js +92 -0
- package/renderer/components/ui/tabs.js +34 -0
- package/renderer/components/ui/tooltip.js +43 -0
- package/renderer/hooks/use-code-copy.js +76 -0
- package/renderer/hooks/use-openapi-title.js +33 -0
- package/renderer/hooks/use-route-state.js +159 -0
- package/renderer/lib/api-docs/agent/index.js +4 -0
- package/renderer/lib/api-docs/agent/indexer.js +254 -0
- package/renderer/lib/api-docs/agent/spec-summary.js +227 -0
- package/renderer/lib/api-docs/agent/types.js +5 -0
- package/renderer/lib/api-docs/agent/use-suggestions.js +97 -0
- package/renderer/lib/api-docs/auth/auth-context.js +157 -0
- package/renderer/lib/api-docs/auth/auth-storage.js +66 -0
- package/renderer/lib/api-docs/auth/crypto.js +64 -0
- package/renderer/lib/api-docs/auth/index.js +3 -0
- package/renderer/lib/api-docs/code-editor/db.js +145 -0
- package/renderer/lib/api-docs/code-editor/hooks.js +254 -0
- package/renderer/lib/api-docs/code-editor/{index.ts → index.js} +3 -4
- package/renderer/lib/api-docs/code-editor/mode-context.js +126 -0
- package/renderer/lib/api-docs/code-editor/types.js +53 -0
- package/renderer/lib/api-docs/codegen/definitions.js +258 -0
- package/renderer/lib/api-docs/codegen/har.js +171 -0
- package/renderer/lib/api-docs/codegen/index.js +118 -0
- package/renderer/lib/api-docs/factories.js +136 -0
- package/renderer/lib/api-docs/{index.ts → index.js} +5 -10
- package/renderer/lib/api-docs/mobile-context.js +116 -0
- package/renderer/lib/api-docs/navigation-context.js +62 -0
- package/renderer/lib/api-docs/parsers/graphql/index.js +50 -0
- package/renderer/lib/api-docs/parsers/graphql/parser.js +350 -0
- package/renderer/lib/api-docs/parsers/graphql/transformer.js +215 -0
- package/renderer/lib/api-docs/parsers/graphql/types.js +46 -0
- package/renderer/lib/api-docs/parsers/openapi/dereferencer.js +43 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/auth.js +486 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/body.js +295 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/index.js +132 -0
- package/renderer/lib/api-docs/parsers/openapi/index.js +127 -0
- package/renderer/lib/api-docs/parsers/openapi/transformer.js +192 -0
- package/renderer/lib/api-docs/parsers/openapi/validator.js +24 -0
- package/renderer/lib/api-docs/playground/context.js +65 -0
- package/renderer/lib/api-docs/playground/navigation-context.js +74 -0
- package/renderer/lib/api-docs/playground/request-builder.js +163 -0
- package/renderer/lib/api-docs/playground/request-runner.js +224 -0
- package/renderer/lib/api-docs/playground/types.js +5 -0
- package/renderer/lib/api-docs/types.js +23 -0
- package/renderer/lib/api-docs/utils.js +212 -0
- package/renderer/lib/cache.js +157 -0
- package/renderer/lib/docs/config/domain-schema.js +161 -0
- package/renderer/lib/docs/config/environment.js +38 -0
- package/renderer/lib/docs/config/index.js +6 -0
- package/renderer/lib/docs/config/loader.js +113 -0
- package/renderer/lib/docs/config/schema.js +281 -0
- package/renderer/lib/docs/index.js +8 -0
- package/renderer/lib/docs/mdx/compiler.js +131 -0
- package/renderer/lib/docs/mdx/frontmatter.js +73 -0
- package/renderer/lib/docs/mdx/index.js +10 -0
- package/renderer/lib/docs/mdx/remark-mermaid.js +63 -0
- package/renderer/lib/docs/navigation/generator.js +269 -0
- package/renderer/lib/docs/navigation/index.js +3 -0
- package/renderer/lib/docs/navigation/types.js +11 -0
- package/renderer/lib/docs-navigation-context.js +40 -0
- package/renderer/lib/docs-navigation.js +140 -0
- package/renderer/lib/multi-tenant/context.js +80 -0
- package/renderer/lib/storage/blob.js +767 -0
- package/renderer/lib/utils/icons.js +30 -0
- package/renderer/lib/utils.js +5 -0
- package/renderer/next.config.js +62 -0
- package/renderer/package.json +1 -0
- package/renderer/tsconfig.json +23 -5
- package/renderer/app/api/assets/[...path]/route.ts +0 -123
- package/renderer/app/api/assets/route.ts +0 -124
- package/renderer/app/api/assets/upload/route.ts +0 -177
- package/renderer/app/api/auth-schemes/route.ts +0 -77
- package/renderer/app/api/chat/route.ts +0 -858
- package/renderer/app/api/codegen/route.ts +0 -72
- package/renderer/app/api/collections/route.ts +0 -1002
- package/renderer/app/api/debug/route.ts +0 -53
- package/renderer/app/api/deploy/route.ts +0 -234
- package/renderer/app/api/device/route.ts +0 -42
- package/renderer/app/api/docs/route.ts +0 -201
- package/renderer/app/api/domains/add/route.ts +0 -132
- package/renderer/app/api/domains/lookup/route.ts +0 -43
- package/renderer/app/api/domains/remove/route.ts +0 -100
- package/renderer/app/api/domains/status/route.ts +0 -158
- package/renderer/app/api/domains/verify/route.ts +0 -181
- package/renderer/app/api/keys/regenerate/route.ts +0 -80
- package/renderer/app/api/local-assets/[...path]/route.ts +0 -122
- package/renderer/app/api/openapi-spec/route.ts +0 -151
- package/renderer/app/api/projects/[slug]/route.ts +0 -153
- package/renderer/app/api/projects/[slug]/stats/route.ts +0 -96
- package/renderer/app/api/projects/register/route.ts +0 -152
- package/renderer/app/api/proxy/route.ts +0 -149
- package/renderer/app/api/proxy-stream/route.ts +0 -168
- package/renderer/app/api/redirects/route.ts +0 -47
- package/renderer/app/api/schema/route.ts +0 -73
- package/renderer/app/api/subdomains/check/route.ts +0 -172
- package/renderer/app/api/suggestions/route.ts +0 -144
- package/renderer/app/layout.tsx +0 -54
- package/renderer/app/llms-full.txt/route.ts +0 -346
- package/renderer/app/llms.txt/route.ts +0 -279
- package/renderer/app/page.tsx +0 -14
- package/renderer/app/robots.txt/route.ts +0 -84
- package/renderer/app/sitemap.xml/route.ts +0 -199
- package/renderer/components/docs/index.ts +0 -12
- package/renderer/components/docs/mdx/accordion.tsx +0 -169
- package/renderer/components/docs/mdx/badge.tsx +0 -132
- package/renderer/components/docs/mdx/callouts.tsx +0 -154
- package/renderer/components/docs/mdx/cards.tsx +0 -241
- package/renderer/components/docs/mdx/changelog.tsx +0 -120
- package/renderer/components/docs/mdx/code-block.tsx +0 -186
- package/renderer/components/docs/mdx/code-group.tsx +0 -421
- package/renderer/components/docs/mdx/file-embeds.tsx +0 -105
- package/renderer/components/docs/mdx/frame.tsx +0 -112
- package/renderer/components/docs/mdx/highlight.tsx +0 -151
- package/renderer/components/docs/mdx/iframe.tsx +0 -134
- package/renderer/components/docs/mdx/image.tsx +0 -235
- package/renderer/components/docs/mdx/index.ts +0 -237
- package/renderer/components/docs/mdx/landing.tsx +0 -684
- package/renderer/components/docs/mdx/mermaid.tsx +0 -240
- package/renderer/components/docs/mdx/param-field.tsx +0 -200
- package/renderer/components/docs/mdx/steps.tsx +0 -113
- package/renderer/components/docs/mdx/tabs.tsx +0 -86
- package/renderer/components/docs/mdx-renderer.tsx +0 -100
- package/renderer/components/docs/navigation/breadcrumbs.tsx +0 -76
- package/renderer/components/docs/navigation/index.ts +0 -8
- package/renderer/components/docs/navigation/page-nav.tsx +0 -64
- package/renderer/components/docs/navigation/sidebar.tsx +0 -515
- package/renderer/components/docs/navigation/toc.tsx +0 -113
- package/renderer/components/docs/notice.tsx +0 -105
- package/renderer/components/docs-header.tsx +0 -278
- package/renderer/components/docs-viewer/agent/agent-chat.tsx +0 -2076
- package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +0 -90
- package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +0 -49
- package/renderer/components/docs-viewer/agent/cards/index.tsx +0 -50
- package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +0 -212
- package/renderer/components/docs-viewer/agent/cards/types.ts +0 -84
- package/renderer/components/docs-viewer/agent/chat-message.tsx +0 -17
- package/renderer/components/docs-viewer/agent/index.tsx +0 -6
- package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +0 -119
- package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +0 -46
- package/renderer/components/docs-viewer/agent/messages/index.ts +0 -17
- package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +0 -721
- package/renderer/components/docs-viewer/agent/messages/types.ts +0 -61
- package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +0 -24
- package/renderer/components/docs-viewer/agent/messages/user-message.tsx +0 -51
- package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +0 -1283
- package/renderer/components/docs-viewer/content/changelog-page.tsx +0 -331
- package/renderer/components/docs-viewer/content/doc-page.tsx +0 -367
- package/renderer/components/docs-viewer/content/documentation-viewer.tsx +0 -17
- package/renderer/components/docs-viewer/content/index.tsx +0 -29
- package/renderer/components/docs-viewer/content/not-found-page.tsx +0 -330
- package/renderer/components/docs-viewer/content/request-details.tsx +0 -330
- package/renderer/components/docs-viewer/content/sections/auth.tsx +0 -69
- package/renderer/components/docs-viewer/content/sections/body.tsx +0 -66
- package/renderer/components/docs-viewer/content/sections/headers.tsx +0 -43
- package/renderer/components/docs-viewer/content/sections/overview.tsx +0 -40
- package/renderer/components/docs-viewer/content/sections/parameters.tsx +0 -43
- package/renderer/components/docs-viewer/content/sections/responses.tsx +0 -87
- package/renderer/components/docs-viewer/global-auth-modal.tsx +0 -352
- package/renderer/components/docs-viewer/index.tsx +0 -1670
- package/renderer/components/docs-viewer/playground/auth-editor.tsx +0 -280
- package/renderer/components/docs-viewer/playground/body-editor.tsx +0 -221
- package/renderer/components/docs-viewer/playground/code-editor.tsx +0 -224
- package/renderer/components/docs-viewer/playground/code-snippet.tsx +0 -387
- package/renderer/components/docs-viewer/playground/graphql-playground.tsx +0 -745
- package/renderer/components/docs-viewer/playground/index.tsx +0 -671
- package/renderer/components/docs-viewer/playground/key-value-editor.tsx +0 -261
- package/renderer/components/docs-viewer/playground/method-selector.tsx +0 -60
- package/renderer/components/docs-viewer/playground/request-builder.tsx +0 -179
- package/renderer/components/docs-viewer/playground/request-tabs.tsx +0 -237
- package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +0 -21
- package/renderer/components/docs-viewer/playground/response-cards/index.tsx +0 -93
- package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +0 -16
- package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +0 -23
- package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +0 -268
- package/renderer/components/docs-viewer/playground/response-cards/types.ts +0 -82
- package/renderer/components/docs-viewer/playground/response-viewer.tsx +0 -43
- package/renderer/components/docs-viewer/search/index.ts +0 -2
- package/renderer/components/docs-viewer/search/search-dialog.tsx +0 -331
- package/renderer/components/docs-viewer/search/use-search.ts +0 -117
- package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +0 -431
- package/renderer/components/docs-viewer/shared/method-badge.tsx +0 -41
- package/renderer/components/docs-viewer/shared/schema-viewer.tsx +0 -349
- package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +0 -259
- package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +0 -316
- package/renderer/components/docs-viewer/sidebar/index.tsx +0 -282
- package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +0 -202
- package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +0 -118
- package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +0 -212
- package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +0 -38
- package/renderer/components/theme-provider.tsx +0 -11
- package/renderer/components/theme-toggle.tsx +0 -76
- package/renderer/components/ui/badge.tsx +0 -46
- package/renderer/components/ui/button.tsx +0 -59
- package/renderer/components/ui/dialog.tsx +0 -118
- package/renderer/components/ui/dropdown-menu.tsx +0 -257
- package/renderer/components/ui/input.tsx +0 -21
- package/renderer/components/ui/label.tsx +0 -24
- package/renderer/components/ui/navigation-menu.tsx +0 -168
- package/renderer/components/ui/select.tsx +0 -190
- package/renderer/components/ui/spinner.tsx +0 -114
- package/renderer/components/ui/tabs.tsx +0 -66
- package/renderer/components/ui/tooltip.tsx +0 -61
- package/renderer/hooks/use-code-copy.ts +0 -88
- package/renderer/hooks/use-openapi-title.ts +0 -44
- package/renderer/lib/api-docs/agent/index.ts +0 -6
- package/renderer/lib/api-docs/agent/indexer.ts +0 -323
- package/renderer/lib/api-docs/agent/spec-summary.ts +0 -335
- package/renderer/lib/api-docs/agent/types.ts +0 -116
- package/renderer/lib/api-docs/auth/auth-context.tsx +0 -225
- package/renderer/lib/api-docs/auth/auth-storage.ts +0 -87
- package/renderer/lib/api-docs/auth/crypto.ts +0 -89
- package/renderer/lib/api-docs/auth/index.ts +0 -4
- package/renderer/lib/api-docs/code-editor/db.ts +0 -164
- package/renderer/lib/api-docs/code-editor/hooks.ts +0 -266
- package/renderer/lib/api-docs/code-editor/mode-context.tsx +0 -207
- package/renderer/lib/api-docs/code-editor/types.ts +0 -105
- package/renderer/lib/api-docs/codegen/definitions.ts +0 -297
- package/renderer/lib/api-docs/codegen/har.ts +0 -251
- package/renderer/lib/api-docs/codegen/index.ts +0 -159
- package/renderer/lib/api-docs/factories.ts +0 -170
- package/renderer/lib/api-docs/mobile-context.tsx +0 -112
- package/renderer/lib/api-docs/navigation-context.tsx +0 -88
- package/renderer/lib/api-docs/parsers/graphql/README.md +0 -129
- package/renderer/lib/api-docs/parsers/graphql/index.ts +0 -91
- package/renderer/lib/api-docs/parsers/graphql/parser.ts +0 -491
- package/renderer/lib/api-docs/parsers/graphql/transformer.ts +0 -246
- package/renderer/lib/api-docs/parsers/graphql/types.ts +0 -283
- package/renderer/lib/api-docs/parsers/openapi/README.md +0 -32
- package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +0 -60
- package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +0 -574
- package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +0 -403
- package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +0 -232
- package/renderer/lib/api-docs/parsers/openapi/index.ts +0 -171
- package/renderer/lib/api-docs/parsers/openapi/transformer.ts +0 -278
- package/renderer/lib/api-docs/parsers/openapi/validator.ts +0 -31
- package/renderer/lib/api-docs/playground/context.tsx +0 -107
- package/renderer/lib/api-docs/playground/navigation-context.tsx +0 -124
- package/renderer/lib/api-docs/playground/request-builder.ts +0 -223
- package/renderer/lib/api-docs/playground/request-runner.ts +0 -282
- package/renderer/lib/api-docs/playground/types.ts +0 -35
- package/renderer/lib/api-docs/types.ts +0 -269
- package/renderer/lib/api-docs/utils.ts +0 -311
- package/renderer/lib/cache.ts +0 -193
- package/renderer/lib/docs/config/domain-schema.ts +0 -260
- package/renderer/lib/docs/config/index.ts +0 -43
- package/renderer/lib/docs/config/loader.ts +0 -142
- package/renderer/lib/docs/config/schema.ts +0 -308
- package/renderer/lib/docs/index.ts +0 -12
- package/renderer/lib/docs/mdx/compiler.ts +0 -176
- package/renderer/lib/docs/mdx/frontmatter.ts +0 -91
- package/renderer/lib/docs/mdx/index.ts +0 -26
- package/renderer/lib/docs/navigation/generator.ts +0 -348
- package/renderer/lib/docs/navigation/index.ts +0 -12
- package/renderer/lib/docs/navigation/types.ts +0 -123
- package/renderer/lib/docs-navigation-context.tsx +0 -80
- package/renderer/lib/multi-tenant/context.ts +0 -105
- package/renderer/lib/storage/blob.ts +0 -1083
- package/renderer/lib/utils/icons.ts +0 -48
- package/renderer/lib/utils.ts +0 -6
- package/renderer/next.config.ts +0 -76
|
@@ -0,0 +1,1448 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState, useCallback, useRef, useMemo } from 'react';
|
|
4
|
+
import { Spinner } from '@phosphor-icons/react';
|
|
5
|
+
import { DocsSidebar } from './sidebar';
|
|
6
|
+
import { NotFoundPage } from './content/not-found-page';
|
|
7
|
+
import { ApiPlayground } from './playground';
|
|
8
|
+
import { RightSidebar } from './sidebar/right-sidebar';
|
|
9
|
+
import { RequestDetails } from './content/request-details';
|
|
10
|
+
import { DocPage } from './content/doc-page';
|
|
11
|
+
import { ChangelogPage } from './content/changelog-page';
|
|
12
|
+
import { GraphQLPlayground } from './playground/graphql-playground';
|
|
13
|
+
import { makeBrainfishCollection } from '@/lib/api-docs/factories';
|
|
14
|
+
import { buildSchema, isNonNullType, isListType } from 'graphql';
|
|
15
|
+
import { GlobalAuthModal } from './global-auth-modal';
|
|
16
|
+
import { AuthProvider } from '@/lib/api-docs/auth';
|
|
17
|
+
import { PlaygroundProvider, usePlaygroundPrefill } from '@/lib/api-docs/playground/context';
|
|
18
|
+
import { PlaygroundNavigationProvider, usePlaygroundNavigation } from '@/lib/api-docs/playground/navigation-context';
|
|
19
|
+
import { NavigationProvider } from '@/lib/api-docs/navigation-context';
|
|
20
|
+
import { ModeProvider, useModeContext } from '@/lib/api-docs/code-editor';
|
|
21
|
+
import { NotesMode } from './code-editor';
|
|
22
|
+
import { DocsHeader } from '@/components/docs-header';
|
|
23
|
+
import { Notice } from '../docs/notice';
|
|
24
|
+
import { DocsNavigationProvider } from '@/lib/docs-navigation-context';
|
|
25
|
+
import { Button } from '@/components/ui/button';
|
|
26
|
+
import { Code, TestTube, Book } from '@phosphor-icons/react';
|
|
27
|
+
import { cn } from '@/lib/utils';
|
|
28
|
+
import { SearchDialog, useSearch } from './search';
|
|
29
|
+
import { useTheme } from 'next-themes';
|
|
30
|
+
import { useRouteState } from '@/hooks/use-route-state';
|
|
31
|
+
import { navigateToPage, navigateToEndpoint, navigateToSection, navigateToTab } from '@/lib/docs-navigation';
|
|
32
|
+
import { useMobile } from '@/lib/api-docs/mobile-context';
|
|
33
|
+
import { AgentPopupButton } from './agent/agent-popup-button';
|
|
34
|
+
import { buildEndpointIndex } from '@/lib/api-docs/agent/indexer';
|
|
35
|
+
// Helper to convert GraphQL type to string representation
|
|
36
|
+
function graphqlTypeToString(type) {
|
|
37
|
+
if (isNonNullType(type)) {
|
|
38
|
+
return `${graphqlTypeToString(type.ofType)}!`;
|
|
39
|
+
}
|
|
40
|
+
if (isListType(type)) {
|
|
41
|
+
return `[${graphqlTypeToString(type.ofType)}]`;
|
|
42
|
+
}
|
|
43
|
+
// Named type
|
|
44
|
+
return type.name || 'Unknown';
|
|
45
|
+
}
|
|
46
|
+
// Parse GraphQL schema using buildSchema (for SDL)
|
|
47
|
+
function parseGraphQLSchema(schemaSDL) {
|
|
48
|
+
const operations = [];
|
|
49
|
+
try {
|
|
50
|
+
const schema = buildSchema(schemaSDL);
|
|
51
|
+
// Get root operation types
|
|
52
|
+
const rootTypes = [
|
|
53
|
+
{
|
|
54
|
+
type: schema.getQueryType(),
|
|
55
|
+
operationType: 'query'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: schema.getMutationType(),
|
|
59
|
+
operationType: 'mutation'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: schema.getSubscriptionType(),
|
|
63
|
+
operationType: 'subscription'
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
for (const { type: rootType, operationType } of rootTypes){
|
|
67
|
+
if (!rootType) continue;
|
|
68
|
+
const fields = rootType.getFields();
|
|
69
|
+
for (const [fieldName, field] of Object.entries(fields)){
|
|
70
|
+
// Skip internal fields
|
|
71
|
+
if (fieldName.startsWith('_')) continue;
|
|
72
|
+
const returnType = graphqlTypeToString(field.type);
|
|
73
|
+
const query = generateGraphQLQueryFromField(operationType, fieldName, field.args, returnType, schema);
|
|
74
|
+
const exampleVariables = generateGraphQLVariablesFromArgs(field.args, schema);
|
|
75
|
+
operations.push({
|
|
76
|
+
id: `${operationType}-${fieldName}`,
|
|
77
|
+
name: fieldName,
|
|
78
|
+
description: field.description || null,
|
|
79
|
+
operationType,
|
|
80
|
+
query,
|
|
81
|
+
exampleVariables
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error('[GraphQL Parser] Failed to parse schema:', err);
|
|
87
|
+
}
|
|
88
|
+
return operations;
|
|
89
|
+
}
|
|
90
|
+
// Get default fields for a type from schema
|
|
91
|
+
function getDefaultFieldsForType(typeName, schema) {
|
|
92
|
+
const type = schema.getType(typeName);
|
|
93
|
+
if (!type || !('getFields' in type)) return [];
|
|
94
|
+
const fields = type.getFields();
|
|
95
|
+
const fieldNames = Object.keys(fields);
|
|
96
|
+
// Priority order for default fields
|
|
97
|
+
const priorityFields = [
|
|
98
|
+
'code',
|
|
99
|
+
'id',
|
|
100
|
+
'name',
|
|
101
|
+
'title',
|
|
102
|
+
'slug'
|
|
103
|
+
];
|
|
104
|
+
const selectedFields = [];
|
|
105
|
+
// First, add priority fields if they exist
|
|
106
|
+
for (const pf of priorityFields){
|
|
107
|
+
if (fieldNames.includes(pf)) {
|
|
108
|
+
selectedFields.push(pf);
|
|
109
|
+
if (selectedFields.length >= 3) break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// If we don't have enough, add other scalar fields
|
|
113
|
+
if (selectedFields.length < 3) {
|
|
114
|
+
for (const [fname, fdef] of Object.entries(fields)){
|
|
115
|
+
if (selectedFields.includes(fname)) continue;
|
|
116
|
+
const ftype = graphqlTypeToString(fdef.type).replace(/[\[\]!]/g, '').trim();
|
|
117
|
+
if ([
|
|
118
|
+
'String',
|
|
119
|
+
'Int',
|
|
120
|
+
'Float',
|
|
121
|
+
'Boolean',
|
|
122
|
+
'ID'
|
|
123
|
+
].includes(ftype)) {
|
|
124
|
+
selectedFields.push(fname);
|
|
125
|
+
if (selectedFields.length >= 3) break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return selectedFields.length > 0 ? selectedFields : [
|
|
130
|
+
'__typename'
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
// Generate example GraphQL query from schema field
|
|
134
|
+
function generateGraphQLQueryFromField(operationType, name, args, returnType, schema) {
|
|
135
|
+
let query = `${operationType} ${name.charAt(0).toUpperCase() + name.slice(1)}`;
|
|
136
|
+
if (args.length > 0) {
|
|
137
|
+
const varDefs = args.map((arg)=>`$${arg.name}: ${graphqlTypeToString(arg.type)}`).join(', ');
|
|
138
|
+
query += `(${varDefs})`;
|
|
139
|
+
}
|
|
140
|
+
query += ` {\n ${name}`;
|
|
141
|
+
if (args.length > 0) {
|
|
142
|
+
const argPairs = args.map((arg)=>`${arg.name}: $${arg.name}`).join(', ');
|
|
143
|
+
query += `(${argPairs})`;
|
|
144
|
+
}
|
|
145
|
+
const baseType = returnType.replace(/[\[\]!]/g, '').trim();
|
|
146
|
+
if ([
|
|
147
|
+
'String',
|
|
148
|
+
'Int',
|
|
149
|
+
'Float',
|
|
150
|
+
'Boolean',
|
|
151
|
+
'ID'
|
|
152
|
+
].includes(baseType)) {
|
|
153
|
+
query += '\n}';
|
|
154
|
+
} else {
|
|
155
|
+
// Get actual fields from the schema for this type
|
|
156
|
+
const defaultFields = getDefaultFieldsForType(baseType, schema);
|
|
157
|
+
const fieldsStr = defaultFields.map((f)=>` ${f}`).join('\n');
|
|
158
|
+
query += ` {\n${fieldsStr}\n }\n}`;
|
|
159
|
+
}
|
|
160
|
+
return query;
|
|
161
|
+
}
|
|
162
|
+
// Generate example value for a GraphQL type
|
|
163
|
+
function generateExampleValue(type, schema, depth = 0) {
|
|
164
|
+
// Prevent infinite recursion
|
|
165
|
+
if (depth > 3) return null;
|
|
166
|
+
// Unwrap NonNull
|
|
167
|
+
if (isNonNullType(type)) {
|
|
168
|
+
return generateExampleValue(type.ofType, schema, depth);
|
|
169
|
+
}
|
|
170
|
+
// Handle List types - return array with one example element
|
|
171
|
+
if (isListType(type)) {
|
|
172
|
+
const itemValue = generateExampleValue(type.ofType, schema, depth);
|
|
173
|
+
return itemValue !== null ? [
|
|
174
|
+
itemValue
|
|
175
|
+
] : [];
|
|
176
|
+
}
|
|
177
|
+
// Get the named type
|
|
178
|
+
const typeName = type.name;
|
|
179
|
+
if (!typeName) return null;
|
|
180
|
+
// Built-in scalar types
|
|
181
|
+
switch(typeName){
|
|
182
|
+
case 'String':
|
|
183
|
+
return 'example';
|
|
184
|
+
case 'Int':
|
|
185
|
+
return 10;
|
|
186
|
+
case 'Float':
|
|
187
|
+
return 1.5;
|
|
188
|
+
case 'Boolean':
|
|
189
|
+
return true;
|
|
190
|
+
case 'ID':
|
|
191
|
+
return 'example-id';
|
|
192
|
+
// Common custom scalars
|
|
193
|
+
case 'DateTime':
|
|
194
|
+
return new Date().toISOString();
|
|
195
|
+
case 'Date':
|
|
196
|
+
return new Date().toISOString().split('T')[0];
|
|
197
|
+
case 'Time':
|
|
198
|
+
return '12:00:00';
|
|
199
|
+
case 'JSON':
|
|
200
|
+
return {};
|
|
201
|
+
case 'JSONObject':
|
|
202
|
+
return {};
|
|
203
|
+
case 'URL':
|
|
204
|
+
return 'https://example.com';
|
|
205
|
+
case 'URI':
|
|
206
|
+
return 'https://example.com';
|
|
207
|
+
case 'Email':
|
|
208
|
+
return 'user@example.com';
|
|
209
|
+
case 'EmailAddress':
|
|
210
|
+
return 'user@example.com';
|
|
211
|
+
case 'UUID':
|
|
212
|
+
return '550e8400-e29b-41d4-a716-446655440000';
|
|
213
|
+
case 'BigInt':
|
|
214
|
+
return '9007199254740991';
|
|
215
|
+
case 'Long':
|
|
216
|
+
return 9007199254740991;
|
|
217
|
+
}
|
|
218
|
+
// Check if it's an enum type
|
|
219
|
+
const schemaType = schema.getType(typeName);
|
|
220
|
+
if (schemaType && 'getValues' in schemaType) {
|
|
221
|
+
const enumType = schemaType;
|
|
222
|
+
const values = enumType.getValues();
|
|
223
|
+
if (values.length > 0) {
|
|
224
|
+
return values[0].name // Return first enum value
|
|
225
|
+
;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Check if it's an input object type
|
|
229
|
+
if (schemaType && 'getFields' in schemaType) {
|
|
230
|
+
const inputType = schemaType;
|
|
231
|
+
const fields = inputType.getFields();
|
|
232
|
+
const result = {};
|
|
233
|
+
// Only include required fields to keep examples concise
|
|
234
|
+
for (const [fieldName, field] of Object.entries(fields)){
|
|
235
|
+
if (isNonNullType(field.type)) {
|
|
236
|
+
// Use default value if available, otherwise generate
|
|
237
|
+
if (field.defaultValue !== undefined) {
|
|
238
|
+
result[fieldName] = field.defaultValue;
|
|
239
|
+
} else {
|
|
240
|
+
result[fieldName] = generateExampleValue(field.type, schema, depth + 1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// If no required fields, include first optional field
|
|
245
|
+
if (Object.keys(result).length === 0) {
|
|
246
|
+
const firstField = Object.entries(fields)[0];
|
|
247
|
+
if (firstField) {
|
|
248
|
+
const [fname, fdef] = firstField;
|
|
249
|
+
// Use default value if available
|
|
250
|
+
if (fdef.defaultValue !== undefined) {
|
|
251
|
+
result[fname] = fdef.defaultValue;
|
|
252
|
+
} else {
|
|
253
|
+
result[fname] = generateExampleValue(fdef.type, schema, depth + 1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
// Unknown type - return null
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
// Generate example variables from GraphQL arguments
|
|
263
|
+
function generateGraphQLVariablesFromArgs(args, schema) {
|
|
264
|
+
const variables = {};
|
|
265
|
+
for (const arg of args){
|
|
266
|
+
// First, check if the argument has a default value in the schema
|
|
267
|
+
if (arg.defaultValue !== undefined) {
|
|
268
|
+
variables[arg.name] = arg.defaultValue;
|
|
269
|
+
} else {
|
|
270
|
+
// Generate example value for arguments without defaults
|
|
271
|
+
const value = generateExampleValue(arg.type, schema, 0);
|
|
272
|
+
if (value !== null) {
|
|
273
|
+
variables[arg.name] = value;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return variables;
|
|
278
|
+
}
|
|
279
|
+
// Convert GraphQL operations to BrainfishCollection for sidebar
|
|
280
|
+
function convertGraphQLToCollection(operations, endpoint) {
|
|
281
|
+
const queries = operations.filter((op)=>op.operationType === 'query');
|
|
282
|
+
const mutations = operations.filter((op)=>op.operationType === 'mutation');
|
|
283
|
+
const subscriptions = operations.filter((op)=>op.operationType === 'subscription');
|
|
284
|
+
const toRequest = (op)=>({
|
|
285
|
+
id: op.id,
|
|
286
|
+
name: op.name,
|
|
287
|
+
description: op.description || '',
|
|
288
|
+
method: 'POST',
|
|
289
|
+
endpoint,
|
|
290
|
+
params: [],
|
|
291
|
+
headers: [],
|
|
292
|
+
auth: {
|
|
293
|
+
authType: 'none',
|
|
294
|
+
authActive: false
|
|
295
|
+
},
|
|
296
|
+
body: {
|
|
297
|
+
contentType: 'application/json',
|
|
298
|
+
body: JSON.stringify({
|
|
299
|
+
query: op.query,
|
|
300
|
+
variables: op.exampleVariables
|
|
301
|
+
}, null, 2)
|
|
302
|
+
},
|
|
303
|
+
requestVariables: [],
|
|
304
|
+
responses: {},
|
|
305
|
+
tags: [
|
|
306
|
+
op.operationType
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
const folders = [];
|
|
310
|
+
if (queries.length > 0) {
|
|
311
|
+
folders.push(makeBrainfishCollection({
|
|
312
|
+
name: 'Queries',
|
|
313
|
+
description: 'GraphQL Query operations',
|
|
314
|
+
requests: queries.map(toRequest),
|
|
315
|
+
folders: [],
|
|
316
|
+
variables: [],
|
|
317
|
+
auth: {
|
|
318
|
+
authType: 'none',
|
|
319
|
+
authActive: false
|
|
320
|
+
},
|
|
321
|
+
headers: []
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
if (mutations.length > 0) {
|
|
325
|
+
folders.push(makeBrainfishCollection({
|
|
326
|
+
name: 'Mutations',
|
|
327
|
+
description: 'GraphQL Mutation operations',
|
|
328
|
+
requests: mutations.map(toRequest),
|
|
329
|
+
folders: [],
|
|
330
|
+
variables: [],
|
|
331
|
+
auth: {
|
|
332
|
+
authType: 'none',
|
|
333
|
+
authActive: false
|
|
334
|
+
},
|
|
335
|
+
headers: []
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
if (subscriptions.length > 0) {
|
|
339
|
+
folders.push(makeBrainfishCollection({
|
|
340
|
+
name: 'Subscriptions',
|
|
341
|
+
description: 'GraphQL Subscription operations',
|
|
342
|
+
requests: subscriptions.map(toRequest),
|
|
343
|
+
folders: [],
|
|
344
|
+
variables: [],
|
|
345
|
+
auth: {
|
|
346
|
+
authType: 'none',
|
|
347
|
+
authActive: false
|
|
348
|
+
},
|
|
349
|
+
headers: []
|
|
350
|
+
}));
|
|
351
|
+
}
|
|
352
|
+
return makeBrainfishCollection({
|
|
353
|
+
name: 'GraphQL API',
|
|
354
|
+
description: 'GraphQL operations',
|
|
355
|
+
folders,
|
|
356
|
+
requests: [],
|
|
357
|
+
variables: [],
|
|
358
|
+
auth: {
|
|
359
|
+
authType: 'none',
|
|
360
|
+
authActive: false
|
|
361
|
+
},
|
|
362
|
+
headers: []
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// Helper to find request by ID in collection
|
|
366
|
+
function findRequestById(collection, id) {
|
|
367
|
+
// Check direct requests
|
|
368
|
+
const found = collection.requests.find((r)=>r.id === id);
|
|
369
|
+
if (found) return found;
|
|
370
|
+
// Check folders recursively
|
|
371
|
+
for (const folder of collection.folders){
|
|
372
|
+
const request = findRequestById(folder, id);
|
|
373
|
+
if (request) return request;
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
// Helper to get the first endpoint from collection
|
|
378
|
+
function getFirstEndpoint(collection) {
|
|
379
|
+
// Check direct requests first
|
|
380
|
+
if (collection.requests.length > 0) {
|
|
381
|
+
return collection.requests[0];
|
|
382
|
+
}
|
|
383
|
+
// Check folders recursively
|
|
384
|
+
for (const folder of collection.folders){
|
|
385
|
+
const firstInFolder = getFirstEndpoint(folder);
|
|
386
|
+
if (firstInFolder) return firstInFolder;
|
|
387
|
+
}
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
// Helper to check if a doc group belongs to a specific tab
|
|
391
|
+
// Group IDs are formatted as: group-{tab-id}-{group-name}
|
|
392
|
+
function isGroupForTab(groupId, tabId) {
|
|
393
|
+
// Check if the group ID starts with "group-{tabId}-"
|
|
394
|
+
const prefix = `group-${tabId}-`;
|
|
395
|
+
return groupId.startsWith(prefix);
|
|
396
|
+
}
|
|
397
|
+
// Helper to check if a tab has doc groups (MDX pages)
|
|
398
|
+
function hasDocGroupsForTab(docGroups, tabId) {
|
|
399
|
+
if (!docGroups || docGroups.length === 0) return false;
|
|
400
|
+
// Check if any doc group belongs to this tab and has pages
|
|
401
|
+
return docGroups.some((g)=>isGroupForTab(g.id, tabId) && g.pages.length > 0);
|
|
402
|
+
}
|
|
403
|
+
// Helper to get the first page from doc groups for a tab
|
|
404
|
+
function getFirstDocPageForTab(docGroups, tabId) {
|
|
405
|
+
if (!docGroups || docGroups.length === 0) return null;
|
|
406
|
+
const tabDocGroup = docGroups.find((g)=>isGroupForTab(g.id, tabId) && g.pages.length > 0);
|
|
407
|
+
return tabDocGroup?.pages[0]?.slug || null;
|
|
408
|
+
}
|
|
409
|
+
function DocsContent() {
|
|
410
|
+
const [collection, setCollection] = useState(null);
|
|
411
|
+
const [selectedApiVersion, setSelectedApiVersion] = useState(null);
|
|
412
|
+
const [loading, setLoading] = useState(true);
|
|
413
|
+
const [isVersionLoading, setIsVersionLoading] = useState(false) // For version switch only
|
|
414
|
+
;
|
|
415
|
+
const [error, setError] = useState(null);
|
|
416
|
+
const [showAuthModal, setShowAuthModal] = useState(false);
|
|
417
|
+
// URL-based route state - single source of truth for selection
|
|
418
|
+
const routeState = useRouteState();
|
|
419
|
+
// Derive active tab from URL (with default fallback)
|
|
420
|
+
const activeTab = routeState.tab || 'api-reference';
|
|
421
|
+
// Derive selected doc page from URL
|
|
422
|
+
const selectedDocPage = routeState.contentType === 'page' ? routeState.contentId : null;
|
|
423
|
+
// Derive selected doc section from URL
|
|
424
|
+
const selectedDocSection = routeState.contentType === 'section' ? routeState.contentId : null;
|
|
425
|
+
// Derive selected request from URL by looking up in collection
|
|
426
|
+
const selectedRequest = useMemo(()=>{
|
|
427
|
+
if (routeState.contentType !== 'endpoint' || !routeState.contentId || !collection) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
return findRequestById(collection, routeState.contentId);
|
|
431
|
+
}, [
|
|
432
|
+
routeState.contentType,
|
|
433
|
+
routeState.contentId,
|
|
434
|
+
collection
|
|
435
|
+
]);
|
|
436
|
+
// Derive not found slug from URL when endpoint doesn't exist
|
|
437
|
+
const notFoundSlug = useMemo(()=>{
|
|
438
|
+
if (routeState.contentType === 'endpoint' && routeState.contentId && collection) {
|
|
439
|
+
const request = findRequestById(collection, routeState.contentId);
|
|
440
|
+
if (!request) {
|
|
441
|
+
return `endpoint/${routeState.contentId}`;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return null;
|
|
445
|
+
}, [
|
|
446
|
+
routeState.contentType,
|
|
447
|
+
routeState.contentId,
|
|
448
|
+
collection
|
|
449
|
+
]);
|
|
450
|
+
// Prefill context for agent
|
|
451
|
+
const { setPrefill } = usePlaygroundPrefill();
|
|
452
|
+
// Playground navigation context for tab navigation
|
|
453
|
+
const { navigateAndHighlight, resetNavigation } = usePlaygroundNavigation();
|
|
454
|
+
// Mode context for switching modes
|
|
455
|
+
const { switchToDocs } = useModeContext();
|
|
456
|
+
// Ref for the scrollable content area
|
|
457
|
+
const contentRef = useRef(null);
|
|
458
|
+
// Track if initial navigation has been done (prevents re-navigation on effect re-runs)
|
|
459
|
+
const hasInitialNavigated = useRef(false);
|
|
460
|
+
// Handle selecting a request - just navigates to URL
|
|
461
|
+
const handleSelectRequest = useCallback((request)=>{
|
|
462
|
+
navigateToEndpoint(activeTab, request.id);
|
|
463
|
+
// Reset tab navigation so the new endpoint can determine its default tab
|
|
464
|
+
resetNavigation();
|
|
465
|
+
// Switch to Docs mode to show endpoint documentation first
|
|
466
|
+
switchToDocs();
|
|
467
|
+
}, [
|
|
468
|
+
activeTab,
|
|
469
|
+
resetNavigation,
|
|
470
|
+
switchToDocs
|
|
471
|
+
]);
|
|
472
|
+
// Handle selecting a documentation section (scroll to heading)
|
|
473
|
+
const handleSelectDocumentation = useCallback((headingId)=>{
|
|
474
|
+
const isIntro = headingId === 'introduction';
|
|
475
|
+
if (isIntro) {
|
|
476
|
+
// Scroll to top
|
|
477
|
+
navigateToTab(activeTab);
|
|
478
|
+
setTimeout(()=>{
|
|
479
|
+
contentRef.current?.scrollTo({
|
|
480
|
+
top: 0,
|
|
481
|
+
behavior: 'smooth'
|
|
482
|
+
});
|
|
483
|
+
}, 50);
|
|
484
|
+
} else {
|
|
485
|
+
// Navigate to section and scroll
|
|
486
|
+
navigateToSection(activeTab, headingId);
|
|
487
|
+
setTimeout(()=>{
|
|
488
|
+
const element = document.getElementById(headingId);
|
|
489
|
+
if (element) {
|
|
490
|
+
element.scrollIntoView({
|
|
491
|
+
behavior: 'smooth',
|
|
492
|
+
block: 'start'
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
}, 50);
|
|
496
|
+
}
|
|
497
|
+
// Switch to Docs mode when selecting documentation
|
|
498
|
+
switchToDocs();
|
|
499
|
+
}, [
|
|
500
|
+
activeTab,
|
|
501
|
+
switchToDocs
|
|
502
|
+
]);
|
|
503
|
+
// Handle selecting a doc page
|
|
504
|
+
const handleSelectDocPage = useCallback((slug)=>{
|
|
505
|
+
// Find which tab this doc page belongs to
|
|
506
|
+
let targetTab = activeTab;
|
|
507
|
+
let releaseSlug = null;
|
|
508
|
+
let sectionId = null;
|
|
509
|
+
// Parse section from slug (e.g., "essentials/markdown#headings" -> slug: "essentials/markdown", section: "headings")
|
|
510
|
+
let pageSlug = slug;
|
|
511
|
+
if (slug.includes('#')) {
|
|
512
|
+
const [pagePart, sectionPart] = slug.split('#');
|
|
513
|
+
pageSlug = pagePart;
|
|
514
|
+
sectionId = sectionPart;
|
|
515
|
+
}
|
|
516
|
+
// Special handling for changelog pages
|
|
517
|
+
if (pageSlug.startsWith('changelog/') || pageSlug === 'changelog') {
|
|
518
|
+
// Find the changelog tab
|
|
519
|
+
const changelogTab = collection?.navigationTabs?.find((t)=>t.type === 'changelog');
|
|
520
|
+
if (changelogTab) {
|
|
521
|
+
targetTab = changelogTab.id;
|
|
522
|
+
}
|
|
523
|
+
// Extract the release slug for scrolling (e.g., "changelog/v1.2.0" -> "v1.2.0")
|
|
524
|
+
if (pageSlug.startsWith('changelog/')) {
|
|
525
|
+
releaseSlug = pageSlug.replace('changelog/', '');
|
|
526
|
+
}
|
|
527
|
+
} else if (collection?.docGroups) {
|
|
528
|
+
for (const group of collection.docGroups){
|
|
529
|
+
const hasPage = (pages)=>{
|
|
530
|
+
for (const page of pages){
|
|
531
|
+
if (page.slug === pageSlug) return true;
|
|
532
|
+
if (page.children && hasPage(page.children)) return true;
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
};
|
|
536
|
+
if (hasPage(group.pages)) {
|
|
537
|
+
// Extract tab from group ID (e.g., "group-guides-getting-started" -> "guides")
|
|
538
|
+
const tabPart = group.id.replace('group-', '').split('-')[0];
|
|
539
|
+
// Find the actual tab ID that matches
|
|
540
|
+
const matchingTab = collection.navigationTabs?.find((t)=>t.id === tabPart || t.id.startsWith(tabPart));
|
|
541
|
+
if (matchingTab) {
|
|
542
|
+
targetTab = matchingTab.id;
|
|
543
|
+
}
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// Navigate to the page via URL
|
|
549
|
+
navigateToPage(targetTab, pageSlug);
|
|
550
|
+
switchToDocs();
|
|
551
|
+
// Scroll to specific release if navigating to a changelog entry
|
|
552
|
+
if (releaseSlug) {
|
|
553
|
+
// Wait for the changelog page to render, then scroll to the release
|
|
554
|
+
setTimeout(()=>{
|
|
555
|
+
const releaseElement = document.getElementById(`release-${releaseSlug}`);
|
|
556
|
+
if (releaseElement) {
|
|
557
|
+
releaseElement.scrollIntoView({
|
|
558
|
+
behavior: 'smooth',
|
|
559
|
+
block: 'start'
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}, 600);
|
|
563
|
+
} else if (sectionId) {
|
|
564
|
+
// Scroll to section within the page after it renders
|
|
565
|
+
setTimeout(()=>{
|
|
566
|
+
const sectionElement = document.getElementById(sectionId);
|
|
567
|
+
if (sectionElement) {
|
|
568
|
+
sectionElement.scrollIntoView({
|
|
569
|
+
behavior: 'smooth',
|
|
570
|
+
block: 'start'
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}, 300);
|
|
574
|
+
} else {
|
|
575
|
+
// Scroll to top of content when navigating to a new page
|
|
576
|
+
setTimeout(()=>{
|
|
577
|
+
contentRef.current?.scrollTo({
|
|
578
|
+
top: 0,
|
|
579
|
+
behavior: 'smooth'
|
|
580
|
+
});
|
|
581
|
+
}, 50);
|
|
582
|
+
}
|
|
583
|
+
}, [
|
|
584
|
+
switchToDocs,
|
|
585
|
+
collection,
|
|
586
|
+
activeTab
|
|
587
|
+
]);
|
|
588
|
+
// Handle API version change
|
|
589
|
+
const handleApiVersionChange = useCallback((version)=>{
|
|
590
|
+
if (version !== selectedApiVersion) {
|
|
591
|
+
setSelectedApiVersion(version);
|
|
592
|
+
// Navigate to tab only (clears selection) when switching versions
|
|
593
|
+
navigateToTab(activeTab);
|
|
594
|
+
}
|
|
595
|
+
}, [
|
|
596
|
+
selectedApiVersion,
|
|
597
|
+
activeTab
|
|
598
|
+
]);
|
|
599
|
+
// Handle tab change from header
|
|
600
|
+
const handleTabChange = useCallback((tabId)=>{
|
|
601
|
+
// Reset mode to docs when switching tabs (exit sandbox/api-client mode)
|
|
602
|
+
switchToDocs();
|
|
603
|
+
// Find the tab config to check its type
|
|
604
|
+
const tabConfig = collection?.navigationTabs?.find((t)=>t.id === tabId);
|
|
605
|
+
const isApiTab = tabConfig?.type === 'openapi' || tabConfig?.type === 'graphql' || tabId === 'api-reference';
|
|
606
|
+
if (tabId === 'changelog') {
|
|
607
|
+
// Switch to Changelog tab
|
|
608
|
+
navigateToTab(tabId);
|
|
609
|
+
} else if (isApiTab) {
|
|
610
|
+
// API Reference or GraphQL tab
|
|
611
|
+
// Check if there are doc groups for this tab (MDX pages)
|
|
612
|
+
const hasGroups = hasDocGroupsForTab(collection?.docGroups, tabId);
|
|
613
|
+
if (hasGroups) {
|
|
614
|
+
// Has doc groups - select the first page from groups
|
|
615
|
+
const firstPage = getFirstDocPageForTab(collection?.docGroups, tabId);
|
|
616
|
+
if (firstPage) {
|
|
617
|
+
navigateToPage(tabId, firstPage);
|
|
618
|
+
switchToDocs();
|
|
619
|
+
} else {
|
|
620
|
+
// No pages in groups - auto-select first endpoint
|
|
621
|
+
const firstEndpoint = collection ? getFirstEndpoint(collection) : null;
|
|
622
|
+
if (firstEndpoint) {
|
|
623
|
+
navigateToEndpoint(tabId, firstEndpoint.id);
|
|
624
|
+
} else {
|
|
625
|
+
navigateToTab(tabId);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
// No doc groups - auto-select first endpoint
|
|
630
|
+
const firstEndpoint = collection ? getFirstEndpoint(collection) : null;
|
|
631
|
+
if (firstEndpoint) {
|
|
632
|
+
navigateToEndpoint(tabId, firstEndpoint.id);
|
|
633
|
+
} else {
|
|
634
|
+
navigateToTab(tabId);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
// Switch to a doc group tab - find and select the first page in that tab
|
|
639
|
+
// Find the first doc group for this tab and select its first page
|
|
640
|
+
if (collection?.docGroups) {
|
|
641
|
+
const tabDocGroup = collection.docGroups.find((g)=>isGroupForTab(g.id, tabId));
|
|
642
|
+
if (tabDocGroup && tabDocGroup.pages.length > 0) {
|
|
643
|
+
const firstPage = tabDocGroup.pages[0];
|
|
644
|
+
navigateToPage(tabId, firstPage.slug);
|
|
645
|
+
switchToDocs();
|
|
646
|
+
} else {
|
|
647
|
+
navigateToTab(tabId);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}, [
|
|
652
|
+
collection,
|
|
653
|
+
switchToDocs
|
|
654
|
+
]);
|
|
655
|
+
// Handler for agent navigation
|
|
656
|
+
const handleAgentNavigate = useCallback((endpointId)=>{
|
|
657
|
+
if (!collection) return;
|
|
658
|
+
const request = findRequestById(collection, endpointId);
|
|
659
|
+
if (request) {
|
|
660
|
+
// Navigate to the endpoint in api-reference tab
|
|
661
|
+
navigateToEndpoint('api-reference', endpointId);
|
|
662
|
+
// Reset tab navigation so the new endpoint can determine its default tab
|
|
663
|
+
resetNavigation();
|
|
664
|
+
}
|
|
665
|
+
}, [
|
|
666
|
+
collection,
|
|
667
|
+
resetNavigation
|
|
668
|
+
]);
|
|
669
|
+
// Handler for agent prefilling parameters
|
|
670
|
+
const handleAgentPrefill = useCallback((data)=>{
|
|
671
|
+
console.log('[Agent] Prefill requested:', data);
|
|
672
|
+
setPrefill(data);
|
|
673
|
+
}, [
|
|
674
|
+
setPrefill
|
|
675
|
+
]);
|
|
676
|
+
// State for debug context - used to trigger agent debugging
|
|
677
|
+
const [debugContext, setDebugContext] = useState(null);
|
|
678
|
+
// Handler for debug requests from playground
|
|
679
|
+
const handleDebugRequest = useCallback((context)=>{
|
|
680
|
+
setDebugContext(context);
|
|
681
|
+
}, []);
|
|
682
|
+
// Clear debug context after it's been used
|
|
683
|
+
const clearDebugContext = useCallback(()=>{
|
|
684
|
+
setDebugContext(null);
|
|
685
|
+
}, []);
|
|
686
|
+
// State for explain context - used to trigger agent explanation
|
|
687
|
+
const [explainContext, setExplainContext] = useState(null);
|
|
688
|
+
// Handler for explain requests from playground
|
|
689
|
+
const handleExplainRequest = useCallback((context)=>{
|
|
690
|
+
setExplainContext(context);
|
|
691
|
+
}, []);
|
|
692
|
+
// Clear explain context after it's been used
|
|
693
|
+
const clearExplainContext = useCallback(()=>{
|
|
694
|
+
setExplainContext(null);
|
|
695
|
+
}, []);
|
|
696
|
+
// Note: Browser back/forward is now handled by useRouteState hook automatically
|
|
697
|
+
// Dynamically set favicon from docs.json config
|
|
698
|
+
useEffect(()=>{
|
|
699
|
+
if (!collection?.docsFavicon) return;
|
|
700
|
+
const faviconPath = collection.docsFavicon;
|
|
701
|
+
// Update or create link elements for favicon
|
|
702
|
+
const updateFaviconLink = (rel, href)=>{
|
|
703
|
+
let link = document.querySelector(`link[rel="${rel}"]`);
|
|
704
|
+
if (!link) {
|
|
705
|
+
link = document.createElement('link');
|
|
706
|
+
link.rel = rel;
|
|
707
|
+
document.head.appendChild(link);
|
|
708
|
+
}
|
|
709
|
+
link.href = href;
|
|
710
|
+
};
|
|
711
|
+
// Determine the type based on file extension
|
|
712
|
+
const ext = faviconPath.split('.').pop()?.toLowerCase();
|
|
713
|
+
const type = ext === 'svg' ? 'image/svg+xml' : ext === 'png' ? 'image/png' : ext === 'ico' ? 'image/x-icon' : 'image/png';
|
|
714
|
+
// Update the favicon link with type
|
|
715
|
+
let iconLink = document.querySelector('link[rel="icon"]');
|
|
716
|
+
if (!iconLink) {
|
|
717
|
+
iconLink = document.createElement('link');
|
|
718
|
+
iconLink.rel = 'icon';
|
|
719
|
+
document.head.appendChild(iconLink);
|
|
720
|
+
}
|
|
721
|
+
iconLink.type = type;
|
|
722
|
+
iconLink.href = faviconPath;
|
|
723
|
+
// Also update shortcut icon and apple-touch-icon
|
|
724
|
+
updateFaviconLink('shortcut icon', faviconPath);
|
|
725
|
+
updateFaviconLink('apple-touch-icon', faviconPath);
|
|
726
|
+
}, [
|
|
727
|
+
collection?.docsFavicon
|
|
728
|
+
]);
|
|
729
|
+
useEffect(()=>{
|
|
730
|
+
async function fetchCollection() {
|
|
731
|
+
try {
|
|
732
|
+
// Only show full loading on initial load
|
|
733
|
+
const isInitialLoad = !collection;
|
|
734
|
+
if (isInitialLoad) {
|
|
735
|
+
setLoading(true);
|
|
736
|
+
} else {
|
|
737
|
+
setIsVersionLoading(true);
|
|
738
|
+
}
|
|
739
|
+
setError(null);
|
|
740
|
+
// Build URL with version param if selected
|
|
741
|
+
const url = selectedApiVersion ? `/api/collections?version=${encodeURIComponent(selectedApiVersion)}` : '/api/collections';
|
|
742
|
+
const response = await fetch(url);
|
|
743
|
+
if (!response.ok) {
|
|
744
|
+
throw new Error(`Failed to fetch collection: ${response.status}`);
|
|
745
|
+
}
|
|
746
|
+
const data = await response.json();
|
|
747
|
+
setCollection(data);
|
|
748
|
+
// Set initial API version if not already set
|
|
749
|
+
if (!selectedApiVersion && data?.selectedApiVersion) {
|
|
750
|
+
setSelectedApiVersion(data.selectedApiVersion);
|
|
751
|
+
}
|
|
752
|
+
// Only run initial navigation logic on first load
|
|
753
|
+
if (isInitialLoad && !hasInitialNavigated.current) {
|
|
754
|
+
hasInitialNavigated.current = true;
|
|
755
|
+
// Helper: Navigate to first content for a given tab
|
|
756
|
+
const navigateToFirstContent = (tabId)=>{
|
|
757
|
+
const tabConfig = data.navigationTabs?.find((t)=>t.id === tabId);
|
|
758
|
+
const isApiTab = tabConfig?.type === 'openapi' || tabConfig?.type === 'graphql' || tabId === 'api-reference';
|
|
759
|
+
// Try doc pages first, then endpoints
|
|
760
|
+
const firstPage = isApiTab ? getFirstDocPageForTab(data.docGroups, tabId) : data.docGroups?.find((g)=>isGroupForTab(g.id, tabId))?.pages[0]?.slug;
|
|
761
|
+
if (firstPage) {
|
|
762
|
+
navigateToPage(tabId, firstPage);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
// Fall back to first endpoint for API tabs
|
|
766
|
+
if (isApiTab) {
|
|
767
|
+
const firstEndpoint = getFirstEndpoint(data);
|
|
768
|
+
if (firstEndpoint) {
|
|
769
|
+
navigateToEndpoint(tabId, firstEndpoint.id);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// No content found, just navigate to tab
|
|
774
|
+
navigateToTab(tabId);
|
|
775
|
+
};
|
|
776
|
+
// Get default tab (first tab in config)
|
|
777
|
+
let defaultTabId = 'api-reference';
|
|
778
|
+
if (data?.navigationTabs?.length > 0) {
|
|
779
|
+
const sortedTabs = [
|
|
780
|
+
...data.navigationTabs
|
|
781
|
+
].sort((a, b)=>a.order - b.order);
|
|
782
|
+
defaultTabId = sortedTabs[0].id;
|
|
783
|
+
}
|
|
784
|
+
// Handle initial navigation after collection loads
|
|
785
|
+
setTimeout(()=>{
|
|
786
|
+
const hash = window.location.hash.slice(1);
|
|
787
|
+
const isTabOnly = hash && !hash.includes('/');
|
|
788
|
+
if (!hash) {
|
|
789
|
+
// No hash - navigate to first content of default tab
|
|
790
|
+
navigateToFirstContent(defaultTabId);
|
|
791
|
+
} else if (isTabOnly) {
|
|
792
|
+
// Just a tab name (e.g., #guides) - navigate to first content
|
|
793
|
+
navigateToFirstContent(hash);
|
|
794
|
+
}
|
|
795
|
+
// View mode (docs/playground/notes) is derived from URL by ModeProvider
|
|
796
|
+
}, 0);
|
|
797
|
+
}
|
|
798
|
+
// Version changes are handled by handleApiVersionChange callback
|
|
799
|
+
} catch (err) {
|
|
800
|
+
console.error('Error fetching collection:', err);
|
|
801
|
+
setError(err instanceof Error ? err.message : 'Failed to load API documentation');
|
|
802
|
+
} finally{
|
|
803
|
+
setLoading(false);
|
|
804
|
+
setIsVersionLoading(false);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
fetchCollection();
|
|
808
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
809
|
+
}, [
|
|
810
|
+
selectedApiVersion
|
|
811
|
+
]);
|
|
812
|
+
// Only show full-page loading on initial load
|
|
813
|
+
if (loading && !collection) {
|
|
814
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
815
|
+
className: "flex items-center justify-center h-screen",
|
|
816
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
817
|
+
className: "text-center",
|
|
818
|
+
children: [
|
|
819
|
+
/*#__PURE__*/ _jsx(Spinner, {
|
|
820
|
+
size: 32,
|
|
821
|
+
className: "text-muted-foreground animate-spin mx-auto mb-3"
|
|
822
|
+
}),
|
|
823
|
+
/*#__PURE__*/ _jsx("p", {
|
|
824
|
+
className: "text-sm text-muted-foreground",
|
|
825
|
+
children: "Loading API documentation..."
|
|
826
|
+
})
|
|
827
|
+
]
|
|
828
|
+
})
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
if (error) {
|
|
832
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
833
|
+
className: "flex items-center justify-center h-screen",
|
|
834
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
835
|
+
className: "text-center",
|
|
836
|
+
children: [
|
|
837
|
+
/*#__PURE__*/ _jsx("p", {
|
|
838
|
+
className: "text-destructive text-lg mb-2",
|
|
839
|
+
children: "Error loading documentation"
|
|
840
|
+
}),
|
|
841
|
+
/*#__PURE__*/ _jsx("p", {
|
|
842
|
+
className: "text-muted-foreground",
|
|
843
|
+
children: error
|
|
844
|
+
})
|
|
845
|
+
]
|
|
846
|
+
})
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
if (!collection) {
|
|
850
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
851
|
+
className: "flex items-center justify-center h-screen",
|
|
852
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
853
|
+
className: "text-center max-w-md",
|
|
854
|
+
children: [
|
|
855
|
+
/*#__PURE__*/ _jsx("p", {
|
|
856
|
+
className: "text-muted-foreground mb-2",
|
|
857
|
+
children: "No API documentation available"
|
|
858
|
+
}),
|
|
859
|
+
/*#__PURE__*/ _jsx("p", {
|
|
860
|
+
className: "text-sm text-muted-foreground",
|
|
861
|
+
children: "Please configure your Brainfish API credentials in your environment variables."
|
|
862
|
+
})
|
|
863
|
+
]
|
|
864
|
+
})
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
// Only show "configure credentials" if there are no endpoints AND no doc groups
|
|
868
|
+
// Multi-tenant docs may have only doc groups without API endpoints
|
|
869
|
+
const hasDocGroups = collection.docGroups && collection.docGroups.length > 0;
|
|
870
|
+
const hasEndpoints = collection.requests.length > 0 || collection.folders.length > 0;
|
|
871
|
+
if (!hasEndpoints && !hasDocGroups) {
|
|
872
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
873
|
+
className: "flex items-center justify-center h-screen",
|
|
874
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
875
|
+
className: "text-center max-w-lg p-8",
|
|
876
|
+
children: [
|
|
877
|
+
/*#__PURE__*/ _jsx("h2", {
|
|
878
|
+
className: "text-2xl font-semibold mb-2",
|
|
879
|
+
children: collection.name || 'Documentation'
|
|
880
|
+
}),
|
|
881
|
+
/*#__PURE__*/ _jsx("p", {
|
|
882
|
+
className: "text-muted-foreground mb-6",
|
|
883
|
+
children: collection.description || 'No documentation content available yet.'
|
|
884
|
+
}),
|
|
885
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
886
|
+
className: "bg-muted/50 rounded-lg p-5 text-left text-sm space-y-4",
|
|
887
|
+
children: [
|
|
888
|
+
/*#__PURE__*/ _jsx("p", {
|
|
889
|
+
className: "font-medium",
|
|
890
|
+
children: "Get started with DevDoc:"
|
|
891
|
+
}),
|
|
892
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
893
|
+
className: "space-y-3",
|
|
894
|
+
children: [
|
|
895
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
896
|
+
children: [
|
|
897
|
+
/*#__PURE__*/ _jsx("p", {
|
|
898
|
+
className: "text-muted-foreground text-xs mb-1",
|
|
899
|
+
children: "Create a new project"
|
|
900
|
+
}),
|
|
901
|
+
/*#__PURE__*/ _jsx("code", {
|
|
902
|
+
className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
|
|
903
|
+
children: "npx create-devdoc-doc my-docs"
|
|
904
|
+
})
|
|
905
|
+
]
|
|
906
|
+
}),
|
|
907
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
908
|
+
children: [
|
|
909
|
+
/*#__PURE__*/ _jsx("p", {
|
|
910
|
+
className: "text-muted-foreground text-xs mb-1",
|
|
911
|
+
children: "Start local development"
|
|
912
|
+
}),
|
|
913
|
+
/*#__PURE__*/ _jsx("code", {
|
|
914
|
+
className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
|
|
915
|
+
children: "npx devdoc dev"
|
|
916
|
+
})
|
|
917
|
+
]
|
|
918
|
+
}),
|
|
919
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
920
|
+
children: [
|
|
921
|
+
/*#__PURE__*/ _jsx("p", {
|
|
922
|
+
className: "text-muted-foreground text-xs mb-1",
|
|
923
|
+
children: "Deploy to production"
|
|
924
|
+
}),
|
|
925
|
+
/*#__PURE__*/ _jsx("code", {
|
|
926
|
+
className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
|
|
927
|
+
children: "npx devdoc deploy"
|
|
928
|
+
})
|
|
929
|
+
]
|
|
930
|
+
})
|
|
931
|
+
]
|
|
932
|
+
}),
|
|
933
|
+
/*#__PURE__*/ _jsxs("a", {
|
|
934
|
+
href: "https://devdoc.sh",
|
|
935
|
+
target: "_blank",
|
|
936
|
+
rel: "noopener noreferrer",
|
|
937
|
+
className: "inline-flex items-center gap-1.5 text-primary hover:underline text-sm font-medium",
|
|
938
|
+
children: [
|
|
939
|
+
"Learn more at devdoc.sh",
|
|
940
|
+
/*#__PURE__*/ _jsx("svg", {
|
|
941
|
+
className: "h-3.5 w-3.5",
|
|
942
|
+
fill: "none",
|
|
943
|
+
viewBox: "0 0 24 24",
|
|
944
|
+
stroke: "currentColor",
|
|
945
|
+
strokeWidth: 2,
|
|
946
|
+
children: /*#__PURE__*/ _jsx("path", {
|
|
947
|
+
strokeLinecap: "round",
|
|
948
|
+
strokeLinejoin: "round",
|
|
949
|
+
d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
950
|
+
})
|
|
951
|
+
})
|
|
952
|
+
]
|
|
953
|
+
})
|
|
954
|
+
]
|
|
955
|
+
})
|
|
956
|
+
]
|
|
957
|
+
})
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return /*#__PURE__*/ _jsx(NavigationProvider, {
|
|
961
|
+
collection: collection,
|
|
962
|
+
onSelectRequest: handleSelectRequest,
|
|
963
|
+
children: /*#__PURE__*/ _jsx(DocsWithMode, {
|
|
964
|
+
collection: collection,
|
|
965
|
+
selectedRequest: selectedRequest,
|
|
966
|
+
selectedDocSection: selectedDocSection,
|
|
967
|
+
selectedDocPage: selectedDocPage,
|
|
968
|
+
activeTab: activeTab,
|
|
969
|
+
onTabChange: handleTabChange,
|
|
970
|
+
contentRef: contentRef,
|
|
971
|
+
showAuthModal: showAuthModal,
|
|
972
|
+
setShowAuthModal: setShowAuthModal,
|
|
973
|
+
handleSelectRequest: handleSelectRequest,
|
|
974
|
+
handleSelectDocumentation: handleSelectDocumentation,
|
|
975
|
+
handleSelectDocPage: handleSelectDocPage,
|
|
976
|
+
handleDebugRequest: handleDebugRequest,
|
|
977
|
+
handleExplainRequest: handleExplainRequest,
|
|
978
|
+
handleAgentNavigate: handleAgentNavigate,
|
|
979
|
+
handleAgentPrefill: handleAgentPrefill,
|
|
980
|
+
debugContext: debugContext,
|
|
981
|
+
clearDebugContext: clearDebugContext,
|
|
982
|
+
explainContext: explainContext,
|
|
983
|
+
clearExplainContext: clearExplainContext,
|
|
984
|
+
navigateAndHighlight: navigateAndHighlight,
|
|
985
|
+
selectedApiVersion: selectedApiVersion,
|
|
986
|
+
handleApiVersionChange: handleApiVersionChange,
|
|
987
|
+
isVersionLoading: isVersionLoading,
|
|
988
|
+
notFoundSlug: notFoundSlug
|
|
989
|
+
})
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
// Mode toggle tabs - switches between Docs, API Client, and Notes
|
|
993
|
+
function ModeToggleTabs({ hasEndpoint }) {
|
|
994
|
+
const { mode, switchToDocs, switchToApiClient, switchToNotes } = useModeContext();
|
|
995
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
996
|
+
className: "flex items-center gap-1 p-1 rounded-lg bg-muted/50 shrink-0",
|
|
997
|
+
children: [
|
|
998
|
+
/*#__PURE__*/ _jsxs(Button, {
|
|
999
|
+
variant: mode === 'docs' ? 'secondary' : 'ghost',
|
|
1000
|
+
size: "sm",
|
|
1001
|
+
onClick: ()=>switchToDocs(),
|
|
1002
|
+
className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'docs' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
|
|
1003
|
+
children: [
|
|
1004
|
+
/*#__PURE__*/ _jsx(Book, {
|
|
1005
|
+
className: "h-3.5 w-3.5",
|
|
1006
|
+
weight: "bold"
|
|
1007
|
+
}),
|
|
1008
|
+
/*#__PURE__*/ _jsx("span", {
|
|
1009
|
+
className: "hidden xs:inline",
|
|
1010
|
+
children: "Docs"
|
|
1011
|
+
})
|
|
1012
|
+
]
|
|
1013
|
+
}),
|
|
1014
|
+
hasEndpoint && /*#__PURE__*/ _jsxs(Button, {
|
|
1015
|
+
variant: mode === 'api_client' ? 'secondary' : 'ghost',
|
|
1016
|
+
size: "sm",
|
|
1017
|
+
onClick: ()=>switchToApiClient(),
|
|
1018
|
+
className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'api_client' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
|
|
1019
|
+
children: [
|
|
1020
|
+
/*#__PURE__*/ _jsx(TestTube, {
|
|
1021
|
+
className: "h-3.5 w-3.5",
|
|
1022
|
+
weight: "bold"
|
|
1023
|
+
}),
|
|
1024
|
+
/*#__PURE__*/ _jsx("span", {
|
|
1025
|
+
className: "hidden xs:inline",
|
|
1026
|
+
children: "API Client"
|
|
1027
|
+
})
|
|
1028
|
+
]
|
|
1029
|
+
}),
|
|
1030
|
+
/*#__PURE__*/ _jsxs(Button, {
|
|
1031
|
+
variant: mode === 'notes' ? 'secondary' : 'ghost',
|
|
1032
|
+
size: "sm",
|
|
1033
|
+
onClick: ()=>switchToNotes(),
|
|
1034
|
+
className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'notes' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
|
|
1035
|
+
children: [
|
|
1036
|
+
/*#__PURE__*/ _jsx(Code, {
|
|
1037
|
+
className: "h-3.5 w-3.5",
|
|
1038
|
+
weight: "bold"
|
|
1039
|
+
}),
|
|
1040
|
+
/*#__PURE__*/ _jsx("span", {
|
|
1041
|
+
className: "hidden xs:inline",
|
|
1042
|
+
children: "Sandbox"
|
|
1043
|
+
})
|
|
1044
|
+
]
|
|
1045
|
+
})
|
|
1046
|
+
]
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
function DocsWithMode({ collection, selectedRequest, selectedDocSection, selectedDocPage, activeTab, onTabChange, contentRef, showAuthModal, setShowAuthModal, handleSelectRequest, handleSelectDocumentation, handleSelectDocPage, handleDebugRequest, handleExplainRequest, handleAgentNavigate, handleAgentPrefill, debugContext, clearDebugContext, explainContext, clearExplainContext, navigateAndHighlight, selectedApiVersion, handleApiVersionChange, isVersionLoading, notFoundSlug }) {
|
|
1050
|
+
const { mode, switchToDocs } = useModeContext();
|
|
1051
|
+
const { setTheme } = useTheme();
|
|
1052
|
+
// Agent panel state - controls popup button and push animation
|
|
1053
|
+
const { isRightSidebarOpen, openRightSidebar } = useMobile();
|
|
1054
|
+
// Build endpoint index for suggestions (memoized)
|
|
1055
|
+
const endpointIndex = useMemo(()=>buildEndpointIndex(collection), [
|
|
1056
|
+
collection
|
|
1057
|
+
]);
|
|
1058
|
+
// GraphQL state
|
|
1059
|
+
const [graphqlOperations, setGraphqlOperations] = useState([]);
|
|
1060
|
+
const [graphqlCollection, setGraphqlCollection] = useState(null);
|
|
1061
|
+
const [graphqlSchemaSDL, setGraphqlSchemaSDL] = useState(undefined);
|
|
1062
|
+
// Use route state for URL-based selection
|
|
1063
|
+
const routeState = useRouteState();
|
|
1064
|
+
// Derive selected GraphQL operation from URL
|
|
1065
|
+
const selectedGraphQLOperation = useMemo(()=>{
|
|
1066
|
+
if (routeState.contentType !== 'endpoint' || !routeState.contentId) {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
return graphqlOperations.find((op)=>op.id === routeState.contentId) || null;
|
|
1070
|
+
}, [
|
|
1071
|
+
routeState.contentType,
|
|
1072
|
+
routeState.contentId,
|
|
1073
|
+
graphqlOperations
|
|
1074
|
+
]);
|
|
1075
|
+
// Get API spec URL from environment or collection
|
|
1076
|
+
const apiSpecUrl = process.env.NEXT_PUBLIC_OPENAPI_URL || collection.name || 'default';
|
|
1077
|
+
// Check if there are endpoints
|
|
1078
|
+
const hasEndpoints = collection.folders.length > 0 || collection.requests.length > 0;
|
|
1079
|
+
// Search functionality
|
|
1080
|
+
const { isOpen: searchOpen, setIsOpen: setSearchOpen, openSearch, searchItems } = useSearch({
|
|
1081
|
+
requests: collection.requests,
|
|
1082
|
+
folders: collection.folders,
|
|
1083
|
+
docGroups: collection.docGroups
|
|
1084
|
+
});
|
|
1085
|
+
// Handle search item selection - use URL hash navigation
|
|
1086
|
+
const handleSearchSelect = useCallback((item)=>{
|
|
1087
|
+
if (item.type === 'endpoint') {
|
|
1088
|
+
// Navigate to endpoint via hash - format: #api-reference/endpoint/{id}
|
|
1089
|
+
window.location.hash = `api-reference/endpoint/${item.id}`;
|
|
1090
|
+
} else if (item.type === 'doc') {
|
|
1091
|
+
// Navigate to doc page via hash - the href already has the correct format
|
|
1092
|
+
// Extract tab and path from href (e.g., #guides/page/quickstart)
|
|
1093
|
+
const hashPath = item.href.replace('#', '');
|
|
1094
|
+
window.location.hash = hashPath;
|
|
1095
|
+
}
|
|
1096
|
+
}, []);
|
|
1097
|
+
// Wrap agent navigate to switch to Docs mode and navigate to endpoint
|
|
1098
|
+
const handleAgentNavigateWithModeSwitch = useCallback((endpointId)=>{
|
|
1099
|
+
// handleAgentNavigate navigates via URL
|
|
1100
|
+
handleAgentNavigate(endpointId);
|
|
1101
|
+
}, [
|
|
1102
|
+
handleAgentNavigate
|
|
1103
|
+
]);
|
|
1104
|
+
// Get the current content title for header
|
|
1105
|
+
// Find the active tab's config
|
|
1106
|
+
const activeTabConfig = collection.navigationTabs?.find((t)=>t.id === activeTab);
|
|
1107
|
+
const activeTabType = activeTabConfig?.type || 'docs';
|
|
1108
|
+
// Filter doc groups for sidebar based on active tab
|
|
1109
|
+
// Group IDs are like "group-guides-getting-started", tab IDs are like "guides"
|
|
1110
|
+
// Filter doc groups for sidebar based on active tab
|
|
1111
|
+
// Group IDs are formatted as: group-{tab-id}-{group-name}
|
|
1112
|
+
const filteredDocGroups = collection.docGroups?.filter((g)=>isGroupForTab(g.id, activeTab)) || [];
|
|
1113
|
+
// Show endpoints in sidebar only when OpenAPI tab is active
|
|
1114
|
+
const showEndpoints = activeTabType === 'openapi';
|
|
1115
|
+
// Show changelog when changelog tab is active
|
|
1116
|
+
const showChangelog = activeTabType === 'changelog';
|
|
1117
|
+
// Show GraphQL playground when graphql tab is active
|
|
1118
|
+
const showGraphQL = activeTabType === 'graphql';
|
|
1119
|
+
const activeGraphQLSchemas = activeTabConfig?.graphqlSchemas || [];
|
|
1120
|
+
// Get the first schema path for stable dependency
|
|
1121
|
+
const schemaPath = activeGraphQLSchemas[0]?.schema;
|
|
1122
|
+
const schemaEndpoint = activeGraphQLSchemas[0]?.endpoint;
|
|
1123
|
+
// Load GraphQL operations when graphql tab is active
|
|
1124
|
+
useEffect(()=>{
|
|
1125
|
+
if (!showGraphQL || !schemaPath) {
|
|
1126
|
+
setGraphqlOperations([]);
|
|
1127
|
+
setGraphqlCollection(null);
|
|
1128
|
+
setGraphqlSchemaSDL(undefined);
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
// Load and parse GraphQL schema
|
|
1132
|
+
const loadGraphQLSchema = async ()=>{
|
|
1133
|
+
try {
|
|
1134
|
+
console.log('[DocsViewer] Loading GraphQL schema from:', schemaPath);
|
|
1135
|
+
const response = await fetch(`/api/schema?path=${encodeURIComponent(schemaPath)}`);
|
|
1136
|
+
if (!response.ok) {
|
|
1137
|
+
console.error('[DocsViewer] Failed to fetch schema:', response.status);
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
const schemaContent = await response.text();
|
|
1141
|
+
console.log('[DocsViewer] Schema loaded, length:', schemaContent.length);
|
|
1142
|
+
setGraphqlSchemaSDL(schemaContent); // Store schema SDL for autocomplete
|
|
1143
|
+
const operations = parseGraphQLSchema(schemaContent);
|
|
1144
|
+
console.log('[DocsViewer] Parsed operations:', operations.length);
|
|
1145
|
+
setGraphqlOperations(operations);
|
|
1146
|
+
// Convert to BrainfishCollection for sidebar
|
|
1147
|
+
const gqlCollection = convertGraphQLToCollection(operations, schemaEndpoint || '');
|
|
1148
|
+
setGraphqlCollection(gqlCollection);
|
|
1149
|
+
} catch (err) {
|
|
1150
|
+
console.error('[DocsViewer] Failed to load GraphQL schema:', err);
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
loadGraphQLSchema();
|
|
1154
|
+
}, [
|
|
1155
|
+
showGraphQL,
|
|
1156
|
+
schemaPath,
|
|
1157
|
+
schemaEndpoint
|
|
1158
|
+
]);
|
|
1159
|
+
// Auto-navigate to first GraphQL operation when none selected and no doc pages
|
|
1160
|
+
useEffect(()=>{
|
|
1161
|
+
if (!showGraphQL || graphqlOperations.length === 0) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
// If there's already content selected (page or endpoint), don't auto-navigate
|
|
1165
|
+
if (routeState.contentType) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
// Check if there are doc groups for this tab
|
|
1169
|
+
const hasGroups = hasDocGroupsForTab(collection?.docGroups, activeTab);
|
|
1170
|
+
if (!hasGroups) {
|
|
1171
|
+
// No doc groups - auto-navigate to first GraphQL operation
|
|
1172
|
+
const firstOperation = graphqlOperations[0];
|
|
1173
|
+
navigateToEndpoint(activeTab, firstOperation.id);
|
|
1174
|
+
}
|
|
1175
|
+
}, [
|
|
1176
|
+
showGraphQL,
|
|
1177
|
+
graphqlOperations,
|
|
1178
|
+
activeTab,
|
|
1179
|
+
collection?.docGroups,
|
|
1180
|
+
routeState.contentType
|
|
1181
|
+
]);
|
|
1182
|
+
// Handle GraphQL operation selection from sidebar - just navigates via URL
|
|
1183
|
+
const handleSelectGraphQLOperation = useCallback((request)=>{
|
|
1184
|
+
navigateToEndpoint(activeTab, request.id);
|
|
1185
|
+
switchToDocs();
|
|
1186
|
+
}, [
|
|
1187
|
+
activeTab,
|
|
1188
|
+
switchToDocs
|
|
1189
|
+
]);
|
|
1190
|
+
// Inject custom CSS and color variables
|
|
1191
|
+
useEffect(()=>{
|
|
1192
|
+
// Create or update style element for custom CSS
|
|
1193
|
+
let styleEl = document.getElementById('docs-custom-css');
|
|
1194
|
+
if (!styleEl) {
|
|
1195
|
+
styleEl = document.createElement('style');
|
|
1196
|
+
styleEl.id = 'docs-custom-css';
|
|
1197
|
+
document.head.appendChild(styleEl);
|
|
1198
|
+
}
|
|
1199
|
+
// Build CSS with color variables
|
|
1200
|
+
let cssContent = '';
|
|
1201
|
+
// Add color variables if provided
|
|
1202
|
+
// We set both --docs-primary (for custom CSS) and --primary (for Tailwind's bg-primary class)
|
|
1203
|
+
if (collection.docsColors) {
|
|
1204
|
+
const colors = collection.docsColors;
|
|
1205
|
+
cssContent += `:root {\n`;
|
|
1206
|
+
if (colors.primary) {
|
|
1207
|
+
cssContent += ` --docs-primary: ${colors.primary};\n`;
|
|
1208
|
+
cssContent += ` --primary: ${colors.primary};\n`;
|
|
1209
|
+
}
|
|
1210
|
+
if (colors.primaryLight) cssContent += ` --docs-primary-light: ${colors.primaryLight};\n`;
|
|
1211
|
+
if (colors.primaryDark) cssContent += ` --docs-primary-dark: ${colors.primaryDark};\n`;
|
|
1212
|
+
cssContent += `}\n`;
|
|
1213
|
+
// Also set for dark mode
|
|
1214
|
+
cssContent += `.dark {\n`;
|
|
1215
|
+
if (colors.primary) cssContent += ` --primary: ${colors.primary};\n`;
|
|
1216
|
+
cssContent += `}\n\n`;
|
|
1217
|
+
}
|
|
1218
|
+
// Add custom CSS if provided
|
|
1219
|
+
if (collection.customCss) {
|
|
1220
|
+
cssContent += collection.customCss;
|
|
1221
|
+
}
|
|
1222
|
+
styleEl.textContent = cssContent;
|
|
1223
|
+
return ()=>{
|
|
1224
|
+
// Cleanup on unmount
|
|
1225
|
+
const el = document.getElementById('docs-custom-css');
|
|
1226
|
+
if (el) el.remove();
|
|
1227
|
+
};
|
|
1228
|
+
}, [
|
|
1229
|
+
collection.customCss,
|
|
1230
|
+
collection.docsColors
|
|
1231
|
+
]);
|
|
1232
|
+
// Apply default theme from theme.json on initial load
|
|
1233
|
+
// Use a ref to track if we've already applied the default theme
|
|
1234
|
+
const hasAppliedDefaultTheme = useRef(false);
|
|
1235
|
+
useEffect(()=>{
|
|
1236
|
+
if (collection?.defaultTheme && !hasAppliedDefaultTheme.current) {
|
|
1237
|
+
setTheme(collection.defaultTheme);
|
|
1238
|
+
hasAppliedDefaultTheme.current = true;
|
|
1239
|
+
}
|
|
1240
|
+
}, [
|
|
1241
|
+
collection?.defaultTheme,
|
|
1242
|
+
setTheme
|
|
1243
|
+
]);
|
|
1244
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
1245
|
+
className: "docs-viewer-root flex flex-col h-screen overflow-hidden",
|
|
1246
|
+
children: [
|
|
1247
|
+
collection.notice && /*#__PURE__*/ _jsx(Notice, {
|
|
1248
|
+
config: collection.notice,
|
|
1249
|
+
storageKey: "docs-notice"
|
|
1250
|
+
}),
|
|
1251
|
+
/*#__PURE__*/ _jsx(SearchDialog, {
|
|
1252
|
+
open: searchOpen,
|
|
1253
|
+
onOpenChange: setSearchOpen,
|
|
1254
|
+
items: searchItems,
|
|
1255
|
+
onSelect: handleSearchSelect
|
|
1256
|
+
}),
|
|
1257
|
+
/*#__PURE__*/ _jsx(DocsHeader, {
|
|
1258
|
+
docGroups: collection.docGroups,
|
|
1259
|
+
navigationTabs: collection.navigationTabs,
|
|
1260
|
+
activeTab: activeTab,
|
|
1261
|
+
onTabChange: onTabChange,
|
|
1262
|
+
hasEndpoints: hasEndpoints,
|
|
1263
|
+
docsName: collection.docsName,
|
|
1264
|
+
docsLogo: collection.docsLogo,
|
|
1265
|
+
onSearchClick: openSearch,
|
|
1266
|
+
docsHeader: collection.docsHeader,
|
|
1267
|
+
docsNavbar: collection.docsNavbar
|
|
1268
|
+
}),
|
|
1269
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
1270
|
+
className: cn("docs-layout flex flex-1 overflow-hidden relative z-0 min-h-0", "transition-[margin] duration-300 ease-in-out", // Push content left when agent panel is open (only on larger screens)
|
|
1271
|
+
isRightSidebarOpen && "lg:mr-96"),
|
|
1272
|
+
children: [
|
|
1273
|
+
!showChangelog && /*#__PURE__*/ _jsx(DocsSidebar, {
|
|
1274
|
+
collection: {
|
|
1275
|
+
...collection,
|
|
1276
|
+
// Show GraphQL operations when GraphQL tab is active, else show REST endpoints
|
|
1277
|
+
folders: showGraphQL && graphqlCollection ? graphqlCollection.folders : showEndpoints ? collection.folders : [],
|
|
1278
|
+
requests: showGraphQL && graphqlCollection ? graphqlCollection.requests : showEndpoints ? collection.requests : [],
|
|
1279
|
+
// Only show filtered doc groups
|
|
1280
|
+
docGroups: filteredDocGroups
|
|
1281
|
+
},
|
|
1282
|
+
selectedRequest: showGraphQL ? selectedGraphQLOperation ? {
|
|
1283
|
+
id: selectedGraphQLOperation.id
|
|
1284
|
+
} : null : selectedRequest,
|
|
1285
|
+
selectedDocSection: selectedDocSection,
|
|
1286
|
+
selectedDocPage: selectedDocPage,
|
|
1287
|
+
activeTab: activeTab,
|
|
1288
|
+
onSelectRequest: showGraphQL ? handleSelectGraphQLOperation : handleSelectRequest,
|
|
1289
|
+
onSelectDocumentation: handleSelectDocumentation,
|
|
1290
|
+
onSelectDocPage: handleSelectDocPage,
|
|
1291
|
+
apiVersions: collection.apiVersions,
|
|
1292
|
+
selectedApiVersion: selectedApiVersion,
|
|
1293
|
+
onApiVersionChange: handleApiVersionChange,
|
|
1294
|
+
isVersionLoading: isVersionLoading
|
|
1295
|
+
}),
|
|
1296
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
1297
|
+
className: "docs-main flex-1 flex flex-col overflow-hidden",
|
|
1298
|
+
style: {
|
|
1299
|
+
minWidth: 0,
|
|
1300
|
+
flexBasis: 0,
|
|
1301
|
+
flexGrow: 1
|
|
1302
|
+
},
|
|
1303
|
+
children: [
|
|
1304
|
+
/*#__PURE__*/ _jsx("div", {
|
|
1305
|
+
className: "docs-main-header flex items-center justify-end px-3 sm:px-4 h-[41px] border-b border-border bg-muted/30 flex-shrink-0",
|
|
1306
|
+
children: /*#__PURE__*/ _jsx(ModeToggleTabs, {
|
|
1307
|
+
hasEndpoint: !!selectedRequest
|
|
1308
|
+
})
|
|
1309
|
+
}),
|
|
1310
|
+
mode === 'docs' ? /*#__PURE__*/ _jsx(DocsNavigationProvider, {
|
|
1311
|
+
onNavigateToPage: handleSelectDocPage,
|
|
1312
|
+
onSwitchTab: onTabChange,
|
|
1313
|
+
activeTab: activeTab,
|
|
1314
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
1315
|
+
ref: contentRef,
|
|
1316
|
+
className: cn("docs-content-area flex-1 bg-background min-w-0", showChangelog || showGraphQL && selectedGraphQLOperation && !selectedDocPage ? "overflow-hidden flex flex-col" : "overflow-y-auto scroll-smooth"),
|
|
1317
|
+
children: showGraphQL && selectedGraphQLOperation && !selectedDocPage ? /*#__PURE__*/ _jsx("div", {
|
|
1318
|
+
className: "flex-1 flex flex-col h-full",
|
|
1319
|
+
children: /*#__PURE__*/ _jsx(GraphQLPlayground, {
|
|
1320
|
+
endpoint: activeGraphQLSchemas[0]?.endpoint || '',
|
|
1321
|
+
defaultQuery: selectedGraphQLOperation?.query,
|
|
1322
|
+
operations: graphqlOperations,
|
|
1323
|
+
selectedOperationId: selectedGraphQLOperation?.id,
|
|
1324
|
+
hideExplorer: true,
|
|
1325
|
+
headers: {},
|
|
1326
|
+
theme: "dark",
|
|
1327
|
+
schemaSDL: graphqlSchemaSDL
|
|
1328
|
+
})
|
|
1329
|
+
}) : showChangelog ? /*#__PURE__*/ _jsx(ChangelogPage, {
|
|
1330
|
+
releases: collection.changelogReleases || [],
|
|
1331
|
+
tabName: activeTabConfig?.tab
|
|
1332
|
+
}) : selectedRequest ? /*#__PURE__*/ _jsx(RequestDetails, {
|
|
1333
|
+
request: selectedRequest
|
|
1334
|
+
}) : selectedDocPage ? /*#__PURE__*/ _jsx(DocPage, {
|
|
1335
|
+
slug: selectedDocPage,
|
|
1336
|
+
onSearch: openSearch
|
|
1337
|
+
}) : notFoundSlug ? /*#__PURE__*/ _jsx(NotFoundPage, {
|
|
1338
|
+
slug: notFoundSlug,
|
|
1339
|
+
onSearch: openSearch
|
|
1340
|
+
}) : /*#__PURE__*/ _jsx("div", {
|
|
1341
|
+
className: "flex-1 flex items-center justify-center bg-background",
|
|
1342
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
1343
|
+
className: "text-center text-muted-foreground",
|
|
1344
|
+
children: [
|
|
1345
|
+
/*#__PURE__*/ _jsx(Book, {
|
|
1346
|
+
className: "h-12 w-12 mx-auto mb-3 opacity-40"
|
|
1347
|
+
}),
|
|
1348
|
+
/*#__PURE__*/ _jsx("p", {
|
|
1349
|
+
className: "text-sm",
|
|
1350
|
+
children: "Select an endpoint from the sidebar"
|
|
1351
|
+
})
|
|
1352
|
+
]
|
|
1353
|
+
})
|
|
1354
|
+
})
|
|
1355
|
+
})
|
|
1356
|
+
}) : mode === 'notes' ? /*#__PURE__*/ _jsx("div", {
|
|
1357
|
+
className: "flex-1 flex flex-col min-h-0 overflow-hidden",
|
|
1358
|
+
children: /*#__PURE__*/ _jsx(NotesMode, {
|
|
1359
|
+
apiSpecUrl: apiSpecUrl,
|
|
1360
|
+
apiName: collection.name
|
|
1361
|
+
})
|
|
1362
|
+
}) : selectedRequest ? /*#__PURE__*/ _jsx("div", {
|
|
1363
|
+
className: "flex-1 flex flex-col min-h-0 overflow-hidden",
|
|
1364
|
+
children: /*#__PURE__*/ _jsx(ApiPlayground, {
|
|
1365
|
+
request: selectedRequest,
|
|
1366
|
+
onDebugRequest: handleDebugRequest,
|
|
1367
|
+
onExplainRequest: handleExplainRequest
|
|
1368
|
+
})
|
|
1369
|
+
}) : /*#__PURE__*/ _jsx("div", {
|
|
1370
|
+
className: "flex-1 flex items-center justify-center bg-background",
|
|
1371
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
1372
|
+
className: "text-center text-muted-foreground",
|
|
1373
|
+
children: [
|
|
1374
|
+
/*#__PURE__*/ _jsx(TestTube, {
|
|
1375
|
+
className: "h-12 w-12 mx-auto mb-3 opacity-40"
|
|
1376
|
+
}),
|
|
1377
|
+
/*#__PURE__*/ _jsx("p", {
|
|
1378
|
+
className: "text-sm",
|
|
1379
|
+
children: "Select an endpoint from the sidebar to test"
|
|
1380
|
+
})
|
|
1381
|
+
]
|
|
1382
|
+
})
|
|
1383
|
+
})
|
|
1384
|
+
]
|
|
1385
|
+
}),
|
|
1386
|
+
/*#__PURE__*/ _jsx(RightSidebar, {
|
|
1387
|
+
request: selectedRequest,
|
|
1388
|
+
collection: collection,
|
|
1389
|
+
apiSummary: collection.apiSummary,
|
|
1390
|
+
onNavigateToEndpoint: handleAgentNavigateWithModeSwitch,
|
|
1391
|
+
onPrefillParameters: handleAgentPrefill,
|
|
1392
|
+
debugContext: debugContext,
|
|
1393
|
+
onClearDebugContext: clearDebugContext,
|
|
1394
|
+
explainContext: explainContext,
|
|
1395
|
+
onClearExplainContext: clearExplainContext,
|
|
1396
|
+
onOpenGlobalAuth: ()=>setShowAuthModal(true),
|
|
1397
|
+
onNavigateToAuthTab: ()=>{
|
|
1398
|
+
navigateAndHighlight('auth', {
|
|
1399
|
+
type: 'auth'
|
|
1400
|
+
}, true);
|
|
1401
|
+
},
|
|
1402
|
+
onNavigateToParamsTab: ()=>{
|
|
1403
|
+
navigateAndHighlight('params', {
|
|
1404
|
+
type: 'param'
|
|
1405
|
+
}, true);
|
|
1406
|
+
},
|
|
1407
|
+
onNavigateToBodyTab: ()=>{
|
|
1408
|
+
navigateAndHighlight('body', {
|
|
1409
|
+
type: 'body'
|
|
1410
|
+
}, true);
|
|
1411
|
+
},
|
|
1412
|
+
onNavigateToHeadersTab: ()=>{
|
|
1413
|
+
navigateAndHighlight('headers', {
|
|
1414
|
+
type: 'header'
|
|
1415
|
+
}, true);
|
|
1416
|
+
},
|
|
1417
|
+
onNavigateToDocSection: handleSelectDocumentation,
|
|
1418
|
+
onNavigateToDocPage: handleSelectDocPage
|
|
1419
|
+
})
|
|
1420
|
+
]
|
|
1421
|
+
}),
|
|
1422
|
+
/*#__PURE__*/ _jsx(GlobalAuthModal, {
|
|
1423
|
+
open: showAuthModal,
|
|
1424
|
+
onClose: ()=>setShowAuthModal(false)
|
|
1425
|
+
}),
|
|
1426
|
+
!isRightSidebarOpen && /*#__PURE__*/ _jsx(AgentPopupButton, {
|
|
1427
|
+
onClick: openRightSidebar,
|
|
1428
|
+
currentEndpoint: selectedRequest ? {
|
|
1429
|
+
id: selectedRequest.id,
|
|
1430
|
+
name: selectedRequest.name
|
|
1431
|
+
} : null,
|
|
1432
|
+
endpointIndex: endpointIndex
|
|
1433
|
+
})
|
|
1434
|
+
]
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1437
|
+
// Wrapper component with providers
|
|
1438
|
+
export function Docs() {
|
|
1439
|
+
return /*#__PURE__*/ _jsx(AuthProvider, {
|
|
1440
|
+
children: /*#__PURE__*/ _jsx(ModeProvider, {
|
|
1441
|
+
children: /*#__PURE__*/ _jsx(PlaygroundProvider, {
|
|
1442
|
+
children: /*#__PURE__*/ _jsx(PlaygroundNavigationProvider, {
|
|
1443
|
+
children: /*#__PURE__*/ _jsx(DocsContent, {})
|
|
1444
|
+
})
|
|
1445
|
+
})
|
|
1446
|
+
})
|
|
1447
|
+
});
|
|
1448
|
+
}
|