@solidxai/core-ui 0.1.12-beta.3 → 0.1.12-beta.5

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 (423) hide show
  1. package/dist/components/auth/AuthLayout.d.ts.map +1 -1
  2. package/dist/components/auth/AuthLayout.js +7 -3
  3. package/dist/components/auth/AuthLayout.js.map +1 -1
  4. package/dist/components/auth/AuthLayout.tsx +9 -2
  5. package/dist/components/auth/AuthSettingsContext.js +1 -1
  6. package/dist/components/auth/AuthSettingsContext.js.map +1 -1
  7. package/dist/components/auth/AuthSettingsContext.tsx +1 -1
  8. package/dist/components/core/chatter/SolidChatterHeader.d.ts.map +1 -1
  9. package/dist/components/core/chatter/SolidChatterHeader.js +18 -4
  10. package/dist/components/core/chatter/SolidChatterHeader.js.map +1 -1
  11. package/dist/components/core/chatter/SolidChatterHeader.tsx +17 -3
  12. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.d.ts.map +1 -1
  13. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.js +12 -2
  14. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.js.map +1 -1
  15. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.tsx +12 -1
  16. package/dist/components/core/extension/solid-core/metadata/MetadataExplorerFormWidget.d.ts +2 -0
  17. package/dist/components/core/extension/solid-core/metadata/MetadataExplorerFormWidget.d.ts.map +1 -1
  18. package/dist/components/core/extension/solid-core/metadata/MetadataExplorerFormWidget.js +4 -2
  19. package/dist/components/core/extension/solid-core/metadata/MetadataExplorerFormWidget.js.map +1 -1
  20. package/dist/components/core/extension/solid-core/metadata/MetadataExplorerFormWidget.tsx +11 -3
  21. package/dist/components/core/json/SolidJsonEditor.css +7 -0
  22. package/dist/components/core/list/SolidDataTable.js +1 -1
  23. package/dist/components/core/list/SolidDataTable.js.map +1 -1
  24. package/dist/components/core/list/SolidDataTable.tsx +1 -1
  25. package/dist/components/core/list/SolidListView.d.ts.map +1 -1
  26. package/dist/components/core/list/SolidListView.js +58 -58
  27. package/dist/components/core/list/SolidListView.js.map +1 -1
  28. package/dist/components/core/list/SolidListView.tsx +5 -4
  29. package/dist/components/core/module/CreateModule.css +60 -6
  30. package/dist/components/core/module/CreateModule.d.ts.map +1 -1
  31. package/dist/components/core/module/CreateModule.js +2 -2
  32. package/dist/components/core/module/CreateModule.js.map +1 -1
  33. package/dist/components/core/module/CreateModule.tsx +56 -37
  34. package/dist/components/layout/AdminTopHeader.js +1 -1
  35. package/dist/components/layout/AdminTopHeader.js.map +1 -1
  36. package/dist/components/layout/AdminTopHeader.tsx +2 -2
  37. package/dist/helpers/modelViewPersistence.d.ts.map +1 -1
  38. package/dist/helpers/modelViewPersistence.js +3 -2
  39. package/dist/helpers/modelViewPersistence.js.map +1 -1
  40. package/dist/helpers/modelViewPersistence.ts +3 -2
  41. package/dist/helpers/modulePackageResumeState.d.ts +6 -0
  42. package/dist/helpers/modulePackageResumeState.d.ts.map +1 -0
  43. package/dist/helpers/modulePackageResumeState.js +46 -0
  44. package/dist/helpers/modulePackageResumeState.js.map +1 -0
  45. package/dist/helpers/modulePackageResumeState.ts +57 -0
  46. package/dist/redux/api/datasourceIntrospectionApi.d.ts +42 -1
  47. package/dist/redux/api/datasourceIntrospectionApi.d.ts.map +1 -1
  48. package/dist/redux/api/datasourceIntrospectionApi.js +34 -1
  49. package/dist/redux/api/datasourceIntrospectionApi.js.map +1 -1
  50. package/dist/redux/api/datasourceIntrospectionApi.ts +60 -0
  51. package/dist/redux/store/defaultStoreConfig.d.ts +11 -0
  52. package/dist/redux/store/defaultStoreConfig.d.ts.map +1 -1
  53. package/dist/resources/shadcn-base.css +70 -16
  54. package/dist/resources/solid-custom.css +3 -86
  55. package/dist/resources/solid-tailwind-generated.css +1 -1
  56. package/dist/resources/themes/solid-dark-purple/theme-variables.css +226 -0
  57. package/dist/resources/themes/solid-dark-purple/theme.css +1 -185
  58. package/dist/resources/themes/solid-light-purple/theme-variables.css +237 -0
  59. package/dist/resources/themes/solid-light-purple/theme.css +1 -206
  60. package/dist/routes/pages/admin/core/DatasourceIntrospectionPage.css +384 -31
  61. package/dist/routes/pages/admin/core/DatasourceIntrospectionPage.d.ts.map +1 -1
  62. package/dist/routes/pages/admin/core/DatasourceIntrospectionPage.js +577 -150
  63. package/dist/routes/pages/admin/core/DatasourceIntrospectionPage.js.map +1 -1
  64. package/dist/routes/pages/admin/core/DatasourceIntrospectionPage.tsx +1088 -423
  65. package/package.json +1 -1
  66. package/dist/components/auth/SolidOTPVerify.d.ts +0 -3
  67. package/dist/components/auth/SolidOTPVerify.d.ts.map +0 -1
  68. package/dist/components/auth/SolidOTPVerify.js +0 -67
  69. package/dist/components/auth/SolidOTPVerify.js.map +0 -1
  70. package/dist/components/auth/SolidOTPVerify.tsx +0 -133
  71. package/dist/components/common/AuthBanner.d.ts +0 -3
  72. package/dist/components/common/AuthBanner.d.ts.map +0 -1
  73. package/dist/components/common/AuthBanner.js +0 -15
  74. package/dist/components/common/AuthBanner.js.map +0 -1
  75. package/dist/components/common/AuthBanner.tsx +0 -41
  76. package/dist/components/common/SingleSelectAutoCompleteField.d.ts +0 -2
  77. package/dist/components/common/SingleSelectAutoCompleteField.d.ts.map +0 -1
  78. package/dist/components/common/SingleSelectAutoCompleteField.js +0 -92
  79. package/dist/components/common/SingleSelectAutoCompleteField.js.map +0 -1
  80. package/dist/components/common/SingleSelectAutoCompleteField.tsx +0 -73
  81. package/dist/components/common/SolidExportStepper.d.ts +0 -12
  82. package/dist/components/common/SolidExportStepper.d.ts.map +0 -1
  83. package/dist/components/common/SolidExportStepper.js +0 -30
  84. package/dist/components/common/SolidExportStepper.js.map +0 -1
  85. package/dist/components/common/SolidExportStepper.tsx +0 -135
  86. package/dist/components/core/common/LoadDynamicJsxComponent.d.ts +0 -2
  87. package/dist/components/core/common/LoadDynamicJsxComponent.d.ts.map +0 -1
  88. package/dist/components/core/common/LoadDynamicJsxComponent.js +0 -50
  89. package/dist/components/core/common/LoadDynamicJsxComponent.js.map +0 -1
  90. package/dist/components/core/common/LoadDynamicJsxComponent.tsx +0 -70
  91. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.d.ts +0 -2
  92. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.d.ts.map +0 -1
  93. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.js +0 -16
  94. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.js.map +0 -1
  95. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.tsx +0 -29
  96. package/dist/components/core/dashboard/DashboardFilter.d.ts +0 -13
  97. package/dist/components/core/dashboard/DashboardFilter.d.ts.map +0 -1
  98. package/dist/components/core/dashboard/DashboardFilter.js +0 -299
  99. package/dist/components/core/dashboard/DashboardFilter.js.map +0 -1
  100. package/dist/components/core/dashboard/DashboardFilter.tsx +0 -348
  101. package/dist/components/core/dashboard/PrimeDataTableWrapper.d.ts +0 -3
  102. package/dist/components/core/dashboard/PrimeDataTableWrapper.d.ts.map +0 -1
  103. package/dist/components/core/dashboard/PrimeDataTableWrapper.js +0 -21
  104. package/dist/components/core/dashboard/PrimeDataTableWrapper.js.map +0 -1
  105. package/dist/components/core/dashboard/PrimeDataTableWrapper.tsx +0 -40
  106. package/dist/components/core/dashboard/SolidDashboard.d.ts +0 -28
  107. package/dist/components/core/dashboard/SolidDashboard.d.ts.map +0 -1
  108. package/dist/components/core/dashboard/SolidDashboard.js +0 -183
  109. package/dist/components/core/dashboard/SolidDashboard.js.map +0 -1
  110. package/dist/components/core/dashboard/SolidDashboard.module.css +0 -83
  111. package/dist/components/core/dashboard/SolidDashboard.tsx +0 -263
  112. package/dist/components/core/dashboard/SolidDashboardBody.d.ts +0 -24
  113. package/dist/components/core/dashboard/SolidDashboardBody.d.ts.map +0 -1
  114. package/dist/components/core/dashboard/SolidDashboardBody.js +0 -162
  115. package/dist/components/core/dashboard/SolidDashboardBody.js.map +0 -1
  116. package/dist/components/core/dashboard/SolidDashboardBody.tsx +0 -168
  117. package/dist/components/core/dashboard/SolidDashboardFilterRequired.d.ts +0 -2
  118. package/dist/components/core/dashboard/SolidDashboardFilterRequired.d.ts.map +0 -1
  119. package/dist/components/core/dashboard/SolidDashboardFilterRequired.js +0 -11
  120. package/dist/components/core/dashboard/SolidDashboardFilterRequired.js.map +0 -1
  121. package/dist/components/core/dashboard/SolidDashboardFilterRequired.tsx +0 -28
  122. package/dist/components/core/dashboard/SolidDashboardHeader.d.ts +0 -3
  123. package/dist/components/core/dashboard/SolidDashboardHeader.d.ts.map +0 -1
  124. package/dist/components/core/dashboard/SolidDashboardHeader.js +0 -6
  125. package/dist/components/core/dashboard/SolidDashboardHeader.js.map +0 -1
  126. package/dist/components/core/dashboard/SolidDashboardHeader.tsx +0 -10
  127. package/dist/components/core/dashboard/SolidDashboardLoading.d.ts +0 -2
  128. package/dist/components/core/dashboard/SolidDashboardLoading.d.ts.map +0 -1
  129. package/dist/components/core/dashboard/SolidDashboardLoading.js +0 -10
  130. package/dist/components/core/dashboard/SolidDashboardLoading.js.map +0 -1
  131. package/dist/components/core/dashboard/SolidDashboardLoading.tsx +0 -61
  132. package/dist/components/core/dashboard/SolidDashboardNotAvailable.d.ts +0 -3
  133. package/dist/components/core/dashboard/SolidDashboardNotAvailable.d.ts.map +0 -1
  134. package/dist/components/core/dashboard/SolidDashboardNotAvailable.js +0 -12
  135. package/dist/components/core/dashboard/SolidDashboardNotAvailable.js.map +0 -1
  136. package/dist/components/core/dashboard/SolidDashboardNotAvailable.tsx +0 -32
  137. package/dist/components/core/dashboard/SolidDashboardRenderError.d.ts +0 -2
  138. package/dist/components/core/dashboard/SolidDashboardRenderError.d.ts.map +0 -1
  139. package/dist/components/core/dashboard/SolidDashboardRenderError.js +0 -11
  140. package/dist/components/core/dashboard/SolidDashboardRenderError.js.map +0 -1
  141. package/dist/components/core/dashboard/SolidDashboardRenderError.tsx +0 -28
  142. package/dist/components/core/dashboard/SolidDashboardVariable.d.ts +0 -19
  143. package/dist/components/core/dashboard/SolidDashboardVariable.d.ts.map +0 -1
  144. package/dist/components/core/dashboard/SolidDashboardVariable.js +0 -171
  145. package/dist/components/core/dashboard/SolidDashboardVariable.js.map +0 -1
  146. package/dist/components/core/dashboard/SolidDashboardVariable.tsx +0 -259
  147. package/dist/components/core/dashboard/SolidQuestionRenderer.d.ts +0 -9
  148. package/dist/components/core/dashboard/SolidQuestionRenderer.d.ts.map +0 -1
  149. package/dist/components/core/dashboard/SolidQuestionRenderer.js +0 -42
  150. package/dist/components/core/dashboard/SolidQuestionRenderer.js.map +0 -1
  151. package/dist/components/core/dashboard/SolidQuestionRenderer.tsx +0 -99
  152. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.d.ts +0 -9
  153. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.d.ts.map +0 -1
  154. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.js +0 -35
  155. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.js.map +0 -1
  156. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.tsx +0 -48
  157. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.d.ts +0 -7
  158. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.d.ts.map +0 -1
  159. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.js +0 -22
  160. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.js.map +0 -1
  161. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.tsx +0 -51
  162. package/dist/components/core/dashboard/chart-renderers/init-chartjs.d.ts +0 -2
  163. package/dist/components/core/dashboard/chart-renderers/init-chartjs.d.ts.map +0 -1
  164. package/dist/components/core/dashboard/chart-renderers/init-chartjs.js +0 -4
  165. package/dist/components/core/dashboard/chart-renderers/init-chartjs.js.map +0 -1
  166. package/dist/components/core/dashboard/chart-renderers/init-chartjs.ts +0 -25
  167. package/dist/components/core/dashboard/dashboard-utils.d.ts +0 -2
  168. package/dist/components/core/dashboard/dashboard-utils.d.ts.map +0 -1
  169. package/dist/components/core/dashboard/dashboard-utils.js +0 -38
  170. package/dist/components/core/dashboard/dashboard-utils.js.map +0 -1
  171. package/dist/components/core/dashboard/dashboard-utils.ts +0 -39
  172. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.d.ts +0 -10
  173. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.d.ts.map +0 -1
  174. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.js +0 -16
  175. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.js.map +0 -1
  176. package/dist/components/core/extension/solid-core/dashboard/dashboardFormViewChangeHandler.ts +0 -19
  177. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.d.ts +0 -8
  178. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.d.ts.map +0 -1
  179. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.js +0 -64
  180. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.js.map +0 -1
  181. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionFieldChangeHandler.ts +0 -30
  182. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.d.ts +0 -8
  183. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.d.ts.map +0 -1
  184. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.js +0 -62
  185. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.js.map +0 -1
  186. package/dist/components/core/extension/solid-core/dashboard/dashboardQuestionOnFormLoadHandler.ts +0 -29
  187. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.d.ts +0 -4
  188. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.d.ts.map +0 -1
  189. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.js +0 -23
  190. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.js.map +0 -1
  191. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.tsx +0 -36
  192. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.d.ts +0 -3
  193. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.d.ts.map +0 -1
  194. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.js +0 -92
  195. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.js.map +0 -1
  196. package/dist/components/core/form/fields/widgets/SolidChatterMessageCoModelEntityIdFormViewWidget.tsx +0 -68
  197. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.d.ts +0 -3
  198. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.d.ts.map +0 -1
  199. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.js +0 -111
  200. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.js.map +0 -1
  201. package/dist/components/core/form/fields/widgets/SolidLovTypeChangeFormEditWidget.tsx +0 -122
  202. package/dist/components/core/kanban/SolidKanbanViewFields.d.ts +0 -12
  203. package/dist/components/core/kanban/SolidKanbanViewFields.d.ts.map +0 -1
  204. package/dist/components/core/kanban/SolidKanbanViewFields.js +0 -145
  205. package/dist/components/core/kanban/SolidKanbanViewFields.js.map +0 -1
  206. package/dist/components/core/kanban/SolidKanbanViewFields.tsx +0 -164
  207. package/dist/components/core/kanban/SolidManyToOneFilterElement.d.ts +0 -2
  208. package/dist/components/core/kanban/SolidManyToOneFilterElement.d.ts.map +0 -1
  209. package/dist/components/core/kanban/SolidManyToOneFilterElement.js +0 -87
  210. package/dist/components/core/kanban/SolidManyToOneFilterElement.js.map +0 -1
  211. package/dist/components/core/kanban/SolidManyToOneFilterElement.tsx +0 -59
  212. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.d.ts +0 -2
  213. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.d.ts.map +0 -1
  214. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.js +0 -73
  215. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.js.map +0 -1
  216. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.tsx +0 -50
  217. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.d.ts +0 -2
  218. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.d.ts.map +0 -1
  219. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.js +0 -20
  220. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.js.map +0 -1
  221. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.tsx +0 -32
  222. package/dist/components/core/kanban/SolidVarInputsFilterElement.d.ts +0 -12
  223. package/dist/components/core/kanban/SolidVarInputsFilterElement.d.ts.map +0 -1
  224. package/dist/components/core/kanban/SolidVarInputsFilterElement.js +0 -81
  225. package/dist/components/core/kanban/SolidVarInputsFilterElement.js.map +0 -1
  226. package/dist/components/core/kanban/SolidVarInputsFilterElement.tsx +0 -184
  227. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.d.ts +0 -4
  228. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.d.ts.map +0 -1
  229. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.js +0 -7
  230. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.js.map +0 -1
  231. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.tsx +0 -9
  232. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.d.ts +0 -4
  233. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.d.ts.map +0 -1
  234. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.js +0 -8
  235. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.js.map +0 -1
  236. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.tsx +0 -16
  237. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.d.ts +0 -4
  238. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.d.ts.map +0 -1
  239. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.js +0 -21
  240. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.js.map +0 -1
  241. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.tsx +0 -23
  242. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.d.ts +0 -4
  243. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.d.ts.map +0 -1
  244. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.js +0 -8
  245. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.js.map +0 -1
  246. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.tsx +0 -14
  247. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.d.ts +0 -4
  248. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.d.ts.map +0 -1
  249. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.js +0 -8
  250. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.js.map +0 -1
  251. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.tsx +0 -13
  252. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.d.ts +0 -4
  253. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.d.ts.map +0 -1
  254. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.js +0 -7
  255. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.js.map +0 -1
  256. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.tsx +0 -9
  257. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.d.ts +0 -4
  258. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.d.ts.map +0 -1
  259. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.js +0 -8
  260. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.js.map +0 -1
  261. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.tsx +0 -12
  262. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.d.ts +0 -4
  263. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.d.ts.map +0 -1
  264. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.js +0 -7
  265. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.js.map +0 -1
  266. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.tsx +0 -9
  267. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.d.ts +0 -4
  268. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.d.ts.map +0 -1
  269. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.js +0 -8
  270. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.js.map +0 -1
  271. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.tsx +0 -14
  272. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.d.ts +0 -4
  273. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.d.ts.map +0 -1
  274. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.js +0 -16
  275. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.js.map +0 -1
  276. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.tsx +0 -20
  277. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.d.ts +0 -4
  278. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.d.ts.map +0 -1
  279. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.js +0 -7
  280. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.js.map +0 -1
  281. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.tsx +0 -9
  282. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.d.ts +0 -4
  283. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.d.ts.map +0 -1
  284. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js +0 -56
  285. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js.map +0 -1
  286. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.tsx +0 -140
  287. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.d.ts +0 -4
  288. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.d.ts.map +0 -1
  289. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js +0 -42
  290. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js.map +0 -1
  291. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.tsx +0 -164
  292. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.d.ts +0 -4
  293. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.d.ts.map +0 -1
  294. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.js +0 -11
  295. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.js.map +0 -1
  296. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.tsx +0 -13
  297. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.d.ts +0 -4
  298. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.d.ts.map +0 -1
  299. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.js +0 -7
  300. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.js.map +0 -1
  301. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.tsx +0 -9
  302. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.d.ts +0 -4
  303. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.d.ts.map +0 -1
  304. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.js +0 -8
  305. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.js.map +0 -1
  306. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.tsx +0 -14
  307. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.d.ts +0 -4
  308. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.d.ts.map +0 -1
  309. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.js +0 -8
  310. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.js.map +0 -1
  311. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.tsx +0 -14
  312. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.d.ts +0 -4
  313. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.d.ts.map +0 -1
  314. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js +0 -37
  315. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js.map +0 -1
  316. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.tsx +0 -121
  317. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.d.ts +0 -4
  318. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.d.ts.map +0 -1
  319. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.js +0 -8
  320. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.js.map +0 -1
  321. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.tsx +0 -12
  322. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.d.ts +0 -4
  323. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.d.ts.map +0 -1
  324. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.js +0 -8
  325. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.js.map +0 -1
  326. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.tsx +0 -13
  327. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.d.ts +0 -4
  328. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.d.ts.map +0 -1
  329. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js +0 -7
  330. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js.map +0 -1
  331. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx +0 -16
  332. package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts +0 -2
  333. package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts.map +0 -1
  334. package/dist/components/core/list/SolidListViewRowButtonContextMenu.js +0 -39
  335. package/dist/components/core/list/SolidListViewRowButtonContextMenu.js.map +0 -1
  336. package/dist/components/core/list/SolidListViewRowButtonContextMenu.tsx +0 -40
  337. package/dist/components/core/list/SolidVarInputsFilterElement.d.ts +0 -12
  338. package/dist/components/core/list/SolidVarInputsFilterElement.d.ts.map +0 -1
  339. package/dist/components/core/list/SolidVarInputsFilterElement.js +0 -81
  340. package/dist/components/core/list/SolidVarInputsFilterElement.js.map +0 -1
  341. package/dist/components/core/list/SolidVarInputsFilterElement.tsx +0 -184
  342. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.d.ts +0 -3
  343. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.d.ts.map +0 -1
  344. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.js +0 -87
  345. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.js.map +0 -1
  346. package/dist/components/core/list/widgets/SolidChatterMessageCoModelEntityIdListViewWidget.tsx +0 -70
  347. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.d.ts +0 -3
  348. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.d.ts.map +0 -1
  349. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.js +0 -33
  350. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.js.map +0 -1
  351. package/dist/components/core/list/widgets/SolidMqMessageStageListViewWidget.tsx +0 -50
  352. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.d.ts +0 -3
  353. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.d.ts.map +0 -1
  354. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.js +0 -158
  355. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.js.map +0 -1
  356. package/dist/components/core/list/widgets/SolidSummarizeListHeaderActionMqMessages.tsx +0 -185
  357. package/dist/components/layout/DashboardHeader.d.ts +0 -3
  358. package/dist/components/layout/DashboardHeader.d.ts.map +0 -1
  359. package/dist/components/layout/DashboardHeader.js +0 -20
  360. package/dist/components/layout/DashboardHeader.js.map +0 -1
  361. package/dist/components/layout/DashboardHeader.tsx +0 -94
  362. package/dist/helpers/# no such endpoints exist, need to calle +0 -3
  363. package/dist/helpers/ToastContainer.d.ts +0 -4
  364. package/dist/helpers/ToastContainer.d.ts.map +0 -1
  365. package/dist/helpers/ToastContainer.js +0 -49
  366. package/dist/helpers/ToastContainer.js.map +0 -1
  367. package/dist/helpers/ToastContainer.tsx +0 -94
  368. package/dist/helpers/showToast.d.ts +0 -5
  369. package/dist/helpers/showToast.d.ts.map +0 -1
  370. package/dist/helpers/showToast.js +0 -17
  371. package/dist/helpers/showToast.js.map +0 -1
  372. package/dist/helpers/showToast.ts +0 -13
  373. package/dist/helpers/studioSandbox.d.ts +0 -31
  374. package/dist/helpers/studioSandbox.d.ts.map +0 -1
  375. package/dist/helpers/studioSandbox.js +0 -104
  376. package/dist/helpers/studioSandbox.js.map +0 -1
  377. package/dist/helpers/studioSandbox.ts +0 -117
  378. package/dist/nextAuth/authProviders.d.ts +0 -4
  379. package/dist/nextAuth/authProviders.d.ts.map +0 -1
  380. package/dist/nextAuth/authProviders.js +0 -198
  381. package/dist/nextAuth/authProviders.js.map +0 -1
  382. package/dist/nextAuth/authProviders.tsx +0 -232
  383. package/dist/nextAuth/handleLogout.d.ts +0 -2
  384. package/dist/nextAuth/handleLogout.d.ts.map +0 -1
  385. package/dist/nextAuth/handleLogout.js +0 -36
  386. package/dist/nextAuth/handleLogout.js.map +0 -1
  387. package/dist/nextAuth/handleLogout.tsx +0 -39
  388. package/dist/nextAuth/refreshAccessToken.d.ts +0 -2
  389. package/dist/nextAuth/refreshAccessToken.d.ts.map +0 -1
  390. package/dist/nextAuth/refreshAccessToken.js +0 -24
  391. package/dist/nextAuth/refreshAccessToken.js.map +0 -1
  392. package/dist/nextAuth/refreshAccessToken.tsx +0 -28
  393. package/dist/redux/api/dashboardApi.d.ts +0 -23
  394. package/dist/redux/api/dashboardApi.d.ts.map +0 -1
  395. package/dist/redux/api/dashboardApi.js +0 -35
  396. package/dist/redux/api/dashboardApi.js.map +0 -1
  397. package/dist/redux/api/dashboardApi.ts +0 -56
  398. package/dist/redux/api/dashboardLayoutApi.d.ts +0 -24
  399. package/dist/redux/api/dashboardLayoutApi.d.ts.map +0 -1
  400. package/dist/redux/api/dashboardLayoutApi.js +0 -34
  401. package/dist/redux/api/dashboardLayoutApi.js.map +0 -1
  402. package/dist/redux/api/dashboardLayoutApi.ts +0 -55
  403. package/dist/redux/api/dashboardQuestionApi.d.ts +0 -5
  404. package/dist/redux/api/dashboardQuestionApi.d.ts.map +0 -1
  405. package/dist/redux/api/dashboardQuestionApi.js +0 -18
  406. package/dist/redux/api/dashboardQuestionApi.js.map +0 -1
  407. package/dist/redux/api/dashboardQuestionApi.ts +0 -17
  408. package/dist/redux/features/settingsSlice.d.ts +0 -20
  409. package/dist/redux/features/settingsSlice.d.ts.map +0 -1
  410. package/dist/redux/features/settingsSlice.js +0 -39
  411. package/dist/redux/features/settingsSlice.js.map +0 -1
  412. package/dist/redux/features/settingsSlice.ts +0 -60
  413. package/dist/resources/images/Footerbg.png +0 -0
  414. package/dist/resources/images/LoginBanner.png +0 -0
  415. package/dist/resources/images/dashboard/Ellipse 1.svg +0 -10
  416. package/dist/resources/images/dashboard/Rectangle 17.svg +0 -10
  417. package/dist/resources/images/dashboard/Rectangle 25.svg +0 -11
  418. package/dist/resources/images/dashboard/image 5.svg +0 -9
  419. package/dist/resources/images/loginhero.png +0 -0
  420. package/dist/resources/images/logo.png +0 -0
  421. package/dist/resources/images/radix-logo-white.png +0 -0
  422. package/dist/resources/images/radix-logo.png +0 -0
  423. package/dist/resources/images/signupBanner.png +0 -0
@@ -1,4 +1,6 @@
1
1
  import {
2
+ ArrowLeft,
3
+ Check,
2
4
  Cog,
3
5
  Database,
4
6
  ExternalLink,
@@ -11,10 +13,11 @@ import {
11
13
  import { camelCase, startCase } from "lodash";
12
14
  import { useEffect, useMemo, useRef, useState } from "react";
13
15
  import { useDispatch } from "react-redux";
14
- import { useParams } from "react-router-dom";
16
+ import { useNavigate, useParams } from "react-router-dom";
15
17
  import { showToast } from "../../../../redux/features/toastSlice";
16
18
  import { SolidJsonEditor } from "../../../../components/core/json/SolidJsonEditor";
17
19
  import { Column, SolidDataTable } from "../../../../components/core/list/SolidDataTable";
20
+ import { waitForBackendAvailability } from "../../../../helpers/waitForBackendAvailability";
18
21
  import {
19
22
  SolidButton,
20
23
  SolidCheckbox,
@@ -38,11 +41,16 @@ import {
38
41
  type DatasourceIntrospectionMappingPreview,
39
42
  type DatasourceIntrospectionMappingRequest,
40
43
  type DatasourceIntrospectionTableRecord,
44
+ type DatasourceIntrospectionApplyResponse,
45
+ type DatasourceIntrospectionCreateMigrationResponse,
41
46
  useApplyDatasourceIntrospectionMappingMutation,
47
+ useCreateDatasourceIntrospectionMigrationArtifactsMutation,
48
+ useGenerateDatasourceIntrospectionCodeMutation,
42
49
  useGetDatasourceIntrospectionBootstrapQuery,
43
50
  useGetDatasourceIntrospectionTableDetailQuery,
44
51
  useGetDatasourceIntrospectionTablesQuery,
45
52
  usePreviewDatasourceIntrospectionMappingMutation,
53
+ useRunDatasourceIntrospectionMigrationMutation,
46
54
  } from "../../../../redux/api/datasourceIntrospectionApi";
47
55
  import { useGetmodelByIdQuery } from "../../../../redux/api/modelApi";
48
56
  import "./DatasourceIntrospectionPage.css";
@@ -52,9 +60,17 @@ type SessionSettings = {
52
60
  prioritizeUnmappedTables: boolean;
53
61
  };
54
62
 
63
+ type WorkspaceStep =
64
+ | "configure"
65
+ | "review-json"
66
+ | "generate-code"
67
+ | "create-migrations"
68
+ | "run-migration";
69
+
55
70
  type DrawerColumnDraft = {
56
71
  columnName: string;
57
72
  fieldName: string;
73
+ displayName: string;
58
74
  dataType: string;
59
75
  solidFieldType: string;
60
76
  ormType: string;
@@ -65,6 +81,7 @@ type DrawerColumnDraft = {
65
81
  numericScale: number | null;
66
82
  ordinalPosition: number | null;
67
83
  isAutoGenerated: boolean;
84
+ isDetectedPrimaryKey: boolean;
68
85
  handledBySuperclass: boolean;
69
86
  superclassFieldName: string | null;
70
87
  fieldId: number | null;
@@ -121,6 +138,49 @@ const scalarFieldTypeOptions = [
121
138
  ];
122
139
 
123
140
  const scalarFieldTypeValueSet = new Set(scalarFieldTypeOptions.map((option) => option.value));
141
+ const mappingStrategyOptions = [
142
+ { value: "generated_id", label: "Legacy generated id" },
143
+ { value: "existing_id", label: "Legacy existing id" },
144
+ ];
145
+
146
+ function getBaseClassNameForLegacyType(value: "none" | "existing_id" | "generated_id") {
147
+ return value === "existing_id"
148
+ ? "LegacyCommonEntityWithExistingId"
149
+ : "LegacyCommonEntityWithGeneratedId";
150
+ }
151
+
152
+ function getSuperclassFieldNameForLegacyType(columnName: string, legacyTableType: "none" | "existing_id" | "generated_id") {
153
+ const normalized = columnName.toLowerCase();
154
+ const legacyFieldMap: Record<string, string> = {
155
+ ss_created_at: "createdAt",
156
+ ss_updated_at: "updatedAt",
157
+ ss_deleted_at: "deletedAt",
158
+ ss_deleted_tracker: "deletedTracker",
159
+ ss_published_at: "publishedAt",
160
+ ss_locale_name: "localeName",
161
+ ss_default_entity_locale_id: "defaultEntityLocaleId",
162
+ ss_created_by_id: "createdBy",
163
+ ss_updated_by_id: "updatedBy",
164
+ };
165
+
166
+ if (normalized === "ss_id" && legacyTableType === "generated_id") {
167
+ return "id";
168
+ }
169
+
170
+ return legacyFieldMap[normalized] ?? null;
171
+ }
172
+
173
+ function getSuggestedFieldNameForLegacyType(column: Pick<DrawerColumnDraft, "columnName" | "isAutoGenerated">, legacyTableType: "none" | "existing_id" | "generated_id") {
174
+ if (legacyTableType === "existing_id" && column.isAutoGenerated) {
175
+ return "id";
176
+ }
177
+
178
+ if (legacyTableType === "generated_id" && column.columnName.toLowerCase() === "id") {
179
+ return "legacyId";
180
+ }
181
+
182
+ return camelCase(column.columnName.replace(/^ss_/i, ""));
183
+ }
124
184
 
125
185
  function getDefaultOrmTypeForSolidFieldType(dataSourceType: string, solidFieldType: string) {
126
186
  const normalizedDatasourceType = dataSourceType.toLowerCase();
@@ -179,12 +239,6 @@ function getDefaultOrmTypeForSolidFieldType(dataSourceType: string, solidFieldTy
179
239
  return ormTypesByDatasource[normalizedDatasourceType]?.[solidFieldType] ?? "varchar";
180
240
  }
181
241
 
182
- function legacyTypeLabel(value: string) {
183
- if (value === "generated_id") return "Legacy generated id";
184
- if (value === "existing_id") return "Legacy existing id";
185
- return "Legacy generated id";
186
- }
187
-
188
242
  function statusLabel(record: DatasourceIntrospectionTableRecord) {
189
243
  return record.mapped ? "Mapped" : "Ready to map";
190
244
  }
@@ -198,6 +252,30 @@ function readQueryError(error: any) {
198
252
  );
199
253
  }
200
254
 
255
+ function isRecoverableGenerateCodeError(error: any) {
256
+ const status = error?.status ?? error?.originalStatus;
257
+ const message = [
258
+ error?.error,
259
+ error?.message,
260
+ error?.data?.message,
261
+ error?.data?.error,
262
+ ]
263
+ .filter(Boolean)
264
+ .join(" ")
265
+ .toLowerCase();
266
+
267
+ if (status === "FETCH_ERROR" || status === "TIMEOUT_ERROR" || status === "PARSING_ERROR") {
268
+ return true;
269
+ }
270
+
271
+ return (
272
+ message.includes("failed to fetch")
273
+ || message.includes("network")
274
+ || message.includes("load failed")
275
+ || message.includes("fetch")
276
+ );
277
+ }
278
+
201
279
  function normalizeName(value: string) {
202
280
  return value.trim().toLowerCase();
203
281
  }
@@ -249,6 +327,7 @@ function buildDrawerDraft(
249
327
  return {
250
328
  columnName: column.columnName,
251
329
  fieldName: matchingField?.name ?? column.fieldName,
330
+ displayName: matchingField?.displayName ?? column.displayName,
252
331
  dataType: column.dataType,
253
332
  solidFieldType: matchingField?.type ?? column.solidFieldType,
254
333
  ormType: matchingField?.ormType ?? column.ormType,
@@ -259,12 +338,13 @@ function buildDrawerDraft(
259
338
  numericScale: column.numericScale,
260
339
  ordinalPosition: column.ordinalPosition,
261
340
  isAutoGenerated: column.isAutoGenerated,
341
+ isDetectedPrimaryKey: column.isPrimaryKey,
262
342
  handledBySuperclass: column.handledBySuperclass,
263
343
  superclassFieldName: column.superclassFieldName,
264
344
  fieldId: matchingField?.id ?? null,
265
345
  include: column.handledBySuperclass ? false : Boolean(matchingField) || !selectedTable.mapped,
266
346
  matched: Boolean(matchingField),
267
- isPrimaryKey: Boolean(matchingField?.isPrimaryKey) || (column.isAutoGenerated && column.fieldName === "id"),
347
+ isPrimaryKey: Boolean(matchingField?.isPrimaryKey) || column.isPrimaryKey || (column.isAutoGenerated && column.fieldName === "id"),
268
348
  };
269
349
  });
270
350
 
@@ -319,6 +399,11 @@ function getDrawerValidationErrors(draft: DrawerDraft) {
319
399
  continue;
320
400
  }
321
401
 
402
+ if (!column.displayName.trim()) {
403
+ errors.push(`Field label is required for column "${column.columnName}".`);
404
+ continue;
405
+ }
406
+
322
407
  if (!scalarFieldTypeValueSet.has(column.solidFieldType)) {
323
408
  errors.push(`SolidX type "${column.solidFieldType}" is not allowed in step 1 for column "${column.columnName}".`);
324
409
  continue;
@@ -377,6 +462,7 @@ function buildMappingRequest(
377
462
  columns: draft.columns.map((column) => ({
378
463
  columnName: column.columnName,
379
464
  fieldName: column.fieldName,
465
+ displayName: column.displayName,
380
466
  dataType: column.dataType,
381
467
  solidFieldType: column.solidFieldType,
382
468
  ormType: column.ormType,
@@ -541,6 +627,7 @@ function parseAndValidateReviewedModelJson(
541
627
 
542
628
  export function DatasourceIntrospectionPage() {
543
629
  const params = useParams();
630
+ const navigate = useNavigate();
544
631
  const dispatch = useDispatch();
545
632
  const moduleId = Number(params.moduleId ?? 0);
546
633
  const isValidModuleId = Number.isFinite(moduleId) && moduleId > 0;
@@ -556,16 +643,25 @@ export function DatasourceIntrospectionPage() {
556
643
  });
557
644
 
558
645
  const [selectedDatasource, setSelectedDatasource] = useState("");
559
- const [selectedTableKey, setSelectedTableKey] = useState("");
646
+ const [selectedRows, setSelectedRows] = useState<DatasourceIntrospectionTableRecord[]>([]);
647
+ const [workspaceTableKey, setWorkspaceTableKey] = useState("");
560
648
  const [tableSearch, setTableSearch] = useState("");
561
649
  const [settingsOpen, setSettingsOpen] = useState(false);
562
650
  const [settingsTab, setSettingsTab] = useState("datasource-info");
563
- const [drawerOpen, setDrawerOpen] = useState(false);
564
651
  const [drawerDraft, setDrawerDraft] = useState<DrawerDraft | null>(null);
565
652
  const [drawerTab, setDrawerTab] = useState("general-info");
566
- const [drawerStep, setDrawerStep] = useState<"edit" | "review">("edit");
567
- const [reviewTab, setReviewTab] = useState("metadata-json");
653
+ const [workspaceStep, setWorkspaceStep] = useState<WorkspaceStep>("configure");
568
654
  const [mappingPreview, setMappingPreview] = useState<DatasourceIntrospectionMappingPreview | null>(null);
655
+ const [persistedMappingResult, setPersistedMappingResult] = useState<DatasourceIntrospectionApplyResponse | null>(null);
656
+ const [migrationArtifactsResult, setMigrationArtifactsResult] = useState<DatasourceIntrospectionCreateMigrationResponse | null>(null);
657
+ const [generateCodeOutput, setGenerateCodeOutput] = useState("");
658
+ const [isGeneratingCodeWorkflow, setIsGeneratingCodeWorkflow] = useState(false);
659
+ const [generateCodeStatusMessage, setGenerateCodeStatusMessage] = useState("");
660
+ const [generateCodeTimeoutMessage, setGenerateCodeTimeoutMessage] = useState<string | null>(null);
661
+ const [generateCodeReady, setGenerateCodeReady] = useState(false);
662
+ const [hasAttemptedGenerateCode, setHasAttemptedGenerateCode] = useState(false);
663
+ const [runMigrationOutput, setRunMigrationOutput] = useState("");
664
+ const [runMigrationCompleted, setRunMigrationCompleted] = useState(false);
569
665
  const [reviewedMetadataJsonValue, setReviewedMetadataJsonValue] = useState<any>(null);
570
666
  const [metadataJsonText, setMetadataJsonText] = useState("");
571
667
  const [metadataJsonValidationError, setMetadataJsonValidationError] = useState<string | null>(null);
@@ -578,15 +674,6 @@ export function DatasourceIntrospectionPage() {
578
674
  const [draftSessionSettings, setDraftSessionSettings] = useState<SessionSettings>(sessionSettings);
579
675
  const drawerBootstrapTimerRef = useRef<number | null>(null);
580
676
 
581
- const scrollDrawerBodyToTop = () => {
582
- if (typeof document === "undefined") return;
583
-
584
- window.requestAnimationFrame(() => {
585
- const drawerBody = document.querySelector<HTMLDivElement>(".sdix-drawer-body");
586
- drawerBody?.scrollTo({ top: 0, left: 0 });
587
- });
588
- };
589
-
590
677
  const [
591
678
  previewMapping,
592
679
  { isLoading: isPreviewMappingLoading },
@@ -596,8 +683,21 @@ export function DatasourceIntrospectionPage() {
596
683
  applyMapping,
597
684
  { isLoading: isApplyMappingLoading },
598
685
  ] = useApplyDatasourceIntrospectionMappingMutation();
686
+ const [
687
+ createMigrationArtifacts,
688
+ { isLoading: isCreateMigrationArtifactsLoading },
689
+ ] = useCreateDatasourceIntrospectionMigrationArtifactsMutation();
690
+ const [
691
+ generateCode,
692
+ { isLoading: isGenerateCodeLoading },
693
+ ] = useGenerateDatasourceIntrospectionCodeMutation();
694
+ const [
695
+ runMigration,
696
+ { isLoading: isRunMigrationLoading },
697
+ ] = useRunDatasourceIntrospectionMigrationMutation();
599
698
 
600
699
  const isSavingMapping = isApplyMappingLoading;
700
+ const isCreatingMigrationArtifacts = isCreateMigrationArtifactsLoading;
601
701
 
602
702
  useEffect(() => {
603
703
  if (!bootstrap) return;
@@ -608,13 +708,22 @@ export function DatasourceIntrospectionPage() {
608
708
  }, [bootstrap, selectedDatasource]);
609
709
 
610
710
  useEffect(() => {
611
- setSelectedTableKey("");
711
+ setSelectedRows([]);
712
+ setWorkspaceTableKey("");
612
713
  setDrawerDraft(null);
613
- setDrawerOpen(false);
614
714
  setTableSearch("");
615
- setDrawerStep("edit");
616
- setReviewTab("metadata-json");
715
+ setWorkspaceStep("configure");
617
716
  setMappingPreview(null);
717
+ setPersistedMappingResult(null);
718
+ setMigrationArtifactsResult(null);
719
+ setGenerateCodeOutput("");
720
+ setIsGeneratingCodeWorkflow(false);
721
+ setGenerateCodeStatusMessage("");
722
+ setGenerateCodeTimeoutMessage(null);
723
+ setGenerateCodeReady(false);
724
+ setHasAttemptedGenerateCode(false);
725
+ setRunMigrationOutput("");
726
+ setRunMigrationCompleted(false);
618
727
  setReviewedMetadataJsonValue(null);
619
728
  setMetadataJsonText("");
620
729
  setMetadataJsonValidationError(null);
@@ -627,11 +736,6 @@ export function DatasourceIntrospectionPage() {
627
736
  }
628
737
  }, []);
629
738
 
630
- useEffect(() => {
631
- if (!drawerOpen) return;
632
- scrollDrawerBodyToTop();
633
- }, [drawerOpen, drawerStep, drawerTab, reviewTab, selectedTableKey]);
634
-
635
739
  const datasourceOptions = useMemo(
636
740
  () => (bootstrap?.datasources ?? []).map((datasource) => ({
637
741
  label: `${datasource.displayName} (${providerLabel(datasource.type)})`,
@@ -653,9 +757,13 @@ export function DatasourceIntrospectionPage() {
653
757
  },
654
758
  );
655
759
 
760
+ const selectedListRow = selectedRows[0] ?? null;
761
+ const selectedListRowKey = selectedListRow ? `${selectedListRow.schema ?? ""}::${selectedListRow.tableName}` : "";
762
+ const isWorkspaceMode = Boolean(workspaceTableKey);
763
+
656
764
  const selectedTable = useMemo(
657
- () => tablesResponse?.records?.find((record) => `${record.schema ?? ""}::${record.tableName}` === selectedTableKey) ?? null,
658
- [tablesResponse, selectedTableKey],
765
+ () => tablesResponse?.records?.find((record) => `${record.schema ?? ""}::${record.tableName}` === workspaceTableKey) ?? null,
766
+ [tablesResponse, workspaceTableKey],
659
767
  );
660
768
 
661
769
  const {
@@ -672,7 +780,7 @@ export function DatasourceIntrospectionPage() {
672
780
  schema: selectedTable?.schema ?? undefined,
673
781
  },
674
782
  {
675
- skip: !drawerOpen || !isValidModuleId || !selectedDatasource || !selectedTable || !!tablesResponse?.synchronizeBlocked,
783
+ skip: !isWorkspaceMode || !isValidModuleId || !selectedDatasource || !selectedTable || !!tablesResponse?.synchronizeBlocked,
676
784
  },
677
785
  );
678
786
 
@@ -682,7 +790,7 @@ export function DatasourceIntrospectionPage() {
682
790
  isFetching: isMappedModelFetching,
683
791
  error: mappedModelError,
684
792
  } = useGetmodelByIdQuery(selectedTable?.mappedModelId ?? 0, {
685
- skip: !drawerOpen || !selectedTable?.mapped || !selectedTable?.mappedModelId,
793
+ skip: !isWorkspaceMode || !selectedTable?.mapped || !selectedTable?.mappedModelId,
686
794
  });
687
795
 
688
796
  const mappedModelData = mappedModelResponse?.data;
@@ -700,7 +808,43 @@ export function DatasourceIntrospectionPage() {
700
808
  );
701
809
 
702
810
  useEffect(() => {
703
- if (!drawerOpen || !selectedTable || !tableDetail) return;
811
+ if (!isWorkspaceMode) {
812
+ setDrawerDraft(null);
813
+ return;
814
+ }
815
+
816
+ if (drawerBootstrapTimerRef.current) {
817
+ window.clearTimeout(drawerBootstrapTimerRef.current);
818
+ }
819
+
820
+ setDrawerDraft(null);
821
+ setDrawerTab("general-info");
822
+ setWorkspaceStep("configure");
823
+ setMappingPreview(null);
824
+ setPersistedMappingResult(null);
825
+ setMigrationArtifactsResult(null);
826
+ setGenerateCodeOutput("");
827
+ setIsGeneratingCodeWorkflow(false);
828
+ setGenerateCodeStatusMessage("");
829
+ setGenerateCodeTimeoutMessage(null);
830
+ setGenerateCodeReady(false);
831
+ setHasAttemptedGenerateCode(false);
832
+ setRunMigrationOutput("");
833
+ setRunMigrationCompleted(false);
834
+ setReviewedMetadataJsonValue(null);
835
+ setMetadataJsonText("");
836
+ setMetadataJsonValidationError(null);
837
+ setMetadataJsonResetToken(`table-${workspaceTableKey}-${Date.now()}`);
838
+ setDrawerBootstrapping(true);
839
+ }, [isWorkspaceMode, workspaceTableKey]);
840
+
841
+ useEffect(() => {
842
+ if (!isWorkspaceMode || !selectedTable) return;
843
+ setSelectedRows([selectedTable]);
844
+ }, [isWorkspaceMode, selectedTable]);
845
+
846
+ useEffect(() => {
847
+ if (!isWorkspaceMode || !selectedTable || !tableDetail) return;
704
848
  if (selectedTable.mapped && (!mappedModelData || mappedModelData.id !== selectedTable.mappedModelId)) return;
705
849
 
706
850
  if (drawerBootstrapTimerRef.current) {
@@ -715,7 +859,7 @@ export function DatasourceIntrospectionPage() {
715
859
  drawerBootstrapTimerRef.current = window.setTimeout(() => {
716
860
  setDrawerBootstrapping(false);
717
861
  }, 150);
718
- }, [drawerOpen, selectedTable, tableDetail, mappedModelData, mappedModelResponse]);
862
+ }, [isWorkspaceMode, selectedTable, tableDetail, mappedModelData, mappedModelResponse]);
719
863
 
720
864
  const filteredRecords = useMemo(() => {
721
865
  const records = [...(tablesResponse?.records ?? [])];
@@ -723,7 +867,7 @@ export function DatasourceIntrospectionPage() {
723
867
 
724
868
  const filtered = searchNeedle
725
869
  ? records.filter((record) => {
726
- const haystack = `${record.tableName} ${record.schema ?? ""} ${record.mappedModelSingularName ?? ""} ${record.mappedModelDisplayName ?? ""}`.toLowerCase();
870
+ const haystack = `${record.tableName} ${record.schema ?? ""} ${record.mappedModelSingularName ?? ""} ${record.mappedModelDisplayName ?? ""} ${record.mappedModuleName ?? ""} ${record.mappedModuleDisplayName ?? ""}`.toLowerCase();
727
871
  return haystack.includes(searchNeedle);
728
872
  })
729
873
  : records;
@@ -848,28 +992,45 @@ export function DatasourceIntrospectionPage() {
848
992
  if (selectedDatasource) {
849
993
  await refetchTables();
850
994
  }
851
- if (selectedTable) {
995
+ if (isWorkspaceMode && selectedTable) {
852
996
  await refetchTableDetail();
853
997
  }
854
998
  };
855
999
 
856
- const openTableDrawer = (record: DatasourceIntrospectionTableRecord) => {
1000
+ const startMappingForRecord = (record: DatasourceIntrospectionTableRecord) => {
857
1001
  if (drawerBootstrapTimerRef.current) {
858
1002
  window.clearTimeout(drawerBootstrapTimerRef.current);
859
1003
  }
860
1004
 
861
- setSelectedTableKey(`${record.schema ?? ""}::${record.tableName}`);
1005
+ setSelectedRows([record]);
1006
+ setWorkspaceTableKey(`${record.schema ?? ""}::${record.tableName}`);
1007
+ };
1008
+
1009
+ const leaveWorkspace = () => {
1010
+ if (drawerBootstrapTimerRef.current) {
1011
+ window.clearTimeout(drawerBootstrapTimerRef.current);
1012
+ }
1013
+
1014
+ setWorkspaceTableKey("");
862
1015
  setDrawerDraft(null);
1016
+ setWorkspaceStep("configure");
863
1017
  setDrawerTab("general-info");
864
- setDrawerStep("edit");
865
- setReviewTab("metadata-json");
866
1018
  setMappingPreview(null);
1019
+ setPersistedMappingResult(null);
1020
+ setMigrationArtifactsResult(null);
1021
+ setGenerateCodeOutput("");
1022
+ setIsGeneratingCodeWorkflow(false);
1023
+ setGenerateCodeStatusMessage("");
1024
+ setGenerateCodeTimeoutMessage(null);
1025
+ setGenerateCodeReady(false);
1026
+ setHasAttemptedGenerateCode(false);
1027
+ setRunMigrationOutput("");
1028
+ setRunMigrationCompleted(false);
867
1029
  setReviewedMetadataJsonValue(null);
868
1030
  setMetadataJsonText("");
869
1031
  setMetadataJsonValidationError(null);
870
- setMetadataJsonResetToken(`table-${record.schema ?? "default"}-${record.tableName}-${Date.now()}`);
871
- setDrawerBootstrapping(true);
872
- setDrawerOpen(true);
1032
+ setMetadataJsonResetToken(`workspace-closed-${Date.now()}`);
1033
+ setDrawerBootstrapping(false);
873
1034
  };
874
1035
 
875
1036
  const applyDraftSettings = () => {
@@ -879,6 +1040,15 @@ export function DatasourceIntrospectionPage() {
879
1040
 
880
1041
  const updateDrawerDraft = (updater: (current: DrawerDraft) => DrawerDraft) => {
881
1042
  setMappingPreview(null);
1043
+ setPersistedMappingResult(null);
1044
+ setMigrationArtifactsResult(null);
1045
+ setGenerateCodeOutput("");
1046
+ setIsGeneratingCodeWorkflow(false);
1047
+ setGenerateCodeStatusMessage("");
1048
+ setGenerateCodeTimeoutMessage(null);
1049
+ setGenerateCodeReady(false);
1050
+ setHasAttemptedGenerateCode(false);
1051
+ setRunMigrationOutput("");
882
1052
  setDrawerDraft((current) => (current ? updater(current) : current));
883
1053
  };
884
1054
 
@@ -891,7 +1061,16 @@ export function DatasourceIntrospectionPage() {
891
1061
  ...current,
892
1062
  columns: current.columns.map((column) => {
893
1063
  if (column.columnName !== columnName) return column;
894
- return { ...column, fieldName: camelCase(nextFieldName) };
1064
+
1065
+ const previousSuggestedLabel = startCase(column.fieldName);
1066
+ const nextNormalizedFieldName = camelCase(nextFieldName);
1067
+ return {
1068
+ ...column,
1069
+ fieldName: nextNormalizedFieldName,
1070
+ displayName: !column.displayName.trim() || column.displayName === previousSuggestedLabel
1071
+ ? startCase(nextNormalizedFieldName)
1072
+ : column.displayName,
1073
+ };
895
1074
  }),
896
1075
  userKeyField: current.userKeyField === current.columns.find((column) => column.columnName === columnName)?.fieldName
897
1076
  ? camelCase(nextFieldName)
@@ -899,6 +1078,17 @@ export function DatasourceIntrospectionPage() {
899
1078
  }));
900
1079
  };
901
1080
 
1081
+ const updateColumnDisplayName = (columnName: string, nextDisplayName: string) => {
1082
+ updateDrawerDraft((current) => ({
1083
+ ...current,
1084
+ columns: current.columns.map((column) => (
1085
+ column.columnName === columnName
1086
+ ? { ...column, displayName: nextDisplayName }
1087
+ : column
1088
+ )),
1089
+ }));
1090
+ };
1091
+
902
1092
  const updateColumnSolidFieldType = (columnName: string, nextSolidFieldType: string) => {
903
1093
  updateDrawerDraft((current) => ({
904
1094
  ...current,
@@ -915,6 +1105,55 @@ export function DatasourceIntrospectionPage() {
915
1105
  }));
916
1106
  };
917
1107
 
1108
+ const updateLegacyTableType = (legacyTableType: "none" | "existing_id" | "generated_id") => {
1109
+ updateDrawerDraft((current) => {
1110
+ const renamedUserKeyColumns = new Map<string, string>();
1111
+
1112
+ const columns = current.columns.map((column) => {
1113
+ const nextSuperclassFieldName = getSuperclassFieldNameForLegacyType(column.columnName, legacyTableType);
1114
+ const nextHandledBySuperclass = Boolean(nextSuperclassFieldName);
1115
+ const nextSuggestedFieldName = getSuggestedFieldNameForLegacyType(column, legacyTableType);
1116
+ const shouldRebuildFieldName = column.handledBySuperclass !== nextHandledBySuperclass
1117
+ || (legacyTableType === "existing_id" && column.isAutoGenerated && (column.fieldName === "id" || column.fieldName === "legacyId"))
1118
+ || (legacyTableType === "generated_id" && column.columnName.toLowerCase() === "id");
1119
+ const nextFieldName = shouldRebuildFieldName ? nextSuggestedFieldName : column.fieldName;
1120
+ const nextDisplayName = !column.displayName.trim() || column.displayName === startCase(column.fieldName)
1121
+ ? startCase(nextFieldName)
1122
+ : column.displayName;
1123
+ const nextInclude = nextHandledBySuperclass
1124
+ ? false
1125
+ : (legacyTableType === "existing_id" && column.isAutoGenerated ? true : column.include);
1126
+ const nextIsPrimaryKey = (
1127
+ legacyTableType === "existing_id" && column.isAutoGenerated && nextFieldName === "id"
1128
+ ) || (
1129
+ legacyTableType === "generated_id" && column.isDetectedPrimaryKey
1130
+ );
1131
+
1132
+ if (current.userKeyField === column.fieldName && current.userKeyField !== nextFieldName) {
1133
+ renamedUserKeyColumns.set(column.fieldName, nextFieldName);
1134
+ }
1135
+
1136
+ return {
1137
+ ...column,
1138
+ fieldName: nextFieldName,
1139
+ displayName: nextDisplayName,
1140
+ handledBySuperclass: nextHandledBySuperclass,
1141
+ superclassFieldName: nextSuperclassFieldName,
1142
+ include: nextInclude,
1143
+ isPrimaryKey: nextIsPrimaryKey,
1144
+ };
1145
+ });
1146
+
1147
+ return {
1148
+ ...current,
1149
+ legacyTableType,
1150
+ baseClassName: getBaseClassNameForLegacyType(legacyTableType),
1151
+ columns,
1152
+ userKeyField: renamedUserKeyColumns.get(current.userKeyField) ?? current.userKeyField,
1153
+ };
1154
+ });
1155
+ };
1156
+
918
1157
  const setColumnIncluded = (columnName: string, include: boolean) => {
919
1158
  updateDrawerDraft((current) => ({
920
1159
  ...current,
@@ -956,7 +1195,7 @@ export function DatasourceIntrospectionPage() {
956
1195
  window.open(`/admin/core/solid-core/model-metadata/form/${targetModelId}`, "_blank", "noopener,noreferrer");
957
1196
  };
958
1197
 
959
- const viewChanges = async () => {
1198
+ const reviewMappingJson = async () => {
960
1199
  if (!drawerDraft || !bootstrap?.module?.id) return;
961
1200
 
962
1201
  const validationErrors = getDrawerValidationErrors(drawerDraft);
@@ -978,8 +1217,11 @@ export function DatasourceIntrospectionPage() {
978
1217
  setMetadataJsonText(JSON.stringify(preview.metadataJson.model, null, 2));
979
1218
  setMetadataJsonValidationError(null);
980
1219
  setMetadataJsonResetToken(`preview-${preview.metadataJson.filePath}-${Date.now()}`);
981
- setReviewTab("metadata-json");
982
- setDrawerStep("review");
1220
+ setPersistedMappingResult(null);
1221
+ setMigrationArtifactsResult(null);
1222
+ setGenerateCodeOutput("");
1223
+ setRunMigrationOutput("");
1224
+ setWorkspaceStep("review-json");
983
1225
  } catch (error: any) {
984
1226
  dispatch(showToast({
985
1227
  severity: "error",
@@ -989,7 +1231,7 @@ export function DatasourceIntrospectionPage() {
989
1231
  }
990
1232
  };
991
1233
 
992
- const saveMapping = async () => {
1234
+ const persistMappingArtifacts = async () => {
993
1235
  if (!drawerDraft || !bootstrap?.module?.id) return;
994
1236
 
995
1237
  const validationErrors = getDrawerValidationErrors(drawerDraft);
@@ -997,15 +1239,14 @@ export function DatasourceIntrospectionPage() {
997
1239
  validationErrors.forEach((detail) => {
998
1240
  dispatch(showToast({ severity: "error", summary: "Validation", detail }));
999
1241
  });
1000
- setDrawerStep("edit");
1242
+ setWorkspaceStep("configure");
1001
1243
  return;
1002
1244
  }
1003
1245
 
1004
1246
  const reviewedModelValidation = parseAndValidateReviewedModelJson(metadataJsonText, drawerDraft);
1005
1247
  if (reviewedModelValidation.error || !reviewedModelValidation.parsed) {
1006
1248
  setMetadataJsonValidationError(reviewedModelValidation.error ?? "Metadata JSON is invalid.");
1007
- setReviewTab("metadata-json");
1008
- setDrawerStep("review");
1249
+ setWorkspaceStep("review-json");
1009
1250
  dispatch(showToast({
1010
1251
  severity: "error",
1011
1252
  summary: "Validation",
@@ -1027,28 +1268,179 @@ export function DatasourceIntrospectionPage() {
1027
1268
 
1028
1269
  dispatch(showToast({
1029
1270
  severity: "success",
1030
- summary: "Saved",
1271
+ summary: "Mapping saved",
1272
+ detail: drawerDraft.mapped
1273
+ ? "The model mapping metadata was updated successfully."
1274
+ : "The model mapping metadata was created successfully.",
1275
+ }));
1276
+
1277
+ setPersistedMappingResult(response);
1278
+ setMigrationArtifactsResult(null);
1279
+ setGenerateCodeOutput("");
1280
+ setIsGeneratingCodeWorkflow(false);
1281
+ setGenerateCodeStatusMessage("");
1282
+ setGenerateCodeTimeoutMessage(null);
1283
+ setGenerateCodeReady(false);
1284
+ setHasAttemptedGenerateCode(false);
1285
+ setRunMigrationOutput("");
1286
+ setRunMigrationCompleted(false);
1287
+ setDrawerDraft((current) => (
1288
+ current
1289
+ ? {
1290
+ ...current,
1291
+ mapped: true,
1292
+ modelId: response.modelId,
1293
+ }
1294
+ : current
1295
+ ));
1296
+ setWorkspaceStep("generate-code");
1297
+ } catch (error: any) {
1298
+ dispatch(showToast({
1299
+ severity: "error",
1300
+ summary: "Save failed",
1301
+ detail: readQueryError(error),
1302
+ }));
1303
+ }
1304
+ };
1305
+
1306
+ const handleGenerateCode = async () => {
1307
+ if (!bootstrap?.module?.id) return;
1308
+
1309
+ setHasAttemptedGenerateCode(true);
1310
+ setRunMigrationCompleted(false);
1311
+ setIsGeneratingCodeWorkflow(true);
1312
+ setGenerateCodeStatusMessage("Submitting module generate-code request...");
1313
+ setGenerateCodeTimeoutMessage(null);
1314
+ setGenerateCodeReady(false);
1315
+ let responseMessage = "";
1316
+
1317
+ try {
1318
+ const response = await generateCode({ moduleId: bootstrap.module.id }).unwrap();
1319
+ responseMessage = response.output || response.message || "";
1320
+ setGenerateCodeOutput(responseMessage);
1321
+ setGenerateCodeStatusMessage("Waiting briefly for the backend restart window...");
1322
+ } catch (error: any) {
1323
+ if (!isRecoverableGenerateCodeError(error)) {
1324
+ setIsGeneratingCodeWorkflow(false);
1325
+ setGenerateCodeStatusMessage("");
1326
+ setGenerateCodeTimeoutMessage(null);
1327
+ setGenerateCodeReady(false);
1328
+ dispatch(showToast({
1329
+ severity: "error",
1330
+ summary: "Generate code failed",
1331
+ detail: readQueryError(error),
1332
+ }));
1333
+ return;
1334
+ }
1335
+
1336
+ setGenerateCodeStatusMessage("The API connection dropped during restart. Waiting for the backend to come back online...");
1337
+ }
1338
+
1339
+ await new Promise((resolve) => window.setTimeout(resolve, 5000));
1340
+ setGenerateCodeStatusMessage("Checking if the backend is back online...");
1341
+
1342
+ const isBackendAvailable = await waitForBackendAvailability({
1343
+ retries: 40,
1344
+ delayMs: 1500,
1345
+ });
1346
+
1347
+ setIsGeneratingCodeWorkflow(false);
1348
+
1349
+ if (!isBackendAvailable) {
1350
+ setGenerateCodeTimeoutMessage(
1351
+ "Code generation took longer than expected. The backend did not come back within 60 seconds, so there may be a compilation failure or another startup issue. Please review the generated code manually and check the API logs before continuing.",
1352
+ );
1353
+ dispatch(showToast({
1354
+ severity: "warn",
1355
+ summary: "Backend restart taking too long",
1356
+ detail: "The generate-code request completed, but the backend did not come back within 60 seconds.",
1357
+ }));
1358
+ return;
1359
+ }
1360
+
1361
+ setGenerateCodeStatusMessage("Backend is back online. You can continue.");
1362
+ setGenerateCodeReady(true);
1363
+ setMigrationArtifactsResult(null);
1364
+ setRunMigrationOutput("");
1365
+ dispatch(showToast({
1366
+ severity: "success",
1367
+ summary: "Code generated",
1368
+ detail: responseMessage || "The backend is back online. You can continue to the migration artifacts step.",
1369
+ }));
1370
+ };
1371
+
1372
+ const handleCreateMigrationArtifacts = async () => {
1373
+ if (!drawerDraft || !bootstrap?.module?.id || !persistedMappingResult?.modelId) return;
1374
+
1375
+ const reviewedModelValidation = parseAndValidateReviewedModelJson(metadataJsonText, drawerDraft);
1376
+ if (reviewedModelValidation.error || !reviewedModelValidation.parsed) {
1377
+ setMetadataJsonValidationError(reviewedModelValidation.error ?? "Metadata JSON is invalid.");
1378
+ setWorkspaceStep("review-json");
1379
+ dispatch(showToast({
1380
+ severity: "error",
1381
+ summary: "Validation",
1382
+ detail: reviewedModelValidation.error ?? "Metadata JSON is invalid.",
1383
+ }));
1384
+ return;
1385
+ }
1386
+
1387
+ try {
1388
+ const response = await createMigrationArtifacts({
1389
+ moduleId: bootstrap.module.id,
1390
+ payload: {
1391
+ ...buildMappingRequest(
1392
+ {
1393
+ ...drawerDraft,
1394
+ mapped: true,
1395
+ modelId: persistedMappingResult.modelId,
1396
+ },
1397
+ mappingPreview?.migration.timestamp ?? null,
1398
+ ),
1399
+ reviewedModel: reviewedModelValidation.parsed,
1400
+ },
1401
+ }).unwrap();
1402
+
1403
+ setMigrationArtifactsResult(response);
1404
+ setWorkspaceStep("run-migration");
1405
+ dispatch(showToast({
1406
+ severity: "success",
1407
+ summary: "Migration artifacts created",
1031
1408
  detail: response.migration.written
1032
- ? "The mapping, metadata JSON, and migration template were written successfully."
1033
- : drawerDraft.mapped
1034
- ? "The model mapping was updated and written back to metadata JSON."
1035
- : "The model mapping was created and written to metadata JSON.",
1409
+ ? "The migration file and datasource registration were written successfully."
1410
+ : "No migration file was required, but the datasource registration was updated successfully.",
1411
+ }));
1412
+ } catch (error: any) {
1413
+ dispatch(showToast({
1414
+ severity: "error",
1415
+ summary: "Create migration artifacts failed",
1416
+ detail: readQueryError(error),
1417
+ }));
1418
+ }
1419
+ };
1420
+
1421
+ const handleRunMigration = async () => {
1422
+ if (!bootstrap?.module?.id || !selectedDatasource) return;
1423
+
1424
+ try {
1425
+ const response = await runMigration({
1426
+ moduleId: bootstrap.module.id,
1427
+ datasource: selectedDatasource,
1428
+ }).unwrap();
1429
+
1430
+ setRunMigrationOutput(response.output || response.message || "");
1431
+ setRunMigrationCompleted(true);
1432
+ dispatch(showToast({
1433
+ severity: "success",
1434
+ summary: "Migration complete",
1435
+ detail: response.message || `Migrations ran successfully for datasource "${selectedDatasource}".`,
1036
1436
  }));
1037
1437
 
1038
- setDrawerOpen(false);
1039
- setDrawerDraft(null);
1040
- setMappingPreview(null);
1041
- setReviewedMetadataJsonValue(null);
1042
- setMetadataJsonText("");
1043
- setMetadataJsonValidationError(null);
1044
- setMetadataJsonResetToken(`saved-${Date.now()}`);
1045
- setDrawerStep("edit");
1046
1438
  await refetchTables();
1047
1439
  await refetchBootstrap();
1048
1440
  } catch (error: any) {
1049
1441
  dispatch(showToast({
1050
1442
  severity: "error",
1051
- summary: "Save failed",
1443
+ summary: "Run migration failed",
1052
1444
  detail: readQueryError(error),
1053
1445
  }));
1054
1446
  }
@@ -1066,6 +1458,65 @@ export function DatasourceIntrospectionPage() {
1066
1458
  );
1067
1459
  }
1068
1460
 
1461
+ const stepSequence: WorkspaceStep[] = [
1462
+ "configure",
1463
+ "review-json",
1464
+ "generate-code",
1465
+ "create-migrations",
1466
+ "run-migration",
1467
+ ];
1468
+ const currentStepIndex = stepSequence.indexOf(workspaceStep);
1469
+ const stepperItems = [
1470
+ {
1471
+ key: "configure" as const,
1472
+ label: "Configure Mapping",
1473
+ complete: currentStepIndex > 0,
1474
+ active: workspaceStep === "configure",
1475
+ disabled: false,
1476
+ onClick: () => setWorkspaceStep("configure"),
1477
+ },
1478
+ {
1479
+ key: "review-json" as const,
1480
+ label: "Review Mapping JSON",
1481
+ complete: currentStepIndex > 1,
1482
+ active: workspaceStep === "review-json",
1483
+ disabled: !mappingPreview,
1484
+ onClick: () => {
1485
+ if (mappingPreview) setWorkspaceStep("review-json");
1486
+ },
1487
+ },
1488
+ {
1489
+ key: "generate-code" as const,
1490
+ label: "Generate Code",
1491
+ complete: currentStepIndex > 2,
1492
+ active: workspaceStep === "generate-code",
1493
+ disabled: !persistedMappingResult,
1494
+ onClick: () => {
1495
+ if (persistedMappingResult) setWorkspaceStep("generate-code");
1496
+ },
1497
+ },
1498
+ {
1499
+ key: "create-migrations" as const,
1500
+ label: "Create Migrations",
1501
+ complete: currentStepIndex > 3,
1502
+ active: workspaceStep === "create-migrations",
1503
+ disabled: !hasAttemptedGenerateCode,
1504
+ onClick: () => {
1505
+ if (hasAttemptedGenerateCode) setWorkspaceStep("create-migrations");
1506
+ },
1507
+ },
1508
+ {
1509
+ key: "run-migration" as const,
1510
+ label: "Run Migration",
1511
+ complete: false,
1512
+ active: workspaceStep === "run-migration",
1513
+ disabled: !migrationArtifactsResult,
1514
+ onClick: () => {
1515
+ if (migrationArtifactsResult) setWorkspaceStep("run-migration");
1516
+ },
1517
+ },
1518
+ ];
1519
+
1069
1520
  const selectableUnmappedColumns = drawerDraft?.columns.filter(
1070
1521
  (column) => !column.handledBySuperclass && !column.matched && !column.isPrimaryKey,
1071
1522
  ) ?? [];
@@ -1107,19 +1558,20 @@ export function DatasourceIntrospectionPage() {
1107
1558
  </div>
1108
1559
  <div className="sdix-form-field">
1109
1560
  <label htmlFor="sdix-user-key-field">User Key Field</label>
1110
- <SolidSelect
1111
- id="sdix-user-key-field"
1112
- value={drawerDraft.userKeyField}
1113
- options={drawerUserKeyOptions}
1114
- placeholder="Select user key field"
1561
+ <SolidSelect
1562
+ id="sdix-user-key-field"
1563
+ value={drawerDraft.userKeyField}
1564
+ options={drawerUserKeyOptions}
1565
+ placeholder="Select user key field"
1115
1566
  onChange={(event) => changeUserKeyField(event.value)}
1116
1567
  />
1117
1568
  </div>
1118
1569
  <div className="sdix-form-field sdix-form-field--full">
1119
1570
  <label htmlFor="sdix-description">Description</label>
1120
1571
  <SolidTextarea
1572
+ className="sdix-description-textarea"
1121
1573
  id="sdix-description"
1122
- rows={3}
1574
+ rows={2}
1123
1575
  value={drawerDraft.description}
1124
1576
  onChange={(event) => updateGeneralField("description", event.target.value)}
1125
1577
  />
@@ -1163,20 +1615,16 @@ export function DatasourceIntrospectionPage() {
1163
1615
  />
1164
1616
  </div>
1165
1617
  <div className="sdix-form-field">
1166
- <label htmlFor="sdix-legacy-type">Legacy Strategy</label>
1167
- <SolidInput
1618
+ <label htmlFor="sdix-legacy-type">Mapping Strategy</label>
1619
+ <SolidSelect
1168
1620
  id="sdix-legacy-type"
1169
- value={legacyTypeLabel(drawerDraft.legacyTableType)}
1170
- disabled
1171
- />
1172
- </div>
1173
- <div className="sdix-form-field">
1174
- <label htmlFor="sdix-base-class">Superclass</label>
1175
- <SolidInput
1176
- id="sdix-base-class"
1177
- value={drawerDraft.baseClassName}
1178
- disabled
1621
+ value={drawerDraft.legacyTableType}
1622
+ options={mappingStrategyOptions}
1623
+ onChange={(event) => updateLegacyTableType(event.value)}
1179
1624
  />
1625
+ <small className="sdix-inline-note">
1626
+ This will use <strong>{drawerDraft.baseClassName}</strong> for the generated entity.
1627
+ </small>
1180
1628
  </div>
1181
1629
  </div>
1182
1630
  </section>
@@ -1196,10 +1644,6 @@ export function DatasourceIntrospectionPage() {
1196
1644
  </div>
1197
1645
  <div className="sdix-column-table">
1198
1646
  <div className="sdix-column-row sdix-column-row--head sdix-column-row--mapping">
1199
- <span>Column</span>
1200
- <span>Field</span>
1201
- <span>Database</span>
1202
- <span>SolidX</span>
1203
1647
  <span className="sdix-column-select-header">
1204
1648
  {selectableUnmappedColumns.length ? (
1205
1649
  <SolidCheckbox
@@ -1211,11 +1655,17 @@ export function DatasourceIntrospectionPage() {
1211
1655
  "Include"
1212
1656
  )}
1213
1657
  </span>
1658
+ <span>Column</span>
1659
+ <span>Field</span>
1660
+ <span>Label</span>
1661
+ <span>Database</span>
1662
+ <span>SolidX</span>
1214
1663
  <span>Status</span>
1215
1664
  <span>Action</span>
1216
1665
  </div>
1217
1666
  {drawerDraft.columns.map((column) => {
1218
1667
  const isUserKey = drawerDraft.userKeyField === column.fieldName;
1668
+ const isPrimaryKeyField = column.isPrimaryKey;
1219
1669
  const statusClassName = column.handledBySuperclass
1220
1670
  ? "is-superclass"
1221
1671
  : column.include
@@ -1236,6 +1686,20 @@ export function DatasourceIntrospectionPage() {
1236
1686
 
1237
1687
  return (
1238
1688
  <div key={column.columnName} className="sdix-column-row sdix-column-row--mapping">
1689
+ <span className="sdix-column-include">
1690
+ {column.handledBySuperclass ? (
1691
+ <span className="sdix-column-placeholder">-</span>
1692
+ ) : column.matched ? (
1693
+ <span className="sdix-column-placeholder">-</span>
1694
+ ) : column.isPrimaryKey ? (
1695
+ <SolidCheckbox checked disabled aria-label="Required included column" />
1696
+ ) : (
1697
+ <SolidCheckbox
1698
+ checked={column.include}
1699
+ onChange={(event) => setColumnIncluded(column.columnName, event.target.checked)}
1700
+ />
1701
+ )}
1702
+ </span>
1239
1703
  <span className="sdix-column-meta">
1240
1704
  <strong>{column.columnName}</strong>
1241
1705
  {column.isAutoGenerated ? <small>Generated id column</small> : null}
@@ -1246,7 +1710,19 @@ export function DatasourceIntrospectionPage() {
1246
1710
  disabled={column.handledBySuperclass}
1247
1711
  onChange={(event) => updateColumnFieldName(column.columnName, event.target.value)}
1248
1712
  />
1249
- {isUserKey ? <small className="sdix-inline-note">User key</small> : null}
1713
+ {isUserKey || isPrimaryKeyField ? (
1714
+ <div className="sdix-inline-note-stack">
1715
+ {isUserKey ? <small className="sdix-inline-note">User key</small> : null}
1716
+ {isPrimaryKeyField ? <small className="sdix-inline-note">Primary key</small> : null}
1717
+ </div>
1718
+ ) : null}
1719
+ </span>
1720
+ <span>
1721
+ <SolidInput
1722
+ value={column.displayName}
1723
+ disabled={column.handledBySuperclass}
1724
+ onChange={(event) => updateColumnDisplayName(column.columnName, event.target.value)}
1725
+ />
1250
1726
  </span>
1251
1727
  <span className="sdix-column-meta">
1252
1728
  <strong>{column.dataType}</strong>
@@ -1262,30 +1738,16 @@ export function DatasourceIntrospectionPage() {
1262
1738
  />
1263
1739
  )}
1264
1740
  </span>
1265
- <span className="sdix-column-include">
1266
- {column.handledBySuperclass ? (
1267
- <span className="sdix-column-placeholder">-</span>
1268
- ) : column.matched ? (
1269
- <span className="sdix-column-placeholder">-</span>
1270
- ) : column.isPrimaryKey ? (
1271
- <SolidCheckbox checked disabled label="Required" />
1272
- ) : (
1273
- <SolidCheckbox
1274
- checked={column.include}
1275
- onChange={(event) => setColumnIncluded(column.columnName, event.target.checked)}
1276
- />
1277
- )}
1278
- </span>
1279
1741
  <span>
1280
1742
  <span className={`sdix-status-badge ${statusClassName}`}>{statusText}</span>
1281
1743
  </span>
1282
1744
  <span className="sdix-column-action">
1283
1745
  {column.handledBySuperclass ? (
1284
- <SolidButton size="small" variant="outline" disabled>
1746
+ <SolidButton size="small" variant="outline" disabled className="sdix-column-action-chip sdix-column-action-chip--managed">
1285
1747
  Managed
1286
1748
  </SolidButton>
1287
1749
  ) : column.isPrimaryKey ? (
1288
- <SolidButton size="small" variant="outline" disabled>
1750
+ <SolidButton size="small" variant="outline" disabled className="sdix-column-action-chip sdix-column-action-chip--required">
1289
1751
  Required
1290
1752
  </SolidButton>
1291
1753
  ) : column.matched ? (
@@ -1321,120 +1783,223 @@ export function DatasourceIntrospectionPage() {
1321
1783
  },
1322
1784
  ] : [];
1323
1785
 
1324
- const reviewTabs = mappingPreview ? [
1325
- {
1326
- value: "metadata-json",
1327
- label: "Metadata JSON",
1328
- content: (
1329
- <div className="sdix-review-panel sdix-review-panel--metadata">
1786
+ const reviewJsonPanel = mappingPreview ? (
1787
+ <div className="sdix-review-panel sdix-review-panel--metadata">
1788
+ <div className="sdix-review-meta sdix-review-meta--compact">
1789
+ <span>Target file</span>
1790
+ <strong>{mappingPreview.metadataJson.filePath}</strong>
1791
+ </div>
1792
+ <SolidJsonEditor
1793
+ className="sdix-json-editor"
1794
+ value={reviewedMetadataJsonValue ?? mappingPreview.metadataJson.model}
1795
+ resetToken={metadataJsonResetToken}
1796
+ onValueChange={(nextValue) => {
1797
+ setReviewedMetadataJsonValue(nextValue);
1798
+ if (metadataJsonValidationError) {
1799
+ setMetadataJsonValidationError(null);
1800
+ }
1801
+ }}
1802
+ onTextChange={(nextText) => {
1803
+ setMetadataJsonText(nextText);
1804
+ }}
1805
+ onErrorChange={setMetadataJsonValidationError}
1806
+ />
1807
+ {metadataJsonValidationError ? (
1808
+ <div className="sdix-json-validation-error">
1809
+ <span>{metadataJsonValidationError}</span>
1810
+ </div>
1811
+ ) : null}
1812
+ </div>
1813
+ ) : null;
1814
+
1815
+ const createMigrationsPanel = mappingPreview ? (
1816
+ <div className="sdix-review-panel sdix-review-panel--migration">
1817
+ {mappingPreview.migration.willGenerate && mappingPreview.migration.filePath ? (
1818
+ <>
1330
1819
  <div className="sdix-review-meta sdix-review-meta--compact">
1331
1820
  <span>Target file</span>
1332
- <strong>{mappingPreview.metadataJson.filePath}</strong>
1821
+ <strong>{mappingPreview.migration.filePath}</strong>
1333
1822
  </div>
1334
- <SolidJsonEditor
1335
- className="sdix-json-editor"
1336
- value={reviewedMetadataJsonValue ?? mappingPreview.metadataJson.model}
1337
- resetToken={metadataJsonResetToken}
1338
- onValueChange={(nextValue) => {
1339
- setReviewedMetadataJsonValue(nextValue);
1340
- if (metadataJsonValidationError) {
1341
- setMetadataJsonValidationError(null);
1342
- }
1343
- }}
1344
- onTextChange={(nextText) => {
1345
- setMetadataJsonText(nextText);
1346
- }}
1347
- onErrorChange={setMetadataJsonValidationError}
1348
- />
1349
- {metadataJsonValidationError ? (
1350
- <div className="sdix-json-validation-error">
1351
- <span>{metadataJsonValidationError}</span>
1352
- </div>
1823
+ <p className="sdix-review-note">
1824
+ This migration preview is generated from the current mapping and stays read-only here. Moving ahead writes the migration file to disk and updates the datasource registration now that the entity code already exists.
1825
+ </p>
1826
+ {mappingPreview.migration.content ? (
1827
+ <pre className="sdix-ddl-code sdix-ddl-code--fill"><code>{mappingPreview.migration.content}</code></pre>
1353
1828
  ) : null}
1829
+ </>
1830
+ ) : (
1831
+ <div className="sdix-empty-state is-inline sdix-ddl-empty">
1832
+ <Database size={18} />
1833
+ <p>{mappingPreview.migration.note}</p>
1354
1834
  </div>
1355
- ),
1356
- },
1357
- {
1358
- value: "migration",
1359
- label: "Migration",
1360
- content: (
1361
- <div className="sdix-review-panel sdix-review-panel--migration">
1362
- {mappingPreview.migration.willGenerate && mappingPreview.migration.filePath ? (
1363
- <>
1364
- <div className="sdix-review-meta sdix-review-meta--compact">
1365
- <span>Target file</span>
1366
- <strong>{mappingPreview.migration.filePath}</strong>
1367
- </div>
1368
- <p className="sdix-review-note">
1369
- This migration preview is generated from the current mapping and is read-only here. Saving the mapping will write a new template migration file to the target location.
1370
- </p>
1371
- {mappingPreview.migration.content ? (
1372
- <pre className="sdix-ddl-code sdix-ddl-code--fill"><code>{mappingPreview.migration.content}</code></pre>
1373
- ) : null}
1374
- </>
1375
- ) : (
1376
- <div className="sdix-empty-state is-inline sdix-ddl-empty">
1377
- <Database size={18} />
1378
- <p>{mappingPreview.migration.note}</p>
1379
- </div>
1380
- )}
1835
+ )}
1836
+ </div>
1837
+ ) : null;
1838
+
1839
+ const generateCodePanel = (
1840
+ <div className="sdix-stage-panel">
1841
+ <div className="sdix-stage-panel__header">
1842
+ <span className="sdix-stage-panel__eyebrow">Step 3</span>
1843
+ <h3>Generate module code</h3>
1844
+ <p>The reviewed metadata JSON is now persisted. Run the normal SolidX module generation flow next so the entity, DTOs, repository, service, controller, and UI code are refreshed before we register the entity on the datasource and write the migration.</p>
1845
+ </div>
1846
+ <div className="sdix-stage-panel__body">
1847
+ <div className="sdix-stage-panel__card">
1848
+ <div className="sdix-stage-panel__card-title">What happens here</div>
1849
+ <ul className="sdix-stage-panel__list">
1850
+ <li>The module generate-code pipeline runs for <strong>{bootstrap?.module?.displayName}</strong>.</li>
1851
+ <li>The newly mapped model entity is generated inside the module source folder.</li>
1852
+ <li>Any existing generated assets for this module may be refreshed.</li>
1853
+ </ul>
1381
1854
  </div>
1382
- ),
1383
- },
1384
- ] : [];
1385
-
1386
- return (
1387
- <div className="sdix-page">
1388
- <div className="sdix-toolbar">
1389
- <div className="sdix-toolbar__left">
1390
- <div className="sdix-toolbar-search">
1391
- <Search size={15} />
1392
- <SolidInput
1393
- value={tableSearch}
1394
- onChange={(event) => setTableSearch(event.target.value)}
1395
- placeholder="Search tables"
1396
- disabled={!selectedDatasource}
1397
- />
1398
- </div>
1855
+ <div className="sdix-stage-panel__actions">
1856
+ <SolidButton
1857
+ leftIcon={<Sparkles size={14} />}
1858
+ loading={isGenerateCodeLoading || isGeneratingCodeWorkflow}
1859
+ disabled={isGenerateCodeLoading || isGeneratingCodeWorkflow}
1860
+ onClick={() => void handleGenerateCode()}
1861
+ >
1862
+ Generate Code
1863
+ </SolidButton>
1399
1864
  </div>
1865
+ {isGeneratingCodeWorkflow ? (
1866
+ <div className="sdix-empty-state is-inline sdix-stage-progress">
1867
+ <SolidSpinner size={30} />
1868
+ <h3>Generating code</h3>
1869
+ <p>{generateCodeStatusMessage || "Waiting for the backend to finish restarting..."}</p>
1870
+ </div>
1871
+ ) : null}
1872
+ {!isGeneratingCodeWorkflow && generateCodeTimeoutMessage ? (
1873
+ <div className="sdix-error is-inline sdix-stage-progress sdix-stage-progress--warning">
1874
+ <ShieldAlert size={22} />
1875
+ <h3>Manual review recommended</h3>
1876
+ <p>{generateCodeTimeoutMessage}</p>
1877
+ </div>
1878
+ ) : null}
1879
+ {generateCodeOutput ? (
1880
+ <pre className="sdix-ddl-code sdix-ddl-code--fill"><code>{generateCodeOutput}</code></pre>
1881
+ ) : null}
1882
+ </div>
1883
+ </div>
1884
+ );
1400
1885
 
1401
- <div className="sdix-toolbar__actions">
1402
- {isBootstrapFetching || isTablesFetching || isTableDetailFetching || isMappedModelFetching ? (
1403
- <div className="sdix-inline-status">
1404
- <SolidSpinner size={16} />
1405
- <span>Refreshing</span>
1406
- </div>
1407
- ) : null}
1408
- <SolidSelect
1409
- value={selectedDatasource}
1410
- options={datasourceOptions}
1411
- placeholder="Datasource"
1412
- className="sdix-toolbar-select sdix-toolbar-select--compact"
1413
- onChange={(event) => setSelectedDatasource(event.value)}
1414
- />
1415
- <SolidButton
1416
- size="small"
1417
- className="sdix-icon-button"
1418
- leftIcon={<RefreshCw size={16} />}
1419
- onClick={() => void handleRefresh()}
1420
- tooltip="Refresh"
1421
- aria-label="Refresh"
1422
- />
1423
- <SolidButton
1424
- size="small"
1425
- className="sdix-icon-button"
1426
- leftIcon={<Cog size={16} />}
1427
- onClick={() => {
1428
- setDraftSessionSettings(sessionSettings);
1429
- setSettingsTab("datasource-info");
1430
- setSettingsOpen(true);
1431
- }}
1432
- tooltip="Session settings"
1433
- aria-label="Session settings"
1434
- />
1886
+ const runMigrationPanel = (
1887
+ <div className="sdix-stage-panel">
1888
+ <div className="sdix-stage-panel__header">
1889
+ <span className="sdix-stage-panel__eyebrow">Step 5</span>
1890
+ <h3>Run datasource migration</h3>
1891
+ <p>With the datasource file updated and module code generated, SolidX can now run the TypeORM migration for the selected datasource and apply the missing system fields to the legacy table.</p>
1892
+ </div>
1893
+ <div className="sdix-stage-panel__body">
1894
+ <div className="sdix-stage-panel__card">
1895
+ <div className="sdix-stage-panel__card-title">Command</div>
1896
+ <pre className="sdix-stage-panel__command"><code>{`npx @solidxai/solidctl@latest migration -d ${selectedDatasource} run`}</code></pre>
1435
1897
  </div>
1898
+ {runMigrationCompleted ? (
1899
+ <div className="sdix-empty-state is-inline sdix-stage-progress">
1900
+ <Check size={24} />
1901
+ <h3>Migration finished</h3>
1902
+ <p>Review the output below. When you are satisfied, click Finish to return to the model list.</p>
1903
+ </div>
1904
+ ) : null}
1905
+ {runMigrationOutput ? (
1906
+ <pre className="sdix-ddl-code sdix-ddl-code--fill"><code>{runMigrationOutput}</code></pre>
1907
+ ) : null}
1436
1908
  </div>
1909
+ </div>
1910
+ );
1911
+
1912
+ const workspaceContent = drawerDraft ? (() => {
1913
+ switch (workspaceStep) {
1914
+ case "review-json":
1915
+ return reviewJsonPanel;
1916
+ case "create-migrations":
1917
+ return createMigrationsPanel;
1918
+ case "generate-code":
1919
+ return generateCodePanel;
1920
+ case "run-migration":
1921
+ return runMigrationPanel;
1922
+ case "configure":
1923
+ default:
1924
+ return (
1925
+ <SolidTabGroup
1926
+ tabs={drawerTabs}
1927
+ value={drawerTab}
1928
+ onValueChange={setDrawerTab}
1929
+ className="sdix-drawer-tabs sdix-wizard-tabs"
1930
+ panelClassName="sdix-drawer-tab-panel sdix-wizard-tab-panel"
1931
+ />
1932
+ );
1933
+ }
1934
+ })() : null;
1935
+
1936
+ const workspaceMeta = drawerDraft ? (() => {
1937
+ switch (workspaceStep) {
1938
+ case "review-json":
1939
+ return (
1940
+ <span>
1941
+ Review the generated metadata JSON before it is written to the module metadata file.
1942
+ </span>
1943
+ );
1944
+ case "generate-code":
1945
+ return persistedMappingResult ? (
1946
+ <span>
1947
+ Metadata JSON has been saved for
1948
+ {" "}
1949
+ <strong>{drawerDraft.displayName || drawerDraft.singularName}</strong>
1950
+ . Generate the module code next so the entity file exists before datasource registration is updated. Continue stays disabled until you attempt code generation at least once.
1951
+ </span>
1952
+ ) : (
1953
+ <span>Save the metadata JSON before generating code.</span>
1954
+ );
1955
+ case "create-migrations":
1956
+ return mappingPreview ? (
1957
+ <span>
1958
+ Create the migration artifacts for
1959
+ {" "}
1960
+ <strong>{mappingPreview.summary.includedColumnNames.length}</strong>
1961
+ {" "}
1962
+ mapped columns
1963
+ {mappingPreview.summary.generatedSystemColumnCount
1964
+ ? ` and ${mappingPreview.summary.generatedSystemColumnCount} SolidX system column migration changes`
1965
+ : ""}
1966
+ .
1967
+ </span>
1968
+ ) : null;
1969
+ case "run-migration":
1970
+ return runMigrationCompleted ? (
1971
+ <span>
1972
+ The datasource migration has completed for
1973
+ {" "}
1974
+ <strong>{selectedDatasource}</strong>
1975
+ . Review the output below and click Finish when you are ready to return to the model list.
1976
+ </span>
1977
+ ) : (
1978
+ <span>
1979
+ Run the datasource migration for
1980
+ {" "}
1981
+ <strong>{selectedDatasource}</strong>
1982
+ {" "}
1983
+ to apply the SolidX system columns on the legacy table.
1984
+ </span>
1985
+ );
1986
+ case "configure":
1987
+ default:
1988
+ return drawerDraft.mapped ? (
1989
+ <span>
1990
+ Editing mapped model
1991
+ {" "}
1992
+ <strong>{selectedTable?.mappedModelDisplayName || selectedTable?.mappedModelSingularName}</strong>
1993
+ {drawerDraft.mappedModuleLabel ? ` in ${drawerDraft.mappedModuleLabel}` : ""}
1994
+ </span>
1995
+ ) : (
1996
+ <span>Configure the field mapping draft before generating the metadata JSON preview.</span>
1997
+ );
1998
+ }
1999
+ })() : null;
1437
2000
 
2001
+ return (
2002
+ <div className="sdix-page">
1438
2003
  {isBootstrapLoading ? (
1439
2004
  <div className="sdix-loading">
1440
2005
  <SolidSpinner size={28} />
@@ -1449,6 +2014,70 @@ export function DatasourceIntrospectionPage() {
1449
2014
  </div>
1450
2015
  ) : (
1451
2016
  <>
2017
+ {!isWorkspaceMode ? (
2018
+ <div className="sdix-toolbar">
2019
+ <div className="sdix-toolbar__left">
2020
+ <div className="sdix-toolbar-search">
2021
+ <Search size={15} />
2022
+ <SolidInput
2023
+ value={tableSearch}
2024
+ onChange={(event) => setTableSearch(event.target.value)}
2025
+ placeholder="Search tables"
2026
+ disabled={!selectedDatasource}
2027
+ />
2028
+ </div>
2029
+ </div>
2030
+
2031
+ <div className="sdix-toolbar__actions">
2032
+ {isBootstrapFetching || isTablesFetching ? (
2033
+ <div className="sdix-inline-status">
2034
+ <SolidSpinner size={16} />
2035
+ <span>Refreshing</span>
2036
+ </div>
2037
+ ) : null}
2038
+ <SolidButton
2039
+ size="small"
2040
+ leftIcon={<Sparkles size={14} />}
2041
+ onClick={() => {
2042
+ if (selectedListRow) {
2043
+ startMappingForRecord(selectedListRow);
2044
+ }
2045
+ }}
2046
+ disabled={!selectedListRow}
2047
+ >
2048
+ Start Mapping
2049
+ </SolidButton>
2050
+ <SolidSelect
2051
+ value={selectedDatasource}
2052
+ options={datasourceOptions}
2053
+ placeholder="Datasource"
2054
+ className="sdix-toolbar-select sdix-toolbar-select--compact"
2055
+ onChange={(event) => setSelectedDatasource(event.value)}
2056
+ />
2057
+ <SolidButton
2058
+ size="small"
2059
+ className="sdix-icon-button"
2060
+ leftIcon={<RefreshCw size={16} />}
2061
+ onClick={() => void handleRefresh()}
2062
+ tooltip="Refresh"
2063
+ aria-label="Refresh"
2064
+ />
2065
+ <SolidButton
2066
+ size="small"
2067
+ className="sdix-icon-button"
2068
+ leftIcon={<Cog size={16} />}
2069
+ onClick={() => {
2070
+ setDraftSessionSettings(sessionSettings);
2071
+ setSettingsTab("datasource-info");
2072
+ setSettingsOpen(true);
2073
+ }}
2074
+ tooltip="Session settings"
2075
+ aria-label="Session settings"
2076
+ />
2077
+ </div>
2078
+ </div>
2079
+ ) : null}
2080
+
1452
2081
  {selectedDatasource && tablesResponse?.synchronizeBlocked ? (
1453
2082
  <div className="sdix-blocker">
1454
2083
  <ShieldAlert size={20} />
@@ -1459,93 +2088,261 @@ export function DatasourceIntrospectionPage() {
1459
2088
  </div>
1460
2089
  ) : null}
1461
2090
 
1462
- <div className="sdix-workbench">
1463
- <div className="sdix-table-shell">
1464
- {!selectedDatasource ? (
1465
- <div className="sdix-empty-state is-inline">
1466
- <Database size={22} />
1467
- <p>Select a datasource to load its tables.</p>
1468
- </div>
1469
- ) : isTablesLoading ? (
1470
- <div className="sdix-loading is-inline">
1471
- <SolidSpinner size={24} />
1472
- <p>Inspecting datasource tables...</p>
2091
+ {!isWorkspaceMode ? (
2092
+ <div className="sdix-workbench">
2093
+ <div className="sdix-table-shell">
2094
+ {!selectedDatasource ? (
2095
+ <div className="sdix-empty-state is-inline">
2096
+ <Database size={22} />
2097
+ <p>Select a datasource to load its tables.</p>
2098
+ </div>
2099
+ ) : isTablesLoading ? (
2100
+ <div className="sdix-loading is-inline">
2101
+ <SolidSpinner size={24} />
2102
+ <p>Inspecting datasource tables...</p>
2103
+ </div>
2104
+ ) : tablesError ? (
2105
+ <div className="sdix-error is-inline">
2106
+ <span>{readQueryError(tablesError)}</span>
2107
+ <SolidButton size="small" variant="outline" onClick={() => void refetchTables()}>
2108
+ Retry
2109
+ </SolidButton>
2110
+ </div>
2111
+ ) : !filteredRecords.length ? (
2112
+ <div className="sdix-empty-state is-inline">
2113
+ <Database size={22} />
2114
+ <p>{tableSearch ? "No tables match the current quick filter." : "No database tables were discovered for this datasource."}</p>
2115
+ </div>
2116
+ ) : (
2117
+ <div className="sdix-table-area">
2118
+ <SolidDataTable
2119
+ value={filteredRecords}
2120
+ dataKey="tableName"
2121
+ viewportHeight="calc(100vh - 162px)"
2122
+ size="small"
2123
+ onRowClick={({ data }) => setSelectedRows([data])}
2124
+ rowClassName={(rowData) => `${rowData.schema ?? ""}::${rowData.tableName}` === selectedListRowKey ? "sdix-table-row-selected" : ""}
2125
+ emptyMessage="No datasource tables found"
2126
+ >
2127
+ <Column
2128
+ header=""
2129
+ body={(rowData: DatasourceIntrospectionTableRecord) => {
2130
+ const rowKey = `${rowData.schema ?? ""}::${rowData.tableName}`;
2131
+ return (
2132
+ <div className="sdix-selection-cell" data-no-row-click="true">
2133
+ <SolidCheckbox
2134
+ checked={rowKey === selectedListRowKey}
2135
+ onChange={(event) => setSelectedRows(event.target.checked ? [rowData] : [])}
2136
+ />
2137
+ </div>
2138
+ );
2139
+ }}
2140
+ style={{ width: 52, minWidth: 52 }}
2141
+ />
2142
+ <Column
2143
+ field="tableName"
2144
+ header="Table"
2145
+ body={(rowData: DatasourceIntrospectionTableRecord) => (
2146
+ <div className="sdix-table-primary-cell">
2147
+ <strong>{rowData.tableName}</strong>
2148
+ </div>
2149
+ )}
2150
+ style={{ minWidth: 240 }}
2151
+ />
2152
+ <Column field="schema" header="Schema" body={(rowData: DatasourceIntrospectionTableRecord) => rowData.schema || "dbo/default"} style={{ minWidth: 120 }} />
2153
+ <Column
2154
+ header="Status"
2155
+ body={(rowData: DatasourceIntrospectionTableRecord) => (
2156
+ <span
2157
+ className={`sdix-status-badge ${rowData.mapped ? "is-mapped" : "is-unmapped"}`}
2158
+ >
2159
+ {statusLabel(rowData)}
2160
+ </span>
2161
+ )}
2162
+ style={{ minWidth: 150 }}
2163
+ />
2164
+ <Column
2165
+ header="Superclass"
2166
+ body={(rowData: DatasourceIntrospectionTableRecord) => rowData.suggestedBaseClassName}
2167
+ style={{ minWidth: 220 }}
2168
+ />
2169
+ <Column field="suggestedUserKeyField" header="User Key" style={{ minWidth: 160 }} />
2170
+ <Column
2171
+ header="Mapped Model"
2172
+ body={(rowData: DatasourceIntrospectionTableRecord) => (
2173
+ rowData.mapped
2174
+ ? (
2175
+ <div className="sdix-table-primary-cell">
2176
+ <strong>{rowData.mappedModelDisplayName || rowData.mappedModelSingularName || "-"}</strong>
2177
+ {rowData.mappedModuleDisplayName || rowData.mappedModuleName ? (
2178
+ <span>{rowData.mappedModuleDisplayName || rowData.mappedModuleName}</span>
2179
+ ) : null}
2180
+ </div>
2181
+ )
2182
+ : <span className="sdix-muted-cell">Not mapped</span>
2183
+ )}
2184
+ style={{ minWidth: 200 }}
2185
+ />
2186
+ <Column
2187
+ header="System Columns"
2188
+ body={(rowData: DatasourceIntrospectionTableRecord) => Math.max(rowData.columnCount - rowData.physicalColumnCount, 0)}
2189
+ style={{ minWidth: 130 }}
2190
+ />
2191
+ <Column
2192
+ header="Columns"
2193
+ body={(rowData: DatasourceIntrospectionTableRecord) => rowData.physicalColumnCount}
2194
+ style={{ minWidth: 110 }}
2195
+ />
2196
+ </SolidDataTable>
2197
+ </div>
2198
+ )}
1473
2199
  </div>
1474
- ) : tablesError ? (
1475
- <div className="sdix-error is-inline">
1476
- <span>{readQueryError(tablesError)}</span>
1477
- <SolidButton size="small" variant="outline" onClick={() => void refetchTables()}>
1478
- Retry
2200
+ </div>
2201
+ ) : (
2202
+ <div className="sdix-workspace-screen">
2203
+ <div className="sdix-workspace-header">
2204
+ <SolidButton size="small" variant="outline" leftIcon={<ArrowLeft size={14} />} onClick={leaveWorkspace}>
2205
+ Back
1479
2206
  </SolidButton>
2207
+ <div className="sdix-workspace-header__identity sdix-workspace-header__identity--right">
2208
+ <h2>{selectedTable?.tableName || "Mapping workspace"}</h2>
2209
+ <p>
2210
+ {selectedTable
2211
+ ? `${selectedTable.schema || "dbo"} · ${selectedDatasourceRecord?.database || selectedDatasourceRecord?.displayName || "Datasource"}${selectedDatasourceRecord ? ` · ${providerLabel(selectedDatasourceRecord.type)}` : ""}`
2212
+ : "Complete the legacy table mapping in a dedicated workspace."}
2213
+ </p>
2214
+ </div>
1480
2215
  </div>
1481
- ) : !filteredRecords.length ? (
1482
- <div className="sdix-empty-state is-inline">
1483
- <Database size={22} />
1484
- <p>{tableSearch ? "No tables match the current quick filter." : "No database tables were discovered for this datasource."}</p>
1485
- </div>
1486
- ) : (
1487
- <div className="sdix-table-area">
1488
- <SolidDataTable
1489
- value={filteredRecords}
1490
- dataKey="tableName"
1491
- viewportHeight="calc(100vh - 162px)"
1492
- size="small"
1493
- onRowClick={({ data }) => openTableDrawer(data)}
1494
- rowClassName={(rowData) => `${rowData.schema ?? ""}::${rowData.tableName}` === selectedTableKey && drawerOpen ? "sdix-table-row-selected" : ""}
1495
- emptyMessage="No datasource tables found"
1496
- >
1497
- <Column
1498
- field="tableName"
1499
- header="Table"
1500
- body={(rowData: DatasourceIntrospectionTableRecord) => (
1501
- <div className="sdix-table-primary-cell">
1502
- <strong>{rowData.tableName}</strong>
1503
- </div>
1504
- )}
1505
- style={{ minWidth: 240 }}
1506
- />
1507
- <Column field="schema" header="Schema" body={(rowData: DatasourceIntrospectionTableRecord) => rowData.schema || "dbo/default"} style={{ minWidth: 120 }} />
1508
- <Column
1509
- header="Status"
1510
- body={(rowData: DatasourceIntrospectionTableRecord) => (
1511
- <span
1512
- className={`sdix-status-badge ${rowData.mapped ? "is-mapped" : "is-unmapped"}`}
2216
+
2217
+ {!selectedTable && !isTablesLoading ? (
2218
+ <div className="sdix-error">
2219
+ <span>The selected table is no longer available for this datasource.</span>
2220
+ <SolidButton size="small" variant="outline" onClick={leaveWorkspace}>
2221
+ Back to table list
2222
+ </SolidButton>
2223
+ </div>
2224
+ ) : drawerLoadingError ? (
2225
+ <div className="sdix-error">
2226
+ <span>{readQueryError(drawerLoadingError)}</span>
2227
+ <SolidButton size="small" variant="outline" onClick={() => void refetchTableDetail()}>
2228
+ Retry
2229
+ </SolidButton>
2230
+ </div>
2231
+ ) : isDrawerBlockingLoading ? (
2232
+ <div className="sdix-loading sdix-workspace-loading">
2233
+ <SolidSpinner size={24} />
2234
+ <p>Preparing column mapping preview...</p>
2235
+ </div>
2236
+ ) : (
2237
+ <div className="sdix-wizard-shell">
2238
+ <div className="sdix-wizard-stepper">
2239
+ {stepperItems.map((step, index) => (
2240
+ <button
2241
+ key={step.key}
2242
+ type="button"
2243
+ className={[
2244
+ "sdix-wizard-stepper-item",
2245
+ step.active ? "is-active" : "",
2246
+ step.complete ? "is-complete" : "",
2247
+ step.disabled ? "is-disabled" : "",
2248
+ ].filter(Boolean).join(" ")}
2249
+ onClick={step.onClick}
2250
+ disabled={step.disabled}
1513
2251
  >
1514
- {statusLabel(rowData)}
1515
- </span>
1516
- )}
1517
- style={{ minWidth: 150 }}
1518
- />
1519
- <Column
1520
- header="Superclass"
1521
- body={(rowData: DatasourceIntrospectionTableRecord) => rowData.suggestedBaseClassName}
1522
- style={{ minWidth: 220 }}
1523
- />
1524
- <Column field="suggestedUserKeyField" header="User Key" style={{ minWidth: 160 }} />
1525
- <Column
1526
- header="Mapped Model"
1527
- body={(rowData: DatasourceIntrospectionTableRecord) => (
1528
- rowData.mapped
1529
- ? (rowData.mappedModelDisplayName || rowData.mappedModelSingularName || "-")
1530
- : <span className="sdix-muted-cell">Not mapped</span>
1531
- )}
1532
- style={{ minWidth: 200 }}
1533
- />
1534
- <Column
1535
- header="System Columns"
1536
- body={(rowData: DatasourceIntrospectionTableRecord) => Math.max(rowData.columnCount - rowData.physicalColumnCount, 0)}
1537
- style={{ minWidth: 130 }}
1538
- />
1539
- <Column
1540
- header="Columns"
1541
- body={(rowData: DatasourceIntrospectionTableRecord) => rowData.physicalColumnCount}
1542
- style={{ minWidth: 110 }}
1543
- />
1544
- </SolidDataTable>
1545
- </div>
1546
- )}
2252
+ <span className="sdix-wizard-stepper-badge">
2253
+ {step.complete ? <Check size={12} /> : index + 1}
2254
+ </span>
2255
+ <span className="sdix-wizard-stepper-label">{step.label}</span>
2256
+ </button>
2257
+ ))}
2258
+ </div>
2259
+
2260
+ <div className="sdix-wizard-panel">
2261
+ <div className="sdix-wizard-panel__body">
2262
+ {workspaceContent}
2263
+ </div>
2264
+ </div>
2265
+
2266
+ {drawerDraft ? (
2267
+ <div className="sdix-wizard-footer">
2268
+ <div className="sdix-wizard-footer__meta">{workspaceMeta}</div>
2269
+ <div className="sdix-wizard-footer__actions">
2270
+ {drawerDraft.mapped && drawerDraft.modelId ? (
2271
+ <SolidButton size="small" variant="outline" leftIcon={<ExternalLink size={14} />} onClick={openMappedModelForm}>
2272
+ Open model form
2273
+ </SolidButton>
2274
+ ) : null}
2275
+ {workspaceStep === "configure" ? (
2276
+ <SolidButton
2277
+ size="small"
2278
+ leftIcon={<Save size={14} />}
2279
+ loading={isPreviewMappingLoading}
2280
+ onClick={() => void reviewMappingJson()}
2281
+ >
2282
+ Review Mapping JSON
2283
+ </SolidButton>
2284
+ ) : null}
2285
+ {workspaceStep === "review-json" ? (
2286
+ <>
2287
+ <SolidButton size="small" variant="outline" onClick={() => setWorkspaceStep("configure")}>
2288
+ Back
2289
+ </SolidButton>
2290
+ <SolidButton size="small" leftIcon={<Save size={14} />} loading={isSavingMapping} onClick={() => void persistMappingArtifacts()}>
2291
+ Save Mapping
2292
+ </SolidButton>
2293
+ </>
2294
+ ) : null}
2295
+ {workspaceStep === "generate-code" ? (
2296
+ <>
2297
+ <SolidButton size="small" variant="outline" onClick={() => setWorkspaceStep("review-json")}>
2298
+ Back
2299
+ </SolidButton>
2300
+ <SolidButton
2301
+ size="small"
2302
+ disabled={!hasAttemptedGenerateCode || isGenerateCodeLoading || isGeneratingCodeWorkflow}
2303
+ onClick={() => setWorkspaceStep("create-migrations")}
2304
+ >
2305
+ Continue
2306
+ </SolidButton>
2307
+ </>
2308
+ ) : null}
2309
+ {workspaceStep === "create-migrations" ? (
2310
+ <>
2311
+ <SolidButton size="small" variant="outline" onClick={() => setWorkspaceStep("generate-code")}>
2312
+ Back
2313
+ </SolidButton>
2314
+ <SolidButton size="small" leftIcon={<Save size={14} />} loading={isCreatingMigrationArtifacts} onClick={() => void handleCreateMigrationArtifacts()}>
2315
+ Create Migration Artifacts
2316
+ </SolidButton>
2317
+ </>
2318
+ ) : null}
2319
+ {workspaceStep === "run-migration" ? (
2320
+ runMigrationCompleted ? (
2321
+ <SolidButton
2322
+ size="small"
2323
+ leftIcon={<Check size={14} />}
2324
+ onClick={() => navigate("/admin/core/solid-core/model-metadata/list")}
2325
+ >
2326
+ Finish
2327
+ </SolidButton>
2328
+ ) : (
2329
+ <>
2330
+ <SolidButton size="small" variant="outline" onClick={() => setWorkspaceStep("create-migrations")}>
2331
+ Back
2332
+ </SolidButton>
2333
+ <SolidButton size="small" leftIcon={<Database size={14} />} loading={isRunMigrationLoading} onClick={() => void handleRunMigration()}>
2334
+ Run Migration
2335
+ </SolidButton>
2336
+ </>
2337
+ )
2338
+ ) : null}
2339
+ </div>
2340
+ </div>
2341
+ ) : null}
2342
+ </div>
2343
+ )}
1547
2344
  </div>
1548
- </div>
2345
+ )}
1549
2346
 
1550
2347
  <SolidDialog
1551
2348
  open={settingsOpen}
@@ -1580,138 +2377,6 @@ export function DatasourceIntrospectionPage() {
1580
2377
  </SolidButton>
1581
2378
  </SolidDialogFooter>
1582
2379
  </SolidDialog>
1583
-
1584
- <SolidDialog
1585
- open={drawerOpen}
1586
- onOpenChange={setDrawerOpen}
1587
- className="sdix-drawer"
1588
- overlayClassName="sdix-drawer-overlay"
1589
- dismissible
1590
- >
1591
- <SolidDialogHeader className="sdix-drawer-header">
1592
- <div className="sdix-drawer-header__identity">
1593
- <SolidDialogTitle>{selectedTable?.tableName || "Table details"}</SolidDialogTitle>
1594
- <SolidDialogDescription className="sdix-drawer-header__meta">
1595
- {selectedTable
1596
- ? `${selectedTable.schema || "default"} · ${selectedDatasourceRecord?.database || selectedDatasourceRecord?.displayName || "Datasource"}${selectedDatasourceRecord ? ` · ${providerLabel(selectedDatasourceRecord.type)}` : ""}`
1597
- : "Review mapping details"}
1598
- </SolidDialogDescription>
1599
- </div>
1600
- <SolidDialogClose />
1601
- </SolidDialogHeader>
1602
- <SolidDialogSeparator />
1603
- <SolidDialogBody className="sdix-drawer-body">
1604
- {!selectedTable ? (
1605
- <div className="sdix-empty-state is-inline">
1606
- <Sparkles size={22} />
1607
- <p>Select a table row to review its structure.</p>
1608
- </div>
1609
- ) : drawerLoadingError ? (
1610
- <div className="sdix-error is-inline">
1611
- <span>{readQueryError(drawerLoadingError)}</span>
1612
- <SolidButton size="small" variant="outline" onClick={() => void refetchTableDetail()}>
1613
- Retry
1614
- </SolidButton>
1615
- </div>
1616
- ) : isDrawerBlockingLoading ? (
1617
- <div className="sdix-loading is-inline">
1618
- <SolidSpinner size={24} />
1619
- <p>Preparing column mapping preview...</p>
1620
- </div>
1621
- ) : (
1622
- <div className="sdix-drawer-stack">
1623
- {drawerDraft && !drawerDraft.mapped && drawerStep === "edit" ? (
1624
- <div className="sdix-detail-callout sdix-system-fields-callout">
1625
- <h3>SolidX system fields are added later</h3>
1626
- <p>
1627
- This preview only lists the legacy table columns that already exist today.
1628
- {" "}
1629
- Framework system fields from the selected superclass, including the namespaced
1630
- {" "}
1631
- <code>ss_*</code>
1632
- {" "}
1633
- columns, are introduced when you save the mapping and then generate/apply the follow-up migrations.
1634
- </p>
1635
- </div>
1636
- ) : null}
1637
- {drawerStep === "edit" ? (
1638
- <SolidTabGroup
1639
- tabs={drawerTabs}
1640
- value={drawerTab}
1641
- onValueChange={setDrawerTab}
1642
- className="sdix-drawer-tabs"
1643
- panelClassName="sdix-drawer-tab-panel"
1644
- />
1645
- ) : (
1646
- <SolidTabGroup
1647
- tabs={reviewTabs}
1648
- value={reviewTab}
1649
- onValueChange={setReviewTab}
1650
- className="sdix-drawer-tabs"
1651
- panelClassName="sdix-drawer-tab-panel"
1652
- />
1653
- )}
1654
- </div>
1655
- )}
1656
- </SolidDialogBody>
1657
- {drawerDraft && !isDrawerBlockingLoading ? (
1658
- <>
1659
- <SolidDialogSeparator />
1660
- <SolidDialogFooter className="sdix-drawer-footer">
1661
- <div className="sdix-drawer-footer__meta">
1662
- {drawerStep === "review" && mappingPreview ? (
1663
- <span>
1664
- Review the metadata update first, then save to apply
1665
- {" "}
1666
- <strong>{mappingPreview.summary.includedColumnNames.length}</strong>
1667
- {" "}
1668
- mapped columns
1669
- {mappingPreview.summary.generatedSystemColumnCount
1670
- ? ` and ${mappingPreview.summary.generatedSystemColumnCount} SolidX system column migration changes`
1671
- : ""}
1672
- .
1673
- </span>
1674
- ) : drawerDraft.mapped ? (
1675
- <span>
1676
- Editing mapped model
1677
- {" "}
1678
- <strong>{selectedTable?.mappedModelDisplayName || selectedTable?.mappedModelSingularName}</strong>
1679
- {drawerDraft.mappedModuleLabel ? ` in ${drawerDraft.mappedModuleLabel}` : ""}
1680
- </span>
1681
- ) : (
1682
- <span>Saving will create the model metadata and write it to the module JSON.</span>
1683
- )}
1684
- </div>
1685
- <div className="sdix-drawer-footer__actions">
1686
- {drawerDraft.mapped && drawerDraft.modelId ? (
1687
- <SolidButton size="small" variant="outline" leftIcon={<ExternalLink size={14} />} onClick={openMappedModelForm}>
1688
- Open model form
1689
- </SolidButton>
1690
- ) : null}
1691
- {drawerStep === "review" ? (
1692
- <>
1693
- <SolidButton size="small" variant="outline" onClick={() => setDrawerStep("edit")}>
1694
- Back to editing
1695
- </SolidButton>
1696
- <SolidButton size="small" leftIcon={<Save size={14} />} loading={isSavingMapping} onClick={() => void saveMapping()}>
1697
- Save mapping
1698
- </SolidButton>
1699
- </>
1700
- ) : (
1701
- <SolidButton
1702
- size="small"
1703
- leftIcon={<Save size={14} />}
1704
- loading={isPreviewMappingLoading}
1705
- onClick={() => void viewChanges()}
1706
- >
1707
- View Changes
1708
- </SolidButton>
1709
- )}
1710
- </div>
1711
- </SolidDialogFooter>
1712
- </>
1713
- ) : null}
1714
- </SolidDialog>
1715
2380
  </>
1716
2381
  )}
1717
2382
  </div>