@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,308 @@
1
+ "use client";
2
+
3
+ import React, { useState, useEffect } from "react";
4
+ import type { Job, JobLog } from "../../system/job-manager";
5
+ import { jobManager } from "../../system/job-manager";
6
+ // Ideally we would import components from @goerp/core/ui/primitives but we are inside core
7
+ // So we mock or use basic HTML/Tailwind for now to avoid circular deps if structure is complex
8
+ // In a real app we'd use the proper UI components.
9
+ // Assuming this page is used inside an app that provides the context or we use relative imports carefully.
10
+
11
+ // Relative imports to core UI components
12
+ import { Badge } from "../primitives/badge";
13
+ import { Button } from "../primitives/button";
14
+ import { Card, CardHeader, CardTitle, CardContent } from "../primitives/card";
15
+ import { ScrollArea } from "../primitives/scroll-area";
16
+ import {
17
+ Table,
18
+ TableBody,
19
+ TableCell,
20
+ TableHead,
21
+ TableHeader,
22
+ TableRow,
23
+ } from "../primitives/table";
24
+
25
+ import {
26
+ Dialog,
27
+ DialogContent,
28
+ DialogHeader,
29
+ DialogTitle,
30
+ DialogTrigger,
31
+ DialogFooter,
32
+ } from "../primitives/dialog";
33
+ import { Input } from "../primitives/input";
34
+ import { Label } from "../primitives/label";
35
+
36
+ export const JobManagementPage = () => {
37
+ const [jobs, setJobs] = useState<Job[]>([]);
38
+ const [selectedJob, setSelectedJob] = useState<string | null>(null);
39
+ const [logs, setLogs] = useState<JobLog[]>([]);
40
+ const [refreshTrigger, setRefreshTrigger] = useState(0);
41
+ const [editingJob, setEditingJob] = useState<Job | null>(null);
42
+ const [editForm, setEditForm] = useState({ schedule: "", description: "" });
43
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
44
+
45
+ // Initial load and periodic refresh
46
+ useEffect(() => {
47
+ setJobs(jobManager.getJobs());
48
+ const interval = setInterval(() => {
49
+ setJobs(jobManager.getJobs());
50
+ if (selectedJob) {
51
+ // Refresh logs if a job is selected
52
+ setLogs(jobManager.getLogs(selectedJob));
53
+ }
54
+ }, 1000); // 1s refresh for demo niceness
55
+ return () => clearInterval(interval);
56
+ }, [refreshTrigger, selectedJob]);
57
+
58
+ useEffect(() => {
59
+ if (selectedJob) {
60
+ setLogs(jobManager.getLogs(selectedJob));
61
+ } else {
62
+ setLogs([]);
63
+ }
64
+ }, [selectedJob]);
65
+
66
+ const handleStart = (id: string) => {
67
+ jobManager.startJob(id);
68
+ setRefreshTrigger((prev) => prev + 1);
69
+ };
70
+
71
+ const handleStop = (id: string) => {
72
+ jobManager.stopJob(id);
73
+ setRefreshTrigger((prev) => prev + 1);
74
+ };
75
+
76
+ const handleEditClick = (job: Job, e: React.MouseEvent) => {
77
+ e.stopPropagation();
78
+ setEditingJob(job);
79
+ setEditForm({
80
+ schedule: job.schedule || "",
81
+ description: job.description || "",
82
+ });
83
+ setIsDialogOpen(true);
84
+ };
85
+
86
+ const handleSaveEdit = () => {
87
+ if (editingJob) {
88
+ jobManager.updateJob(editingJob.id, editForm);
89
+ setRefreshTrigger((prev) => prev + 1);
90
+ setIsDialogOpen(false);
91
+ setEditingJob(null);
92
+ }
93
+ };
94
+
95
+ const getStatusBadge = (status: string) => {
96
+ switch (status) {
97
+ case "running":
98
+ return (
99
+ <Badge
100
+ variant="default"
101
+ className="bg-emerald-500 hover:bg-emerald-600"
102
+ >
103
+ Running
104
+ </Badge>
105
+ );
106
+ case "stopped":
107
+ return <Badge variant="secondary">Stopped</Badge>;
108
+ case "failed":
109
+ return <Badge variant="destructive">Failed</Badge>;
110
+ default:
111
+ return <Badge variant="outline">{status}</Badge>;
112
+ }
113
+ };
114
+
115
+ const [logSearchTerm, setLogSearchTerm] = useState("");
116
+
117
+ const filteredLogs = logs.filter(
118
+ (log) =>
119
+ log.message.toLowerCase().includes(logSearchTerm.toLowerCase()) ||
120
+ log.level.toLowerCase().includes(logSearchTerm.toLowerCase()),
121
+ );
122
+
123
+ return (
124
+ <div className="p-6 space-y-6 h-full flex flex-col">
125
+ <div className="flex justify-between items-center mb-4">
126
+ <div>
127
+ <h1 className="text-2xl font-bold tracking-tight">Job Management</h1>
128
+ <p className="text-muted-foreground text-sm">
129
+ Monitor and control system background jobs.
130
+ </p>
131
+ </div>
132
+ <Button
133
+ onClick={() => setRefreshTrigger((prev) => prev + 1)}
134
+ variant="outline"
135
+ >
136
+ Refresh
137
+ </Button>
138
+ </div>
139
+
140
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6 flex-1 min-h-0">
141
+ {/* Job List */}
142
+ <Card className="md:col-span-2 flex flex-col min-h-0">
143
+ <CardHeader>
144
+ <CardTitle>Active Jobs</CardTitle>
145
+ </CardHeader>
146
+ <CardContent className="flex-1 overflow-auto p-0">
147
+ <Table>
148
+ <TableHeader>
149
+ <TableRow>
150
+ <TableHead>Job Name</TableHead>
151
+ <TableHead>Schedule</TableHead>
152
+ <TableHead>Status</TableHead>
153
+ <TableHead>Last Run</TableHead>
154
+ <TableHead className="text-right">Actions</TableHead>
155
+ </TableRow>
156
+ </TableHeader>
157
+ <TableBody>
158
+ {jobs.map((job) => (
159
+ <TableRow
160
+ key={job.id}
161
+ className={`cursor-pointer ${selectedJob === job.id ? "bg-muted/50" : ""}`}
162
+ onClick={() => setSelectedJob(job.id)}
163
+ >
164
+ <TableCell>
165
+ <div className="font-medium">{job.name}</div>
166
+ <div className="text-xs text-muted-foreground">
167
+ {job.description}
168
+ </div>
169
+ </TableCell>
170
+ <TableCell>{job.schedule}</TableCell>
171
+ <TableCell>{getStatusBadge(job.status)}</TableCell>
172
+ <TableCell className="text-muted-foreground">
173
+ {job.lastRun ? job.lastRun.toLocaleTimeString() : "-"}
174
+ </TableCell>
175
+ <TableCell className="text-right">
176
+ <div
177
+ className="flex justify-end gap-2"
178
+ onClick={(e) => e.stopPropagation()}
179
+ >
180
+ <Button
181
+ size="sm"
182
+ variant="outline"
183
+ onClick={(e) => handleEditClick(job, e)}
184
+ >
185
+ Edit
186
+ </Button>
187
+ {job.status === "running" ? (
188
+ <Button
189
+ size="sm"
190
+ variant="destructive"
191
+ onClick={() => handleStop(job.id)}
192
+ >
193
+ Stop
194
+ </Button>
195
+ ) : (
196
+ <Button size="sm" onClick={() => handleStart(job.id)}>
197
+ Start
198
+ </Button>
199
+ )}
200
+ </div>
201
+ </TableCell>
202
+ </TableRow>
203
+ ))}
204
+ </TableBody>
205
+ </Table>
206
+ </CardContent>
207
+ </Card>
208
+
209
+ {/* Edit Dialog */}
210
+ <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
211
+ <DialogContent>
212
+ <DialogHeader>
213
+ <DialogTitle>Edit Job: {editingJob?.name}</DialogTitle>
214
+ </DialogHeader>
215
+ <div className="space-y-4 py-4">
216
+ <div className="space-y-2">
217
+ <Label htmlFor="schedule">Schedule</Label>
218
+ <Input
219
+ id="schedule"
220
+ value={editForm.schedule}
221
+ onChange={(e) =>
222
+ setEditForm({ ...editForm, schedule: e.target.value })
223
+ }
224
+ />
225
+ </div>
226
+ <div className="space-y-2">
227
+ <Label htmlFor="description">Description</Label>
228
+ <Input
229
+ id="description"
230
+ value={editForm.description}
231
+ onChange={(e) =>
232
+ setEditForm({ ...editForm, description: e.target.value })
233
+ }
234
+ />
235
+ </div>
236
+ </div>
237
+ <DialogFooter>
238
+ <Button variant="outline" onClick={() => setIsDialogOpen(false)}>
239
+ Cancel
240
+ </Button>
241
+ <Button onClick={handleSaveEdit}>Save Changes</Button>
242
+ </DialogFooter>
243
+ </DialogContent>
244
+ </Dialog>
245
+
246
+ {/* Log Viewer */}
247
+ <Card className="flex flex-col min-h-0 h-full">
248
+ <CardHeader className="pb-3 border-b flex flex-row items-center justify-between space-y-0">
249
+ <CardTitle>
250
+ {selectedJob
251
+ ? `Logs: ${jobs.find((j) => j.id === selectedJob)?.name}`
252
+ : "Job Logs"}
253
+ </CardTitle>
254
+ </CardHeader>
255
+ <div className="p-2 border-b">
256
+ <input
257
+ type="text"
258
+ placeholder="Search logs..."
259
+ className="w-full px-3 py-2 text-sm border rounded-md bg-background"
260
+ value={logSearchTerm}
261
+ onChange={(e) => setLogSearchTerm(e.target.value)}
262
+ />
263
+ </div>
264
+ <CardContent className="flex-1 p-0 min-h-0 bg-slate-50 dark:bg-slate-900/50">
265
+ <ScrollArea className="h-[600px] w-full p-4">
266
+ {!selectedJob && (
267
+ <div className="text-center text-muted-foreground py-10">
268
+ Select a job to view its logs
269
+ </div>
270
+ )}
271
+ {selectedJob && filteredLogs.length === 0 && (
272
+ <div className="text-center text-muted-foreground py-10">
273
+ {logs.length === 0
274
+ ? "No logs available"
275
+ : "No logs match your search"}
276
+ </div>
277
+ )}
278
+ <div className="space-y-2 font-mono text-xs">
279
+ {filteredLogs.map((log) => (
280
+ <div
281
+ key={log.id}
282
+ className="flex gap-2 border-b border-border/50 pb-1 last:border-0"
283
+ >
284
+ <span className="text-muted-foreground whitespace-nowrap">
285
+ {log.timestamp.toLocaleTimeString()}
286
+ </span>
287
+ <span
288
+ className={`font-semibold uppercase w-16 ${
289
+ log.level === "error"
290
+ ? "text-red-500"
291
+ : log.level === "warning"
292
+ ? "text-yellow-500"
293
+ : "text-blue-500"
294
+ }`}
295
+ >
296
+ [{log.level}]
297
+ </span>
298
+ <span className="break-all">{log.message}</span>
299
+ </div>
300
+ ))}
301
+ </div>
302
+ </ScrollArea>
303
+ </CardContent>
304
+ </Card>
305
+ </div>
306
+ </div>
307
+ );
308
+ };
@@ -0,0 +1,30 @@
1
+ import Image from "next/image";
2
+ import Link from "next/link";
3
+ import { Button } from "../primitives/button";
4
+
5
+ export function NotFoundPage() {
6
+ return (
7
+ <div className="min-h-screen w-full flex flex-col items-center justify-center gap-y-6 text-center text-foreground bg-background p-4">
8
+ <div className="flex flex-col-reverse justify-center items-center gap-y-6 md:flex-row md:text-start">
9
+ <Image
10
+ src="/images/illustrations/characters/character-02.svg"
11
+ alt=""
12
+ height={232}
13
+ width={249}
14
+ priority
15
+ />
16
+
17
+ <h1 className="inline-grid text-6xl font-black">
18
+ 404 <span className="text-3xl font-semibold">Page Not Found</span>
19
+ </h1>
20
+ </div>
21
+ <p className="max-w-prose text-xl text-muted-foreground">
22
+ We couldn&apos;t find the page you&apos;re looking for. It might have
23
+ been moved or doesn&apos;t exist.
24
+ </p>
25
+ <Button size="lg" asChild>
26
+ <Link href="/">Home Page</Link>
27
+ </Button>
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,66 @@
1
+ import * as React from "react";
2
+ import { cva } from "class-variance-authority";
3
+ import type { VariantProps } from "class-variance-authority";
4
+ import { cn } from "../../utils";
5
+
6
+ /**
7
+ * Badge Variants — Enhanced with Plane-inspired semantic tokens
8
+ *
9
+ * New variants:
10
+ * - danger: Red subtle background for errors/alerts
11
+ * - info: Blue subtle background for informational
12
+ * - accent: Brand color subtle background
13
+ *
14
+ * Updated variants:
15
+ * - success: Now uses semantic token (was hardcoded bg-green-500)
16
+ * - warning: Now uses semantic token (was hardcoded bg-yellow-500)
17
+ */
18
+ const badgeVariants = cva(
19
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
20
+ {
21
+ variants: {
22
+ variant: {
23
+ // Existing variants (backwards-compatible)
24
+ default: "border-transparent bg-primary text-primary-foreground",
25
+ secondary: "border-transparent bg-secondary text-secondary-foreground",
26
+ destructive:
27
+ "border-transparent bg-destructive text-destructive-foreground",
28
+ outline: "text-foreground",
29
+
30
+ // Enhanced semantic variants (using Design Tokens)
31
+ success:
32
+ "border-transparent bg-success-subtle text-success-text",
33
+ warning:
34
+ "border-transparent bg-warning-subtle text-warning-text",
35
+ danger:
36
+ "border-transparent bg-danger-subtle text-danger-text",
37
+ info:
38
+ "border-transparent bg-info-subtle text-info-text",
39
+ accent:
40
+ "border-transparent bg-accent-primary-subtle text-accent-primary",
41
+ },
42
+ size: {
43
+ default: "",
44
+ sm: "px-1.5 py-0 text-[10px]",
45
+ lg: "px-3 py-1 text-sm",
46
+ },
47
+ },
48
+ defaultVariants: {
49
+ variant: "default",
50
+ size: "default",
51
+ },
52
+ },
53
+ );
54
+
55
+ export interface BadgeProps
56
+ extends React.HTMLAttributes<HTMLDivElement>,
57
+ VariantProps<typeof badgeVariants> {}
58
+
59
+ function Badge({ className, variant, size, ...props }: BadgeProps) {
60
+ return (
61
+ <div className={cn(badgeVariants({ variant, size }), className)} {...props} />
62
+ );
63
+ }
64
+
65
+ export { Badge, badgeVariants };
66
+
@@ -0,0 +1,103 @@
1
+ import { Slot } from "@radix-ui/react-slot";
2
+ import { ChevronRight, Ellipsis } from "lucide-react";
3
+
4
+ import type { ComponentProps } from "react";
5
+
6
+ import { cn } from "../../utils";
7
+
8
+ export function Breadcrumb({ ...props }: ComponentProps<"nav">) {
9
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
10
+ }
11
+
12
+ export function BreadcrumbList({ className, ...props }: ComponentProps<"ol">) {
13
+ return (
14
+ <ol
15
+ data-slot="breadcrumb-list"
16
+ className={cn(
17
+ "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ export function BreadcrumbItem({ className, ...props }: ComponentProps<"li">) {
26
+ return (
27
+ <li
28
+ data-slot="breadcrumb-item"
29
+ className={cn("inline-flex items-center gap-1.5", className)}
30
+ {...props}
31
+ />
32
+ );
33
+ }
34
+
35
+ export function BreadcrumbLink({
36
+ asChild,
37
+ className,
38
+ ...props
39
+ }: ComponentProps<"a"> & {
40
+ asChild?: boolean;
41
+ }) {
42
+ const Comp = asChild ? Slot : "a";
43
+
44
+ return (
45
+ <Comp
46
+ data-slot="breadcrumb-link"
47
+ className={cn("transition-colors hover:text-foreground", className)}
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ export function BreadcrumbPage({
54
+ className,
55
+ ...props
56
+ }: ComponentProps<"span">) {
57
+ return (
58
+ <span
59
+ data-slot="breadcrumb-page"
60
+ role="link"
61
+ aria-disabled="true"
62
+ aria-current="page"
63
+ className={cn("font-normal text-foreground", className)}
64
+ {...props}
65
+ />
66
+ );
67
+ }
68
+
69
+ export function BreadcrumbSeparator({
70
+ children,
71
+ className,
72
+ ...props
73
+ }: ComponentProps<"li">) {
74
+ return (
75
+ <li
76
+ data-slot="breadcrumb-separator"
77
+ role="presentation"
78
+ aria-hidden="true"
79
+ className={cn("[&>svg]:size-3.5", className)}
80
+ {...props}
81
+ >
82
+ {children ?? <ChevronRight />}
83
+ </li>
84
+ );
85
+ }
86
+
87
+ export function BreadcrumbEllipsis({
88
+ className,
89
+ ...props
90
+ }: ComponentProps<"span">) {
91
+ return (
92
+ <span
93
+ data-slot="breadcrumb-ellipsis"
94
+ role="presentation"
95
+ aria-hidden="true"
96
+ aria-label="More"
97
+ className={cn("flex h-9 w-9 items-center justify-center", className)}
98
+ {...props}
99
+ >
100
+ <Ellipsis className="h-4 w-4" />
101
+ </span>
102
+ );
103
+ }
@@ -0,0 +1,129 @@
1
+ import * as React from "react";
2
+ import { cva } from "class-variance-authority";
3
+ import type { VariantProps } from "class-variance-authority";
4
+ import { cn } from "../../utils";
5
+
6
+ /**
7
+ * Button Variants — Enhanced with Plane-inspired semantic tokens
8
+ *
9
+ * New variants:
10
+ * - accent: Brand CTA button (indigo)
11
+ * - danger: Destructive action (red, solid)
12
+ * - danger-outline: Destructive action (red, outlined)
13
+ * - success: Positive action (green)
14
+ *
15
+ * New sizes:
16
+ * - xs: Ultra-compact for ERP table actions
17
+ * - compact: Compact for toolbars
18
+ */
19
+ const buttonVariants = cva(
20
+ "inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
21
+ {
22
+ variants: {
23
+ variant: {
24
+ // Existing variants (backwards-compatible)
25
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
26
+ destructive:
27
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
28
+ outline:
29
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
30
+ secondary:
31
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
32
+ ghost: "hover:bg-accent hover:text-accent-foreground",
33
+ link: "text-primary underline-offset-4 hover:underline",
34
+
35
+ // New Plane-inspired variants using semantic tokens
36
+ accent:
37
+ "bg-accent-primary text-text-on-color hover:bg-accent-primary-hover active:bg-accent-primary-active disabled:bg-layer-disabled disabled:text-text-disabled",
38
+ danger:
39
+ "bg-danger text-text-on-color hover:bg-danger-hover active:bg-danger-hover disabled:bg-layer-disabled disabled:text-text-disabled",
40
+ "danger-outline":
41
+ "border border-danger bg-layer-2 text-danger-text hover:bg-danger-subtle active:bg-danger-subtle disabled:border-border-subtle disabled:bg-layer-2 disabled:text-text-disabled",
42
+ success:
43
+ "bg-success-semantic text-text-on-color hover:bg-success-semantic/90 active:bg-success-semantic/80 disabled:bg-layer-disabled disabled:text-text-disabled",
44
+ tertiary:
45
+ "bg-layer-3 text-text-secondary hover:bg-layer-3-hover active:bg-layer-3-hover disabled:bg-transparent disabled:text-text-disabled",
46
+ },
47
+ size: {
48
+ // Existing sizes (backwards-compatible)
49
+ default: "h-10 px-4 py-2",
50
+ sm: "h-9 rounded-md px-3",
51
+ lg: "h-11 rounded-md px-8",
52
+ icon: "h-10 w-10",
53
+
54
+ // New ERP-specific compact sizes
55
+ xs: "h-7 rounded-sm px-2 text-xs",
56
+ compact: "h-8 rounded-md px-3 text-xs",
57
+ "icon-sm": "h-8 w-8",
58
+ "icon-xs": "h-7 w-7",
59
+ },
60
+ },
61
+ defaultVariants: {
62
+ variant: "default",
63
+ size: "default",
64
+ },
65
+ },
66
+ );
67
+
68
+ export interface ButtonProps
69
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
70
+ VariantProps<typeof buttonVariants> {
71
+ asChild?: boolean;
72
+ loading?: boolean;
73
+ prependIcon?: React.ReactElement;
74
+ appendIcon?: React.ReactElement;
75
+ }
76
+
77
+ import { Slot } from "@radix-ui/react-slot";
78
+
79
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
80
+ ({ className, variant, size, asChild = false, loading = false, prependIcon, appendIcon, children, disabled, ...props }, ref) => {
81
+ if (asChild) {
82
+ return (
83
+ <Slot
84
+ className={cn(buttonVariants({ variant, size }), className)}
85
+ ref={ref}
86
+ {...({ disabled: disabled || loading } as any)}
87
+ {...props}
88
+ >
89
+ {React.isValidElement(children) && (prependIcon || appendIcon) ? (
90
+ React.cloneElement(children as React.ReactElement, {} as any, (
91
+ <>
92
+ {prependIcon && React.cloneElement(prependIcon, {
93
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4"),
94
+ } as React.Attributes & Record<string, unknown>)}
95
+ {(children as any).props.children}
96
+ {appendIcon && React.cloneElement(appendIcon, {
97
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4"),
98
+ } as React.Attributes & Record<string, unknown>)}
99
+ </>
100
+ ))
101
+ ) : (
102
+ children
103
+ )}
104
+ </Slot>
105
+ );
106
+ }
107
+
108
+ return (
109
+ <button
110
+ className={cn(buttonVariants({ variant, size }), className)}
111
+ ref={ref}
112
+ disabled={disabled || loading}
113
+ {...props}
114
+ >
115
+ {prependIcon && React.cloneElement(prependIcon, {
116
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4"),
117
+ } as React.Attributes & Record<string, unknown>)}
118
+ {children}
119
+ {appendIcon && React.cloneElement(appendIcon, {
120
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4"),
121
+ } as React.Attributes & Record<string, unknown>)}
122
+ </button>
123
+ );
124
+ },
125
+ );
126
+ Button.displayName = "Button";
127
+
128
+ export { Button, buttonVariants };
129
+