insforge 1.3.0 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/auth/package.json +5 -3
  3. package/auth/src/lib/broadcastService.ts +115 -117
  4. package/auth/src/lib/insforge.ts +8 -0
  5. package/auth/src/main.tsx +2 -4
  6. package/auth/src/pages/SignInPage.tsx +60 -60
  7. package/auth/src/pages/SignUpPage.tsx +60 -60
  8. package/auth/src/pages/VerifyEmailPage.tsx +18 -0
  9. package/auth/tsconfig.json +2 -1
  10. package/backend/package.json +10 -6
  11. package/backend/src/api/middlewares/rate-limiters.ts +127 -127
  12. package/backend/src/api/routes/ai/index.routes.ts +475 -468
  13. package/backend/src/api/routes/auth/index.routes.ts +85 -32
  14. package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
  15. package/backend/src/api/routes/database/index.routes.ts +2 -0
  16. package/backend/src/api/routes/database/records.routes.ts +39 -175
  17. package/backend/src/api/routes/database/rpc.routes.ts +69 -0
  18. package/backend/src/api/routes/deployments/index.routes.ts +192 -0
  19. package/backend/src/api/routes/docs/index.routes.ts +3 -2
  20. package/backend/src/api/routes/email/index.routes.ts +35 -35
  21. package/backend/src/api/routes/functions/index.routes.ts +3 -3
  22. package/backend/src/api/routes/metadata/index.routes.ts +26 -0
  23. package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
  24. package/backend/src/infra/database/database.manager.ts +0 -10
  25. package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
  26. package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
  27. package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
  28. package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
  29. package/backend/src/infra/security/token.manager.ts +1 -4
  30. package/backend/src/providers/ai/openrouter.provider.ts +12 -3
  31. package/backend/src/providers/database/base.provider.ts +39 -0
  32. package/backend/src/providers/database/cloud.provider.ts +159 -0
  33. package/backend/src/providers/deployments/vercel.provider.ts +516 -0
  34. package/backend/src/server.ts +19 -7
  35. package/backend/src/services/ai/ai-config.service.ts +6 -6
  36. package/backend/src/services/ai/ai-model.service.ts +60 -60
  37. package/backend/src/services/ai/ai-usage.service.ts +7 -7
  38. package/backend/src/services/ai/chat-completion.service.ts +415 -220
  39. package/backend/src/services/ai/helpers.ts +64 -64
  40. package/backend/src/services/ai/index.ts +13 -13
  41. package/backend/src/services/auth/auth-config.service.ts +4 -4
  42. package/backend/src/services/auth/auth-otp.service.ts +6 -6
  43. package/backend/src/services/auth/auth.service.ts +134 -74
  44. package/backend/src/services/auth/index.ts +4 -4
  45. package/backend/src/services/auth/oauth-config.service.ts +12 -12
  46. package/backend/src/services/database/database-advance.service.ts +19 -55
  47. package/backend/src/services/database/database-table.service.ts +38 -85
  48. package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
  49. package/backend/src/services/deployments/deployment.service.ts +693 -0
  50. package/backend/src/services/functions/function.service.ts +61 -41
  51. package/backend/src/services/logs/audit.service.ts +10 -10
  52. package/backend/src/services/secrets/secret.service.ts +101 -27
  53. package/backend/src/services/storage/storage.service.ts +30 -30
  54. package/backend/src/services/usage/usage.service.ts +6 -6
  55. package/backend/src/types/ai.ts +8 -0
  56. package/backend/src/types/auth.ts +5 -1
  57. package/backend/src/types/database.ts +2 -0
  58. package/backend/src/types/deployments.ts +33 -0
  59. package/backend/src/types/storage.ts +1 -1
  60. package/backend/src/types/webhooks.ts +45 -0
  61. package/backend/src/utils/cookies.ts +34 -35
  62. package/backend/src/utils/environment.ts +0 -14
  63. package/backend/src/utils/s3-config-loader.ts +64 -64
  64. package/backend/src/utils/seed.ts +334 -301
  65. package/backend/src/utils/sql-parser.ts +126 -0
  66. package/backend/src/utils/utils.ts +114 -114
  67. package/backend/src/utils/validations.ts +10 -10
  68. package/backend/tests/local/test-rpc.sh +141 -0
  69. package/backend/tests/local/test-secrets.sh +1 -1
  70. package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
  71. package/backend/tests/manual/test-rawsql-modes.sh +24 -24
  72. package/backend/tests/unit/database-advance.test.ts +326 -0
  73. package/backend/tests/unit/helpers.test.ts +2 -2
  74. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
  75. package/docker-compose.prod.yml +1 -1
  76. package/docker-compose.yml +1 -1
  77. package/docs/agent-docs/deployment.md +79 -0
  78. package/docs/changelog.mdx +165 -72
  79. package/docs/core-concepts/ai/architecture.mdx +1 -23
  80. package/docs/core-concepts/ai/sdk.mdx +26 -1
  81. package/docs/core-concepts/authentication/architecture.mdx +6 -8
  82. package/docs/core-concepts/authentication/sdk.mdx +387 -91
  83. package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
  84. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
  85. package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
  86. package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
  87. package/docs/core-concepts/database/architecture.mdx +58 -21
  88. package/docs/core-concepts/database/pgvector.mdx +138 -0
  89. package/docs/core-concepts/database/sdk.mdx +17 -17
  90. package/docs/core-concepts/deployments/architecture.mdx +152 -0
  91. package/docs/core-concepts/email/architecture.mdx +4 -2
  92. package/docs/core-concepts/functions/architecture.mdx +1 -1
  93. package/docs/core-concepts/functions/sdk.mdx +0 -1
  94. package/docs/core-concepts/realtime/architecture.mdx +1 -1
  95. package/docs/core-concepts/storage/architecture.mdx +1 -1
  96. package/docs/core-concepts/storage/sdk.mdx +25 -25
  97. package/docs/docs.json +14 -6
  98. package/docs/favicon.png +0 -0
  99. package/docs/favicon.svg +3 -18
  100. package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
  101. package/docs/images/changelog/dec-2025/moreModels.png +0 -0
  102. package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
  103. package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
  104. package/docs/images/changelog/dec-2025/realtime2.png +0 -0
  105. package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
  106. package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
  107. package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
  108. package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
  109. package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
  110. package/docs/images/mcp-setup/claude-code-connect.png +0 -0
  111. package/docs/images/mcp-setup/cline-1.png +0 -0
  112. package/docs/images/mcp-setup/cline-2.png +0 -0
  113. package/docs/images/mcp-setup/cline-3.png +0 -0
  114. package/docs/images/mcp-setup/connect-project.png +0 -0
  115. package/docs/images/mcp-setup/copilot-1.png +0 -0
  116. package/docs/images/mcp-setup/copilot-2.png +0 -0
  117. package/docs/images/mcp-setup/copilot-3.png +0 -0
  118. package/docs/images/mcp-setup/mcp-json-1.png +0 -0
  119. package/docs/images/mcp-setup/mcp-json-2.png +0 -0
  120. package/docs/images/mcp-setup/qoder-1.png +0 -0
  121. package/docs/images/mcp-setup/qoder-2.png +0 -0
  122. package/docs/images/mcp-setup/roocode-1.png +0 -0
  123. package/docs/images/mcp-setup/roocode-2.png +0 -0
  124. package/docs/images/mcp-setup/trae-1.png +0 -0
  125. package/docs/images/mcp-setup/trae-2.png +0 -0
  126. package/docs/images/mcp-setup/trae-3.png +0 -0
  127. package/docs/images/mcp-setup/trae-4.png +0 -0
  128. package/docs/images/mcp-setup/trae-5.png +0 -0
  129. package/docs/images/mcp-setup/windsurf-1.png +0 -0
  130. package/docs/images/mcp-setup/windsurf-2.png +0 -0
  131. package/docs/insforge-instructions-sdk.md +7 -3
  132. package/docs/introduction.mdx +9 -8
  133. package/docs/mcp-setup.mdx +332 -0
  134. package/docs/oauth-server.mdx +563 -0
  135. package/docs/partnership.mdx +79 -10
  136. package/docs/quickstart.mdx +1 -1
  137. package/docs/vscode-extension.mdx +74 -0
  138. package/eslint.config.js +1 -0
  139. package/examples/response-examples.md +1 -1
  140. package/frontend/package.json +1 -1
  141. package/frontend/src/App.tsx +8 -3
  142. package/frontend/src/assets/logos/antigravity.svg +1 -0
  143. package/frontend/src/assets/logos/copilot.svg +10 -0
  144. package/frontend/src/assets/logos/deepseek.svg +139 -0
  145. package/frontend/src/assets/logos/kiro.svg +9 -0
  146. package/frontend/src/assets/logos/qoder.svg +4 -0
  147. package/frontend/src/assets/logos/qwen.svg +15 -0
  148. package/frontend/src/components/CodeBlock.tsx +2 -2
  149. package/frontend/src/components/ConnectCTA.tsx +3 -2
  150. package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
  151. package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
  152. package/frontend/src/components/datagrid/index.ts +1 -1
  153. package/frontend/src/components/index.ts +0 -1
  154. package/frontend/src/components/layout/AppHeader.tsx +4 -27
  155. package/frontend/src/components/layout/AppSidebar.tsx +85 -100
  156. package/frontend/src/components/layout/Layout.tsx +34 -32
  157. package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
  158. package/frontend/src/components/radix/Select.tsx +151 -151
  159. package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
  160. package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
  161. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
  162. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
  163. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
  164. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
  165. package/frontend/src/features/ai/components/index.ts +6 -6
  166. package/frontend/src/features/ai/helpers.ts +147 -141
  167. package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
  168. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
  169. package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
  170. package/frontend/src/features/auth/components/index.ts +5 -5
  171. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
  172. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
  173. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
  174. package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
  175. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
  176. package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
  177. package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
  178. package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
  179. package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
  180. package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
  181. package/frontend/src/features/database/constants.ts +16 -28
  182. package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
  183. package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
  184. package/frontend/src/features/database/hooks/useTables.ts +5 -7
  185. package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
  186. package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
  187. package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
  188. package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
  189. package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
  190. package/frontend/src/features/database/services/advance.service.ts +1 -15
  191. package/frontend/src/features/database/services/record.service.ts +4 -20
  192. package/frontend/src/features/database/services/table.service.ts +1 -4
  193. package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
  194. package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
  195. package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
  196. package/frontend/src/features/database/templates/notion-clone.ts +8 -8
  197. package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
  198. package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
  199. package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
  200. package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
  201. package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
  202. package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
  203. package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
  204. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
  205. package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
  206. package/frontend/src/features/functions/components/index.ts +5 -5
  207. package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
  208. package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
  209. package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
  210. package/frontend/src/features/functions/services/function.service.ts +8 -25
  211. package/frontend/src/features/functions/services/secret.service.ts +23 -41
  212. package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
  213. package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
  214. package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
  215. package/frontend/src/features/logs/components/index.ts +1 -0
  216. package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
  217. package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
  218. package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
  219. package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
  220. package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
  221. package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
  222. package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
  223. package/frontend/src/features/onboard/components/index.ts +9 -4
  224. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
  225. package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
  226. package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
  227. package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
  228. package/frontend/src/features/onboard/index.ts +17 -13
  229. package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
  230. package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
  231. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
  232. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
  233. package/frontend/src/index.css +249 -249
  234. package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
  235. package/frontend/src/lib/hooks/useMetadata.ts +45 -1
  236. package/frontend/src/lib/hooks/useModal.tsx +2 -0
  237. package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
  238. package/frontend/src/lib/services/metadata.service.ts +20 -3
  239. package/frontend/src/lib/utils/menuItems.ts +223 -207
  240. package/frontend/src/lib/utils/utils.ts +196 -196
  241. package/functions/server.ts +315 -315
  242. package/functions/worker-template.js +1 -1
  243. package/openapi/ai.yaml +115 -5
  244. package/openapi/auth.yaml +97 -17
  245. package/openapi/logs.yaml +0 -2
  246. package/openapi/metadata.yaml +0 -2
  247. package/openapi/records.yaml +21 -21
  248. package/openapi/tables.yaml +1 -2
  249. package/package.json +1 -1
  250. package/shared-schemas/package.json +1 -1
  251. package/shared-schemas/src/ai-api.schema.ts +251 -143
  252. package/shared-schemas/src/ai.schema.ts +63 -63
  253. package/shared-schemas/src/auth-api.schema.ts +34 -6
  254. package/shared-schemas/src/auth.schema.ts +17 -10
  255. package/shared-schemas/src/cloud-events.schema.ts +26 -0
  256. package/shared-schemas/src/deployments-api.schema.ts +55 -0
  257. package/shared-schemas/src/deployments.schema.ts +30 -0
  258. package/shared-schemas/src/docs.schema.ts +8 -2
  259. package/shared-schemas/src/email-api.schema.ts +30 -30
  260. package/shared-schemas/src/functions-api.schema.ts +13 -4
  261. package/shared-schemas/src/functions.schema.ts +1 -1
  262. package/shared-schemas/src/index.ts +22 -18
  263. package/shared-schemas/src/metadata.schema.ts +30 -4
  264. package/shared-schemas/src/secrets-api.schema.ts +44 -0
  265. package/shared-schemas/src/secrets.schema.ts +15 -0
  266. package/zeabur/README.md +13 -0
  267. package/zeabur/template.yml +20 -51
  268. package/backend/src/types/profile.ts +0 -55
  269. package/frontend/src/components/ProjectInfoModal.tsx +0 -128
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 360 360">
2
+ <path d="M0 0 C8.45956306 4.64859349 17.03492587 9.05737965 25.62646484 13.45507812 C35.94064308 18.73615638 46.20021508 24.08574219 56.33837891 29.70019531 C60.93127679 32.23740806 65.54938733 34.70010478 70.22802734 37.07617188 C71.25460449 37.59977295 72.28118164 38.12337402 73.33886719 38.6628418 C75.28471386 39.6507789 77.23519308 40.62967567 79.19140625 41.59692383 C94.44801591 49.35763099 107.18372609 61.63167743 113.12646484 77.95507812 C116.37052962 89.18293866 117.71418243 99.67618473 117.64404297 111.35375977 C117.64948321 112.90977629 117.65661637 114.46578765 117.6652832 116.02178955 C117.68328039 120.18867483 117.67655226 124.3551573 117.66376686 128.52204823 C117.6535313 132.90781064 117.66305996 137.29354205 117.66931152 141.67930603 C117.67655065 149.02967437 117.66709186 156.37988092 117.64794922 163.73022461 C117.62611449 172.21191498 117.63329451 180.69322163 117.65525484 189.17490298 C117.67342881 196.48914394 117.67595961 203.80326975 117.66550016 211.11752599 C117.65928555 215.4726465 117.65837483 219.82758668 117.67164612 224.18269539 C117.68323589 228.26977101 117.67512247 232.35635219 117.65206909 236.44337463 C117.64680176 237.93808612 117.64826182 239.43283958 117.65711975 240.9275341 C117.70487235 249.80634667 117.67385394 257.18676325 111.19677734 263.97851562 C105.01838896 268.27113085 99.84578784 270.81278068 92.12646484 269.95507812 C86.24835492 268.12378936 80.6307852 265.70302465 75.09130859 263.02929688 C74.08487305 262.54505249 74.08487305 262.54505249 73.05810547 262.05102539 C71.74995505 261.41408682 70.44755 260.76518081 69.15185547 260.10327148 C65.80562878 258.43539968 65.80562878 258.43539968 62.14990234 258.02539062 C58.98189922 259.48095963 55.89766732 261.08162886 52.81396484 262.70507812 C31.66683754 273.53145894 7.879152 279.1734137 -15.56103516 273.27929688 C-29.96427589 268.53072845 -43.522752 260.21129735 -56.74584961 252.91015625 C-65.20658318 248.26292717 -73.78166356 243.85297279 -82.37353516 239.45507812 C-92.73494986 234.14969763 -103.04383106 228.77807901 -113.22827148 223.13745117 C-117.61487591 220.7121832 -122.02051548 218.3523125 -126.49462891 216.09179688 C-144.92851472 206.77069867 -159.53107706 196.26073344 -166.87353516 175.95507812 C-170.40841014 164.57563629 -171.48687341 154.13568281 -171.43994141 142.28710938 C-171.44520066 140.6339229 -171.45148534 138.98073941 -171.45872498 137.32756042 C-171.46904174 133.88611597 -171.46469852 130.44508715 -171.44995117 127.00366211 C-171.43622844 123.52149836 -171.44307898 120.04043199 -171.47045898 116.55834961 C-171.66845678 91.32396442 -170.57684979 68.85551921 -158.87353516 45.95507812 C-158.5707666 45.35646973 -158.26799805 44.75786133 -157.95605469 44.14111328 C-144.25891835 17.53719946 -120.61497607 -5.27853503 -91.90478516 -14.73242188 C-55.45872058 -26.15124702 -32.49958176 -17.93650795 0 0 Z M-26.49462891 75.57226562 C-41.50953513 91.36017014 -51.56466723 110.88445494 -56.87353516 131.95507812 C-57.04812256 132.64343246 -57.22270996 133.3317868 -57.40258789 134.04100037 C-59.03902872 141.26298246 -59.13145209 148.23786406 -59.06884766 155.61914062 C-59.06601776 156.89236176 -59.06318787 158.16558289 -59.06027222 159.47738647 C-59.05103501 162.82781835 -59.03313308 166.17796649 -59.01086426 169.52832031 C-58.99023766 172.96091285 -58.98123492 176.39353495 -58.97119141 179.82617188 C-58.94923605 186.53588423 -58.91583775 193.24546484 -58.87353516 199.95507812 C-33.50750049 190.25188654 -15.7042659 163.60234245 -4.87353516 139.95507812 C3.47576167 120.30197406 3.52446533 100.92569279 3.31396484 79.95507812 C3.298888 77.33008582 3.28520492 74.70508512 3.27294922 72.08007812 C3.24018836 65.70489233 3.19022781 59.33002534 3.12646484 52.95507812 C-6.49426422 52.95507812 -20.09393042 69.18110618 -26.49462891 75.57226562 Z " fill="#FEFEFE" transform="translate(206.87353515625,51.044921875)"/>
3
+ <path d="M0 0 C13.58332159 12.63939585 21.35936472 28.62481997 22.67781067 47.21190071 C22.8179475 51.32768651 22.84699493 55.42601099 22.82226562 59.54321289 C22.82770586 61.09922942 22.83483903 62.65524078 22.84350586 64.21124268 C22.86150305 68.37812796 22.85477492 72.54461042 22.84198952 76.71150136 C22.83175396 81.09726377 22.84128262 85.48299518 22.84753418 89.86875916 C22.85477331 97.21912749 22.84531452 104.56933405 22.82617188 111.91967773 C22.80433715 120.4013681 22.81151717 128.88267475 22.8334775 137.3643561 C22.85165147 144.67859706 22.85418227 151.99272287 22.84372282 159.30697912 C22.83750821 163.66209963 22.83659748 168.0170398 22.84986877 172.37214851 C22.86145854 176.45922413 22.85334512 180.54580532 22.83029175 184.63282776 C22.82502441 186.12753925 22.82648448 187.6222927 22.83534241 189.11698723 C22.88309501 197.99579979 22.85207659 205.37621637 16.375 212.16796875 C10.19661162 216.46058397 5.0240105 219.00223381 -2.6953125 218.14453125 C-8.57342243 216.31324248 -14.19099214 213.89247777 -19.73046875 211.21875 C-20.40142578 210.89592041 -21.07238281 210.57309082 -21.76367188 210.24047852 C-23.07182229 209.60353995 -24.37422735 208.95463393 -25.66992188 208.29272461 C-29.01614857 206.62485281 -29.01614857 206.62485281 -32.671875 206.21484375 C-35.83987812 207.67041275 -38.92411003 209.27108198 -42.0078125 210.89453125 C-63.01039551 221.64691186 -87.56497118 227.88521904 -110.8046875 221.2578125 C-113.49120846 220.31901443 -116.08930499 219.2864896 -118.6953125 218.14453125 C-119.82259766 217.66306641 -119.82259766 217.66306641 -120.97265625 217.171875 C-125.42618753 215.12341648 -128.35985945 212.80539436 -131.6953125 209.14453125 C-132.36304688 208.54125 -133.03078125 207.93796875 -133.71875 207.31640625 C-146.4627668 195.57277302 -152.27949535 180.00393496 -154.6953125 163.14453125 C-154.89640625 161.86707031 -155.0975 160.58960938 -155.3046875 159.2734375 C-155.64241733 155.53830638 -155.71660927 152.75835057 -154.6953125 149.14453125 C-151.18119184 145.5774339 -147.07344088 143.50518479 -142.6953125 141.14453125 C-117.17173915 123.13239991 -99.71251874 95.06912469 -93.71525574 64.52392578 C-91.64212663 52.40094394 -92.11339648 39.90290772 -92.0078125 27.64453125 C-91.97614793 24.97131057 -91.94008514 22.29817127 -91.90429688 19.625 C-91.82007902 13.13161606 -91.75145039 6.63821553 -91.6953125 0.14453125 C-83.75330252 -4.01067896 -76.05029871 -7.80216897 -67.3828125 -10.23046875 C-66.56748047 -10.47667969 -65.75214844 -10.72289063 -64.91210938 -10.9765625 C-43.36343574 -17.25087797 -17.42754833 -15.00550887 0 0 Z " fill="#2ADB5C" transform="translate(301.6953125,102.85546875)"/>
4
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M174.82 108.75L155.38 75L165.64 57.75C166.46 56.31 166.46 54.53 165.64 53.09L155.38 35.84C154.86 34.91 153.87 34.33 152.78 34.33H114.88L106.14 19.03C105.62 18.1 104.63 17.52 103.54 17.52H83.3C82.21 17.52 81.22 18.1 80.7 19.03L61.26 52.77H41.02C39.93 52.77 38.94 53.35 38.42 54.28L28.16 71.53C27.34 72.97 27.34 74.75 28.16 76.19L45.52 107.5L36.78 122.8C35.96 124.24 35.96 126.02 36.78 127.46L47.04 144.71C47.56 145.64 48.55 146.22 49.64 146.22H87.54L96.28 161.52C96.8 162.45 97.79 163.03 98.88 163.03H119.12C120.21 163.03 121.2 162.45 121.72 161.52L141.16 127.78H158.52C159.61 127.78 160.6 127.2 161.12 126.27L171.38 109.02C172.2 107.58 172.2 105.8 171.38 104.36L174.82 108.75Z" fill="url(#paint0_radial)"/>
3
+ <path d="M119.12 163.03H98.88L87.54 144.71H49.64L61.26 126.39H80.7L38.42 55.29H61.26L83.3 19.03L93.56 37.35L83.3 55.29H161.58L151.32 72.54L170.76 106.28H151.32L141.16 88.34L101.18 163.03H119.12Z" fill="white"/>
4
+ <path d="M127.86 79.83H76.14L101.18 122.11L127.86 79.83Z" fill="url(#paint1_radial)"/>
5
+ <defs>
6
+ <radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(100 100) rotate(90) scale(100)">
7
+ <stop stop-color="#665CEE"/>
8
+ <stop offset="1" stop-color="#332E91"/>
9
+ </radialGradient>
10
+ <radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(100 100) rotate(90) scale(100)">
11
+ <stop stop-color="#665CEE"/>
12
+ <stop offset="1" stop-color="#332E91"/>
13
+ </radialGradient>
14
+ </defs>
15
+ </svg>
@@ -36,8 +36,8 @@ export function CodeBlock({
36
36
  {/* Header row with label and copy button */}
37
37
  <div className="flex items-center justify-between mb-2">
38
38
  {label && (
39
- <div className="bg-white dark:bg-neutral-700 rounded px-2 shrink-0">
40
- <span className="text-gray-900 dark:text-neutral-50 text-xs">{label}</span>
39
+ <div className="bg-white dark:bg-neutral-700 rounded px-2 shrink-0 h-5 flex items-center">
40
+ <span className="text-gray-900 dark:text-neutral-50 text-xs leading-5">{label}</span>
41
41
  </div>
42
42
  )}
43
43
  {showCopy && (
@@ -1,7 +1,7 @@
1
1
  import { useNavigate } from 'react-router-dom';
2
2
  import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
3
3
  import { isInsForgeCloudProject } from '@/lib/utils/utils';
4
- import { postMessageToParent } from '@/lib/utils/cloudMessaging';
4
+ import { useModal } from '@/lib/hooks/useModal';
5
5
 
6
6
  interface ConnectCTAProps {
7
7
  className?: string;
@@ -11,6 +11,7 @@ interface ConnectCTAProps {
11
11
  export function ConnectCTA({ className, fallback }: ConnectCTAProps) {
12
12
  const navigate = useNavigate();
13
13
  const { hasCompletedOnboarding } = useMcpUsage();
14
+ const { setOnboardingModalOpen } = useModal();
14
15
 
15
16
  if (hasCompletedOnboarding) {
16
17
  return fallback;
@@ -18,7 +19,7 @@ export function ConnectCTA({ className, fallback }: ConnectCTAProps) {
18
19
 
19
20
  const handleConnect = () => {
20
21
  if (isInsForgeCloudProject()) {
21
- postMessageToParent({ type: 'SHOW_ONBOARDING_OVERLAY' });
22
+ setOnboardingModalOpen(true);
22
23
  } else {
23
24
  void navigate('/dashboard/onboard');
24
25
  }
@@ -16,6 +16,14 @@ import { useTheme } from '@/lib/contexts/ThemeContext';
16
16
  import type { DataGridColumn, DataGridRow, DataGridRowType } from './datagridTypes';
17
17
  import SortableHeaderRenderer from './SortableHeader';
18
18
 
19
+ // Custom selection cell renderer props
20
+ export interface SelectionCellProps<TRow extends DataGridRowType = DataGridRow> {
21
+ row: TRow;
22
+ isSelected: boolean;
23
+ onToggle: (checked: boolean) => void;
24
+ tabIndex: number;
25
+ }
26
+
19
27
  // Generic DataGrid props
20
28
  export interface DataGridProps<TRow extends DataGridRowType = DataGridRow> {
21
29
  data: TRow[];
@@ -40,6 +48,10 @@ export interface DataGridProps<TRow extends DataGridRowType = DataGridRow> {
40
48
  showPagination?: boolean;
41
49
  showTypeBadge?: boolean;
42
50
  noPadding?: boolean;
51
+ selectionColumnWidth?: number;
52
+ renderSelectionCell?: (props: SelectionCellProps<TRow>) => React.ReactNode;
53
+ rowClass?: (row: TRow) => string | undefined;
54
+ rightPanel?: React.ReactNode;
43
55
  }
44
56
 
45
57
  // Main DataGrid component
@@ -66,6 +78,10 @@ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
66
78
  showPagination = true,
67
79
  showTypeBadge = true,
68
80
  noPadding = false,
81
+ selectionColumnWidth,
82
+ renderSelectionCell,
83
+ rowClass,
84
+ rightPanel,
69
85
  }: DataGridProps<TRow>) {
70
86
  const { resolvedTheme } = useTheme();
71
87
 
@@ -77,31 +93,35 @@ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
77
93
 
78
94
  // Add selection column if enabled and not hidden
79
95
  if (showSelection && selectedRows !== undefined && onSelectedRowsChange) {
96
+ const colWidth = selectionColumnWidth ?? 45;
80
97
  cols.push({
81
98
  ...SelectColumn,
82
99
  key: SELECT_COLUMN_KEY,
83
100
  frozen: true,
84
- width: 45,
85
- minWidth: 45,
86
- maxWidth: 45,
87
- resizable: false,
88
- renderCell: ({ row, tabIndex }) => (
89
- <Checkbox
90
- checked={selectedRows.has(keyGetter(row))}
91
- onChange={(checked) => {
92
- const newSelectedRows = new Set(selectedRows);
93
- if (checked) {
94
- newSelectedRows.add(String(keyGetter(row)));
95
- } else {
96
- newSelectedRows.delete(String(keyGetter(row)));
97
- }
98
- onSelectedRowsChange(newSelectedRows);
99
- }}
100
- tabIndex={tabIndex}
101
- />
102
- ),
101
+ width: colWidth,
102
+ minWidth: colWidth,
103
+ maxWidth: renderSelectionCell ? undefined : colWidth,
104
+ resizable: !!renderSelectionCell,
105
+ renderCell: ({ row, tabIndex }) => {
106
+ const isSelected = selectedRows.has(keyGetter(row));
107
+ const handleToggle = (checked: boolean) => {
108
+ const newSelectedRows = new Set(selectedRows);
109
+ if (checked) {
110
+ newSelectedRows.add(String(keyGetter(row)));
111
+ } else {
112
+ newSelectedRows.delete(String(keyGetter(row)));
113
+ }
114
+ onSelectedRowsChange(newSelectedRows);
115
+ };
116
+
117
+ if (renderSelectionCell) {
118
+ return renderSelectionCell({ row, isSelected, onToggle: handleToggle, tabIndex });
119
+ }
120
+
121
+ return <Checkbox checked={isSelected} onChange={handleToggle} tabIndex={tabIndex} />;
122
+ },
103
123
  renderHeaderCell: () => {
104
- const selectedCount = data.filter((row) => selectedRows.has(String(row.id))).length;
124
+ const selectedCount = data.filter((row) => selectedRows.has(keyGetter(row))).length;
105
125
  const totalCount = data.length;
106
126
  const isAllSelected = totalCount > 0 && selectedCount === totalCount;
107
127
  const isPartiallySelected = selectedCount > 0 && selectedCount < totalCount;
@@ -114,10 +134,10 @@ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
114
134
  const newSelectedRows = new Set(selectedRows);
115
135
  if (checked) {
116
136
  // Select all
117
- data.forEach((row) => newSelectedRows.add(String(row.id)));
137
+ data.forEach((row) => newSelectedRows.add(keyGetter(row)));
118
138
  } else {
119
139
  // Unselect all
120
- data.forEach((row) => newSelectedRows.delete(String(row.id)));
140
+ data.forEach((row) => newSelectedRows.delete(keyGetter(row)));
121
141
  }
122
142
  onSelectedRowsChange(newSelectedRows);
123
143
  }}
@@ -182,6 +202,8 @@ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
182
202
  showSelection,
183
203
  showTypeBadge,
184
204
  keyGetter,
205
+ selectionColumnWidth,
206
+ renderSelectionCell,
185
207
  ]);
186
208
 
187
209
  // Loading state - only show full loading screen if not sorting
@@ -200,48 +222,54 @@ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
200
222
  className
201
223
  )}
202
224
  >
203
- <div
204
- className={cn(
205
- 'flex-1 overflow-hidden relative border border-border-gray dark:border-neutral-700 rounded-sm',
206
- !noPadding && 'mx-3'
207
- )}
208
- >
209
- <ReactDataGrid
210
- columns={gridColumns}
211
- rows={isRefreshing ? [] : data}
212
- rowKeyGetter={keyGetter}
213
- onRowsChange={() => {}}
214
- selectedRows={selectedRows}
215
- onSelectedRowsChange={onSelectedRowsChange}
216
- sortColumns={sortColumns || []}
217
- onSortColumnsChange={onSortColumnsChange}
218
- onCellClick={onCellClick}
219
- className={`h-full fill-grid ${resolvedTheme === 'dark' ? 'rdg-dark' : 'rdg-light'}`}
220
- headerRowHeight={36}
221
- rowHeight={36}
222
- enableVirtualization={true}
223
- renderers={{
224
- noRowsFallback: emptyState ? (
225
- <div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
226
- {emptyState}
227
- </div>
228
- ) : (
229
- <div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
230
- <div className="text-sm text-zinc-500 dark:text-zinc-400">No data to display</div>
231
- </div>
232
- ),
233
- }}
234
- />
225
+ <div className={cn('flex-1 overflow-hidden flex min-h-0', !noPadding && 'mx-3')}>
226
+ <div
227
+ className={cn(
228
+ 'overflow-hidden relative border border-border-gray dark:border-neutral-700 rounded-sm',
229
+ rightPanel ? 'rounded-r-none border-r-0' : 'flex-1'
230
+ )}
231
+ style={rightPanel ? { width: 'calc(100% - 480px)' } : undefined}
232
+ >
233
+ <ReactDataGrid
234
+ key={rightPanel ? 'with-panel' : 'no-panel'}
235
+ columns={gridColumns}
236
+ rows={isRefreshing ? [] : data}
237
+ rowKeyGetter={keyGetter}
238
+ onRowsChange={() => {}}
239
+ selectedRows={selectedRows}
240
+ onSelectedRowsChange={onSelectedRowsChange}
241
+ sortColumns={sortColumns || []}
242
+ onSortColumnsChange={onSortColumnsChange}
243
+ onCellClick={onCellClick}
244
+ rowClass={rowClass}
245
+ className={`h-full fill-grid ${resolvedTheme === 'dark' ? 'rdg-dark' : 'rdg-light'}`}
246
+ headerRowHeight={36}
247
+ rowHeight={36}
248
+ enableVirtualization={true}
249
+ renderers={{
250
+ noRowsFallback: emptyState ? (
251
+ <div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
252
+ {emptyState}
253
+ </div>
254
+ ) : (
255
+ <div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
256
+ <div className="text-sm text-zinc-500 dark:text-zinc-400">No data to display</div>
257
+ </div>
258
+ ),
259
+ }}
260
+ />
235
261
 
236
- {/* Loading mask overlay */}
237
- {isRefreshing && (
238
- <div className="absolute inset-0 bg-white dark:bg-neutral-800 flex items-center justify-center z-50 mt-9">
239
- <div className="flex items-center gap-1">
240
- <div className="w-5 h-5 border-2 border-zinc-500 dark:border-neutral-700 border-t-transparent rounded-full animate-spin" />
241
- <span className="text-sm text-zinc-500 dark:text-zinc-400">Loading</span>
262
+ {/* Loading mask overlay */}
263
+ {isRefreshing && (
264
+ <div className="absolute inset-0 bg-white dark:bg-neutral-800 flex items-center justify-center z-50 mt-9">
265
+ <div className="flex items-center gap-1">
266
+ <div className="w-5 h-5 border-2 border-zinc-500 dark:border-neutral-700 border-t-transparent rounded-full animate-spin" />
267
+ <span className="text-sm text-zinc-500 dark:text-zinc-400">Loading</span>
268
+ </div>
242
269
  </div>
243
- </div>
244
- )}
270
+ )}
271
+ </div>
272
+ {rightPanel}
245
273
  </div>
246
274
  {showPagination && onPageChange && (
247
275
  <PaginationControls
@@ -15,7 +15,8 @@ export type ConvertedValue =
15
15
  | number // INTEGER, FLOAT
16
16
  | boolean // BOOLEAN
17
17
  | null // NULL values for any nullable column
18
- | JSON; // JSON (as parsed object or string)
18
+ | Record<string, unknown> // JSON objects (e.g., metadata fields)
19
+ | string[]; // Array of strings (e.g., providers)
19
20
 
20
21
  /**
21
22
  * User input values - these are the types of values users enter in forms and cell editors
@@ -3,7 +3,7 @@ export * from './cell-editors';
3
3
 
4
4
  // datagrid types
5
5
  export type * from './datagridTypes';
6
- export type { DataGridProps } from './DataGrid';
6
+ export type { DataGridProps, SelectionCellProps } from './DataGrid';
7
7
  export type {
8
8
  Column,
9
9
  SortColumn,
@@ -14,7 +14,6 @@ export { CodeBlock } from './CodeBlock';
14
14
  export { CodeEditor } from './CodeEditor';
15
15
  export { ConfirmDialog } from './ConfirmDialog';
16
16
  export { ConnectCTA } from './ConnectCTA';
17
- export { ProjectInfoModal } from './ProjectInfoModal';
18
17
  export { CopyButton } from './CopyButton';
19
18
  export { DeleteActionButton } from './DeleteActionButton';
20
19
  export { EmptyState } from './EmptyState';
@@ -10,16 +10,11 @@ import {
10
10
  Separator,
11
11
  ThemeToggle,
12
12
  } from '@/components';
13
- import {
14
- McpConnectionStatus,
15
- OnboardingModal,
16
- getOnboardingSkipped,
17
- setOnboardingSkipped,
18
- } from '@/features/onboard';
19
- import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
13
+ import { McpConnectionStatus } from '@/features/onboard';
20
14
  import { cn } from '@/lib/utils/utils';
21
15
  import { useTheme } from '@/lib/contexts/ThemeContext';
22
16
  import { useAuth } from '@/lib/contexts/AuthContext';
17
+ import { useModal } from '@/lib/hooks/useModal';
23
18
 
24
19
  // Import SVG icons
25
20
  import DiscordIcon from '@/assets/logos/discord.svg?react';
@@ -30,9 +25,8 @@ import InsForgeLogoDark from '@/assets/logos/insforge_dark.svg';
30
25
  export default function AppHeader() {
31
26
  const { resolvedTheme } = useTheme();
32
27
  const { user, logout } = useAuth();
33
- const { hasCompletedOnboarding, isLoading: isMcpLoading } = useMcpUsage();
28
+ const { setOnboardingModalOpen } = useModal();
34
29
  const [githubStars, setGithubStars] = useState<number | null>(null);
35
- const [isOnboardingModalOpen, setIsOnboardingModalOpen] = useState(false);
36
30
 
37
31
  // Fetch GitHub stars
38
32
  useEffect(() => {
@@ -48,21 +42,6 @@ export default function AppHeader() {
48
42
  });
49
43
  }, []);
50
44
 
51
- // Auto-open onboarding modal if user hasn't connected and hasn't skipped
52
- useEffect(() => {
53
- if (!isMcpLoading && !hasCompletedOnboarding && !getOnboardingSkipped()) {
54
- setIsOnboardingModalOpen(true);
55
- }
56
- }, [isMcpLoading, hasCompletedOnboarding]);
57
-
58
- // When MCP connection is established, close onboarding modal and clear skip flag
59
- useEffect(() => {
60
- if (hasCompletedOnboarding) {
61
- setIsOnboardingModalOpen(false);
62
- setOnboardingSkipped(false);
63
- }
64
- }, [hasCompletedOnboarding]);
65
-
66
45
  const formatStars = (count: number): string => {
67
46
  if (count >= 1000) {
68
47
  return `${(count / 1000).toFixed(1)}k`;
@@ -139,7 +118,7 @@ export default function AppHeader() {
139
118
  <ThemeToggle />
140
119
  <Separator className="h-5 mx-2" orientation="vertical" />
141
120
  {/* MCP Connection Status */}
142
- <McpConnectionStatus onConnectClick={() => setIsOnboardingModalOpen(true)} />
121
+ <McpConnectionStatus onConnectClick={() => setOnboardingModalOpen(true)} />
143
122
 
144
123
  {/* User Profile*/}
145
124
  <Separator className="h-5 mx-2" orientation="vertical" />
@@ -179,8 +158,6 @@ export default function AppHeader() {
179
158
  </DropdownMenu>
180
159
  </div>
181
160
  </div>
182
- {/* Onboarding Modal */}
183
- <OnboardingModal open={isOnboardingModalOpen} onOpenChange={setIsOnboardingModalOpen} />
184
161
  </>
185
162
  );
186
163
  }
@@ -1,100 +1,85 @@
1
- import { useMemo, useState } from 'react';
2
- import { useLogSources } from '@/features/logs/hooks/useLogSources';
3
- import { PrimaryMenu } from './PrimaryMenu';
4
- import { SecondaryMenu } from './SecondaryMenu';
5
- import {
6
- staticMenuItems,
7
- documentationMenuItem,
8
- usageMenuItem,
9
- type PrimaryMenuItem,
10
- } from '@/lib/utils/menuItems';
11
- import { useLocation, matchPath } from 'react-router-dom';
12
- import { isInsForgeCloudProject, isIframe } from '@/lib/utils/utils';
13
- import { postMessageToParent } from '@/lib/utils/cloudMessaging';
14
- import { ProjectInfoModal } from '@/components/ProjectInfoModal';
15
- import { Settings } from 'lucide-react';
16
-
17
- interface AppSidebarProps extends React.HTMLAttributes<HTMLElement> {
18
- isCollapsed: boolean;
19
- onToggleCollapse: () => void;
20
- }
21
-
22
- export default function AppSidebar({ isCollapsed, onToggleCollapse }: AppSidebarProps) {
23
- const { pathname } = useLocation();
24
- const { menuItems: logsMenuItems, isLoading: logsLoading } = useLogSources();
25
- const [isProjectInfoModalOpen, setIsProjectInfoModalOpen] = useState(false);
26
-
27
- const isCloud = isInsForgeCloudProject();
28
- const isInIframe = isIframe();
29
-
30
- // Create a settings menu item that behaves differently based on iframe context
31
- const settingsMenuItem: PrimaryMenuItem = useMemo(
32
- () => ({
33
- id: 'settings',
34
- label: 'Settings',
35
- href: '',
36
- icon: Settings,
37
- onClick: () => {
38
- if (isInIframe) {
39
- // In iframe: use postMessage to show cloud's settings overlay
40
- postMessageToParent({ type: 'SHOW_SETTINGS_OVERLAY' }, '*');
41
- } else {
42
- // Not in iframe: show local project info modal
43
- setIsProjectInfoModalOpen(true);
44
- }
45
- },
46
- }),
47
- [isInIframe]
48
- );
49
-
50
- // Build bottom menu items based on deployment environment
51
- const bottomMenuItems = useMemo(() => {
52
- const items = [];
53
-
54
- // Only show Usage when in iframe (postMessage to parent works)
55
- if (isCloud && isInIframe) {
56
- items.push(usageMenuItem);
57
- }
58
-
59
- items.push(documentationMenuItem);
60
- items.push(settingsMenuItem);
61
- return items;
62
- }, [isCloud, isInIframe, settingsMenuItem]);
63
-
64
- // Find which primary menu item matches the current route
65
- // Items with secondary menus use prefix matching (end: false)
66
- // Items without secondary menus use exact matching (end: true)
67
- const activeMenu = staticMenuItems.find((item) => {
68
- const hasSecondaryMenu = !!item.secondaryMenu || item.id === 'logs';
69
- return matchPath({ path: item.href, end: !hasSecondaryMenu }, pathname);
70
- });
71
-
72
- // Get secondary menu items (special case for logs)
73
- const secondaryMenuItems = activeMenu?.id === 'logs' ? logsMenuItems : activeMenu?.secondaryMenu;
74
- const isLoading = activeMenu?.id === 'logs' ? logsLoading : false;
75
-
76
- return (
77
- <>
78
- <div className="flex h-full">
79
- <PrimaryMenu
80
- items={staticMenuItems}
81
- bottomItems={bottomMenuItems}
82
- activeItemId={activeMenu?.id}
83
- isCollapsed={isCollapsed}
84
- onToggleCollapse={onToggleCollapse}
85
- />
86
-
87
- {/* Render the secondary menu - always visible when there are items */}
88
- {secondaryMenuItems && activeMenu && (
89
- <SecondaryMenu title={activeMenu.label} items={secondaryMenuItems} loading={isLoading} />
90
- )}
91
- </div>
92
-
93
- {/* Project Info Modal for cloud deployments accessed directly (not in iframe) */}
94
- <ProjectInfoModal
95
- open={isProjectInfoModalOpen}
96
- onClose={() => setIsProjectInfoModalOpen(false)}
97
- />
98
- </>
99
- );
100
- }
1
+ import { useMemo } from 'react';
2
+ import { useLogSources } from '@/features/logs/hooks/useLogSources';
3
+ import { PrimaryMenu } from './PrimaryMenu';
4
+ import { SecondaryMenu } from './SecondaryMenu';
5
+ import {
6
+ staticMenuItems,
7
+ documentationMenuItem,
8
+ usageMenuItem,
9
+ settingsMenuItem,
10
+ deploymentsMenuItem,
11
+ type PrimaryMenuItem,
12
+ } from '@/lib/utils/menuItems';
13
+ import { useLocation, matchPath } from 'react-router-dom';
14
+ import { isInsForgeCloudProject, isIframe } from '@/lib/utils/utils';
15
+
16
+ interface AppSidebarProps extends React.HTMLAttributes<HTMLElement> {
17
+ isCollapsed: boolean;
18
+ onToggleCollapse: () => void;
19
+ }
20
+
21
+ export default function AppSidebar({ isCollapsed, onToggleCollapse }: AppSidebarProps) {
22
+ const { pathname } = useLocation();
23
+ const { menuItems: logsMenuItems, isLoading: logsLoading } = useLogSources();
24
+
25
+ const isCloud = isInsForgeCloudProject();
26
+ const isInIframe = isIframe();
27
+
28
+ // Build main menu items - add deployments for cloud projects
29
+ const mainMenuItems = useMemo(() => {
30
+ if (isCloud) {
31
+ // Insert deployments after visualizer (at the end of main items)
32
+ return [...staticMenuItems, deploymentsMenuItem];
33
+ }
34
+ return staticMenuItems;
35
+ }, [isCloud]);
36
+
37
+ // Build bottom menu items based on deployment environment
38
+ const bottomMenuItems = useMemo(() => {
39
+ const items: PrimaryMenuItem[] = [];
40
+
41
+ // Only show Usage when in iframe (postMessage to parent works)
42
+ if (isCloud && isInIframe) {
43
+ items.push(usageMenuItem);
44
+ }
45
+
46
+ items.push(documentationMenuItem);
47
+ items.push(settingsMenuItem);
48
+ return items;
49
+ }, [isCloud, isInIframe]);
50
+
51
+ // Find which primary menu item matches the current route
52
+ // Items with secondary menus use prefix matching (end: false)
53
+ // Items without secondary menus use exact matching (end: true)
54
+ const activeMenu = useMemo(() => {
55
+ const allItems = [...mainMenuItems, ...bottomMenuItems];
56
+ return allItems.find((item) => {
57
+ if (item.external || item.onClick) {
58
+ return false;
59
+ }
60
+ const hasSecondaryMenu = !!item.secondaryMenu || item.id === 'logs';
61
+ return matchPath({ path: item.href, end: !hasSecondaryMenu }, pathname);
62
+ });
63
+ }, [mainMenuItems, bottomMenuItems, pathname]);
64
+
65
+ // Get secondary menu items (special case for logs)
66
+ const secondaryMenuItems = activeMenu?.id === 'logs' ? logsMenuItems : activeMenu?.secondaryMenu;
67
+ const isLoading = activeMenu?.id === 'logs' ? logsLoading : false;
68
+
69
+ return (
70
+ <div className="flex h-full">
71
+ <PrimaryMenu
72
+ items={mainMenuItems}
73
+ bottomItems={bottomMenuItems}
74
+ activeItemId={activeMenu?.id}
75
+ isCollapsed={isCollapsed}
76
+ onToggleCollapse={onToggleCollapse}
77
+ />
78
+
79
+ {/* Render the secondary menu - always visible when there are items */}
80
+ {secondaryMenuItems && activeMenu && (
81
+ <SecondaryMenu title={activeMenu.label} items={secondaryMenuItems} loading={isLoading} />
82
+ )}
83
+ </div>
84
+ );
85
+ }
@@ -1,32 +1,34 @@
1
- import React, { useState } from 'react';
2
- import AppSidebar from './AppSidebar';
3
- import AppHeader from './AppHeader';
4
- import { ThemeProvider } from '@/lib/contexts/ThemeContext';
5
- import { isIframe } from '@/lib/utils/utils';
6
-
7
- interface LayoutProps {
8
- children: React.ReactNode;
9
- }
10
-
11
- export default function Layout({ children }: LayoutProps) {
12
- // Sidebar is expanded by default; user can toggle via UI
13
- const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
14
-
15
- const handleToggleCollapse = () => {
16
- setSidebarCollapsed(!sidebarCollapsed);
17
- };
18
-
19
- return (
20
- <ThemeProvider forcedTheme={isIframe() ? 'dark' : undefined}>
21
- <div className="h-screen bg-gray-50 dark:bg-neutral-800 flex flex-col">
22
- {!isIframe() && <AppHeader />}
23
-
24
- {/* Main layout - sidebars + content in flexbox */}
25
- <div className="flex-1 flex overflow-hidden">
26
- <AppSidebar isCollapsed={sidebarCollapsed} onToggleCollapse={handleToggleCollapse} />
27
- <main className="flex-1 overflow-y-auto">{children}</main>
28
- </div>
29
- </div>
30
- </ThemeProvider>
31
- );
32
- }
1
+ import React, { useState } from 'react';
2
+ import AppSidebar from './AppSidebar';
3
+ import AppHeader from './AppHeader';
4
+ import { ThemeProvider } from '@/lib/contexts/ThemeContext';
5
+ import { OnboardingModal } from '@/features/onboard';
6
+ import { isIframe } from '@/lib/utils/utils';
7
+
8
+ interface LayoutProps {
9
+ children: React.ReactNode;
10
+ }
11
+
12
+ export default function Layout({ children }: LayoutProps) {
13
+ // Sidebar is expanded by default; user can toggle via UI
14
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
15
+
16
+ const handleToggleCollapse = () => {
17
+ setSidebarCollapsed(!sidebarCollapsed);
18
+ };
19
+
20
+ return (
21
+ <ThemeProvider forcedTheme={isIframe() ? 'dark' : undefined}>
22
+ <div className="h-screen bg-gray-50 dark:bg-neutral-800 flex flex-col">
23
+ {!isIframe() && <AppHeader />}
24
+
25
+ {/* Main layout - sidebars + content in flexbox */}
26
+ <div className="flex-1 flex overflow-hidden">
27
+ <AppSidebar isCollapsed={sidebarCollapsed} onToggleCollapse={handleToggleCollapse} />
28
+ <main className="flex-1 overflow-y-auto">{children}</main>
29
+ </div>
30
+ </div>
31
+ <OnboardingModal />
32
+ </ThemeProvider>
33
+ );
34
+ }