@qlover/create-app 0.7.15 → 0.9.0

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 (363) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/configs/_common/.github/workflows/general-check.yml +1 -1
  3. package/dist/configs/_common/.github/workflows/release.yml +2 -2
  4. package/dist/configs/_common/.gitignore.template +6 -0
  5. package/dist/configs/_common/.prettierignore +17 -5
  6. package/dist/configs/_common/.vscode/settings.json +6 -1
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/templates/next-app/.env.template +1 -1
  10. package/dist/templates/next-app/README.en.md +0 -1
  11. package/dist/templates/next-app/README.md +0 -1
  12. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  13. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  14. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  15. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  16. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  17. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  18. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  20. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  21. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  22. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  23. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  24. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  25. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  26. package/dist/templates/next-app/config/common.ts +22 -13
  27. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  28. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  29. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  30. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  31. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  32. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  33. package/dist/templates/next-app/docs/en/index.md +0 -1
  34. package/dist/templates/next-app/docs/en/project-structure.md +0 -1
  35. package/dist/templates/next-app/docs/zh/index.md +0 -1
  36. package/dist/templates/next-app/docs/zh/project-structure.md +0 -1
  37. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  38. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  39. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  40. package/dist/templates/next-app/package.json +7 -3
  41. package/dist/templates/next-app/public/locales/en.json +172 -207
  42. package/dist/templates/next-app/public/locales/zh.json +172 -207
  43. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  44. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  45. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  46. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  47. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  48. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  49. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  50. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  51. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  52. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  53. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  54. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  55. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  56. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  57. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  58. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  59. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  60. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  61. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  62. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  63. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  64. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  65. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  66. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  67. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  68. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  69. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  70. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  71. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  72. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  73. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  74. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  75. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  76. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  77. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  78. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  79. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  80. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  81. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  82. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  83. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  84. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  85. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  86. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  87. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  88. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  89. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  90. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  91. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  92. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  93. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  94. package/dist/templates/react-app/.prettierignore +17 -0
  95. package/dist/templates/react-app/README.en.md +71 -54
  96. package/dist/templates/react-app/README.md +35 -18
  97. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  98. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  99. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  100. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  101. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  102. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  103. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  104. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  105. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  106. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  107. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  108. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  109. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  110. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  111. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  112. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  113. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  114. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  115. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  116. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  117. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  118. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  119. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  120. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  121. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  122. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  123. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  124. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  125. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  126. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  127. package/dist/templates/react-app/__tests__/src/uikit/components/chatMessage/ChatRoot.test.tsx +274 -0
  128. package/dist/templates/react-app/config/IOCIdentifier.ts +11 -8
  129. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  130. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  131. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  132. package/dist/templates/react-app/config/Identifier/components/component.chatMessage.ts +56 -0
  133. package/dist/templates/react-app/config/Identifier/components/component.messageBaseList.ts +103 -0
  134. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  135. package/dist/templates/react-app/config/Identifier/pages/index.ts +9 -0
  136. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  137. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  138. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  139. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  140. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  141. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  142. package/dist/templates/react-app/config/Identifier/pages/page.message.ts +20 -0
  143. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  144. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  145. package/dist/templates/react-app/config/app.router.ts +81 -61
  146. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  147. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  148. package/dist/templates/react-app/config/i18n/chatMessageI18n.ts +17 -0
  149. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  150. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  151. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  152. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  153. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  154. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  155. package/dist/templates/react-app/config/i18n/messageBaseListI18n.ts +22 -0
  156. package/dist/templates/react-app/config/i18n/messageI18n.ts +14 -0
  157. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  158. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  159. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  160. package/dist/templates/react-app/config/theme.ts +14 -4
  161. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  162. package/dist/templates/react-app/docs/en/components/chat-message-component.md +314 -0
  163. package/dist/templates/react-app/docs/en/components/chat-message-refactor.md +270 -0
  164. package/dist/templates/react-app/docs/en/components/message-base-list-component.md +172 -0
  165. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  166. package/dist/templates/react-app/docs/en/env.md +1132 -278
  167. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  168. package/dist/templates/react-app/docs/en/index.md +733 -104
  169. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  170. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  171. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  172. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  173. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  174. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  175. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  176. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  177. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  178. package/dist/templates/react-app/docs/en/store.md +1194 -184
  179. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  180. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  181. package/dist/templates/react-app/docs/zh/components/chat-message-component.md +314 -0
  182. package/dist/templates/react-app/docs/zh/components/chat-message-refactor.md +270 -0
  183. package/dist/templates/react-app/docs/zh/components/message-base-list-component.md +172 -0
  184. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  185. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  186. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  187. package/dist/templates/react-app/docs/zh/index.md +717 -104
  188. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  189. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  190. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  191. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  192. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  193. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  194. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  195. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  196. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  197. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  198. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  199. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  200. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  201. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  202. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  203. package/dist/templates/react-app/eslint.config.mjs +247 -0
  204. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  205. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  206. package/dist/templates/react-app/package.json +31 -3
  207. package/dist/templates/react-app/playwright.config.ts +79 -0
  208. package/dist/templates/react-app/public/locales/en/common.json +233 -179
  209. package/dist/templates/react-app/public/locales/zh/common.json +233 -179
  210. package/dist/templates/react-app/src/App.tsx +15 -42
  211. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  212. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  213. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  214. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  215. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  216. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  217. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  218. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  219. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  220. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  221. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  222. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  223. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  224. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  225. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  226. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  227. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  228. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  229. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  230. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  231. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  232. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  233. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  234. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  235. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  236. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  237. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  238. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  239. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  240. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  241. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  242. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  243. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  244. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  245. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  246. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  247. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  248. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  249. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  250. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  251. package/dist/templates/react-app/src/core/globals.ts +9 -9
  252. package/dist/templates/react-app/src/main.tsx +4 -4
  253. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  254. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  255. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  256. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  257. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  258. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  259. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  260. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  261. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  262. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  263. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  264. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  265. package/dist/templates/react-app/src/pages/base/MessagePage.tsx +40 -0
  266. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  267. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  268. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  269. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  270. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  271. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  272. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  273. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  274. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  275. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  276. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  277. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  278. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  279. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  280. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  281. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  282. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  283. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  284. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  285. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  286. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  287. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  288. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  289. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  290. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  291. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  292. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  293. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  294. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  295. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  296. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  297. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  298. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  299. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  300. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  301. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  302. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  303. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  304. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  305. package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +240 -0
  306. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  307. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  308. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  309. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  310. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  311. package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +176 -0
  312. package/dist/templates/react-app/src/uikit/components/chatMessage/ChatRoot.tsx +21 -0
  313. package/dist/templates/react-app/src/uikit/components/chatMessage/FocusBar.tsx +106 -0
  314. package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +271 -0
  315. package/dist/templates/react-app/src/uikit/components/chatMessage/MessageItem.tsx +102 -0
  316. package/dist/templates/react-app/src/uikit/components/chatMessage/MessagesList.tsx +86 -0
  317. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  318. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  319. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  320. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  321. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  322. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  323. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  324. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  325. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  326. package/dist/templates/react-app/tsconfig.json +8 -1
  327. package/dist/templates/react-app/tsconfig.node.json +1 -1
  328. package/dist/templates/react-app/tsconfig.test.json +3 -1
  329. package/dist/templates/react-app/vite.config.ts +50 -34
  330. package/package.json +2 -1
  331. package/dist/configs/react-app/eslint.config.js +0 -94
  332. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  333. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  334. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  335. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  336. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  337. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  338. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  339. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  340. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  341. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  342. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  343. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  344. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  345. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  346. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  347. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  348. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  349. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  350. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  351. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  352. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  353. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  354. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  355. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  356. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  357. package/dist/templates/react-app/config/i18n.ts +0 -15
  358. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  359. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  360. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  361. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  362. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  363. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -0,0 +1,240 @@
1
+ import { useFactory, useStore } from '@brain-toolkit/react-kit';
2
+ import { messageBaseListI18n } from '@config/i18n/messageBaseListI18n';
3
+ import { I } from '@config/IOCIdentifier';
4
+ import {
5
+ MessageSender,
6
+ MessagesStore,
7
+ MessageStatus,
8
+ SenderStrategyPlugin,
9
+ SendFailureStrategy,
10
+ ThreadUtil
11
+ } from '@qlover/corekit-bridge';
12
+ import { Button, Input } from 'antd';
13
+ import { random } from 'lodash';
14
+ import { useCallback, useMemo, useState } from 'react';
15
+ import { useI18nInterface } from '../hooks/useI18nInterface';
16
+ import { useIOC } from '../hooks/useIOC';
17
+ import type {
18
+ MessageGetwayInterface,
19
+ MessagesStateInterface,
20
+ MessageStoreMsg
21
+ } from '@qlover/corekit-bridge';
22
+
23
+ interface MessageBaseMsg extends MessageStoreMsg<string, unknown> {}
24
+
25
+ function createMessagesState(): MessagesStateInterface<MessageBaseMsg> {
26
+ return {
27
+ messages: []
28
+ };
29
+ }
30
+
31
+ class MessageBaseApi implements MessageGetwayInterface {
32
+ async sendMessage<M extends MessageStoreMsg<string>>(
33
+ message: M
34
+ ): Promise<unknown> {
35
+ const times = random(200, 1000);
36
+
37
+ await ThreadUtil.sleep(times);
38
+
39
+ const messageContent = message.content ?? '';
40
+ if (messageContent.includes('Failed') || messageContent.includes('error')) {
41
+ throw new Error('Failed to send message');
42
+ }
43
+
44
+ if (times % 5 === 0) {
45
+ throw new Error(`Network error(${times})`);
46
+ }
47
+
48
+ // Return object response to demonstrate formatting
49
+ return {
50
+ status: 'success',
51
+ timestamp: new Date().toISOString(),
52
+ delay: `${times}ms`,
53
+ echo: message.content,
54
+ data: {
55
+ message: 'Message received successfully',
56
+ processed: true,
57
+ metadata: {
58
+ length: message.content?.length || 0,
59
+ type: 'text'
60
+ }
61
+ }
62
+ };
63
+ }
64
+ }
65
+
66
+ export function MessageBaseList() {
67
+ const [inputValue, setInputValue] = useState('');
68
+ const logger = useIOC(I.Logger);
69
+ const tt = useI18nInterface(messageBaseListI18n);
70
+ const messagesStore = useFactory(
71
+ MessagesStore<MessageBaseMsg>,
72
+ createMessagesState
73
+ );
74
+ const messageBaseApi = useFactory(MessageBaseApi);
75
+
76
+ const [messagesSender] = useState(() =>
77
+ new MessageSender<MessageBaseMsg>(messagesStore, {
78
+ gateway: messageBaseApi,
79
+ logger
80
+ }).use(new SenderStrategyPlugin(SendFailureStrategy.KEEP_FAILED))
81
+ );
82
+
83
+ const messages = useStore(messagesStore, (state) => state.messages);
84
+
85
+ const loadingMessage = useMemo(() => {
86
+ return messages.find((message) => message.loading);
87
+ }, [messages]);
88
+
89
+ const onSend = useCallback(() => {
90
+ messagesSender.send({
91
+ content: inputValue
92
+ });
93
+ setInputValue('');
94
+ }, [inputValue, messagesSender]);
95
+
96
+ /**
97
+ * Render message result with proper formatting
98
+ * - For objects/arrays: display as formatted JSON
99
+ * - For strings: display as plain text
100
+ */
101
+ const renderResult = (result: unknown) => {
102
+ if (!result) return null;
103
+
104
+ // Check if result is an object or array
105
+ if (typeof result === 'object') {
106
+ try {
107
+ const jsonString = JSON.stringify(result, null, 2);
108
+ return (
109
+ <pre
110
+ data-testid="MessageResultJson"
111
+ className="text-xs font-mono bg-green-100 p-2 rounded mt-1 overflow-x-auto whitespace-pre-wrap"
112
+ >
113
+ {jsonString}
114
+ </pre>
115
+ );
116
+ } catch {
117
+ return String(result);
118
+ }
119
+ }
120
+
121
+ // For strings and other primitives
122
+ return <span data-testid="MessageResultText">{String(result)}</span>;
123
+ };
124
+
125
+ return (
126
+ <div data-testid="MessageBaseList" className="max-w-4xl mx-auto">
127
+ {/* Page Title */}
128
+ <div className="mb-6">
129
+ <h1 className="text-2xl font-bold text-text mb-2">{tt.title}</h1>
130
+ <p className="text-sm text-text-secondary">{tt.description}</p>
131
+ </div>
132
+
133
+ {/* Messages Container */}
134
+ <div className="bg-secondary rounded-lg shadow-sm border border-primary mb-4">
135
+ <div
136
+ data-testid="MessageBaseListItems"
137
+ className="flex flex-col gap-3 p-4 max-h-96 min-h-64 overflow-y-auto"
138
+ >
139
+ {messages.length === 0 ? (
140
+ <div className="flex items-center justify-center h-full text-text-secondary">
141
+ <div className="text-center">
142
+ <p className="text-base mb-1">{tt.noMessages}</p>
143
+ <p className="text-sm">{tt.getStarted}</p>
144
+ </div>
145
+ </div>
146
+ ) : (
147
+ messages.map((message) => (
148
+ <div
149
+ key={message.id}
150
+ data-testid="MessageBaseListItem"
151
+ className="space-y-2"
152
+ >
153
+ {/* User Message */}
154
+ <div className="flex justify-end">
155
+ <div className="max-w-[70%] bg-blue-500 text-white rounded-lg px-4 py-2 shadow-sm">
156
+ <div className="text-sm font-medium mb-1">{tt.user}</div>
157
+ <div className="wrap-break-word">{message.content}</div>
158
+ </div>
159
+ </div>
160
+
161
+ {/* Gateway Response */}
162
+ <div className="flex justify-start">
163
+ <div className="max-w-[70%]">
164
+ {message.loading ? (
165
+ <div className="bg-base rounded-lg px-4 py-2 shadow-sm border border-primary">
166
+ <div className="text-sm font-medium text-text-secondary mb-1">
167
+ {tt.gateway}
168
+ </div>
169
+ <div className="flex items-center gap-2 text-text-secondary">
170
+ <div className="flex gap-1">
171
+ <span
172
+ className="animate-bounce inline-block w-1.5 h-1.5 bg-text-secondary rounded-full"
173
+ style={{ animationDelay: '0ms' }}
174
+ ></span>
175
+ <span
176
+ className="animate-bounce inline-block w-1.5 h-1.5 bg-text-secondary rounded-full"
177
+ style={{ animationDelay: '150ms' }}
178
+ ></span>
179
+ <span
180
+ className="animate-bounce inline-block w-1.5 h-1.5 bg-text-secondary rounded-full"
181
+ style={{ animationDelay: '300ms' }}
182
+ ></span>
183
+ </div>
184
+ <span className="text-sm">{tt.processing}</span>
185
+ </div>
186
+ </div>
187
+ ) : message.status === MessageStatus.FAILED ? (
188
+ <div className="bg-red-50 border border-red-200 rounded-lg px-4 py-2 shadow-sm">
189
+ <div className="text-sm font-medium text-red-800 mb-1">
190
+ {tt.gatewayFailed}
191
+ </div>
192
+ <div className="text-red-600 text-sm">
193
+ ❌ {(message as any).error?.message || tt.sendFailed}
194
+ </div>
195
+ </div>
196
+ ) : message.result ? (
197
+ <div className="bg-green-50 border border-green-200 rounded-lg px-4 py-2 shadow-sm">
198
+ <div className="text-sm font-medium text-green-800 mb-1">
199
+ ✓ {tt.gatewayResponse}
200
+ </div>
201
+ <div className="text-green-900">
202
+ {renderResult(message.result)}
203
+ </div>
204
+ </div>
205
+ ) : null}
206
+ </div>
207
+ </div>
208
+ </div>
209
+ ))
210
+ )}
211
+ </div>
212
+ </div>
213
+
214
+ {/* Input Area */}
215
+ <div className="bg-secondary rounded-lg shadow-sm border border-primary p-4">
216
+ <div className="flex gap-2">
217
+ <Input
218
+ value={inputValue}
219
+ onPressEnter={onSend}
220
+ onChange={(e) => setInputValue(e.target.value)}
221
+ placeholder={tt.inputPlaceholder}
222
+ size="large"
223
+ className="flex-1"
224
+ disabled={loadingMessage?.loading}
225
+ />
226
+ <Button
227
+ disabled={!inputValue || loadingMessage?.loading}
228
+ loading={loadingMessage?.loading}
229
+ type="primary"
230
+ size="large"
231
+ onClick={onSend}
232
+ >
233
+ {tt.sendButton}
234
+ </Button>
235
+ </div>
236
+ <div className="mt-2 text-xs text-text-secondary">{tt.errorTip}</div>
237
+ </div>
238
+ </div>
239
+ );
240
+ }
@@ -1,16 +1,16 @@
1
+ import { IOCIdentifier } from '@config/IOCIdentifier';
1
2
  import { UserAuthProvider } from './UserAuthProvider';
2
- import { useStrictEffect } from '../hooks/useStrictEffect';
3
- import { IOC } from '@/core/IOC';
4
3
  import { useI18nGuard } from '../hooks/useI18nGuard';
5
- import { IOCIdentifier } from '@config/IOCIdentifier';
4
+ import { useIOC } from '../hooks/useIOC';
6
5
  import { useNavigateBridge } from '../hooks/useNavigateBridge';
6
+ import { useStrictEffect } from '../hooks/useStrictEffect';
7
7
 
8
8
  export function ProcessExecutorProvider({
9
9
  children
10
10
  }: {
11
11
  children: React.ReactNode;
12
12
  }) {
13
- const processerExecutor = IOC(IOCIdentifier.ProcesserExecutorInterface);
13
+ const processerExecutor = useIOC(IOCIdentifier.ProcesserExecutorInterface);
14
14
 
15
15
  useI18nGuard();
16
16
 
@@ -20,5 +20,9 @@ export function ProcessExecutorProvider({
20
20
  processerExecutor.starup();
21
21
  }, []);
22
22
 
23
- return <UserAuthProvider>{children}</UserAuthProvider>;
23
+ return (
24
+ <UserAuthProvider data-testid="ProcessExecutorProvider">
25
+ {children}
26
+ </UserAuthProvider>
27
+ );
24
28
  }
@@ -1,13 +1,16 @@
1
1
  import { Suspense } from 'react';
2
+ import type { RouterLoaderRender } from '@/base/cases/RouterLoader';
3
+ import { BaseRouteProvider } from '@/uikit/components/BaseRouteProvider';
2
4
  import { Loading } from './Loading';
3
- import BaseRouteProvider from '@/uikit/components/BaseRouteProvider';
4
- import { RouterLoaderRender } from '@/base/cases/RouterLoader';
5
5
 
6
6
  export const RouterRenderComponent: RouterLoaderRender = (route) => {
7
7
  const Component = route.element();
8
8
 
9
9
  return (
10
- <Suspense fallback={<Loading fullscreen />}>
10
+ <Suspense
11
+ data-testid="RouterRenderComponent"
12
+ fallback={<Loading fullscreen />}
13
+ >
11
14
  <BaseRouteProvider {...route.meta}>
12
15
  <Component />
13
16
  </BaseRouteProvider>
@@ -1,80 +1,137 @@
1
- import { IOC } from '@/core/IOC';
2
- import { useStore } from '@/uikit/hooks/useStore';
3
- import { useTranslation } from 'react-i18next';
4
- import { Select } from 'antd';
5
1
  import {
6
- BulbOutlined,
7
- BulbFilled,
8
2
  HeartFilled,
9
- HeartOutlined
3
+ SettingOutlined,
4
+ MoonOutlined,
5
+ SettingFilled,
6
+ MoonFilled,
7
+ HeartOutlined,
8
+ SunOutlined,
9
+ SunFilled
10
10
  } from '@ant-design/icons';
11
- import clsx from 'clsx';
12
- import { useMemo } from 'react';
13
- import * as i18nKeys from '@config/Identifier/common';
11
+ import { useStore } from '@brain-toolkit/react-kit/hooks/useStore';
12
+ import * as i18nKeys from '@config/Identifier/common/common';
14
13
  import { IOCIdentifier } from '@config/IOCIdentifier';
14
+ import { themeConfig, type SupportedTheme } from '@config/theme';
15
+ import { Dropdown } from 'antd';
16
+ import { clsx } from 'clsx';
17
+ import { useMemo } from 'react';
18
+ import { useAppTranslation } from '../hooks/useAppTranslation';
19
+ import { useIOC } from '../hooks/useIOC';
20
+ import type { ItemType } from 'antd/es/menu/interface';
15
21
 
16
22
  const colorMap: Record<
17
23
  string,
18
- { i18nkey: string; colors: string[]; icons: React.ElementType[] }
24
+ {
25
+ i18nkey: string;
26
+ selectedColor: string;
27
+ normalColor: string;
28
+ Icon: React.ElementType;
29
+ SelectedIcon: React.ElementType;
30
+ TriggerIcon: React.ElementType;
31
+ }
19
32
  > = {
20
- default: {
33
+ system: {
34
+ i18nkey: 'System',
35
+ selectedColor: 'text-text',
36
+ normalColor: 'text-text-secondary',
37
+ Icon: SettingOutlined,
38
+ SelectedIcon: SettingFilled,
39
+ TriggerIcon: SettingOutlined
40
+ },
41
+ light: {
21
42
  i18nkey: i18nKeys.HEADER_THEME_DEFAULT,
22
- colors: ['text-text', 'text-text-secondary'],
23
- icons: [BulbFilled, BulbOutlined]
43
+ selectedColor: 'text-text',
44
+ normalColor: 'text-text-secondary',
45
+ Icon: SunOutlined,
46
+ SelectedIcon: SunFilled,
47
+ TriggerIcon: SunOutlined
24
48
  },
25
49
  dark: {
26
50
  i18nkey: i18nKeys.HEADER_THEME_DARK,
27
- colors: ['text-[#9333ea]', 'text-[#a855f7]'],
28
- icons: [BulbFilled, BulbOutlined]
51
+ selectedColor: 'text-[#9333ea]',
52
+ normalColor: 'text-[#a855f7]',
53
+ Icon: MoonOutlined,
54
+ SelectedIcon: MoonFilled,
55
+ TriggerIcon: MoonOutlined
29
56
  },
30
57
  pink: {
31
58
  i18nkey: i18nKeys.HEADER_THEME_PINK,
32
- colors: ['text-[#f472b6]', 'text-[#ec4899]'],
33
- icons: [HeartFilled, HeartOutlined]
59
+ selectedColor: 'text-[#f472b6]',
60
+ normalColor: 'text-[#ec4899]',
61
+ Icon: HeartOutlined,
62
+ SelectedIcon: HeartFilled,
63
+ TriggerIcon: HeartOutlined
34
64
  }
35
65
  };
36
66
 
37
- export default function ThemeSwitcher() {
38
- const themeService = IOC(IOCIdentifier.ThemeService);
67
+ const themesList = ['system', ...themeConfig.supportedThemes];
68
+
69
+ export function ThemeSwitcher() {
70
+ const themeService = useIOC(IOCIdentifier.ThemeService);
39
71
  const { theme } = useStore(themeService);
40
72
  const themes = themeService.getSupportedThemes();
41
- const { t } = useTranslation('common');
73
+ const { t } = useAppTranslation('common');
42
74
 
43
75
  const themeOptions = useMemo(() => {
44
- return themes.map((themeName) => {
45
- const { i18nkey, colors, icons } =
46
- colorMap[themeName] || colorMap.default;
47
- const [currentColor, normalColor] = colors;
48
- const [CurrentIcon, NormalIcon] = icons;
49
- const isSelf = theme === themeName;
76
+ return themesList.map((themeName) => {
77
+ const { i18nkey, selectedColor, normalColor, Icon, SelectedIcon } =
78
+ colorMap[themeName] || colorMap.light;
79
+
80
+ const isCurrentTheme =
81
+ theme === themeName || (themeName === theme && theme === 'system');
50
82
 
51
83
  return {
52
- key: themeName + i18nkey,
84
+ key: themeName,
53
85
  value: themeName,
54
86
  label: (
55
87
  <div
88
+ data-testid={`ThemeSwitcherOption-${themeName}`}
56
89
  className={clsx(
57
90
  'flex items-center gap-2',
58
- isSelf ? currentColor : normalColor
91
+ isCurrentTheme ? selectedColor : normalColor
59
92
  )}
60
93
  >
61
- {isSelf ? <CurrentIcon /> : <NormalIcon />}
94
+ {isCurrentTheme ? <SelectedIcon /> : <Icon />}
62
95
  <span>{t(i18nkey)}</span>
63
96
  </div>
64
97
  )
65
- };
98
+ } as ItemType;
66
99
  });
67
100
  }, [theme, themes, t]);
68
101
 
102
+ // const nextTheme = useMemo(() => {
103
+ // if (!theme) {
104
+ // return themeConfig.defaultTheme;
105
+ // }
106
+ // const targetIndex = themes.indexOf(theme as SupportedTheme) + 1;
107
+ // return themes[targetIndex % themes.length];
108
+ // }, [theme]);
109
+
110
+ const TriggerIcon = colorMap[theme || themeConfig.defaultTheme].TriggerIcon;
111
+
69
112
  return (
70
- <div className="flex items-center gap-2">
71
- <Select
72
- value={theme}
73
- onChange={(value) => themeService.changeTheme(value)}
74
- options={themeOptions}
75
- style={{ width: 120 }}
76
- className="min-w-40 max-w-full"
77
- />
78
- </div>
113
+ <Dropdown
114
+ data-testid="ThemeSwitcherDropdown"
115
+ trigger={['hover']}
116
+ placement="bottom"
117
+ menu={{
118
+ // @ts-ignore
119
+ 'data-testid': 'ThemeSwitcherSelect',
120
+ items: themeOptions,
121
+ selectedKeys: [theme],
122
+ onClick: ({ key }) => {
123
+ themeService.changeTheme(key as SupportedTheme);
124
+ }
125
+ }}
126
+ >
127
+ <span
128
+ data-testid="ThemeSwitcher"
129
+ data-testvalue={theme}
130
+ className="text-text hover:text-text-hover cursor-pointer text-lg transition-colors"
131
+ // onClick={() => setTheme(nextTheme)}
132
+ >
133
+ <TriggerIcon />
134
+ </span>
135
+ </Dropdown>
79
136
  );
80
137
  }
@@ -1,15 +1,15 @@
1
- import { IOC } from '@/core/IOC';
2
- import { Loading } from './Loading';
3
- import { useStore } from '../hooks/useStore';
1
+ import { useStore } from '@brain-toolkit/react-kit/hooks/useStore';
4
2
  import { IOCIdentifier } from '@config/IOCIdentifier';
3
+ import { Loading } from './Loading';
4
+ import { useIOC } from '../hooks/useIOC';
5
5
 
6
6
  export function UserAuthProvider({ children }: { children: React.ReactNode }) {
7
- const userService = IOC(IOCIdentifier.UserServiceInterface);
7
+ const userService = useIOC(IOCIdentifier.UserServiceInterface);
8
8
 
9
9
  useStore(userService.store);
10
10
 
11
11
  if (!userService.isAuthenticated()) {
12
- return <Loading fullscreen />;
12
+ return <Loading data-testid="UserAuthProvider" fullscreen />;
13
13
  }
14
14
 
15
15
  return children;
@@ -0,0 +1,17 @@
1
+ export function With<T>(props: {
2
+ fallback?: React.ReactNode;
3
+ it: T;
4
+ children: React.ReactNode | ((it: NonNullable<T>) => React.ReactNode);
5
+ }) {
6
+ const { fallback, it, children } = props;
7
+
8
+ if (it != null && it !== false) {
9
+ if (typeof children === 'function') {
10
+ return children(it as NonNullable<T>);
11
+ }
12
+
13
+ return children;
14
+ }
15
+
16
+ return fallback ?? null;
17
+ }
@@ -0,0 +1,176 @@
1
+ import {
2
+ MessageSender,
3
+ ChatMessageRole,
4
+ MessageStatus
5
+ } from '@qlover/corekit-bridge';
6
+ import type {
7
+ ChatMessage,
8
+ ChatMessageStore,
9
+ ChatMessageBridgeInterface,
10
+ ChatMessageBridgePlugin,
11
+ DisabledSendParams,
12
+ MessageSenderConfig,
13
+ GatewayOptions
14
+ } from '@qlover/corekit-bridge';
15
+ import type { TextAreaRef } from 'antd/es/input/TextArea';
16
+
17
+ export class ChatMessageBridge<T = string>
18
+ implements ChatMessageBridgeInterface<T>
19
+ {
20
+ protected ref: TextAreaRef | null = null;
21
+ protected readonly messageSender: MessageSender<ChatMessage<T>>;
22
+
23
+ constructor(
24
+ protected readonly messages: ChatMessageStore<T>,
25
+ config?: MessageSenderConfig
26
+ ) {
27
+ this.messageSender = new MessageSender(messages, config);
28
+ }
29
+
30
+ use(plugin: ChatMessageBridgePlugin<T> | ChatMessageBridgePlugin<T>[]): this {
31
+ if (Array.isArray(plugin)) {
32
+ plugin.forEach((p) => this.messageSender.use(p));
33
+ } else {
34
+ this.messageSender.use(plugin);
35
+ }
36
+
37
+ return this;
38
+ }
39
+
40
+ getMessageStore(): ChatMessageStore<T> {
41
+ return this.messages;
42
+ }
43
+
44
+ /**
45
+ * Disable rules
46
+ * 1. If streaming, don't allow sending
47
+ * 2. If sending, don't allow sending
48
+ */
49
+ getDisabledSend(params?: DisabledSendParams<T>): boolean {
50
+ const disabledSend =
51
+ params?.disabledSend || this.messages.state.disabledSend;
52
+
53
+ if (disabledSend || this.messages.state.streaming) {
54
+ return true;
55
+ }
56
+
57
+ const sendingMessage = this.getSendingMessage();
58
+ if (sendingMessage) {
59
+ return true;
60
+ }
61
+
62
+ return false;
63
+ }
64
+
65
+ onChangeContent(content: T): void {
66
+ const firstDraft = this.getFirstDraftMessage();
67
+
68
+ // If draft message exists, update its content
69
+ if (firstDraft && firstDraft.id) {
70
+ this.messages.updateDraftMessage(firstDraft.id, {
71
+ content
72
+ });
73
+ } else {
74
+ // If no draft message, create a new one
75
+ this.messages.addDraftMessage({
76
+ content,
77
+ role: ChatMessageRole.USER
78
+ });
79
+ }
80
+ }
81
+
82
+ getFirstDraftMessage(): ChatMessage<T> | null {
83
+ return this.messages.getFirstDraftMessage();
84
+ }
85
+
86
+ setRef(ref: unknown): void {
87
+ this.ref = ref as TextAreaRef;
88
+ }
89
+
90
+ focus(): void {
91
+ requestAnimationFrame(() => {
92
+ this.ref?.focus();
93
+ });
94
+ }
95
+
96
+ sendMessage(
97
+ messages: ChatMessage<T>,
98
+ gatewayOptions?: GatewayOptions<ChatMessage<T>>
99
+ ): Promise<ChatMessage<T>> {
100
+ if (this.messages.state.disabledSend) {
101
+ throw new Error('Send is disabled');
102
+ }
103
+
104
+ return this.messageSender.send(messages, gatewayOptions);
105
+ }
106
+
107
+ /**
108
+ * Send message
109
+ *
110
+ * - If passing an object that doesn't exist, sending is not allowed; only draft messages and resending history messages are allowed
111
+ * - If streaming, sending is not allowed
112
+ * - If loading, sending is not allowed
113
+ * - If no message to send, sending is not allowed
114
+ *
115
+ * @param message - Message object
116
+ * @param gatewayOptions - Gateway options
117
+ */
118
+ send(
119
+ message?: ChatMessage<T>,
120
+ gatewayOptions?: GatewayOptions<ChatMessage<T>>
121
+ ): Promise<ChatMessage<T>> {
122
+ const disabledSend = this.getDisabledSend();
123
+
124
+ if (disabledSend) {
125
+ throw new Error('Send is not allowed');
126
+ }
127
+
128
+ // 3. If no message to send, sending is not allowed
129
+ const targetMessage = this.messages.getReadySendMessage(message);
130
+
131
+ if (!targetMessage) {
132
+ throw new Error('No message to send');
133
+ }
134
+
135
+ // 4. If loading, sending is not allowed
136
+ if (targetMessage.loading) {
137
+ return Promise.resolve(targetMessage);
138
+ }
139
+
140
+ return this.sendMessage(targetMessage, gatewayOptions);
141
+ }
142
+
143
+ getSendingMessage(messages?: ChatMessage<T>[]): ChatMessage<T> | null {
144
+ messages = messages || this.messages.getMessages();
145
+
146
+ return (
147
+ messages.find(
148
+ (msg) =>
149
+ msg.status === MessageStatus.SENDING &&
150
+ msg.role === ChatMessageRole.USER
151
+ ) || null
152
+ );
153
+ }
154
+
155
+ stop(messageId?: string): boolean {
156
+ if (!messageId) {
157
+ const sendingMessage = this.getSendingMessage();
158
+ if (sendingMessage) {
159
+ messageId = sendingMessage.id;
160
+ }
161
+ }
162
+
163
+ if (!messageId) {
164
+ return false;
165
+ }
166
+
167
+ return this.messageSender.stop(messageId);
168
+ }
169
+
170
+ /**
171
+ * Stop all sending messages
172
+ */
173
+ stopAll(): void {
174
+ this.messageSender.stopAll();
175
+ }
176
+ }