@qlover/create-app 0.7.15 → 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 (340) hide show
  1. package/CHANGELOG.md +4 -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 +0 -1
  9. package/dist/templates/next-app/README.md +0 -1
  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/index.md +0 -1
  32. package/dist/templates/next-app/docs/en/project-structure.md +0 -1
  33. package/dist/templates/next-app/docs/zh/index.md +0 -1
  34. package/dist/templates/next-app/docs/zh/project-structure.md +0 -1
  35. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  36. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  37. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  38. package/dist/templates/next-app/package.json +7 -3
  39. package/dist/templates/next-app/public/locales/en.json +172 -207
  40. package/dist/templates/next-app/public/locales/zh.json +172 -207
  41. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  42. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  43. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  44. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  45. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  46. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  47. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  48. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  49. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  50. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  51. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  52. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  53. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  54. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  55. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  56. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  57. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  58. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  59. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  60. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  61. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  62. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  63. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  64. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  65. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  66. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  67. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  68. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  69. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  70. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  71. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  72. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  73. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  74. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  75. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  76. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  77. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  78. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  79. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  80. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  81. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  82. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  83. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  84. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  85. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  86. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  87. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  88. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  89. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  90. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  91. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  92. package/dist/templates/react-app/.prettierignore +17 -0
  93. package/dist/templates/react-app/README.en.md +71 -54
  94. package/dist/templates/react-app/README.md +35 -18
  95. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  96. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  97. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  98. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  99. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  100. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  101. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  102. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  103. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  104. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  105. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  106. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  107. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  108. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  109. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  110. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  111. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  112. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  113. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  114. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  115. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  116. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  117. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  118. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  119. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  120. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  121. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  122. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  123. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  124. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  125. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  126. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  127. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  128. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  129. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  130. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  131. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  132. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  133. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  134. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  135. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  136. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  137. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  138. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  139. package/dist/templates/react-app/config/app.router.ts +66 -69
  140. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  141. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  142. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  143. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  144. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  145. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  146. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  147. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  148. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  149. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  150. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  151. package/dist/templates/react-app/config/theme.ts +14 -4
  152. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  153. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  154. package/dist/templates/react-app/docs/en/env.md +1132 -278
  155. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  156. package/dist/templates/react-app/docs/en/index.md +733 -104
  157. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  158. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  159. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  160. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  161. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  162. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  163. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  164. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  165. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  166. package/dist/templates/react-app/docs/en/store.md +1194 -184
  167. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  168. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  169. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  170. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  171. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  172. package/dist/templates/react-app/docs/zh/index.md +717 -104
  173. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  174. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  175. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  176. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  177. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  178. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  179. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  180. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  181. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  182. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  183. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  184. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  185. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  186. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  187. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  188. package/dist/templates/react-app/eslint.config.mjs +247 -0
  189. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  190. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  191. package/dist/templates/react-app/package.json +31 -3
  192. package/dist/templates/react-app/playwright.config.ts +79 -0
  193. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  194. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  195. package/dist/templates/react-app/src/App.tsx +15 -42
  196. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  197. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  198. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  199. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  200. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  201. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  202. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  203. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  204. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  205. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  206. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  207. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  208. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  209. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  210. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  211. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  212. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  213. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  214. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  215. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  216. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  217. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  218. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  219. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  220. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  221. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  222. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  223. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  224. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  225. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  226. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  227. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  228. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  229. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  230. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  231. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  232. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  233. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  234. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  235. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  236. package/dist/templates/react-app/src/core/globals.ts +9 -9
  237. package/dist/templates/react-app/src/main.tsx +4 -4
  238. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  239. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  240. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  241. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  242. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  243. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  244. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  245. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  246. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  247. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  248. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  249. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  250. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  251. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  252. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  253. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  254. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  255. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  256. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  257. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  258. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  259. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  260. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  261. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  262. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  263. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  264. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  265. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  266. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  267. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  268. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  269. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  270. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  271. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  272. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  273. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  274. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  275. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  276. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  277. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  278. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  279. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  280. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  281. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  282. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  283. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  284. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  285. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  286. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  287. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  288. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  289. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  290. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  291. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  292. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  293. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  294. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  295. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  296. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  297. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  298. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  299. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  300. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  301. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  302. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  303. package/dist/templates/react-app/tsconfig.json +8 -1
  304. package/dist/templates/react-app/tsconfig.node.json +1 -1
  305. package/dist/templates/react-app/tsconfig.test.json +3 -1
  306. package/dist/templates/react-app/vite.config.ts +50 -34
  307. package/package.json +2 -1
  308. package/dist/configs/react-app/eslint.config.js +0 -94
  309. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  310. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  311. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  312. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  313. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  314. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  315. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  316. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  317. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  318. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  319. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  320. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  321. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  322. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  323. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  324. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  325. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  326. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  327. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  328. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  329. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  330. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  331. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  332. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  333. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  334. package/dist/templates/react-app/config/i18n.ts +0 -15
  335. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  336. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  337. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  338. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  339. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  340. 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));