@qlover/create-app 0.7.14 → 0.8.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 (361) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/configs/_common/.gitignore.template +6 -0
  3. package/dist/configs/_common/.prettierignore +17 -5
  4. package/dist/configs/_common/.vscode/settings.json +6 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/templates/next-app/.env.template +1 -1
  8. package/dist/templates/next-app/README.en.md +130 -0
  9. package/dist/templates/next-app/README.md +114 -20
  10. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  11. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  12. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  13. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  14. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  15. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  16. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  17. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  18. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  20. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  21. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  22. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  23. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  24. package/dist/templates/next-app/config/common.ts +22 -13
  25. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  26. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  27. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  28. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  29. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  30. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  31. package/dist/templates/next-app/docs/en/api.md +387 -0
  32. package/dist/templates/next-app/docs/en/component.md +544 -0
  33. package/dist/templates/next-app/docs/en/database.md +496 -0
  34. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  35. package/dist/templates/next-app/docs/en/env.md +563 -0
  36. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  37. package/dist/templates/next-app/docs/en/index.md +165 -0
  38. package/dist/templates/next-app/docs/en/page.md +457 -0
  39. package/dist/templates/next-app/docs/en/project-structure.md +176 -0
  40. package/dist/templates/next-app/docs/en/router.md +427 -0
  41. package/dist/templates/next-app/docs/en/theme.md +532 -0
  42. package/dist/templates/next-app/docs/en/validator.md +478 -0
  43. package/dist/templates/next-app/docs/zh/api.md +387 -0
  44. package/dist/templates/next-app/docs/zh/component.md +544 -0
  45. package/dist/templates/next-app/docs/zh/database.md +496 -0
  46. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  47. package/dist/templates/next-app/docs/zh/env.md +563 -0
  48. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  49. package/dist/templates/next-app/docs/zh/index.md +165 -0
  50. package/dist/templates/next-app/docs/zh/page.md +457 -0
  51. package/dist/templates/next-app/docs/zh/project-structure.md +176 -0
  52. package/dist/templates/next-app/docs/zh/router.md +427 -0
  53. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  54. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  55. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  56. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  57. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  58. package/dist/templates/next-app/package.json +7 -3
  59. package/dist/templates/next-app/public/locales/en.json +172 -207
  60. package/dist/templates/next-app/public/locales/zh.json +172 -207
  61. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  62. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  63. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  64. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  65. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  66. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  67. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  68. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  69. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  70. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  71. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  72. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  73. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  74. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  75. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  76. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  77. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  78. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  79. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  80. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  81. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  82. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  83. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  84. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  85. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  86. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  87. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  88. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  89. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  90. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  91. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  92. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  93. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  94. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  95. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  96. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  97. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  98. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  99. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  100. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  101. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  102. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  103. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  104. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  105. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  106. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  107. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  108. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  109. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  110. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  111. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  112. package/dist/templates/react-app/.prettierignore +17 -0
  113. package/dist/templates/react-app/README.en.md +71 -54
  114. package/dist/templates/react-app/README.md +35 -18
  115. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  116. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  117. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  118. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  119. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  120. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  121. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  122. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  123. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  124. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  125. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  126. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  127. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  128. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  129. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  130. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  131. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  132. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  133. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  134. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  135. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  136. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  137. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  138. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  139. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  140. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  141. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  142. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  143. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  144. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  145. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  146. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  147. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  148. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  149. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  150. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  151. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  152. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  153. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  154. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  155. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  156. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  157. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  158. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  159. package/dist/templates/react-app/config/app.router.ts +66 -69
  160. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  161. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  162. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  163. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  164. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  165. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  166. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  167. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  168. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  169. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  170. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  171. package/dist/templates/react-app/config/theme.ts +14 -4
  172. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  173. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  174. package/dist/templates/react-app/docs/en/env.md +1132 -278
  175. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  176. package/dist/templates/react-app/docs/en/index.md +733 -104
  177. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  178. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  179. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  180. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  181. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  182. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  183. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  184. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  185. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  186. package/dist/templates/react-app/docs/en/store.md +1194 -184
  187. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  188. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  189. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  190. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  191. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  192. package/dist/templates/react-app/docs/zh/index.md +717 -104
  193. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  194. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  195. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  196. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  197. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  198. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  199. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  200. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  201. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  202. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  203. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  204. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  205. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  206. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  207. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  208. package/dist/templates/react-app/eslint.config.mjs +247 -0
  209. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  210. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  211. package/dist/templates/react-app/package.json +31 -3
  212. package/dist/templates/react-app/playwright.config.ts +79 -0
  213. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  214. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  215. package/dist/templates/react-app/src/App.tsx +15 -42
  216. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  217. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  218. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  219. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  220. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  221. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  222. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  223. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  224. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  225. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  226. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  227. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  228. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  229. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  230. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  231. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  232. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  233. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  234. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  235. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  236. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  237. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  238. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  239. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  240. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  241. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  242. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  243. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  244. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  245. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  246. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  247. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  248. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  249. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  250. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  251. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  252. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  253. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  254. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  255. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  256. package/dist/templates/react-app/src/core/globals.ts +9 -9
  257. package/dist/templates/react-app/src/main.tsx +4 -4
  258. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  259. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  260. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  261. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  262. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  263. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  264. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  265. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  266. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  267. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  268. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  269. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  270. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  271. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  272. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  273. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  274. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  275. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  276. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  277. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  278. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  279. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  280. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  281. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  282. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  283. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  284. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  285. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  286. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  287. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  288. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  289. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  290. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  291. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  292. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  293. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  294. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  295. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  296. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  297. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  298. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  299. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  300. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  301. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  302. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  303. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  304. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  305. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  306. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  307. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  308. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  309. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  310. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  311. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  312. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  313. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  314. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  315. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  316. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  317. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  318. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  319. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  320. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  321. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  322. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  323. package/dist/templates/react-app/tsconfig.json +8 -1
  324. package/dist/templates/react-app/tsconfig.node.json +1 -1
  325. package/dist/templates/react-app/tsconfig.test.json +3 -1
  326. package/dist/templates/react-app/vite.config.ts +50 -34
  327. package/package.json +2 -1
  328. package/dist/configs/react-app/eslint.config.js +0 -94
  329. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  330. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  331. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  332. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  333. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  334. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  335. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  336. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  337. package/dist/templates/next-app/docs/env.md +0 -94
  338. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  339. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  340. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  341. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  342. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  343. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  344. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  345. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  346. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  347. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  348. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  349. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  350. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  351. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  352. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  353. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  354. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  355. package/dist/templates/react-app/config/i18n.ts +0 -15
  356. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  357. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  358. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  359. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  360. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  361. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -0,0 +1,197 @@
1
+ import { inject, injectable } from 'inversify';
2
+ import pLimit from 'p-limit';
3
+ import { Datetime } from '@/base/cases/Datetime';
4
+ import type {
5
+ BridgeOrderBy,
6
+ DBBridgeInterface
7
+ } from '@/server/port/DBBridgeInterface';
8
+ import type { PaginationInterface } from '@/server/port/PaginationInterface';
9
+ import {
10
+ localesSchema,
11
+ type LocalesSchema
12
+ } from '@migrations/schema/LocalesSchema';
13
+ import { I } from '@config/IOCIdentifier';
14
+ import type {
15
+ LocalesRepositoryInterface,
16
+ UpsertResult
17
+ } from '../port/LocalesRepositoryInterface';
18
+
19
+ @injectable()
20
+ export class LocalesRepository implements LocalesRepositoryInterface {
21
+ readonly name = 'next_app_locales';
22
+
23
+ protected safeFields = Object.keys(localesSchema.shape);
24
+
25
+ constructor(
26
+ @inject(I.DBBridgeInterface) protected dbBridge: DBBridgeInterface,
27
+ @inject(Datetime) protected datetime: Datetime
28
+ ) {}
29
+
30
+ async getAll(): Promise<LocalesSchema[]> {
31
+ const result = await this.dbBridge.get({
32
+ table: this.name,
33
+ fields: this.safeFields
34
+ });
35
+ return (result.data as LocalesSchema[]) || [];
36
+ }
37
+
38
+ async getLocales(
39
+ localeName: string,
40
+ orderBy?: BridgeOrderBy
41
+ ): Promise<LocalesSchema[]> {
42
+ const result = await this.dbBridge.get({
43
+ table: this.name,
44
+ fields: this.safeFields,
45
+ orderBy
46
+ });
47
+
48
+ const data = result.data as LocalesSchema[];
49
+ return data && data.length > 0 ? data : [];
50
+ }
51
+
52
+ async add(params: LocalesSchema): Promise<LocalesSchema[] | null> {
53
+ const now = this.datetime.timestampz();
54
+ const data = {
55
+ ...params,
56
+ created_at: now,
57
+ updated_at: now
58
+ };
59
+
60
+ const result = await this.dbBridge.add({
61
+ table: this.name,
62
+ fields: this.safeFields,
63
+ data
64
+ });
65
+
66
+ return (result.data as LocalesSchema[]) || null;
67
+ }
68
+
69
+ async updateById(
70
+ id: number,
71
+ params: Partial<Omit<LocalesSchema, 'id' | 'created_at'>>
72
+ ): Promise<void> {
73
+ const data = {
74
+ ...params,
75
+ updated_at: this.datetime.timestampz()
76
+ };
77
+
78
+ await this.dbBridge.update({
79
+ table: this.name,
80
+ fields: this.safeFields,
81
+ data,
82
+ where: [['id', '=', id]]
83
+ });
84
+ }
85
+
86
+ async pagination<T = LocalesSchema>(params: {
87
+ page: number;
88
+ pageSize: number;
89
+ orderBy?: BridgeOrderBy;
90
+ }): Promise<PaginationInterface<T>> {
91
+ const result = await this.dbBridge.pagination({
92
+ table: this.name,
93
+ fields: this.safeFields,
94
+ page: params.page,
95
+ pageSize: params.pageSize,
96
+ orderBy: params.orderBy
97
+ });
98
+
99
+ return {
100
+ list: (result.data || []) as T[],
101
+ total: result.count || 0,
102
+ page: params.page,
103
+ pageSize: params.pageSize
104
+ };
105
+ }
106
+
107
+ /**
108
+ * batch upsert data, support chunk processing and concurrency control
109
+ * @param data - data to upsert
110
+ * @param options - options
111
+ * @param options.chunkSize - chunk size, default 100
112
+ * @param options.concurrency - concurrency, default 3
113
+ * @returns UpsertResult - contains success/failure details with returned data
114
+ */
115
+ async upsert(
116
+ data: Partial<LocalesSchema>[],
117
+ options?: {
118
+ chunkSize?: number;
119
+ concurrency?: number;
120
+ }
121
+ ): Promise<UpsertResult> {
122
+ const { chunkSize = 100, concurrency = 3 } = options || {};
123
+
124
+ // Initialize result
125
+ const result: UpsertResult = {
126
+ totalCount: data.length,
127
+ successCount: 0,
128
+ failureCount: 0,
129
+ successChunks: [],
130
+ failureChunks: [],
131
+ allReturnedData: []
132
+ };
133
+
134
+ if (data.length === 0) {
135
+ return result;
136
+ }
137
+
138
+ const now = this.datetime.timestampz();
139
+
140
+ // Add timestamps to all data
141
+ const dataWithTimestamp = data.map((item) => ({
142
+ ...item,
143
+ created_at: item.created_at || now,
144
+ updated_at: now
145
+ }));
146
+
147
+ // Split data into chunks
148
+ const chunks: Partial<LocalesSchema>[][] = [];
149
+ for (let i = 0; i < dataWithTimestamp.length; i += chunkSize) {
150
+ chunks.push(dataWithTimestamp.slice(i, i + chunkSize));
151
+ }
152
+
153
+ // Use p-limit to control concurrency
154
+ const limit = pLimit(concurrency);
155
+
156
+ // Execute upsert for each chunk and collect results
157
+ const tasks = chunks.map((chunk, index) =>
158
+ limit(async () => {
159
+ try {
160
+ const response = await this.dbBridge.upsert({
161
+ table: this.name,
162
+ fields: this.safeFields,
163
+ data: chunk
164
+ });
165
+
166
+ // Extract returned data from database
167
+ const returnedData = (response.data as LocalesSchema[]) || [];
168
+ const affectedCount = response.count || returnedData.length;
169
+
170
+ // Success
171
+ result.successCount += affectedCount;
172
+ result.allReturnedData.push(...returnedData);
173
+ result.successChunks.push({
174
+ success: true,
175
+ chunkIndex: index,
176
+ inputData: chunk,
177
+ returnedData: returnedData,
178
+ affectedCount: affectedCount
179
+ });
180
+ } catch (error) {
181
+ // Failure
182
+ result.failureCount += chunk.length;
183
+ result.failureChunks.push({
184
+ success: false,
185
+ chunkIndex: index,
186
+ inputData: chunk,
187
+ error: error instanceof Error ? error.message : String(error)
188
+ });
189
+ }
190
+ })
191
+ );
192
+
193
+ await Promise.all(tasks);
194
+
195
+ return result;
196
+ }
197
+ }
@@ -0,0 +1,122 @@
1
+ import { inject, injectable } from 'inversify';
2
+ import { revalidateTag } from 'next/cache';
3
+ import type { LocalesSchema } from '@migrations/schema/LocalesSchema';
4
+ import type { LocaleType } from '@config/i18n';
5
+ import { i18nConfig } from '@config/i18n';
6
+ import { splitI18nKey } from '@config/i18n/i18nKeyScheam';
7
+ import { LocalesRepository } from '../repositorys/LocalesRepository';
8
+ import type { BridgeOrderBy } from '../port/DBBridgeInterface';
9
+ import type {
10
+ LocalesRepositoryInterface,
11
+ UpsertResult
12
+ } from '../port/LocalesRepositoryInterface';
13
+ import type { PaginationInterface } from '../port/PaginationInterface';
14
+
15
+ export type ImportLocalesData = {
16
+ namespace?: string;
17
+
18
+ values: {
19
+ [key in LocaleType]?: Record<string, string>;
20
+ };
21
+ };
22
+
23
+ @injectable()
24
+ export class ApiLocaleService {
25
+ constructor(
26
+ @inject(LocalesRepository)
27
+ protected localesRepository: LocalesRepositoryInterface
28
+ ) {}
29
+
30
+ async getLocalesJson(
31
+ localeName: string,
32
+ orderBy?: BridgeOrderBy
33
+ ): Promise<Record<string, string>> {
34
+ const locales = await this.localesRepository.getLocales(
35
+ localeName,
36
+ orderBy
37
+ );
38
+ return locales.reduce(
39
+ (acc, locale) => {
40
+ // @ts-expect-error localeName is valid
41
+ acc[locale.value] = locale[localeName];
42
+ return acc;
43
+ },
44
+ {} as Record<string, string>
45
+ );
46
+ }
47
+
48
+ async getLocales(params: {
49
+ page: number;
50
+ pageSize: number;
51
+ orderBy?: BridgeOrderBy;
52
+ }): Promise<PaginationInterface<LocalesSchema>> {
53
+ return this.localesRepository.pagination({
54
+ page: params.page,
55
+ pageSize: params.pageSize,
56
+ orderBy: params.orderBy
57
+ });
58
+ }
59
+
60
+ async update(data: Partial<LocalesSchema>): Promise<void> {
61
+ await this.localesRepository.updateById(
62
+ data.id!,
63
+ data as Omit<LocalesSchema, 'id' | 'created_at'>
64
+ );
65
+
66
+ // 清除所有支持的语言的缓存
67
+ const revalidatePromises = i18nConfig.supportedLngs.map(async (locale) => {
68
+ await revalidateTag(`i18n-${locale}`);
69
+ });
70
+ await Promise.all(revalidatePromises);
71
+ }
72
+
73
+ async create(data: Partial<LocalesSchema>): Promise<void> {
74
+ await this.localesRepository.add(data as LocalesSchema);
75
+
76
+ // 清除所有支持的语言的缓存
77
+ const revalidatePromises = i18nConfig.supportedLngs.map(async (locale) => {
78
+ await revalidateTag(`i18n-${locale}`);
79
+ });
80
+ await Promise.all(revalidatePromises);
81
+ }
82
+
83
+ async importLocales(data: ImportLocalesData): Promise<UpsertResult> {
84
+ const { namespace = 'common', values } = data;
85
+
86
+ const result: Record<string, Record<string, string>> = {};
87
+
88
+ Object.entries(values).forEach(([locale, values2]) => {
89
+ Object.entries(values2).forEach(([key, value]) => {
90
+ if (!result[key]) {
91
+ result[key] = {};
92
+ }
93
+
94
+ result[key]!['value'] = key;
95
+ result[key]![locale] = value;
96
+
97
+ const { namespace: namespace2 } = splitI18nKey(key);
98
+ result[key]!['namespace'] = namespace2 || namespace;
99
+ });
100
+ });
101
+
102
+ const localesSchemas = Object.values(result) as Partial<LocalesSchema>[];
103
+
104
+ // Use batch upsert method with chunk processing
105
+ const upsertResult = await this.localesRepository.upsert(localesSchemas, {
106
+ chunkSize: 100, // 100 items per chunk
107
+ concurrency: 3 // max 3 concurrent requests
108
+ });
109
+
110
+ // Clear cache for all supported languages if any data was successfully imported
111
+ if (upsertResult.successCount > 0) {
112
+ const revalidatePromises = i18nConfig.supportedLngs.map(
113
+ async (locale) => {
114
+ await revalidateTag(`i18n-${locale}`);
115
+ }
116
+ );
117
+ await Promise.all(revalidatePromises);
118
+ }
119
+
120
+ return upsertResult;
121
+ }
122
+ }
@@ -10,11 +10,15 @@ import type {
10
10
  BridgeEvent,
11
11
  DBBridgeInterface,
12
12
  DBBridgeResponse,
13
+ BridgeOrderBy,
13
14
  Where
14
15
  } from '@/server/port/DBBridgeInterface';
15
16
  import { I } from '@config/IOCIdentifier';
16
17
  import type { LoggerInterface } from '@qlover/logger';
17
- import type { PostgrestFilterBuilder } from '@supabase/postgrest-js';
18
+ import type {
19
+ PostgrestFilterBuilder,
20
+ PostgrestResponseFailure
21
+ } from '@supabase/postgrest-js';
18
22
 
19
23
  const whereHandlerMaps = {
20
24
  '=': 'eq',
@@ -55,13 +59,24 @@ export class SupabaseBridge implements DBBridgeInterface {
55
59
  result: PostgrestSingleResponse<unknown>
56
60
  ): Promise<SupabaseBridgeResponse<unknown>> {
57
61
  if (result.error) {
58
- this.logger.info(result);
59
- throw new Error(result.error.message);
62
+ if (this.hasPausedProject(result)) {
63
+ throw new Error(
64
+ 'Project is paused, Please Restore project: https://supabase.com/dashboard'
65
+ );
66
+ }
67
+
68
+ throw new Error(result.error.details + ' ' + result.error.message);
60
69
  }
61
70
 
62
71
  return result as SupabaseBridgeResponse<unknown>;
63
72
  }
64
73
 
74
+ protected hasPausedProject(error: PostgrestResponseFailure): boolean {
75
+ return (
76
+ error.status === 0 && error.error.message === 'TypeError: fetch failed'
77
+ );
78
+ }
79
+
65
80
  protected handleWhere(
66
81
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
82
  handler: PostgrestFilterBuilder<any, any, any, any, string, unknown, any>,
@@ -84,6 +99,16 @@ export class SupabaseBridge implements DBBridgeInterface {
84
99
  }
85
100
  }
86
101
 
102
+ protected handleOrderBy(
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ handler: PostgrestFilterBuilder<any, any, any, any, string, unknown, any>,
105
+ orderBy?: BridgeOrderBy
106
+ ): void {
107
+ if (orderBy) {
108
+ handler.order(orderBy[0], { ascending: orderBy[1] === 0 });
109
+ }
110
+ }
111
+
87
112
  async add(event: BridgeEvent): Promise<DBBridgeResponse<unknown>> {
88
113
  const { table, data } = event;
89
114
  if (!data) {
@@ -91,8 +116,22 @@ export class SupabaseBridge implements DBBridgeInterface {
91
116
  }
92
117
  const res = await this.supabase
93
118
  .from(table)
94
- .insert(Array.isArray(data) ? data : [data])
95
- .select();
119
+ .insert(Array.isArray(data) ? data : [data]);
120
+ return this.catch(res);
121
+ }
122
+
123
+ async upsert(event: BridgeEvent): Promise<DBBridgeResponse<unknown>> {
124
+ const { table, data, fields = '*' } = event;
125
+ if (!data) {
126
+ throw new Error('Data is required for upsert operation');
127
+ }
128
+ const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
129
+ const res = await this.supabase
130
+ .from(table)
131
+ .upsert(Array.isArray(data) ? data : [data], {
132
+ onConflict: 'value'
133
+ })
134
+ .select(selectFields); // Request to return the upserted data
96
135
  return this.catch(res);
97
136
  }
98
137
 
@@ -119,17 +158,26 @@ export class SupabaseBridge implements DBBridgeInterface {
119
158
  }
120
159
 
121
160
  async get(event: BridgeEvent): Promise<SupabaseBridgeResponse<unknown>> {
122
- const { table, fields = '*', where } = event;
161
+ const { table, fields = '*', where, orderBy } = event;
123
162
  const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
124
163
  const handler = this.supabase.from(table).select(selectFields);
125
164
 
126
165
  this.handleWhere(handler, where ?? []);
127
166
 
167
+ this.handleOrderBy(handler, orderBy);
168
+
128
169
  return this.catch(await handler);
129
170
  }
130
171
 
131
172
  async pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>> {
132
- const { table, fields = '*', where, page = 1, pageSize = 10 } = event;
173
+ const {
174
+ table,
175
+ fields = '*',
176
+ where,
177
+ page = 1,
178
+ pageSize = 10,
179
+ orderBy
180
+ } = event;
133
181
  const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
134
182
 
135
183
  // 获取总数
@@ -141,10 +189,11 @@ export class SupabaseBridge implements DBBridgeInterface {
141
189
  const countResult = await this.catch(await countHandler);
142
190
 
143
191
  // 获取分页数据
144
- const handler = this.supabase
145
- .from(table)
146
- .select(selectFields)
147
- .range((page - 1) * pageSize, page * pageSize - 1);
192
+ const handler = this.supabase.from(table).select(selectFields);
193
+
194
+ this.handleOrderBy(handler, orderBy);
195
+
196
+ handler.range((page - 1) * pageSize, page * pageSize - 1);
148
197
 
149
198
  this.handleWhere(handler, where ?? []);
150
199
  const result = await this.catch(await handler);
@@ -0,0 +1,6 @@
1
+ import type { ValidationFaildResult } from '../port/ValidatorInterface';
2
+ import type { ExecutorError } from '@qlover/fe-corekit';
3
+
4
+ export interface ExtendedExecutorError extends ExecutorError {
5
+ issues?: ValidationFaildResult[];
6
+ }
@@ -0,0 +1,131 @@
1
+ import { ExecutorError } from '@qlover/fe-corekit';
2
+ import { omit } from 'lodash';
3
+ import type { LocalesSchema } from '@migrations/schema/LocalesSchema';
4
+ import { localesSchema } from '@migrations/schema/LocalesSchema';
5
+ import type { LocaleType } from '@config/i18n';
6
+ import { i18nConfig } from '@config/i18n';
7
+ import {
8
+ type ValidationFaildResult,
9
+ type ValidatorInterface
10
+ } from '../port/ValidatorInterface';
11
+ import type { ExtendedExecutorError } from './ExtendedExecutorError';
12
+ import type { ImportLocalesData } from '../services/ApiLocaleService';
13
+
14
+ export class LocalesValidator implements ValidatorInterface {
15
+ validate(data: unknown): void | ValidationFaildResult {
16
+ if (typeof data !== 'object' || data === null) {
17
+ return {
18
+ path: ['form'],
19
+ message: 'form is required'
20
+ };
21
+ }
22
+
23
+ const result = localesSchema
24
+ .omit({ id: true, created_at: true, updated_at: true })
25
+ .safeParse(data);
26
+
27
+ if (!result.success) {
28
+ return result.error.issues[0];
29
+ }
30
+ }
31
+
32
+ getThrow(
33
+ data: unknown
34
+ ): Omit<LocalesSchema, 'id' | 'created_at' | 'updated_at'> {
35
+ const result = this.validate(data);
36
+
37
+ if (result == null) {
38
+ return omit(data as LocalesSchema, ['id', 'created_at', 'updated_at']);
39
+ }
40
+
41
+ const error: ExtendedExecutorError = new ExecutorError(result.message);
42
+ error.issues = [result];
43
+ throw error;
44
+ }
45
+ }
46
+
47
+ export class LocalesImportValidator implements ValidatorInterface {
48
+ getHasAnyFilesLocale(
49
+ values: FormData
50
+ ): { language: LocaleType; value: FormDataEntryValue }[] {
51
+ const hasAnyFilesLocale = [];
52
+ for (const language of i18nConfig.supportedLngs) {
53
+ const value = values.get(language);
54
+ if (value != null) {
55
+ hasAnyFilesLocale.push({ language, value });
56
+ }
57
+ }
58
+ return hasAnyFilesLocale;
59
+ }
60
+
61
+ async validate(data: {
62
+ namespace?: string;
63
+ values: unknown;
64
+ }): Promise<void | ValidationFaildResult> {
65
+ const values = data.values;
66
+ if (!(values instanceof FormData)) {
67
+ return {
68
+ path: ['form'],
69
+ message: 'FormData is required'
70
+ };
71
+ }
72
+
73
+ const hasAnyFilesLocale = this.getHasAnyFilesLocale(values);
74
+
75
+ if (hasAnyFilesLocale.length === 0) {
76
+ return {
77
+ path: ['form'],
78
+ message: 'At least one language file is required'
79
+ };
80
+ }
81
+
82
+ for (const { language, value } of hasAnyFilesLocale) {
83
+ if (!(value instanceof File) || value.type !== 'application/json') {
84
+ return {
85
+ path: [language],
86
+ message: `File for language ${language} is not a JSON File`
87
+ };
88
+ }
89
+
90
+ try {
91
+ const content = await (value as File).text();
92
+ JSON.parse(content);
93
+ } catch {
94
+ return {
95
+ path: [language],
96
+ message: `File for language ${language} is not a valid JSON`
97
+ };
98
+ }
99
+ }
100
+ }
101
+
102
+ async getThrow(data: {
103
+ namespace?: string;
104
+ values: unknown;
105
+ }): Promise<ImportLocalesData> {
106
+ const result = await this.validate(data);
107
+
108
+ console.log(result);
109
+ if (result == null) {
110
+ const hasAnyFilesLocales = this.getHasAnyFilesLocale(
111
+ data.values as FormData
112
+ );
113
+ const result: { [key in LocaleType]?: Record<string, string> } = {};
114
+
115
+ for (const { language, value } of hasAnyFilesLocales) {
116
+ const content = await (value as File).text();
117
+ const jsonData = JSON.parse(content);
118
+ result[language as LocaleType] = jsonData;
119
+ }
120
+
121
+ return {
122
+ namespace: data.namespace || 'common',
123
+ values: result
124
+ };
125
+ }
126
+
127
+ const error: ExtendedExecutorError = new ExecutorError(result.message);
128
+ error.issues = [result];
129
+ throw error;
130
+ }
131
+ }
@@ -6,7 +6,8 @@ import {
6
6
  V_PASSWORD_MIN_LENGTH,
7
7
  V_PASSWORD_MAX_LENGTH,
8
8
  V_PASSWORD_SPECIAL_CHARS
9
- } from '@config/Identifier/validator';
9
+ } from '@config/Identifier/common/validators';
10
+ import type { ExtendedExecutorError } from './ExtendedExecutorError';
10
11
  import type {
11
12
  ValidatorInterface,
12
13
  ValidationFaildResult
@@ -25,10 +26,6 @@ const passwordSchema = z
25
26
  .max(50, { message: V_PASSWORD_MAX_LENGTH })
26
27
  .regex(/^\S+$/, { message: V_PASSWORD_SPECIAL_CHARS });
27
28
 
28
- interface ExtendedExecutorError extends ExecutorError {
29
- issues?: ValidationFaildResult[];
30
- }
31
-
32
29
  export class LoginValidator implements ValidatorInterface {
33
30
  validateEmail(data: unknown): void | ValidationFaildResult {
34
31
  const emailResult = emailSchema.safeParse(data);
@@ -5,8 +5,9 @@ import {
5
5
  type ValidationFaildResult,
6
6
  type ValidatorInterface
7
7
  } from '../port/ValidatorInterface';
8
+ import type { BridgeOrderBy } from '../port/DBBridgeInterface';
8
9
 
9
- const pageSchema = z
10
+ const numberSchema = z
10
11
  .number()
11
12
  .or(z.string())
12
13
  .transform((val) => Number(val))
@@ -14,16 +15,16 @@ const pageSchema = z
14
15
  message: API_PAGE_INVALID
15
16
  });
16
17
 
18
+ const paginationSchema = z.object({
19
+ page: numberSchema,
20
+ pageSize: numberSchema.optional().default(10),
21
+ orderBy: z.string().optional(),
22
+ order: z.string().optional().default('0')
23
+ });
24
+
17
25
  export class PaginationValidator implements ValidatorInterface {
18
26
  protected defaultPageSize = 10;
19
27
 
20
- validatePageSize(value: unknown): void | ValidationFaildResult {
21
- const result = pageSchema.safeParse(value);
22
- if (!result.success) {
23
- return result.error.issues[0];
24
- }
25
- }
26
-
27
28
  validate(data: unknown): void | ValidationFaildResult {
28
29
  if (typeof data !== 'object' || data === null) {
29
30
  return {
@@ -32,17 +33,32 @@ export class PaginationValidator implements ValidatorInterface {
32
33
  };
33
34
  }
34
35
 
35
- return this.validatePageSize((data as Record<string, unknown>).page);
36
+ const result = paginationSchema.safeParse(data);
37
+ if (!result.success) {
38
+ return result.error.issues[0];
39
+ }
36
40
  }
37
41
 
38
- getThrow(
39
- data: unknown
40
- ): Pick<PaginationInterface<unknown>, 'page' | 'pageSize'> {
41
- const result = this.validate(data);
42
- if (result) {
43
- throw new Error(result.message);
42
+ getThrow(data: unknown): Pick<
43
+ PaginationInterface<unknown>,
44
+ 'page' | 'pageSize'
45
+ > & {
46
+ orders: BridgeOrderBy;
47
+ } {
48
+ const result = paginationSchema.safeParse(data);
49
+ if (!result.success) {
50
+ throw new Error(result.error.issues[0].message);
44
51
  }
45
52
 
46
- return { page: 1, pageSize: 10 };
53
+ const order = result.data.order;
54
+
55
+ return {
56
+ page: result.data.page,
57
+ pageSize: result.data.pageSize,
58
+ orders: [
59
+ result.data.orderBy || 'updated_at',
60
+ order == '0' || order == '1' ? (+order as 0 | 1) : 0
61
+ ]
62
+ };
47
63
  }
48
64
  }
@@ -1,6 +1,7 @@
1
1
  /* custom variables - for antd and custom css */
2
2
  html,
3
- .fe-theme {
3
+ .fe-theme .ant-pagination-css-var,
4
+ .fe-theme.ant-pagination {
4
5
  /* Antd Pagination 组件变量 */
5
6
  .ant-pagination-css-var {
6
7
  --fe-pagination-item-bg: rgb(var(--color-bg-base));