@goplusvn/core 0.1.0 → 0.1.1

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 (369) hide show
  1. package/package.json +2 -1
  2. package/src/assets/erp_wallpaper.png +0 -0
  3. package/src/assets/goeat_logo.png +0 -0
  4. package/src/audit/audit-manager.ts +139 -0
  5. package/src/audit/index.ts +11 -0
  6. package/src/audit/memory-audit-logger.ts +86 -0
  7. package/src/audit/types.ts +50 -0
  8. package/src/auth/auth-service.ts +97 -0
  9. package/src/auth/index.ts +266 -0
  10. package/src/code-generation/index.ts +69 -0
  11. package/src/configs/auth-routes.ts +17 -0
  12. package/src/configs/crud.ts +136 -0
  13. package/src/configs/data/navigations.ts +781 -0
  14. package/src/configs/data/oauth-links.ts +10 -0
  15. package/src/configs/entities/material-categories.config.ts +125 -0
  16. package/src/configs/i18n.ts +12 -0
  17. package/src/configs/index.ts +26 -0
  18. package/src/configs/status.ts +25 -0
  19. package/src/configs/themes.ts +100 -0
  20. package/src/crud/components/crud-bulk-actions.tsx +91 -0
  21. package/src/crud/components/crud-card-view.tsx +241 -0
  22. package/src/crud/components/crud-context.tsx +122 -0
  23. package/src/crud/components/crud-delete-dialog.tsx +145 -0
  24. package/src/crud/components/crud-dialog.tsx +406 -0
  25. package/src/crud/components/crud-empty-state.tsx +104 -0
  26. package/src/crud/components/crud-export-button.tsx +170 -0
  27. package/src/crud/components/crud-field-renderer.tsx +653 -0
  28. package/src/crud/components/crud-filter-chips.tsx +102 -0
  29. package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
  30. package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
  31. package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
  32. package/src/crud/components/crud-filters/index.tsx +76 -0
  33. package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
  34. package/src/crud/components/crud-filters/select-filter.tsx +141 -0
  35. package/src/crud/components/crud-filters/text-filter.tsx +86 -0
  36. package/src/crud/components/crud-form.tsx +642 -0
  37. package/src/crud/components/crud-import-dialog.tsx +440 -0
  38. package/src/crud/components/crud-infinite-scroll.tsx +116 -0
  39. package/src/crud/components/crud-page.tsx +1017 -0
  40. package/src/crud/components/crud-provider.tsx +277 -0
  41. package/src/crud/components/crud-row-actions.tsx +189 -0
  42. package/src/crud/components/crud-search.tsx +82 -0
  43. package/src/crud/components/crud-sheet.tsx +336 -0
  44. package/src/crud/components/crud-table-skeleton.tsx +26 -0
  45. package/src/crud/components/crud-table-toolbar.tsx +91 -0
  46. package/src/crud/components/crud-table.tsx +352 -0
  47. package/src/crud/components/crud-virtual-table.tsx +55 -0
  48. package/src/crud/components/index.tsx +20 -0
  49. package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
  50. package/src/crud/crud-filters/datetime-filter.tsx +82 -0
  51. package/src/crud/crud-filters/filter-builder.tsx +64 -0
  52. package/src/crud/crud-filters/index.tsx +78 -0
  53. package/src/crud/crud-filters/radio-filter.tsx +79 -0
  54. package/src/crud/crud-filters/select-filter.tsx +148 -0
  55. package/src/crud/crud-filters/text-filter.tsx +81 -0
  56. package/src/crud/index.ts +43 -0
  57. package/src/crud/lib/crud-service.test.ts +334 -0
  58. package/src/crud/lib/crud-service.ts +358 -0
  59. package/src/crud/lib/crud-utils.test.ts +354 -0
  60. package/src/crud/lib/crud-utils.ts +299 -0
  61. package/src/crud/lib/crud-validator.ts +247 -0
  62. package/src/crud/lib/data-loader.ts +234 -0
  63. package/src/crud/lib/field-calculator.ts +241 -0
  64. package/src/crud/lib/field-formatter.ts +240 -0
  65. package/src/crud/lib/import-export-service.test.ts +290 -0
  66. package/src/crud/lib/import-export-service.ts +352 -0
  67. package/src/crud/lib/import-server-utils.ts +109 -0
  68. package/src/crud/lib/lazy-loader.ts +241 -0
  69. package/src/crud/lib/parse-filters.ts +85 -0
  70. package/src/crud/lib/permissions.ts +52 -0
  71. package/src/crud/lib/serialize-config.ts +60 -0
  72. package/src/crud/lib/stream-loader.ts +145 -0
  73. package/src/crud/lib/translate-config.ts +335 -0
  74. package/src/crud/lib/types.ts +11 -0
  75. package/src/crud/pages/entity-crud-page.tsx +144 -0
  76. package/src/crud/server.ts +8 -0
  77. package/src/home/constants.tsx +142 -0
  78. package/src/home/feature-showcase.tsx +171 -0
  79. package/src/home/home-page.tsx +191 -0
  80. package/src/home/hooks/index.ts +1 -0
  81. package/src/home/hooks/useWidgetPreferences.ts +167 -0
  82. package/src/home/index.ts +33 -0
  83. package/src/home/quick-access-dialog.tsx +271 -0
  84. package/src/home/quick-access-menu.tsx +267 -0
  85. package/src/home/types.ts +140 -0
  86. package/src/home/welcome-card.tsx +92 -0
  87. package/src/home/widget-container.tsx +258 -0
  88. package/src/home/widgets/base-widget.tsx +200 -0
  89. package/src/home/widgets/customers-widget.tsx +74 -0
  90. package/src/home/widgets/index.ts +6 -0
  91. package/src/home/widgets/orders-widget.tsx +87 -0
  92. package/src/home/widgets/revenue-widget.tsx +71 -0
  93. package/src/home/widgets/stock-widget.tsx +109 -0
  94. package/src/hooks/index.tsx +598 -0
  95. package/src/hooks/use-tenant.test.tsx +30 -0
  96. package/src/hooks/use-tenant.ts +5 -0
  97. package/src/index.ts +17 -0
  98. package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
  99. package/src/infrastructure/api-service.ts +317 -0
  100. package/src/infrastructure/cache/cache-manager.ts +107 -0
  101. package/src/infrastructure/cache/cache.ts +120 -0
  102. package/src/infrastructure/cache/index.ts +8 -0
  103. package/src/infrastructure/cache/types.ts +48 -0
  104. package/src/infrastructure/cron/cron-manager.ts +239 -0
  105. package/src/infrastructure/cron/index.ts +6 -0
  106. package/src/infrastructure/cron/types.ts +41 -0
  107. package/src/infrastructure/event-bus/event-bus.ts +145 -0
  108. package/src/infrastructure/event-bus/index.ts +2 -0
  109. package/src/infrastructure/event-bus/types.ts +22 -0
  110. package/src/infrastructure/index.ts +32 -0
  111. package/src/infrastructure/lock/decorators.ts +67 -0
  112. package/src/infrastructure/lock/index.ts +2 -0
  113. package/src/infrastructure/lock/lock-manager.ts +33 -0
  114. package/src/infrastructure/logger/index.ts +2 -0
  115. package/src/infrastructure/logger/logger.ts +96 -0
  116. package/src/infrastructure/logger/types.ts +25 -0
  117. package/src/layout/index.tsx +185 -0
  118. package/src/navigation/index.ts +91 -0
  119. package/src/notification/index.ts +14 -0
  120. package/src/notification/notification-service.ts +120 -0
  121. package/src/notification/storage/in-memory.ts +56 -0
  122. package/src/notification/storage/index.ts +1 -0
  123. package/src/notification/types.ts +51 -0
  124. package/src/organization/branch-service.ts +299 -0
  125. package/src/organization/branches.config.ts +154 -0
  126. package/src/organization/index.ts +5 -0
  127. package/src/plugin/apps-registry.ts +97 -0
  128. package/src/plugin/index.ts +5 -0
  129. package/src/plugin/types.ts +41 -0
  130. package/src/providers/index.tsx +109 -0
  131. package/src/providers/tenant-provider.tsx +45 -0
  132. package/src/rbac/components/roles/role-card.tsx +158 -0
  133. package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
  134. package/src/rbac/components/roles/role-toolbar.tsx +123 -0
  135. package/src/rbac/hooks/use-role-operations.ts +159 -0
  136. package/src/rbac/hooks/use-roles-data.ts +59 -0
  137. package/src/rbac/index.ts +297 -0
  138. package/src/rbac/lib/permission-helpers.ts +63 -0
  139. package/src/rbac/pages/action-list-page.tsx +25 -0
  140. package/src/rbac/pages/resource-list-page.tsx +25 -0
  141. package/src/rbac/pages/role-list-page.tsx +378 -0
  142. package/src/rbac/permission-service.ts +140 -0
  143. package/src/rbac/permissions.ts +135 -0
  144. package/src/rbac/resource-service.ts +115 -0
  145. package/src/rbac/resource-validator.ts +119 -0
  146. package/src/rbac/role-service.ts +165 -0
  147. package/src/rbac/server.ts +16 -0
  148. package/src/rbac/types.ts +38 -0
  149. package/src/schemas/action.schema.ts +66 -0
  150. package/src/schemas/branch.schema.ts +52 -0
  151. package/src/schemas/coming-soon-schema.ts +9 -0
  152. package/src/schemas/company.schema.ts +44 -0
  153. package/src/schemas/forgot-passward-schema.ts +9 -0
  154. package/src/schemas/index.ts +30 -0
  155. package/src/schemas/material-category.schema.ts +43 -0
  156. package/src/schemas/material-pricing.schema.ts +74 -0
  157. package/src/schemas/material.schema.ts +76 -0
  158. package/src/schemas/materials.ts +52 -0
  159. package/src/schemas/new-passward-schema.ts +15 -0
  160. package/src/schemas/partner-company.schema.ts +149 -0
  161. package/src/schemas/register-schema.ts +36 -0
  162. package/src/schemas/resource.schema.ts +133 -0
  163. package/src/schemas/role.schema.ts +11 -0
  164. package/src/schemas/sign-in-schema.ts +24 -0
  165. package/src/schemas/supplier-pricing.schema.ts +15 -0
  166. package/src/schemas/supplier.schema.ts +120 -0
  167. package/src/schemas/system-category-group.schema.ts +67 -0
  168. package/src/schemas/system-category.schema.ts +77 -0
  169. package/src/schemas/system-config.schema.ts +118 -0
  170. package/src/schemas/uom.schema.ts +75 -0
  171. package/src/schemas/user-supplier.schema.ts +179 -0
  172. package/src/schemas/user.schema.ts +18 -0
  173. package/src/schemas/verify-email-schema.ts +9 -0
  174. package/src/schemas/warehouse.schema.ts +49 -0
  175. package/src/system/components/categories/category-list.tsx +529 -0
  176. package/src/system/components/categories/category-manager.tsx +89 -0
  177. package/src/system/components/categories/group-sidebar.tsx +308 -0
  178. package/src/system/components/settings/setting-dialogs.tsx +197 -0
  179. package/src/system/components/settings/setting-field.tsx +291 -0
  180. package/src/system/components/settings/setting-form-dialog.tsx +308 -0
  181. package/src/system/components/settings/settings-groups.ts +80 -0
  182. package/src/system/components/settings/settings-search.tsx +71 -0
  183. package/src/system/components/settings/settings-section.tsx +74 -0
  184. package/src/system/components/settings/settings-sidebar.tsx +81 -0
  185. package/src/system/constants.ts +3 -0
  186. package/src/system/index.ts +150 -0
  187. package/src/system/job-manager.ts +176 -0
  188. package/src/system/pages/components/categories/category-list.tsx +537 -0
  189. package/src/system/pages/components/categories/category-manager.tsx +90 -0
  190. package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
  191. package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
  192. package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
  193. package/src/system/pages/components/settings/setting-field.tsx +292 -0
  194. package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
  195. package/src/system/pages/components/settings/settings-groups.ts +87 -0
  196. package/src/system/pages/components/settings/settings-page.tsx +372 -0
  197. package/src/system/pages/components/settings/settings-search.tsx +71 -0
  198. package/src/system/pages/components/settings/settings-section.tsx +74 -0
  199. package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
  200. package/src/system/pages/components/settings/system-settings.tsx +244 -0
  201. package/src/system/pages/system-category-page.tsx +15 -0
  202. package/src/system/pages/system-settings-page.tsx +380 -0
  203. package/src/system/schemas/system-category-group.schema.ts +46 -0
  204. package/src/system/schemas/system-category.schema.ts +56 -0
  205. package/src/system/services/settings-service.ts +127 -0
  206. package/src/system/services/system-category-service.ts +63 -0
  207. package/src/system/types.ts +45 -0
  208. package/src/types/index.ts +703 -0
  209. package/src/ui/auth/auth-layout.tsx +135 -0
  210. package/src/ui/auth/forgot-password-form.tsx +98 -0
  211. package/src/ui/auth/index.tsx +7 -0
  212. package/src/ui/auth/new-password-form.tsx +107 -0
  213. package/src/ui/auth/oauth-links.tsx +30 -0
  214. package/src/ui/auth/register-form.tsx +202 -0
  215. package/src/ui/auth/sign-in-form.tsx +238 -0
  216. package/src/ui/auth/verify-email-form.tsx +104 -0
  217. package/src/ui/crud/index.tsx +10 -0
  218. package/src/ui/data-display/accordion.tsx +65 -0
  219. package/src/ui/data-display/aspect-ratio.tsx +11 -0
  220. package/src/ui/data-display/avatar.tsx +163 -0
  221. package/src/ui/data-display/bento-grid.tsx +77 -0
  222. package/src/ui/data-display/carousel.tsx +249 -0
  223. package/src/ui/data-display/chart.tsx +363 -0
  224. package/src/ui/data-display/code-block-highlight.tsx +54 -0
  225. package/src/ui/data-display/collapsible.tsx +42 -0
  226. package/src/ui/data-display/compact-stat-bar.tsx +149 -0
  227. package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
  228. package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
  229. package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
  230. package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
  231. package/src/ui/data-display/data-table/data-table.tsx +597 -0
  232. package/src/ui/data-display/data-table/index.ts +44 -0
  233. package/src/ui/data-display/data-table-column-header.tsx +75 -0
  234. package/src/ui/data-display/data-table-pagination.tsx +130 -0
  235. package/src/ui/data-display/data-table-view-options.tsx +59 -0
  236. package/src/ui/data-display/formatted-number-input.tsx +210 -0
  237. package/src/ui/data-display/highlight.tsx +20 -0
  238. package/src/ui/data-display/hover-card.tsx +48 -0
  239. package/src/ui/data-display/index.tsx +50 -0
  240. package/src/ui/data-display/iphone-15-pro.tsx +114 -0
  241. package/src/ui/data-display/kanban/index.ts +4 -0
  242. package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
  243. package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
  244. package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
  245. package/src/ui/data-display/kanban/kanban-types.ts +21 -0
  246. package/src/ui/data-display/kpi-card.tsx +68 -0
  247. package/src/ui/data-display/media-grid.tsx +110 -0
  248. package/src/ui/data-display/safari.tsx +175 -0
  249. package/src/ui/data-display/show-more-text.tsx +55 -0
  250. package/src/ui/data-display/tabs.tsx +68 -0
  251. package/src/ui/data-display/timeline.tsx +256 -0
  252. package/src/ui/feedback/alert.tsx +60 -0
  253. package/src/ui/feedback/context-menu.tsx +245 -0
  254. package/src/ui/feedback/drawer.tsx +132 -0
  255. package/src/ui/feedback/error-dialog.tsx +273 -0
  256. package/src/ui/feedback/index.tsx +183 -0
  257. package/src/ui/feedback/progress.tsx +32 -0
  258. package/src/ui/feedback/sheet.tsx +148 -0
  259. package/src/ui/feedback/sonner.tsx +36 -0
  260. package/src/ui/forms/command.tsx +157 -0
  261. package/src/ui/forms/date-picker.tsx +73 -0
  262. package/src/ui/forms/date-range-picker.tsx +76 -0
  263. package/src/ui/forms/date-time-picker.tsx +109 -0
  264. package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
  265. package/src/ui/forms/editor/index.tsx +130 -0
  266. package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
  267. package/src/ui/forms/emoji-picker.tsx +109 -0
  268. package/src/ui/forms/file-dropzone.tsx +169 -0
  269. package/src/ui/forms/file-thumbnail.tsx +29 -0
  270. package/src/ui/forms/index.tsx +201 -0
  271. package/src/ui/forms/input-file.tsx +99 -0
  272. package/src/ui/forms/input-group.tsx +46 -0
  273. package/src/ui/forms/input-otp.tsx +81 -0
  274. package/src/ui/forms/input-phone.tsx +172 -0
  275. package/src/ui/forms/input-spin.tsx +116 -0
  276. package/src/ui/forms/input-tags.tsx +219 -0
  277. package/src/ui/forms/input-time.tsx +42 -0
  278. package/src/ui/forms/multi-select.tsx +629 -0
  279. package/src/ui/forms/multiple-date-picker.tsx +74 -0
  280. package/src/ui/forms/radio-group.tsx +42 -0
  281. package/src/ui/forms/rating.tsx +158 -0
  282. package/src/ui/forms/time-picker.tsx +57 -0
  283. package/src/ui/index.tsx +17 -0
  284. package/src/ui/layout/animated-list.tsx +77 -0
  285. package/src/ui/layout/animated-sidebar.tsx +294 -0
  286. package/src/ui/layout/command-menu.tsx +355 -0
  287. package/src/ui/layout/customizer.tsx +324 -0
  288. package/src/ui/layout/footer.tsx +43 -0
  289. package/src/ui/layout/full-screen-toggle.tsx +52 -0
  290. package/src/ui/layout/header-breadcrumb.tsx +77 -0
  291. package/src/ui/layout/horizontal-layout-header.tsx +83 -0
  292. package/src/ui/layout/horizontal-layout.tsx +50 -0
  293. package/src/ui/layout/index.tsx +25 -0
  294. package/src/ui/layout/language-dropdown.tsx +103 -0
  295. package/src/ui/layout/logo.tsx +63 -0
  296. package/src/ui/layout/main-layout.tsx +57 -0
  297. package/src/ui/layout/mode-dropdown.tsx +58 -0
  298. package/src/ui/layout/notification-dropdown.tsx +127 -0
  299. package/src/ui/layout/page-tabs.tsx +306 -0
  300. package/src/ui/layout/route-cache.tsx +214 -0
  301. package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
  302. package/src/ui/layout/sidebar.tsx +279 -0
  303. package/src/ui/layout/tab-content-cache.tsx +201 -0
  304. package/src/ui/layout/tab-navigation-provider.tsx +536 -0
  305. package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
  306. package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
  307. package/src/ui/layout/user-dropdown.tsx +188 -0
  308. package/src/ui/layout/vertical-layout-header.tsx +65 -0
  309. package/src/ui/layout/vertical-layout.tsx +47 -0
  310. package/src/ui/management/audit-log-page.tsx +209 -0
  311. package/src/ui/management/cache-management.tsx +349 -0
  312. package/src/ui/management/index.ts +3 -0
  313. package/src/ui/management/job-management.tsx +308 -0
  314. package/src/ui/pages/not-found.tsx +30 -0
  315. package/src/ui/primitives/badge.tsx +66 -0
  316. package/src/ui/primitives/breadcrumb.tsx +103 -0
  317. package/src/ui/primitives/button.tsx +129 -0
  318. package/src/ui/primitives/calendar.tsx +74 -0
  319. package/src/ui/primitives/card.tsx +86 -0
  320. package/src/ui/primitives/checkbox.tsx +31 -0
  321. package/src/ui/primitives/client.ts +30 -0
  322. package/src/ui/primitives/combobox.tsx +290 -0
  323. package/src/ui/primitives/dialog.tsx +121 -0
  324. package/src/ui/primitives/dropdown-menu.tsx +239 -0
  325. package/src/ui/primitives/dynamic-icon.tsx +24 -0
  326. package/src/ui/primitives/index.tsx +134 -0
  327. package/src/ui/primitives/input-number.tsx +131 -0
  328. package/src/ui/primitives/input.tsx +22 -0
  329. package/src/ui/primitives/keyboard.tsx +23 -0
  330. package/src/ui/primitives/label.tsx +24 -0
  331. package/src/ui/primitives/menubar.tsx +262 -0
  332. package/src/ui/primitives/navigation-menu.tsx +157 -0
  333. package/src/ui/primitives/pagination.tsx +118 -0
  334. package/src/ui/primitives/popover.tsx +56 -0
  335. package/src/ui/primitives/prefetch-link.tsx +60 -0
  336. package/src/ui/primitives/resizable.tsx +59 -0
  337. package/src/ui/primitives/scroll-area.tsx +63 -0
  338. package/src/ui/primitives/select.tsx +172 -0
  339. package/src/ui/primitives/separator.tsx +51 -0
  340. package/src/ui/primitives/sidebar.tsx +844 -0
  341. package/src/ui/primitives/slider.tsx +27 -0
  342. package/src/ui/primitives/status-badge.tsx +47 -0
  343. package/src/ui/primitives/sticky-layout.tsx +50 -0
  344. package/src/ui/primitives/switch.tsx +29 -0
  345. package/src/ui/primitives/table.tsx +116 -0
  346. package/src/ui/primitives/tabs.tsx +55 -0
  347. package/src/ui/primitives/toggle-group.tsx +70 -0
  348. package/src/ui/primitives/toggle.tsx +47 -0
  349. package/src/ui/primitives/tooltip.tsx +59 -0
  350. package/src/user/components/dangerous-zone.tsx +34 -0
  351. package/src/user/components/delete-account-form.tsx +40 -0
  352. package/src/user/components/index.ts +4 -0
  353. package/src/user/components/profile-info-form.tsx +390 -0
  354. package/src/user/components/profile-info.tsx +32 -0
  355. package/src/user/components/unified-profile-dialog.tsx +1019 -0
  356. package/src/user/components/user-stats.tsx +27 -0
  357. package/src/user/components/user-toolbar.tsx +137 -0
  358. package/src/user/components/users-card-view.tsx +253 -0
  359. package/src/user/index.ts +11 -0
  360. package/src/user/pages/user-list-page.tsx +234 -0
  361. package/src/user/pages/users-client-page.tsx +385 -0
  362. package/src/user/profile-page.tsx +19 -0
  363. package/src/user/schemas.ts +68 -0
  364. package/src/user/types.ts +34 -0
  365. package/src/user/user-service.ts +538 -0
  366. package/src/utils/index.ts +906 -0
  367. package/src/workflow/activity-timeline.tsx +412 -0
  368. package/src/workflow/approval-workflow.tsx +31 -0
  369. package/src/workflow/index.ts +2 -0
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Search, Command } from "lucide-react";
5
+ import { cn } from "../../../utils";
6
+ import { Input } from "../../../ui/primitives/input";
7
+
8
+ interface SettingsSearchProps {
9
+ value: string;
10
+ onChange: (value: string) => void;
11
+ onKeyDown?: (e: React.KeyboardEvent) => void;
12
+ className?: string;
13
+ resultCount?: number;
14
+ }
15
+
16
+ export function SettingsSearch({
17
+ value,
18
+ onChange,
19
+ onKeyDown,
20
+ className,
21
+ resultCount,
22
+ }: SettingsSearchProps) {
23
+ const inputRef = React.useRef<HTMLInputElement>(null);
24
+
25
+ // Global keyboard shortcut (Cmd+K / Ctrl+K)
26
+ React.useEffect(() => {
27
+ const handleKeyDown = (e: KeyboardEvent) => {
28
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
29
+ e.preventDefault();
30
+ inputRef.current?.focus();
31
+ }
32
+ if (e.key === "Escape" && document.activeElement === inputRef.current) {
33
+ inputRef.current?.blur();
34
+ onChange("");
35
+ }
36
+ };
37
+
38
+ document.addEventListener("keydown", handleKeyDown);
39
+ return () => document.removeEventListener("keydown", handleKeyDown);
40
+ }, [onChange]);
41
+
42
+ return (
43
+ <div className={cn("relative", className)}>
44
+ <div className="relative">
45
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
46
+ <Input
47
+ ref={inputRef}
48
+ type="text"
49
+ placeholder="Tìm kiếm cấu hình..."
50
+ value={value}
51
+ onChange={(e) => onChange(e.target.value)}
52
+ onKeyDown={onKeyDown}
53
+ className={cn(
54
+ "pl-9 pr-20 h-11 bg-muted/50 border-0 focus-visible:bg-background focus-visible:ring-1",
55
+ "placeholder:text-muted-foreground/60 text-sm",
56
+ )}
57
+ />
58
+ <div className="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1">
59
+ {resultCount !== undefined && value && (
60
+ <span className="text-xs text-muted-foreground mr-2">
61
+ {resultCount} kết quả
62
+ </span>
63
+ )}
64
+ <kbd className="hidden sm:inline-flex items-center gap-0.5 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground bg-muted rounded border">
65
+ <Command className="h-2.5 w-2.5" />K
66
+ </kbd>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,74 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { ChevronDown } from "lucide-react";
5
+ import { cn } from "../../../utils";
6
+ import {
7
+ Collapsible,
8
+ CollapsibleContent,
9
+ CollapsibleTrigger,
10
+ } from "../../../ui/data-display/collapsible";
11
+
12
+ interface SettingsSectionProps {
13
+ id: string;
14
+ title: string;
15
+ description?: string;
16
+ count?: number;
17
+ defaultOpen?: boolean;
18
+ children: React.ReactNode;
19
+ className?: string;
20
+ }
21
+
22
+ export function SettingsSection({
23
+ id,
24
+ title,
25
+ description,
26
+ count,
27
+ defaultOpen = true,
28
+ children,
29
+ className,
30
+ }: SettingsSectionProps) {
31
+ const [isOpen, setIsOpen] = React.useState(defaultOpen);
32
+
33
+ return (
34
+ <Collapsible
35
+ open={isOpen}
36
+ onOpenChange={setIsOpen}
37
+ className={cn("space-y-3", className)}
38
+ >
39
+ <div id={`section-${id}`} className="scroll-mt-20">
40
+ <CollapsibleTrigger asChild>
41
+ <button className="flex items-center gap-2 w-full group text-left">
42
+ <ChevronDown
43
+ className={cn(
44
+ "h-4 w-4 text-muted-foreground transition-transform duration-200",
45
+ !isOpen && "-rotate-90",
46
+ )}
47
+ />
48
+ <div className="flex-1 flex items-center justify-between">
49
+ <div>
50
+ <h3 className="text-sm font-semibold text-foreground group-hover:text-primary transition-colors">
51
+ {title}
52
+ </h3>
53
+ {description && (
54
+ <p className="text-xs text-muted-foreground mt-0.5">
55
+ {description}
56
+ </p>
57
+ )}
58
+ </div>
59
+ {count !== undefined && (
60
+ <span className="text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded-full">
61
+ {count}
62
+ </span>
63
+ )}
64
+ </div>
65
+ </button>
66
+ </CollapsibleTrigger>
67
+ </div>
68
+
69
+ <CollapsibleContent className="space-y-2">
70
+ <div className="ml-6 space-y-1 border-l pl-4">{children}</div>
71
+ </CollapsibleContent>
72
+ </Collapsible>
73
+ );
74
+ }
@@ -0,0 +1,81 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import {
5
+ Settings,
6
+ TrendingUp,
7
+ Plug,
8
+ Bell,
9
+ Shield,
10
+ Bot,
11
+ Palette,
12
+ Wrench,
13
+ } from "lucide-react";
14
+ import { cn } from "../../../utils";
15
+ import type { SettingGroup } from "../../types";
16
+
17
+ interface SettingsSidebarProps {
18
+ groups: SettingGroup[];
19
+ activeGroup: string;
20
+ onGroupChange: (groupId: string) => void;
21
+ className?: string;
22
+ }
23
+
24
+ const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
25
+ Settings,
26
+ TrendingUp,
27
+ Plug,
28
+ Bell,
29
+ Shield,
30
+ Bot,
31
+ Palette,
32
+ Wrench,
33
+ };
34
+
35
+ export function SettingsSidebar({
36
+ groups,
37
+ activeGroup,
38
+ onGroupChange,
39
+ className,
40
+ }: SettingsSidebarProps) {
41
+ return (
42
+ <nav className={cn("w-64 shrink-0", className)}>
43
+ <div className="sticky top-6 space-y-1">
44
+ {groups.map((group) => {
45
+ const Icon = iconMap[group.icon] || Settings;
46
+ const isActive = activeGroup === group.id;
47
+
48
+ return (
49
+ <button
50
+ key={group.id}
51
+ onClick={() => onGroupChange(group.id)}
52
+ className={cn(
53
+ "w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-all duration-200",
54
+ "hover:bg-accent/50",
55
+ isActive &&
56
+ "bg-primary/10 text-primary font-medium border-l-2 border-primary",
57
+ )}
58
+ >
59
+ <Icon
60
+ className={cn(
61
+ "h-4 w-4 shrink-0",
62
+ isActive ? "text-primary" : "text-muted-foreground",
63
+ )}
64
+ />
65
+ <div className="flex-1 min-w-0">
66
+ <p
67
+ className={cn(
68
+ "text-sm truncate",
69
+ !isActive && "text-foreground/80",
70
+ )}
71
+ >
72
+ {group.label}
73
+ </p>
74
+ </div>
75
+ </button>
76
+ );
77
+ })}
78
+ </div>
79
+ </nav>
80
+ );
81
+ }
@@ -0,0 +1,3 @@
1
+ export const STATUS_ACTIVE = "active";
2
+ export const STATUS_INACTIVE = "inactive";
3
+ export const STATUS_VALUES = [STATUS_ACTIVE, STATUS_INACTIVE] as const;
@@ -0,0 +1,150 @@
1
+ // @goerp/core/system
2
+ // Module registry, manifest loader, and core system utilities
3
+
4
+ export interface ModuleManifest {
5
+ /** Unique module identifier */
6
+ name: string;
7
+ /** Semantic version */
8
+ version: string;
9
+ /** Module category (e.g., 'Supply Chain', 'HR', 'Sales') */
10
+ category?: string;
11
+ /** Human-readable description */
12
+ description?: string;
13
+ /** Module dependencies */
14
+ depends?: string[];
15
+ /** Entities registered by this module */
16
+ entities?: string[];
17
+ /** Navigation items */
18
+ navigation?: NavigationItem[];
19
+ /** Permissions defined by this module */
20
+ permissions?: string[];
21
+ /** Feature flags */
22
+ features?: Record<string, FeatureConfig>;
23
+ }
24
+
25
+ export interface NavigationItem {
26
+ label: string;
27
+ icon?: string;
28
+ path?: string;
29
+ children?: NavigationItem[];
30
+ permission?: string;
31
+ }
32
+
33
+ export interface FeatureConfig {
34
+ enabled: boolean;
35
+ component?: React.ComponentType<any>;
36
+ }
37
+
38
+ /**
39
+ * Module Registry - Central registry for all modules
40
+ */
41
+ class ModuleRegistry {
42
+ private modules = new Map<string, ModuleManifest>();
43
+ private initialized = false;
44
+
45
+ /**
46
+ * Register a module with the registry
47
+ */
48
+ register(manifest: ModuleManifest): void {
49
+ if (this.modules.has(manifest.name)) {
50
+ console.warn(
51
+ `Module "${manifest.name}" is already registered. Skipping.`,
52
+ );
53
+ return;
54
+ }
55
+
56
+ // Validate dependencies
57
+ if (manifest.depends) {
58
+ for (const dep of manifest.depends) {
59
+ if (dep !== "@goerp/core" && !this.modules.has(dep)) {
60
+ console.warn(
61
+ `Module "${manifest.name}" depends on "${dep}" which is not registered yet.`,
62
+ );
63
+ }
64
+ }
65
+ }
66
+
67
+ this.modules.set(manifest.name, manifest);
68
+ }
69
+
70
+ /**
71
+ * Get all registered modules
72
+ */
73
+ getModules(): ModuleManifest[] {
74
+ return Array.from(this.modules.values());
75
+ }
76
+
77
+ /**
78
+ * Get a specific module by name
79
+ */
80
+ getModule(name: string): ModuleManifest | undefined {
81
+ return this.modules.get(name);
82
+ }
83
+
84
+ /**
85
+ * Get combined navigation from all modules
86
+ */
87
+ getNavigation(): NavigationItem[] {
88
+ const items: NavigationItem[] = [];
89
+ for (const manifest of this.modules.values()) {
90
+ if (manifest.navigation) {
91
+ items.push(...manifest.navigation);
92
+ }
93
+ }
94
+ return items;
95
+ }
96
+
97
+ /**
98
+ * Get all permissions from all modules
99
+ */
100
+ getPermissions(): string[] {
101
+ const permissions: string[] = [];
102
+ for (const manifest of this.modules.values()) {
103
+ if (manifest.permissions) {
104
+ permissions.push(...manifest.permissions);
105
+ }
106
+ }
107
+ return permissions;
108
+ }
109
+
110
+ /**
111
+ * Get all entities from all modules
112
+ */
113
+ getEntities(): string[] {
114
+ const entities: string[] = [];
115
+ for (const manifest of this.modules.values()) {
116
+ if (manifest.entities) {
117
+ entities.push(...manifest.entities);
118
+ }
119
+ }
120
+ return entities;
121
+ }
122
+
123
+ /**
124
+ * Check if registry is initialized
125
+ */
126
+ isInitialized(): boolean {
127
+ return this.initialized;
128
+ }
129
+
130
+ /**
131
+ * Mark registry as initialized
132
+ */
133
+ markInitialized(): void {
134
+ this.initialized = true;
135
+ }
136
+
137
+ /**
138
+ * Clear all registered modules (useful for testing)
139
+ */
140
+ clear(): void {
141
+ this.modules.clear();
142
+ this.initialized = false;
143
+ }
144
+ }
145
+
146
+ // Singleton registry instance
147
+ export const registry = new ModuleRegistry();
148
+
149
+ // Export types
150
+ export type { ModuleRegistry };
@@ -0,0 +1,176 @@
1
+ export interface Job {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ status: "running" | "stopped" | "failed";
6
+ lastRun?: Date;
7
+ nextRun?: Date;
8
+ schedule?: string; // cron expression or description
9
+ }
10
+
11
+ export interface JobLog {
12
+ id: string;
13
+ jobId: string;
14
+ level: "info" | "warning" | "error";
15
+ message: string;
16
+ timestamp: Date;
17
+ }
18
+
19
+ /**
20
+ * JobManager - manages background jobs and their logs
21
+ */
22
+ class JobManagerImpl {
23
+ private jobs: Map<string, Job> = new Map();
24
+ private logs: JobLog[] = [];
25
+ private timers: Map<string, NodeJS.Timeout> = new Map();
26
+
27
+ constructor() {
28
+ // Initialize with demonstrable jobs
29
+ this.addJob({
30
+ id: "data-sync",
31
+ name: "Data Synchronization",
32
+ description: "Syncs data with external ERP systems",
33
+ status: "stopped",
34
+ schedule: "Every 15 minutes",
35
+ });
36
+
37
+ this.addJob({
38
+ id: "email-notifications",
39
+ name: "Email Notifications",
40
+ description: "Sends queued email notifications",
41
+ status: "stopped",
42
+ schedule: "Every 1 minute",
43
+ });
44
+
45
+ this.addJob({
46
+ id: "backup-daily",
47
+ name: "Daily Backup",
48
+ description: "Performs full database backup",
49
+ status: "stopped",
50
+ schedule: "Daily at 00:00",
51
+ });
52
+ this.addJob({
53
+ id: "cache-cleanup",
54
+ name: "Cache Cleanup",
55
+ description: "Removes expired cache entries",
56
+ status: "stopped",
57
+ schedule: "Every hour",
58
+ });
59
+
60
+ this.addJob({
61
+ id: "zalo-price-sync",
62
+ name: "Zalo Price Sync",
63
+ description: "Syncs silver price to Zalo groups",
64
+ status: "stopped",
65
+ schedule: "Every 30 minutes",
66
+ });
67
+ }
68
+
69
+ private addJob(job: Job) {
70
+ this.jobs.set(job.id, job);
71
+ }
72
+
73
+ getJobs(): Job[] {
74
+ return Array.from(this.jobs.values());
75
+ }
76
+
77
+ getJob(id: string): Job | undefined {
78
+ return this.jobs.get(id);
79
+ }
80
+
81
+ startJob(id: string): boolean {
82
+ const job = this.jobs.get(id);
83
+ if (!job || job.status === "running") return false;
84
+
85
+ job.status = "running";
86
+ job.lastRun = new Date();
87
+
88
+ this.log(id, "info", `Job "${job.name}" started manually.`);
89
+
90
+ // Simulate job activity
91
+ const timer = setInterval(() => {
92
+ this.log(id, "info", `Job "${job.name}" is processing items...`);
93
+
94
+ // Randomly log warnings or simulated work
95
+ if (Math.random() > 0.8) {
96
+ this.log(
97
+ id,
98
+ "warning",
99
+ `Job "${job.name}" encountered minor issue processing batch.`,
100
+ );
101
+ }
102
+ }, 8000); // Log every 8 seconds
103
+
104
+ this.timers.set(id, timer);
105
+ return true;
106
+ }
107
+
108
+ stopJob(id: string): boolean {
109
+ const job = this.jobs.get(id);
110
+ if (!job || job.status !== "running") return false;
111
+
112
+ job.status = "stopped";
113
+
114
+ const timer = this.timers.get(id);
115
+ if (timer) {
116
+ clearInterval(timer);
117
+ this.timers.delete(id);
118
+ }
119
+
120
+ this.log(id, "info", `Job "${job.name}" stopped manually.`);
121
+ return true;
122
+ }
123
+
124
+ log(jobId: string, level: "info" | "warning" | "error", message: string) {
125
+ const log: JobLog = {
126
+ id: crypto.randomUUID(),
127
+ jobId,
128
+ level,
129
+ message,
130
+ timestamp: new Date(),
131
+ };
132
+ this.logs.unshift(log);
133
+
134
+ // Keep logs size manageable
135
+ if (this.logs.length > 2000) {
136
+ this.logs = this.logs.slice(0, 2000);
137
+ }
138
+ }
139
+
140
+ updateJob(
141
+ id: string,
142
+ updates: Partial<Pick<Job, "schedule" | "description">>,
143
+ ): boolean {
144
+ const job = this.jobs.get(id);
145
+ if (!job) return false;
146
+
147
+ if (updates.schedule !== undefined) job.schedule = updates.schedule;
148
+ if (updates.description !== undefined)
149
+ job.description = updates.description;
150
+
151
+ this.log(id, "info", `Job config updated: ${JSON.stringify(updates)}`);
152
+ return true;
153
+ }
154
+
155
+ getLogs(jobId?: string, date?: Date): JobLog[] {
156
+ let filtered = this.logs;
157
+
158
+ if (jobId) {
159
+ filtered = filtered.filter((l) => l.jobId === jobId);
160
+ }
161
+
162
+ if (date) {
163
+ // Simple day matching
164
+ filtered = filtered.filter(
165
+ (l) =>
166
+ l.timestamp.getDate() === date.getDate() &&
167
+ l.timestamp.getMonth() === date.getMonth() &&
168
+ l.timestamp.getFullYear() === date.getFullYear(),
169
+ );
170
+ }
171
+
172
+ return filtered;
173
+ }
174
+ }
175
+
176
+ export const jobManager = new JobManagerImpl();