shutro-erp 0.3.6 → 0.3.7

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 (623) hide show
  1. package/dist/account_asset/.kosh/bindings.js +1 -1
  2. package/dist/account_asset/.kosh/schema.d.ts +530 -8
  3. package/dist/account_asset/i18n/bn.d.ts +2 -0
  4. package/dist/account_asset/i18n/bn.js +97 -0
  5. package/dist/account_asset/index.js +2 -0
  6. package/dist/account_asset/module.d.ts +4899 -1445
  7. package/dist/account_budget/.kosh/bindings.js +1 -1
  8. package/dist/account_budget/.kosh/schema.d.ts +1130 -56
  9. package/dist/account_budget/i18n/bn.d.ts +2 -0
  10. package/dist/account_budget/i18n/bn.js +63 -0
  11. package/dist/account_budget/index.js +14 -0
  12. package/dist/account_budget/module.d.ts +17958 -4532
  13. package/dist/account_budget/module.js +15 -0
  14. package/dist/account_portal/.kosh/bindings.js +1 -1
  15. package/dist/account_portal/.kosh/schema.d.ts +530 -8
  16. package/dist/account_portal/i18n/bn.d.ts +2 -0
  17. package/dist/account_portal/i18n/bn.js +6 -0
  18. package/dist/account_portal/index.js +2 -0
  19. package/dist/account_portal/module.d.ts +5167 -1693
  20. package/dist/accounting/.kosh/bindings.js +1 -1
  21. package/dist/accounting/.kosh/schema.d.ts +530 -8
  22. package/dist/accounting/closing.js +1 -0
  23. package/dist/accounting/fiscal.d.ts +578 -0
  24. package/dist/accounting/fiscal.js +401 -0
  25. package/dist/accounting/followups.d.ts +618 -0
  26. package/dist/accounting/followups.js +420 -0
  27. package/dist/accounting/i18n/bn.d.ts +2 -0
  28. package/dist/accounting/i18n/bn.js +425 -0
  29. package/dist/accounting/index.d.ts +2 -0
  30. package/dist/accounting/index.js +649 -2
  31. package/dist/accounting/module.d.ts +4998 -1451
  32. package/dist/accounting/module.js +124 -18
  33. package/dist/accounting/statements.d.ts +878 -0
  34. package/dist/accounting/statements.js +728 -0
  35. package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
  36. package/dist/accounting/web/BankReconcilePage.js +138 -0
  37. package/dist/accounting/web/FollowupsPage.d.ts +8 -0
  38. package/dist/accounting/web/FollowupsPage.js +54 -0
  39. package/dist/accounting/web/PostingPreview.d.ts +8 -0
  40. package/dist/accounting/web/PostingPreview.js +26 -0
  41. package/dist/accounting/web/index.d.ts +3 -0
  42. package/dist/accounting/web/index.js +9 -0
  43. package/dist/accounting/web/messages.js +140 -0
  44. package/dist/approvals/.kosh/bindings.js +1 -1
  45. package/dist/approvals/.kosh/schema.d.ts +272 -4
  46. package/dist/approvals/demo.d.ts +7 -0
  47. package/dist/approvals/demo.js +41 -0
  48. package/dist/approvals/i18n/bn.d.ts +2 -0
  49. package/dist/approvals/i18n/bn.js +133 -0
  50. package/dist/approvals/index.d.ts +19 -1
  51. package/dist/approvals/index.js +477 -7
  52. package/dist/approvals/mails.d.ts +7 -2
  53. package/dist/approvals/mails.js +8 -3
  54. package/dist/approvals/module.d.ts +2930 -1
  55. package/dist/approvals/module.js +468 -7
  56. package/dist/approvals/web/Config.d.ts +12 -0
  57. package/dist/approvals/web/Config.js +60 -0
  58. package/dist/approvals/web/Matrix.d.ts +9 -0
  59. package/dist/approvals/web/Matrix.js +26 -0
  60. package/dist/approvals/web/index.d.ts +3 -1
  61. package/dist/approvals/web/index.js +8 -1
  62. package/dist/approvals/web/messages.js +92 -0
  63. package/dist/approvals_purchase/.kosh/bindings.js +15 -0
  64. package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
  65. package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
  66. package/dist/approvals_purchase/i18n/bn.js +5 -0
  67. package/dist/approvals_purchase/index.d.ts +3 -0
  68. package/dist/approvals_purchase/index.js +47 -0
  69. package/dist/approvals_purchase/module.d.ts +12670 -0
  70. package/dist/approvals_purchase/module.js +84 -0
  71. package/dist/attendance/.kosh/bindings.js +1 -1
  72. package/dist/attendance/.kosh/schema.d.ts +59 -1
  73. package/dist/attendance/i18n/bn.d.ts +2 -0
  74. package/dist/attendance/i18n/bn.js +147 -0
  75. package/dist/attendance/index.js +3 -1
  76. package/dist/attendance/module.d.ts +452 -8
  77. package/dist/automation/engine.js +1 -1
  78. package/dist/calendar/.kosh/bindings.js +1 -1
  79. package/dist/calendar/.kosh/schema.d.ts +2 -1
  80. package/dist/calendar/i18n/bn.d.ts +2 -0
  81. package/dist/calendar/i18n/bn.js +80 -0
  82. package/dist/calendar/index.js +77 -0
  83. package/dist/calendar/module.d.ts +26 -0
  84. package/dist/calendar/module.js +14 -4
  85. package/dist/cli/apps.js +25 -5
  86. package/dist/cli/init.js +14 -4
  87. package/dist/cli/templates.d.ts +1 -1
  88. package/dist/cli/templates.js +34 -5
  89. package/dist/contacts/.kosh/bindings.js +1 -1
  90. package/dist/contacts/.kosh/schema.d.ts +2 -1
  91. package/dist/contacts/i18n/bn.d.ts +2 -0
  92. package/dist/contacts/i18n/bn.js +67 -0
  93. package/dist/contacts/index.js +3 -0
  94. package/dist/contacts/module.d.ts +42 -0
  95. package/dist/contacts/module.js +6 -1
  96. package/dist/crm/.kosh/bindings.js +1 -1
  97. package/dist/crm/.kosh/schema.d.ts +2 -1
  98. package/dist/crm/i18n/bn.d.ts +2 -0
  99. package/dist/crm/i18n/bn.js +80 -0
  100. package/dist/crm/index.js +22 -0
  101. package/dist/crm/module.d.ts +20 -0
  102. package/dist/crm/module.js +4 -2
  103. package/dist/documents/.kosh/bindings.js +1 -1
  104. package/dist/documents/.kosh/schema.d.ts +2 -1
  105. package/dist/documents/i18n/bn.d.ts +2 -0
  106. package/dist/documents/i18n/bn.js +83 -0
  107. package/dist/documents/index.js +128 -1
  108. package/dist/documents/module.d.ts +20 -0
  109. package/dist/documents/module.js +1 -0
  110. package/dist/event/.kosh/bindings.js +1 -1
  111. package/dist/event/.kosh/schema.d.ts +2 -1
  112. package/dist/event/i18n/bn.d.ts +2 -0
  113. package/dist/event/i18n/bn.js +101 -0
  114. package/dist/event/index.js +66 -0
  115. package/dist/event/module.d.ts +20 -0
  116. package/dist/event/module.js +8 -1
  117. package/dist/event_account/.kosh/bindings.js +1 -1
  118. package/dist/event_account/.kosh/schema.d.ts +530 -8
  119. package/dist/event_account/i18n/bn.d.ts +2 -0
  120. package/dist/event_account/i18n/bn.js +5 -0
  121. package/dist/event_account/index.js +2 -0
  122. package/dist/event_account/module.d.ts +4905 -1431
  123. package/dist/expense/.kosh/bindings.js +1 -1
  124. package/dist/expense/.kosh/schema.d.ts +323 -2
  125. package/dist/expense/i18n/bn.d.ts +2 -0
  126. package/dist/expense/i18n/bn.js +155 -0
  127. package/dist/expense/index.js +8 -1
  128. package/dist/expense/module.d.ts +2715 -694
  129. package/dist/expense/module.js +3 -1
  130. package/dist/expense_account/.kosh/bindings.js +1 -1
  131. package/dist/expense_account/.kosh/schema.d.ts +587 -8
  132. package/dist/expense_account/i18n/bn.d.ts +2 -0
  133. package/dist/expense_account/i18n/bn.js +15 -0
  134. package/dist/expense_account/index.js +2 -0
  135. package/dist/expense_account/module.d.ts +8094 -2619
  136. package/dist/helpdesk/.kosh/bindings.js +1 -1
  137. package/dist/helpdesk/.kosh/schema.d.ts +2 -1
  138. package/dist/helpdesk/i18n/bn.d.ts +2 -0
  139. package/dist/helpdesk/i18n/bn.js +127 -0
  140. package/dist/helpdesk/index.js +2 -0
  141. package/dist/helpdesk/module.d.ts +20 -0
  142. package/dist/hr/.kosh/bindings.js +1 -1
  143. package/dist/hr/.kosh/schema.d.ts +59 -1
  144. package/dist/hr/demo.js +11 -1
  145. package/dist/hr/i18n/bn.d.ts +2 -0
  146. package/dist/hr/i18n/bn.js +126 -0
  147. package/dist/hr/index.d.ts +1 -1
  148. package/dist/hr/index.js +158 -12
  149. package/dist/hr/module.d.ts +932 -59
  150. package/dist/hr/module.js +114 -17
  151. package/dist/{mrp → indent}/.kosh/bindings.js +2 -2
  152. package/dist/indent/.kosh/schema.d.ts +2084 -0
  153. package/dist/indent/demo.d.ts +7 -0
  154. package/dist/indent/demo.js +48 -0
  155. package/dist/indent/i18n/bn.d.ts +2 -0
  156. package/dist/indent/i18n/bn.js +143 -0
  157. package/dist/indent/index.d.ts +3 -0
  158. package/dist/indent/index.js +450 -0
  159. package/dist/{mrp → indent}/module.d.ts +7164 -3075
  160. package/dist/indent/module.js +792 -0
  161. package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
  162. package/dist/indent_purchase/.kosh/bindings.js +15 -0
  163. package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
  164. package/dist/indent_purchase/i18n/bn.d.ts +2 -0
  165. package/dist/indent_purchase/i18n/bn.js +13 -0
  166. package/dist/indent_purchase/index.d.ts +3 -0
  167. package/dist/indent_purchase/index.js +61 -0
  168. package/dist/indent_purchase/module.d.ts +27950 -0
  169. package/dist/indent_purchase/module.js +163 -0
  170. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  171. package/dist/l10n_bd/.kosh/schema.d.ts +530 -8
  172. package/dist/l10n_bd/i18n/bn.d.ts +2 -0
  173. package/dist/l10n_bd/i18n/bn.js +69 -0
  174. package/dist/l10n_bd/index.js +2 -0
  175. package/dist/l10n_bd/module.d.ts +5167 -1693
  176. package/dist/l10n_bd_payroll/.kosh/bindings.js +1 -1
  177. package/dist/l10n_bd_payroll/.kosh/schema.d.ts +587 -8
  178. package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
  179. package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
  180. package/dist/l10n_bd_payroll/index.js +2 -0
  181. package/dist/l10n_bd_payroll/module.d.ts +5910 -1548
  182. package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
  183. package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
  184. package/dist/{mrp_account → l10n_bd_pos}/.kosh/schema.d.ts +693 -651
  185. package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
  186. package/dist/l10n_bd_pos/i18n/bn.js +32 -0
  187. package/dist/l10n_bd_pos/index.d.ts +3 -0
  188. package/dist/l10n_bd_pos/index.js +111 -0
  189. package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +7402 -7647
  190. package/dist/l10n_bd_pos/module.js +43 -0
  191. package/dist/l10n_in/.kosh/bindings.js +1 -1
  192. package/dist/l10n_in/.kosh/schema.d.ts +530 -8
  193. package/dist/l10n_in/i18n/bn.d.ts +2 -0
  194. package/dist/l10n_in/i18n/bn.js +95 -0
  195. package/dist/l10n_in/index.js +2 -0
  196. package/dist/l10n_in/module.d.ts +6703 -1652
  197. package/dist/l10n_in/module.js +25 -5
  198. package/dist/l10n_in/web/GstSettings.js +2 -2
  199. package/dist/mail/inbound/handle.js +2 -4
  200. package/dist/mail/inbound/models.js +5 -3
  201. package/dist/mail/index.d.ts +12 -1
  202. package/dist/mail/index.js +139 -2
  203. package/dist/mail/send.d.ts +56 -0
  204. package/dist/mail/send.js +394 -0
  205. package/dist/mail/web/SendButton.d.ts +9 -0
  206. package/dist/mail/web/SendButton.js +71 -0
  207. package/dist/mail/web/SendSelected.d.ts +8 -0
  208. package/dist/mail/web/SendSelected.js +33 -0
  209. package/dist/mail/web/index.d.ts +2 -0
  210. package/dist/mail/web/index.js +6 -0
  211. package/dist/mail/web/messages.js +36 -0
  212. package/dist/maintenance/.kosh/bindings.js +1 -1
  213. package/dist/maintenance/.kosh/schema.d.ts +2 -1
  214. package/dist/maintenance/i18n/bn.d.ts +2 -0
  215. package/dist/maintenance/i18n/bn.js +132 -0
  216. package/dist/maintenance/index.js +85 -0
  217. package/dist/maintenance/module.d.ts +25 -0
  218. package/dist/maintenance/module.js +27 -9
  219. package/dist/maintenance_stock/.kosh/bindings.js +1 -1
  220. package/dist/maintenance_stock/.kosh/schema.d.ts +298 -2
  221. package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
  222. package/dist/maintenance_stock/i18n/bn.js +21 -0
  223. package/dist/maintenance_stock/index.js +2 -0
  224. package/dist/maintenance_stock/module.d.ts +5302 -1256
  225. package/dist/maintenance_stock/module.js +1 -0
  226. package/dist/modules-sdk/apps.d.ts +10 -0
  227. package/dist/modules-sdk/apps.js +32 -0
  228. package/dist/modules-sdk/index.d.ts +1 -1
  229. package/dist/modules-sdk/manifest.d.ts +68 -2
  230. package/dist/payment/.kosh/bindings.js +1 -1
  231. package/dist/payment/.kosh/schema.d.ts +530 -8
  232. package/dist/payment/i18n/bn.d.ts +2 -0
  233. package/dist/payment/i18n/bn.js +59 -0
  234. package/dist/payment/index.js +85 -0
  235. package/dist/payment/module.d.ts +5134 -1660
  236. package/dist/payment/module.js +17 -3
  237. package/dist/payment/settle.js +1 -0
  238. package/dist/payroll/.kosh/bindings.js +1 -1
  239. package/dist/payroll/.kosh/schema.d.ts +59 -1
  240. package/dist/payroll/i18n/bn.d.ts +2 -0
  241. package/dist/payroll/i18n/bn.js +206 -0
  242. package/dist/payroll/index.js +2 -0
  243. package/dist/payroll/module.d.ts +936 -48
  244. package/dist/payroll_account/.kosh/bindings.js +1 -1
  245. package/dist/payroll_account/.kosh/schema.d.ts +587 -8
  246. package/dist/payroll_account/i18n/bn.d.ts +2 -0
  247. package/dist/payroll_account/i18n/bn.js +10 -0
  248. package/dist/payroll_account/index.js +2 -0
  249. package/dist/payroll_account/module.d.ts +7534 -3192
  250. package/dist/permissions/approvals.d.ts +97 -4
  251. package/dist/permissions/approvals.js +780 -31
  252. package/dist/permissions/index.d.ts +1 -1
  253. package/dist/permissions/index.js +2 -2
  254. package/dist/permissions/models.js +177 -5
  255. package/dist/permissions/routes.d.ts +3 -0
  256. package/dist/permissions/routes.js +36 -2
  257. package/dist/permissions/web/ApprovalPanel.js +43 -5
  258. package/dist/permissions/web/messages.js +52 -0
  259. package/dist/portal/.kosh/bindings.js +1 -1
  260. package/dist/portal/.kosh/schema.d.ts +2 -1
  261. package/dist/portal/documents.d.ts +3 -0
  262. package/dist/portal/documents.js +21 -1
  263. package/dist/portal/i18n/bn.d.ts +2 -0
  264. package/dist/portal/i18n/bn.js +33 -0
  265. package/dist/portal/index.js +2 -0
  266. package/dist/portal/module.d.ts +20 -0
  267. package/dist/portal/routes-documents.js +76 -0
  268. package/dist/pos/.kosh/bindings.js +1 -1
  269. package/dist/pos/.kosh/schema.d.ts +531 -8
  270. package/dist/pos/i18n/bn.d.ts +2 -0
  271. package/dist/pos/i18n/bn.js +133 -0
  272. package/dist/pos/index.js +83 -1
  273. package/dist/pos/module.d.ts +6888 -1777
  274. package/dist/pos/module.js +49 -5
  275. package/dist/pos/routes.js +80 -7
  276. package/dist/pos/web/Register.js +2 -5
  277. package/dist/pos_stock/.kosh/bindings.js +1 -1
  278. package/dist/pos_stock/.kosh/schema.d.ts +626 -9
  279. package/dist/pos_stock/i18n/bn.d.ts +2 -0
  280. package/dist/pos_stock/i18n/bn.js +6 -0
  281. package/dist/pos_stock/index.js +2 -0
  282. package/dist/pos_stock/module.d.ts +10798 -3276
  283. package/dist/product/.kosh/bindings.js +1 -1
  284. package/dist/product/.kosh/schema.d.ts +202 -1
  285. package/dist/product/i18n/bn.d.ts +2 -0
  286. package/dist/product/i18n/bn.js +175 -0
  287. package/dist/product/index.d.ts +1 -0
  288. package/dist/product/index.js +288 -1
  289. package/dist/product/module.d.ts +1725 -0
  290. package/dist/product/module.js +66 -6
  291. package/dist/product/pricelist.d.ts +575 -0
  292. package/dist/product/pricelist.js +257 -0
  293. package/dist/product/variants.d.ts +908 -0
  294. package/dist/product/variants.js +251 -0
  295. package/dist/production/.kosh/bindings.d.ts +22 -0
  296. package/dist/production/.kosh/bindings.js +15 -0
  297. package/dist/production/.kosh/schema.d.ts +2345 -0
  298. package/dist/{mrp → production}/demo.d.ts +1 -1
  299. package/dist/{mrp → production}/demo.js +5 -5
  300. package/dist/production/depth.d.ts +790 -0
  301. package/dist/production/depth.js +262 -0
  302. package/dist/production/i18n/bn.d.ts +2 -0
  303. package/dist/production/i18n/bn.js +350 -0
  304. package/dist/production/index.d.ts +6 -0
  305. package/dist/production/index.js +1256 -0
  306. package/dist/production/module.d.ts +17327 -0
  307. package/dist/production/module.js +1333 -0
  308. package/dist/production/plan.d.ts +921 -0
  309. package/dist/production/plan.js +511 -0
  310. package/dist/production/schedule.d.ts +656 -0
  311. package/dist/production/schedule.js +309 -0
  312. package/dist/production_account/.kosh/bindings.d.ts +22 -0
  313. package/dist/production_account/.kosh/bindings.js +15 -0
  314. package/dist/production_account/.kosh/schema.d.ts +3496 -0
  315. package/dist/production_account/i18n/bn.d.ts +2 -0
  316. package/dist/production_account/i18n/bn.js +93 -0
  317. package/dist/production_account/index.d.ts +4 -0
  318. package/dist/production_account/index.js +246 -0
  319. package/dist/production_account/module.d.ts +1192 -0
  320. package/dist/{mrp_account → production_account}/module.js +72 -18
  321. package/dist/production_account/overhead.d.ts +1195 -0
  322. package/dist/production_account/overhead.js +554 -0
  323. package/dist/project/.kosh/bindings.js +1 -1
  324. package/dist/project/.kosh/schema.d.ts +65 -2
  325. package/dist/project/i18n/bn.d.ts +2 -0
  326. package/dist/project/i18n/bn.js +383 -0
  327. package/dist/project/index.js +123 -0
  328. package/dist/project/module.d.ts +20 -0
  329. package/dist/project/module.js +73 -14
  330. package/dist/project_account/.kosh/bindings.js +1 -1
  331. package/dist/project_account/.kosh/schema.d.ts +530 -8
  332. package/dist/project_account/i18n/bn.d.ts +2 -0
  333. package/dist/project_account/i18n/bn.js +6 -0
  334. package/dist/project_account/index.js +2 -0
  335. package/dist/project_account/module.d.ts +4926 -1452
  336. package/dist/project_portal/.kosh/bindings.js +1 -1
  337. package/dist/project_portal/.kosh/schema.d.ts +65 -2
  338. package/dist/project_portal/i18n/bn.d.ts +2 -0
  339. package/dist/project_portal/i18n/bn.js +6 -0
  340. package/dist/project_portal/index.js +2 -0
  341. package/dist/project_portal/module.d.ts +40 -0
  342. package/dist/project_purchase/.kosh/bindings.js +1 -1
  343. package/dist/project_purchase/.kosh/schema.d.ts +1126 -53
  344. package/dist/project_purchase/i18n/bn.d.ts +2 -0
  345. package/dist/project_purchase/i18n/bn.js +4 -0
  346. package/dist/project_purchase/index.js +2 -0
  347. package/dist/project_purchase/module.d.ts +17912 -4446
  348. package/dist/purchase/.kosh/bindings.js +1 -1
  349. package/dist/purchase/.kosh/schema.d.ts +813 -3
  350. package/dist/purchase/comparison.d.ts +993 -0
  351. package/dist/purchase/comparison.js +415 -0
  352. package/dist/purchase/extras.d.ts +1509 -0
  353. package/dist/purchase/extras.js +445 -0
  354. package/dist/purchase/i18n/bn.d.ts +2 -0
  355. package/dist/purchase/i18n/bn.js +413 -0
  356. package/dist/purchase/index.d.ts +5 -0
  357. package/dist/purchase/index.js +1280 -4
  358. package/dist/purchase/module.d.ts +7139 -398
  359. package/dist/purchase/module.js +295 -11
  360. package/dist/purchase/request.d.ts +696 -0
  361. package/dist/purchase/request.js +446 -0
  362. package/dist/purchase/tender.d.ts +1208 -0
  363. package/dist/purchase/tender.js +507 -0
  364. package/dist/purchase/vendorprice.d.ts +340 -0
  365. package/dist/purchase/vendorprice.js +153 -0
  366. package/dist/purchase_account/.kosh/bindings.js +1 -1
  367. package/dist/purchase_account/.kosh/schema.d.ts +1130 -57
  368. package/dist/purchase_account/i18n/bn.d.ts +2 -0
  369. package/dist/purchase_account/i18n/bn.js +22 -0
  370. package/dist/purchase_account/index.js +19 -0
  371. package/dist/purchase_account/module.d.ts +12276 -2247
  372. package/dist/purchase_account/module.js +241 -9
  373. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  374. package/dist/purchase_portal/.kosh/schema.d.ts +813 -3
  375. package/dist/purchase_portal/i18n/bn.d.ts +2 -0
  376. package/dist/purchase_portal/i18n/bn.js +5 -0
  377. package/dist/purchase_portal/index.js +2 -0
  378. package/dist/purchase_portal/module.d.ts +6849 -353
  379. package/dist/purchase_stock/.kosh/bindings.js +1 -1
  380. package/dist/purchase_stock/.kosh/schema.d.ts +910 -4
  381. package/dist/purchase_stock/i18n/bn.d.ts +2 -0
  382. package/dist/purchase_stock/i18n/bn.js +19 -0
  383. package/dist/purchase_stock/index.d.ts +1 -1
  384. package/dist/purchase_stock/index.js +29 -0
  385. package/dist/purchase_stock/module.d.ts +12410 -1864
  386. package/dist/purchase_stock/module.js +81 -9
  387. package/dist/purchase_stock/scorecard.d.ts +22 -0
  388. package/dist/purchase_stock/scorecard.js +77 -0
  389. package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
  390. package/dist/purchase_stock/web/Scorecard.js +22 -0
  391. package/dist/purchase_stock/web/index.d.ts +11 -0
  392. package/dist/purchase_stock/web/index.js +16 -0
  393. package/dist/purchase_stock/web/messages.d.ts +2 -0
  394. package/dist/purchase_stock/web/messages.js +27 -0
  395. package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
  396. package/dist/purchase_stock_account/.kosh/schema.d.ts +1286 -58
  397. package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
  398. package/dist/purchase_stock_account/i18n/bn.js +8 -0
  399. package/dist/purchase_stock_account/index.js +18 -0
  400. package/dist/purchase_stock_account/module.d.ts +7 -37995
  401. package/dist/purchase_stock_account/module.js +24 -3
  402. package/dist/recruitment/.kosh/bindings.js +1 -1
  403. package/dist/recruitment/.kosh/schema.d.ts +59 -1
  404. package/dist/recruitment/i18n/bn.d.ts +2 -0
  405. package/dist/recruitment/i18n/bn.js +93 -0
  406. package/dist/recruitment/index.js +64 -0
  407. package/dist/recruitment/module.d.ts +458 -8
  408. package/dist/recruitment/module.js +11 -3
  409. package/dist/reporting/documents.d.ts +5 -0
  410. package/dist/reporting/documents.js +11 -1
  411. package/dist/reporting/index.d.ts +1 -1
  412. package/dist/reporting/index.js +1 -1
  413. package/dist/reporting/web/CalendarView.d.ts +18 -5
  414. package/dist/reporting/web/CalendarView.js +163 -29
  415. package/dist/reporting/web/messages.js +18 -0
  416. package/dist/sale_account/.kosh/bindings.js +1 -1
  417. package/dist/sale_account/.kosh/schema.d.ts +642 -16
  418. package/dist/sale_account/i18n/bn.d.ts +2 -0
  419. package/dist/sale_account/i18n/bn.js +48 -0
  420. package/dist/sale_account/index.d.ts +1 -1
  421. package/dist/sale_account/index.js +102 -4
  422. package/dist/sale_account/module.d.ts +8254 -2212
  423. package/dist/sale_account/module.js +535 -46
  424. package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
  425. package/dist/sale_crm/.kosh/bindings.js +15 -0
  426. package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +389 -567
  427. package/dist/sale_crm/i18n/bn.d.ts +2 -0
  428. package/dist/sale_crm/i18n/bn.js +9 -0
  429. package/dist/sale_crm/index.d.ts +7 -0
  430. package/dist/sale_crm/index.js +104 -0
  431. package/dist/sale_crm/module.d.ts +5609 -0
  432. package/dist/sale_crm/module.js +73 -0
  433. package/dist/sale_portal/.kosh/bindings.js +1 -1
  434. package/dist/sale_portal/.kosh/schema.d.ts +291 -4
  435. package/dist/sale_portal/i18n/bn.d.ts +2 -0
  436. package/dist/sale_portal/i18n/bn.js +7 -0
  437. package/dist/sale_portal/index.js +10 -0
  438. package/dist/sale_portal/module.d.ts +2564 -294
  439. package/dist/sale_project/.kosh/bindings.js +1 -1
  440. package/dist/sale_project/.kosh/schema.d.ts +354 -5
  441. package/dist/sale_project/i18n/bn.d.ts +2 -0
  442. package/dist/sale_project/i18n/bn.js +12 -0
  443. package/dist/sale_project/index.js +2 -0
  444. package/dist/sale_project/module.d.ts +6249 -2402
  445. package/dist/sale_stock/.kosh/bindings.js +1 -1
  446. package/dist/sale_stock/.kosh/schema.d.ts +387 -5
  447. package/dist/sale_stock/i18n/bn.d.ts +2 -0
  448. package/dist/sale_stock/i18n/bn.js +15 -0
  449. package/dist/sale_stock/index.js +2 -0
  450. package/dist/sale_stock/module.d.ts +8057 -1759
  451. package/dist/sale_stock/module.js +20 -3
  452. package/dist/sales/.kosh/bindings.js +1 -1
  453. package/dist/sales/.kosh/schema.d.ts +291 -4
  454. package/dist/sales/i18n/bn.d.ts +2 -0
  455. package/dist/sales/i18n/bn.js +128 -0
  456. package/dist/sales/index.js +120 -5
  457. package/dist/sales/module.d.ts +3567 -633
  458. package/dist/sales/module.js +306 -11
  459. package/dist/server/api/duplicate.d.ts +14 -0
  460. package/dist/server/api/duplicate.js +75 -0
  461. package/dist/server/api/explain.d.ts +70 -0
  462. package/dist/server/api/explain.js +111 -0
  463. package/dist/server/api/metadata.d.ts +2 -0
  464. package/dist/server/api/metadata.js +9 -0
  465. package/dist/server/api/openapi.js +15 -0
  466. package/dist/server/api/rest.d.ts +1 -0
  467. package/dist/server/api/rest.js +76 -12
  468. package/dist/server/api/views.js +1 -1
  469. package/dist/server/apps.d.ts +16 -1
  470. package/dist/server/apps.js +164 -2
  471. package/dist/server/auth/base.js +2 -0
  472. package/dist/server/auth/service.d.ts +8 -0
  473. package/dist/server/auth/service.js +19 -0
  474. package/dist/server/events.d.ts +13 -0
  475. package/dist/server/events.js +22 -0
  476. package/dist/server/i18n.d.ts +27 -0
  477. package/dist/server/i18n.js +143 -0
  478. package/dist/server/index.d.ts +2 -0
  479. package/dist/server/index.js +2 -0
  480. package/dist/server/server.js +6 -0
  481. package/dist/settings/company.d.ts +3 -1
  482. package/dist/settings/company.js +26 -5
  483. package/dist/settings/routes.d.ts +10 -0
  484. package/dist/settings/routes.js +19 -3
  485. package/dist/settings/web/AppsPage.d.ts +3 -2
  486. package/dist/settings/web/AppsPage.js +26 -8
  487. package/dist/settings/web/CompaniesPage.js +91 -6
  488. package/dist/settings/web/messages.js +64 -0
  489. package/dist/sign/.kosh/bindings.js +1 -1
  490. package/dist/sign/.kosh/schema.d.ts +2 -1
  491. package/dist/sign/i18n/bn.d.ts +2 -0
  492. package/dist/sign/i18n/bn.js +97 -0
  493. package/dist/sign/index.d.ts +15 -0
  494. package/dist/sign/index.js +129 -1
  495. package/dist/sign/module.d.ts +40 -0
  496. package/dist/sign/module.js +11 -2
  497. package/dist/stock/.kosh/bindings.js +1 -1
  498. package/dist/stock/.kosh/schema.d.ts +298 -2
  499. package/dist/stock/i18n/bn.d.ts +2 -0
  500. package/dist/stock/i18n/bn.js +311 -0
  501. package/dist/stock/index.d.ts +3 -1
  502. package/dist/stock/index.js +442 -3
  503. package/dist/stock/ledger.d.ts +78 -0
  504. package/dist/stock/ledger.js +582 -0
  505. package/dist/stock/module.d.ts +5280 -2044
  506. package/dist/stock/module.js +222 -23
  507. package/dist/stock/replenish.js +16 -1
  508. package/dist/stock/returns.d.ts +157 -0
  509. package/dist/stock/returns.js +163 -0
  510. package/dist/stock/web/Ledger.d.ts +9 -0
  511. package/dist/stock/web/Ledger.js +108 -0
  512. package/dist/stock/web/Operations.d.ts +8 -0
  513. package/dist/stock/web/Operations.js +33 -0
  514. package/dist/stock/web/ReturnButton.d.ts +7 -0
  515. package/dist/stock/web/ReturnButton.js +62 -0
  516. package/dist/stock/web/index.d.ts +3 -0
  517. package/dist/stock/web/index.js +9 -0
  518. package/dist/stock/web/messages.js +154 -0
  519. package/dist/stock_account/.kosh/bindings.js +1 -1
  520. package/dist/stock_account/.kosh/schema.d.ts +682 -9
  521. package/dist/stock_account/i18n/bn.d.ts +2 -0
  522. package/dist/stock_account/i18n/bn.js +73 -0
  523. package/dist/stock_account/index.d.ts +1 -0
  524. package/dist/stock_account/index.js +131 -3
  525. package/dist/stock_account/landed.d.ts +429 -0
  526. package/dist/stock_account/landed.js +335 -0
  527. package/dist/stock_account/module.d.ts +11247 -3363
  528. package/dist/stock_account/module.js +135 -6
  529. package/dist/stock_account/web/LandedPreview.d.ts +7 -0
  530. package/dist/stock_account/web/LandedPreview.js +23 -0
  531. package/dist/stock_account/web/index.d.ts +11 -0
  532. package/dist/stock_account/web/index.js +16 -0
  533. package/dist/stock_account/web/messages.d.ts +2 -0
  534. package/dist/stock_account/web/messages.js +27 -0
  535. package/dist/todo/i18n/bn.d.ts +2 -0
  536. package/dist/todo/i18n/bn.js +66 -0
  537. package/dist/todo/index.js +59 -0
  538. package/dist/todo/module.d.ts +5 -0
  539. package/dist/todo/module.js +5 -3
  540. package/dist/trade_finance/.kosh/bindings.js +1 -1
  541. package/dist/trade_finance/.kosh/schema.d.ts +2 -1
  542. package/dist/trade_finance/i18n/bn.d.ts +2 -0
  543. package/dist/trade_finance/i18n/bn.js +162 -0
  544. package/dist/trade_finance/index.js +93 -0
  545. package/dist/trade_finance/module.d.ts +26 -0
  546. package/dist/trade_finance/module.js +27 -8
  547. package/dist/trade_finance_account/.kosh/bindings.js +1 -1
  548. package/dist/trade_finance_account/.kosh/schema.d.ts +530 -8
  549. package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
  550. package/dist/trade_finance_account/i18n/bn.js +27 -0
  551. package/dist/trade_finance_account/index.js +2 -0
  552. package/dist/trade_finance_account/module.d.ts +4906 -1432
  553. package/dist/trade_finance_account/module.js +1 -0
  554. package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
  555. package/dist/trade_finance_purchase/.kosh/schema.d.ts +813 -3
  556. package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
  557. package/dist/trade_finance_purchase/i18n/bn.js +6 -0
  558. package/dist/trade_finance_purchase/index.js +2 -0
  559. package/dist/trade_finance_purchase/module.d.ts +6909 -413
  560. package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
  561. package/dist/trade_finance_sale/.kosh/schema.d.ts +291 -4
  562. package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
  563. package/dist/trade_finance_sale/i18n/bn.js +6 -0
  564. package/dist/trade_finance_sale/index.js +2 -0
  565. package/dist/trade_finance_sale/module.d.ts +2601 -331
  566. package/dist/ui/api.d.ts +2 -0
  567. package/dist/ui/app.d.ts +9 -0
  568. package/dist/ui/app.js +24 -4
  569. package/dist/ui/components/AppIcon.js +2 -2
  570. package/dist/ui/components/Explain.d.ts +69 -0
  571. package/dist/ui/components/Explain.js +62 -0
  572. package/dist/ui/context.d.ts +8 -1
  573. package/dist/ui/context.js +34 -1
  574. package/dist/ui/i18n/messages.d.ts +36 -0
  575. package/dist/ui/i18n/messages.js +72 -0
  576. package/dist/ui/index.d.ts +2 -1
  577. package/dist/ui/index.js +1 -0
  578. package/dist/ui/registry.d.ts +14 -0
  579. package/dist/ui/registry.js +10 -0
  580. package/dist/ui/views/FormView.d.ts +6 -0
  581. package/dist/ui/views/FormView.js +47 -10
  582. package/dist/ui/views/ListView.d.ts +8 -0
  583. package/dist/ui/views/ListView.js +10 -3
  584. package/dist/ui/views/StatsRow.js +2 -1
  585. package/dist/views/extend.js +12 -0
  586. package/dist/views/types.d.ts +13 -2
  587. package/dist/views/validate.js +8 -1
  588. package/dist/website/.kosh/bindings.js +1 -1
  589. package/dist/website/.kosh/schema.d.ts +2 -1
  590. package/dist/website/i18n/bn.d.ts +2 -0
  591. package/dist/website/i18n/bn.js +113 -0
  592. package/dist/website/index.js +36 -0
  593. package/dist/website/module.d.ts +20 -0
  594. package/dist/website/module.js +29 -5
  595. package/dist/website_crm/.kosh/bindings.js +1 -1
  596. package/dist/website_crm/.kosh/schema.d.ts +2 -1
  597. package/dist/website_crm/i18n/bn.d.ts +2 -0
  598. package/dist/website_crm/i18n/bn.js +5 -0
  599. package/dist/website_crm/index.js +2 -0
  600. package/dist/website_crm/module.d.ts +40 -0
  601. package/dist/website_sale/.kosh/bindings.js +1 -1
  602. package/dist/website_sale/.kosh/schema.d.ts +642 -17
  603. package/dist/website_sale/i18n/bn.d.ts +2 -0
  604. package/dist/website_sale/i18n/bn.js +132 -0
  605. package/dist/website_sale/index.js +83 -1
  606. package/dist/website_sale/module.d.ts +18705 -5550
  607. package/dist/website_sale/module.js +32 -10
  608. package/dist/website_sale/shop.js +22 -9
  609. package/dist/website_sale_stock/.kosh/bindings.js +1 -1
  610. package/dist/website_sale_stock/.kosh/schema.d.ts +737 -18
  611. package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
  612. package/dist/website_sale_stock/i18n/bn.js +4 -0
  613. package/dist/website_sale_stock/index.js +2 -0
  614. package/dist/website_sale_stock/module.d.ts +10 -24997
  615. package/dist/website_sale_stock/module.js +7 -3
  616. package/package.json +36 -8
  617. package/dist/mrp/index.d.ts +0 -3
  618. package/dist/mrp/index.js +0 -393
  619. package/dist/mrp/module.js +0 -757
  620. package/dist/mrp_account/index.d.ts +0 -3
  621. package/dist/mrp_account/index.js +0 -22
  622. /package/dist/{mrp → approvals_purchase}/.kosh/bindings.d.ts +0 -0
  623. /package/dist/{mrp_account → indent}/.kosh/bindings.d.ts +0 -0
package/dist/ui/api.d.ts CHANGED
@@ -73,6 +73,8 @@ export interface CurrentUser {
73
73
  readonly twoFactorEnabled: boolean;
74
74
  readonly administrator: boolean;
75
75
  readonly administratorNeedsSecondFactor: boolean;
76
+ /** May turn on Developer mode (RFC 0031 §3.1); older servers send none. */
77
+ readonly developer?: boolean;
76
78
  /** The policy requires two-factor sign-in of everyone and it is not on (RFC 0019 §3.5); older servers send none. */
77
79
  readonly twoFactorSetupRequired?: boolean;
78
80
  /** The user's photo version, or null (older servers send none). */
package/dist/ui/app.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * The Kosh back-office app (RFC 0007): TanStack Router routes from apps, menus and actions, TanStack Query for
3
+ * server state, the shell (launcher, menus filtered by the server, company, language, theme), and the view
4
+ * renderers from the registry. Search state lives in the URL (`?view=kanban&q=...`), so deep links and the back
5
+ * button work.
6
+ *
7
+ * Routes: `/login`, `/` (launcher), `/:app` (first menu entry), `/:app/a/:action` (list / kanban),
8
+ * `/:app/a/:action/:id` (form; `new` for a new record).
9
+ */
1
10
  import { type ReactElement, type ReactNode } from 'react';
2
11
  import { type KoshApi } from './api.js';
3
12
  import type { Registry } from './registry.js';
package/dist/ui/app.js CHANGED
@@ -18,6 +18,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState, }
18
18
  import { I18nextProvider, useTranslation } from 'react-i18next';
19
19
  import { ApiError } from './api.js';
20
20
  import { Avatar, imageUrl } from './components/Avatar.js';
21
+ import { Explain } from './components/Explain.js';
21
22
  import { Alert, Button, Menu, MenuCheckboxItem, MenuContent, MenuItem, MenuLabel, MenuSeparator, MenuTrigger, Spinner, } from './components/primitives.js';
22
23
  import { KoshProvider, useKosh } from './context.js';
23
24
  import { DesignProvider } from './design.js';
@@ -167,10 +168,10 @@ function CompanyBlock({ me, company, collapsed, onChange, }) {
167
168
  function UserMenu({ user, collapsed, corner, }) {
168
169
  const { t } = useTranslation();
169
170
  const { api, registry, persister, lang, setLang } = useServices();
170
- const { theme, setTheme, density, setDensity } = useKosh();
171
+ const { theme, setTheme, density, setDensity, developer, canDevelop, setDeveloper } = useKosh();
171
172
  const queryClient = useQueryClient();
172
173
  const navigate = useNavigate();
173
- return (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": user.name, "data-kosh-account": corner === undefined ? 'sidebar' : 'corner', className: cn('flex min-w-0 items-center gap-2 rounded-md px-1.5 py-1.5 text-sm hover:bg-muted', corner === undefined ? 'w-full' : 'rounded-full border bg-surface pe-3', collapsed && 'justify-center'), children: [_jsx(Avatar, { name: user.name, src: imageUrl('user', user.id, user.avatar) }), collapsed ? null : _jsx("span", { className: "truncate", children: user.name }), corner === undefined ? null : (_jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }))] }) }), _jsxs(MenuContent, { align: corner === undefined ? 'start' : 'end', side: corner === undefined ? 'top' : 'bottom', className: corner === undefined ? undefined : 'max-h-[80vh] w-64 overflow-y-auto', children: [_jsxs(MenuLabel, { children: [user.name, _jsx("span", { className: "block text-xs font-normal text-muted-foreground", children: user.login })] }), registry.userPages().map((p) => (_jsx(MenuItem, { onSelect: () => void navigate({ to: '/me/$page', params: { page: p.name } }), children: t(p.label) }, p.name))), corner === undefined ? null : (_jsxs(_Fragment, { children: [corner.companies.length < 2 && !user.administrator ? null : (_jsxs(_Fragment, { children: [_jsx(MenuSeparator, {}), _jsx(MenuLabel, { children: t('shell.company') }), corner.companies.length < 2
174
+ return (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": user.name, "data-kosh-account": corner === undefined ? 'sidebar' : 'corner', className: cn('flex min-w-0 items-center gap-2 rounded-md px-1.5 py-1.5 text-sm hover:bg-muted', corner === undefined ? 'w-full' : 'rounded-full border bg-surface pe-3', collapsed && 'justify-center'), children: [_jsx(Avatar, { name: user.name, src: imageUrl('user', user.id, user.avatar) }), collapsed ? null : _jsx("span", { className: "truncate", children: user.name }), corner === undefined ? null : (_jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }))] }) }), _jsxs(MenuContent, { align: corner === undefined ? 'start' : 'end', side: corner === undefined ? 'top' : 'bottom', className: corner === undefined ? undefined : 'max-h-[80vh] w-64 overflow-y-auto', children: [_jsxs(MenuLabel, { children: [user.name, _jsx("span", { className: "block text-xs font-normal text-muted-foreground", children: user.login })] }), registry.userPages().map((p) => (_jsx(MenuItem, { onSelect: () => void navigate({ to: '/me/$page', params: { page: p.name } }), children: t(p.label) }, p.name))), canDevelop ? (_jsx(MenuCheckboxItem, { checked: developer, onCheckedChange: (on) => setDeveloper(on === true), children: t('explain.developerMode') })) : null, corner === undefined ? null : (_jsxs(_Fragment, { children: [corner.companies.length < 2 && !user.administrator ? null : (_jsxs(_Fragment, { children: [_jsx(MenuSeparator, {}), _jsx(MenuLabel, { children: t('shell.company') }), corner.companies.length < 2
174
175
  ? null
175
176
  : corner.companies.map((c) => (_jsx(MenuCheckboxItem, { checked: c.id === corner.current, onCheckedChange: () => {
176
177
  if (c.id !== corner.current)
@@ -260,7 +261,7 @@ function Shell() {
260
261
  setDrawer(false);
261
262
  setPalette(true);
262
263
  }, top: _jsx(CompanyBlock, { me: user, company: current, collapsed: inDrawer ? false : collapsed, onChange: switchCompany }), bottom: _jsx(UserMenu, { user: user, collapsed: inDrawer ? false : collapsed }), onNavigate: inDrawer ? () => setDrawer(false) : undefined }));
263
- return (_jsx(KoshProvider, { api: api, registry: registry, uid: user.id, companyId: current, lang: lang, tz: Intl.DateTimeFormat().resolvedOptions().timeZone, grouping: user.groupings?.[String(current)] ?? 'international', accent: user.accents?.[String(current)] ?? null, ...(realtime === undefined ? {} : { realtime }), ...(offline === undefined ? {} : { offline }), switchCompany: switchCompany, children: _jsx(ToastProvider, { children: _jsxs(DesignProvider, { children: [_jsx(OfflineAgent, { uid: user.id }), _jsxs(PaletteContext.Provider, { value: openPalette, children: [_jsx("a", { href: "#content", className: "sr-only focus:not-sr-only focus:absolute focus:start-2 focus:top-2 focus:z-50 focus:rounded focus:bg-surface focus:px-3 focus:py-2", children: t('shell.skip') }), params.app === undefined ? (_jsxs("div", { className: "flex min-h-screen flex-col", children: [_jsxs("div", { className: "flex h-14 items-center gap-2 px-4 lg:px-6", children: [userPage === undefined ? null : (_jsxs(Link, { to: "/", className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-sm text-muted-foreground hover:bg-muted hover:text-foreground", children: [_jsx(House, { className: "size-4", "aria-hidden": true }), t('shell.home')] })), _jsx("span", { className: "flex-1" }), registry
264
+ return (_jsx(KoshProvider, { api: api, registry: registry, uid: user.id, companyId: current, lang: lang, tz: Intl.DateTimeFormat().resolvedOptions().timeZone, grouping: user.groupings?.[String(current)] ?? 'international', accent: user.accents?.[String(current)] ?? null, ...(realtime === undefined ? {} : { realtime }), ...(offline === undefined ? {} : { offline }), switchCompany: switchCompany, canDevelop: user.developer === true, children: _jsx(ToastProvider, { children: _jsxs(DesignProvider, { children: [_jsx(OfflineAgent, { uid: user.id }), _jsxs(PaletteContext.Provider, { value: openPalette, children: [_jsx("a", { href: "#content", className: "sr-only focus:not-sr-only focus:absolute focus:start-2 focus:top-2 focus:z-50 focus:rounded focus:bg-surface focus:px-3 focus:py-2", children: t('shell.skip') }), params.app === undefined ? (_jsxs("div", { className: "flex min-h-screen flex-col", children: [_jsxs("div", { className: "flex h-14 items-center gap-2 px-4 lg:px-6", children: [userPage === undefined ? null : (_jsxs(Link, { to: "/", className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-sm text-muted-foreground hover:bg-muted hover:text-foreground", children: [_jsx(House, { className: "size-4", "aria-hidden": true }), t('shell.home')] })), _jsx("span", { className: "flex-1" }), registry
264
265
  .headerItems()
265
266
  .filter((item) => item.home)
266
267
  .map(({ name, component: Item }) => (_jsx(Item, { api: api }, name))), _jsx(UserMenu, { user: user, collapsed: false, corner: {
@@ -402,7 +403,7 @@ function WindowActionPage() {
402
403
  },
403
404
  });
404
405
  };
405
- return (_jsxs("section", { className: "grid gap-3", "aria-labelledby": "action-title", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h1", { id: "action-title", className: "text-lg font-semibold", children: action.data.label ?? served.data.view.label ?? model }), served.data.operations.create && action.data.views.includes('form') ? (_jsxs(_Fragment, { children: [_jsxs(Button, { variant: "primary", size: "sm", "data-kosh-new": true, onClick: () => open('new'), children: [_jsx(Plus, { "aria-hidden": true }), t('views.new')] }), registry.createAssists().map((Assist, i) => (_jsx(Assist
406
+ return (_jsxs("section", { className: "grid gap-3", "aria-labelledby": "action-title", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h1", { id: "action-title", className: "text-lg font-semibold", children: _jsx(Explain, { model: model, target: { model: true }, children: action.data.label ?? served.data.view.label ?? model }) }), served.data.operations.create && action.data.views.includes('form') ? (_jsxs(_Fragment, { children: [_jsxs(Button, { variant: "primary", size: "sm", "data-kosh-new": true, onClick: () => open('new'), children: [_jsx(Plus, { "aria-hidden": true }), t('views.new')] }), registry.createAssists().map((Assist, i) => (_jsx(Assist
406
407
  // biome-ignore lint/suspicious/noArrayIndexKey: registered once at start, never reordered
407
408
  , { api: api, model: model, onCreate: (values, proposed) => {
408
409
  setPrefill(actionId, { values, proposed });
@@ -501,6 +502,19 @@ function OpenRecordPage() {
501
502
  return _jsx(Alert, { children: t('app.notFound') });
502
503
  return (_jsx(Navigate, { to: "/$app/a/$action/$id", params: { app: route.app, action: route.action, id }, replace: true }));
503
504
  }
505
+ /** A model's list where this user may open it (the explain popovers' relation links, RFC 0031 §3.1). */
506
+ function OpenModelPage() {
507
+ const { api } = useServices();
508
+ const { t } = useTranslation();
509
+ const { model } = useParams({ strict: false });
510
+ const routes = useQuery({ queryKey: ['routes'], queryFn: () => api.routes() });
511
+ if (routes.isPending)
512
+ return _jsx(Spinner, { label: t('app.loading') });
513
+ const route = routes.data?.[model];
514
+ if (route?.app === undefined)
515
+ return _jsx(Alert, { children: t('app.notFound') });
516
+ return (_jsx(Navigate, { to: "/$app/a/$action", params: { app: route.app, action: route.action }, replace: true }));
517
+ }
504
518
  function ActivatePage() {
505
519
  const navigate = useNavigate();
506
520
  return _jsx(Activate, { api: useServices().api, onSignedIn: () => void navigate({ to: '/' }) });
@@ -572,6 +586,11 @@ const openRoute = createRoute({
572
586
  path: '/open/$model/$id',
573
587
  component: OpenRecordPage,
574
588
  });
589
+ const openModelRoute = createRoute({
590
+ getParentRoute: () => shellRoute,
591
+ path: '/open/$model',
592
+ component: OpenModelPage,
593
+ });
575
594
  /** A personal page from the user menu (`registry.registerUserPage`), outside any app. */
576
595
  function UserPage() {
577
596
  const { page } = useParams({ strict: false });
@@ -595,6 +614,7 @@ const routeTree = rootRoute.addChildren([
595
614
  shellRoute.addChildren([
596
615
  indexRoute,
597
616
  openRoute,
617
+ openModelRoute,
598
618
  userPageRoute,
599
619
  appRoute,
600
620
  actionRoute,
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  * App icons by name (`app.icon` in a module manifest): the launcher's tiles and the App manager's cards. Names
4
4
  * follow Lucide; an unknown name shows a neutral grid, never a broken image.
5
5
  */
6
- import { BadgeCheck, Banknote, BookOpen, Boxes, Briefcase, Building, Building2, CalendarDays, ChartColumn, Clock, Factory, FolderKanban, FolderOpen, Globe, Landmark, LayoutGrid, LifeBuoy, ListChecks, LockKeyhole, Mail, MessageSquare, MessagesSquare, Package, PencilRuler, Plug, Receipt, Ruler, ScrollText, Settings, ShieldCheck, ShoppingCart, Signature, Sparkles, Store, Ticket, TrendingUp, UserPlus, Users, Wallet, Warehouse, Workflow, Wrench, } from 'lucide-react';
6
+ import { BadgeCheck, Banknote, BookOpen, Boxes, Briefcase, Building, Building2, CalendarDays, ChartColumn, ClipboardList, Clock, Factory, FolderKanban, FolderOpen, Globe, Landmark, LayoutGrid, LifeBuoy, ListChecks, LockKeyhole, Mail, MessageSquare, MessagesSquare, Package, PencilRuler, Plug, Receipt, Ruler, ScrollText, Settings, ShieldCheck, ShoppingCart, Signature, Sparkles, Store, Ticket, TrendingUp, UserPlus, Users, Wallet, Warehouse, Workflow, Wrench, } from 'lucide-react';
7
7
  import { cn } from '../lib/cn.js';
8
8
  const ICONS = {
9
9
  settings: Settings,
@@ -51,6 +51,7 @@ const ICONS = {
51
51
  sites: Globe,
52
52
  counter: Store,
53
53
  spend: Wallet,
54
+ requests: ClipboardList,
54
55
  attendance: Clock,
55
56
  payroll: Banknote,
56
57
  helpdesk: LifeBuoy,
@@ -60,7 +61,6 @@ const ICONS = {
60
61
  event: Ticket,
61
62
  trade_finance: Landmark,
62
63
  maintenance: Wrench,
63
- mrp: Factory,
64
64
  stock: Warehouse,
65
65
  recruitment: UserPlus,
66
66
  hr: Briefcase,
@@ -0,0 +1,69 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ export interface ExplainedField {
3
+ readonly key: string;
4
+ readonly label: string;
5
+ readonly kind: string;
6
+ readonly help: string | null;
7
+ readonly target: string | null;
8
+ readonly inverse: string | null;
9
+ readonly required: boolean;
10
+ readonly readonly: boolean;
11
+ readonly stored: boolean;
12
+ readonly computed: boolean;
13
+ readonly depends: readonly string[];
14
+ readonly hasDefault: boolean;
15
+ readonly default: string | null;
16
+ readonly ondelete: string | null;
17
+ readonly translate: boolean;
18
+ readonly index: boolean;
19
+ readonly options: readonly (readonly [string, string])[] | null;
20
+ readonly module: string | null;
21
+ }
22
+ export interface Explained {
23
+ readonly model: string;
24
+ readonly label: string;
25
+ readonly module: string | null;
26
+ readonly extendedBy: readonly string[];
27
+ readonly fields: readonly ExplainedField[];
28
+ readonly transitions: readonly {
29
+ readonly name: string;
30
+ readonly field: string;
31
+ readonly from: readonly string[];
32
+ readonly to: string;
33
+ readonly guarded: boolean;
34
+ readonly message: string | null;
35
+ readonly requires: string | null;
36
+ }[];
37
+ readonly incoming: readonly {
38
+ readonly model: string;
39
+ readonly field: string;
40
+ readonly label: string;
41
+ readonly kind: string;
42
+ }[];
43
+ }
44
+ /** A model's explanation, fetched once per model while Developer mode is on. */
45
+ export declare function useExplain(model: string | null | undefined): Explained | undefined;
46
+ /** What to explain: a field, a transition (button), a domain (tile or menu), or the model itself. */
47
+ export type ExplainTarget = {
48
+ readonly field: string;
49
+ } | {
50
+ readonly transition: string;
51
+ } | {
52
+ readonly action: string;
53
+ readonly domain?: unknown;
54
+ } | {
55
+ readonly model: true;
56
+ };
57
+ /**
58
+ * Wraps `children` with the explain popover of `target` on `model` when Developer mode is on; renders them unchanged
59
+ * otherwise.
60
+ */
61
+ export declare function Explain({ model, target, asChild, focusable, children, }: {
62
+ readonly model: string;
63
+ readonly target: ExplainTarget;
64
+ /** Attach to the child element itself (a button) instead of wrapping it in a focusable span. */
65
+ readonly asChild?: boolean;
66
+ /** Hover only, no tab stop: inside a control that is itself focusable (a clickable tile). */
67
+ readonly focusable?: boolean;
68
+ readonly children: ReactNode;
69
+ }): ReactElement;
@@ -0,0 +1,62 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Explain popovers (RFC 0031 §3.1). With Developer mode on, a field label, a list column, a button, a stat tile or a
4
+ * page title opens — on hover or keyboard focus — a dark card saying what it is: the field's kind, what it points to
5
+ * (a link to that model's list) and back through which field, whether it is stored or computed and from what, its
6
+ * default and rules, the module that declared it; a button's states and guard; a model's relations in and out. The
7
+ * facts come from `GET /api/v1/meta/explain/:model` (developers and administrators only). Off, nothing changes.
8
+ */
9
+ import { useQuery } from '@tanstack/react-query';
10
+ import { HoverCard } from 'radix-ui';
11
+ import { useTranslation } from 'react-i18next';
12
+ import { useKosh } from '../context.js';
13
+ /** A model's explanation, fetched once per model while Developer mode is on. */
14
+ export function useExplain(model) {
15
+ const { api, developer } = useKosh();
16
+ const query = useQuery({
17
+ queryKey: ['kosh', 'explain', model],
18
+ queryFn: () => api.call('GET', `/api/v1/meta/explain/${encodeURIComponent(model ?? '')}`),
19
+ enabled: developer && typeof model === 'string' && model !== '',
20
+ staleTime: Number.POSITIVE_INFINITY,
21
+ retry: false,
22
+ });
23
+ return query.data;
24
+ }
25
+ function Row({ name, children, }) {
26
+ return (_jsxs("li", { className: "flex gap-2", children: [_jsx("span", { className: "shrink-0 text-neutral-400", children: name }), _jsx("span", { className: "min-w-0 break-words font-mono text-neutral-100", children: children })] }));
27
+ }
28
+ /** A link to a model's records, opened in a new tab (the generic list of the model). */
29
+ function ModelLink({ model }) {
30
+ return (_jsx("a", { href: `/open/${encodeURIComponent(model)}`, target: "_blank", rel: "noreferrer", className: "text-sky-300 underline underline-offset-2 hover:text-sky-200", children: model }));
31
+ }
32
+ function Body({ model, target, }) {
33
+ const { t } = useTranslation();
34
+ const explained = useExplain(model);
35
+ if (explained === undefined)
36
+ return _jsx("p", { className: "text-neutral-400", children: t('explain.loading') });
37
+ const yes = t('explain.yes');
38
+ if ('field' in target) {
39
+ const f = explained.fields.find((x) => x.key === target.field);
40
+ if (f === undefined)
41
+ return _jsx("p", { className: "text-neutral-400", children: t('explain.unknown') });
42
+ return (_jsxs(_Fragment, { children: [f.help === null ? null : (_jsx("p", { className: "mb-2 rounded bg-sky-900/60 px-2 py-1 text-sky-100", children: f.help })), _jsxs("ul", { className: "space-y-0.5", children: [_jsx(Row, { name: t('explain.label'), children: f.label }), _jsx(Row, { name: t('explain.field'), children: f.key }), _jsx(Row, { name: t('explain.model'), children: explained.model }), _jsx(Row, { name: t('explain.type'), children: f.kind }), f.target === null ? null : (_jsxs(Row, { name: t('explain.relation'), children: [_jsx(ModelLink, { model: f.target }), f.inverse === null ? null : ` ← ${f.inverse}`] })), f.ondelete === null ? null : _jsx(Row, { name: t('explain.ondelete'), children: f.ondelete }), f.required ? _jsx(Row, { name: t('explain.required'), children: yes }) : null, f.readonly ? _jsx(Row, { name: t('explain.readonly'), children: yes }) : null, _jsx(Row, { name: t('explain.stored'), children: f.stored ? yes : t('explain.no') }), f.computed ? (_jsx(Row, { name: t('explain.computed'), children: f.depends.length === 0 ? yes : f.depends.join(', ') })) : null, f.hasDefault ? _jsx(Row, { name: t('explain.default'), children: f.default ?? '—' }) : null, f.translate ? _jsx(Row, { name: t('explain.translated'), children: yes }) : null, f.index ? _jsx(Row, { name: t('explain.indexed'), children: yes }) : null, f.options === null ? null : (_jsx(Row, { name: t('explain.selection'), children: f.options.map(([value, label]) => `[${value}] ${label}`).join(' · ') })), f.module === null ? null : _jsx(Row, { name: t('explain.module'), children: f.module })] })] }));
43
+ }
44
+ if ('transition' in target) {
45
+ const tr = explained.transitions.find((x) => x.name === target.transition);
46
+ return (_jsxs("ul", { className: "space-y-0.5", children: [_jsx(Row, { name: t('explain.button'), children: target.transition }), _jsx(Row, { name: t('explain.model'), children: explained.model }), tr === undefined ? null : (_jsxs(_Fragment, { children: [_jsxs(Row, { name: t('explain.states'), children: [`${tr.from.join(', ')} → ${tr.to}`, " (", tr.field, ")"] }), tr.guarded ? _jsx(Row, { name: t('explain.guard'), children: tr.message ?? yes }) : null, tr.requires === null ? null : _jsx(Row, { name: t('explain.requires'), children: tr.requires })] }))] }));
47
+ }
48
+ if ('action' in target)
49
+ return (_jsxs("ul", { className: "space-y-0.5", children: [_jsx(Row, { name: t('explain.action'), children: target.action }), _jsx(Row, { name: t('explain.model'), children: _jsx(ModelLink, { model: explained.model }) }), target.domain === undefined ? null : (_jsx(Row, { name: t('explain.domain'), children: JSON.stringify(target.domain) }))] }));
50
+ const outgoing = explained.fields.filter((f) => f.target !== null);
51
+ return (_jsxs("ul", { className: "space-y-0.5", children: [_jsx(Row, { name: t('explain.model'), children: explained.model }), explained.module === null ? null : _jsx(Row, { name: t('explain.module'), children: explained.module }), explained.extendedBy.length === 0 ? null : (_jsx(Row, { name: t('explain.extendedBy'), children: explained.extendedBy.join(', ') })), _jsx("li", { className: "pt-1 text-neutral-400", children: t('explain.out', { count: outgoing.length }) }), outgoing.map((f) => (_jsxs("li", { className: "font-mono text-neutral-100", children: [f.key, " (", f.kind, ") \u2192 ", _jsx(ModelLink, { model: f.target })] }, f.key))), _jsx("li", { className: "pt-1 text-neutral-400", children: t('explain.in', { count: explained.incoming.length }) }), explained.incoming.map((r) => (_jsxs("li", { className: "font-mono text-neutral-100", children: [_jsx(ModelLink, { model: r.model }), ".", r.field, " (", r.kind, ")"] }, `${r.model}.${r.field}`)))] }));
52
+ }
53
+ /**
54
+ * Wraps `children` with the explain popover of `target` on `model` when Developer mode is on; renders them unchanged
55
+ * otherwise.
56
+ */
57
+ export function Explain({ model, target, asChild = false, focusable = true, children, }) {
58
+ const { developer } = useKosh();
59
+ if (!developer)
60
+ return _jsx(_Fragment, { children: children });
61
+ return (_jsxs(HoverCard.Root, { openDelay: 250, closeDelay: 150, children: [_jsx(HoverCard.Trigger, { asChild: true, children: asChild ? (children) : (_jsx("span", { tabIndex: focusable ? 0 : undefined, "data-kosh-explain": "", className: "inline-flex cursor-help items-center gap-0.5 underline decoration-dotted decoration-sky-500 underline-offset-2 outline-none focus-visible:ring-2 focus-visible:ring-sky-500", children: children })) }), _jsx(HoverCard.Portal, { children: _jsxs(HoverCard.Content, { side: "bottom", align: "start", sideOffset: 6, collisionPadding: 12, className: "z-50 max-h-[70vh] max-w-[min(32rem,calc(100vw-2rem))] overflow-auto rounded-md bg-neutral-950 p-3 text-xs leading-relaxed text-neutral-100 shadow-xl ring-1 ring-white/10", children: [_jsx(Body, { model: model, target: target }), _jsx(HoverCard.Arrow, { className: "fill-neutral-950" })] }) })] }));
62
+ }
@@ -26,13 +26,18 @@ export interface KoshContextValue {
26
26
  readonly offline?: OfflineQueue;
27
27
  /** Switches to another of the user's companies, when the shell offers it (Settings › Companies). */
28
28
  readonly switchCompany?: (company: number) => void;
29
+ /** Developer mode is on (RFC 0031 §3.1): fields, buttons and models explain themselves on hover. */
30
+ readonly developer: boolean;
31
+ /** The user may turn Developer mode on (administrators and developers). */
32
+ readonly canDevelop: boolean;
33
+ setDeveloper(on: boolean): void;
29
34
  }
30
35
  /** The renderer context. @throws outside {@link KoshProvider} */
31
36
  export declare function useKosh(): KoshContextValue;
32
37
  export type Density = 'comfortable' | 'compact';
33
38
  /** Applies the theme to `<html>` (the `dark` class) and follows the system when asked to. */
34
39
  declare function useTheme(): [ThemeChoice, (t: ThemeChoice) => void];
35
- export declare function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, accent, realtime, offline, switchCompany, children, }: {
40
+ export declare function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, accent, realtime, offline, switchCompany, canDevelop, children, }: {
36
41
  readonly api: KoshApi;
37
42
  readonly registry: Registry;
38
43
  readonly uid: number;
@@ -46,6 +51,8 @@ export declare function KoshProvider({ api, registry, uid, companyId, lang, tz,
46
51
  readonly realtime?: RealtimeClient;
47
52
  readonly offline?: OfflineQueue;
48
53
  readonly switchCompany?: (company: number) => void;
54
+ /** The user may turn Developer mode on (`me.developer`). */
55
+ readonly canDevelop?: boolean;
49
56
  readonly children: ReactNode;
50
57
  }): ReactElement;
51
58
  /** Theme switching without a signed-in user (the sign-in page). */
@@ -16,6 +16,31 @@ export function useKosh() {
16
16
  }
17
17
  const THEME_KEY = 'kosh.theme';
18
18
  const DENSITY_KEY = 'kosh.density';
19
+ const DEVELOPER_KEY = 'kosh.developer';
20
+ function readDeveloper() {
21
+ try {
22
+ return localStorage.getItem(DEVELOPER_KEY) === 'on';
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ /** Developer mode, remembered per browser. */
29
+ function useDeveloper() {
30
+ const [on, setOn] = useState(readDeveloper);
31
+ useEffect(() => {
32
+ try {
33
+ if (on)
34
+ localStorage.setItem(DEVELOPER_KEY, 'on');
35
+ else
36
+ localStorage.removeItem(DEVELOPER_KEY);
37
+ }
38
+ catch {
39
+ // storage unavailable: the choice lasts for this page only
40
+ }
41
+ }, [on]);
42
+ return [on, setOn];
43
+ }
19
44
  function readDensity() {
20
45
  try {
21
46
  return JSON.parse(localStorage.getItem(DENSITY_KEY) ?? 'null') === 'compact'
@@ -87,9 +112,11 @@ function useTheme() {
87
112
  }, [theme]);
88
113
  return [theme, setTheme];
89
114
  }
90
- export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, accent, realtime, offline, switchCompany, children, }) {
115
+ export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, accent, realtime, offline, switchCompany, canDevelop = false, children, }) {
91
116
  const [theme, setTheme] = useTheme();
92
117
  const [density, setDensity] = useDensity();
118
+ const [developerOn, setDeveloper] = useDeveloper();
119
+ const developer = canDevelop && developerOn;
93
120
  useAccent(accent);
94
121
  const format = useMemo(() => createFormatter(lang, tz, grouping === undefined ? {} : { grouping }), [lang, tz, grouping]);
95
122
  const value = useMemo(() => ({
@@ -102,6 +129,9 @@ export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping
102
129
  setTheme,
103
130
  density,
104
131
  setDensity,
132
+ developer,
133
+ canDevelop,
134
+ setDeveloper,
105
135
  ...(realtime === undefined ? {} : { realtime }),
106
136
  ...(offline === undefined ? {} : { offline }),
107
137
  ...(switchCompany === undefined ? {} : { switchCompany }),
@@ -115,6 +145,9 @@ export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping
115
145
  setTheme,
116
146
  density,
117
147
  setDensity,
148
+ developer,
149
+ canDevelop,
150
+ setDeveloper,
118
151
  realtime,
119
152
  offline,
120
153
  switchCompany,
@@ -3,6 +3,39 @@
3
3
  * Modules ship their own namespaces; labels from model metadata come translated by the server (`Accept-Language`).
4
4
  */
5
5
  export declare const en: {
6
+ explain: {
7
+ developerMode: string;
8
+ loading: string;
9
+ unknown: string;
10
+ yes: string;
11
+ no: string;
12
+ label: string;
13
+ field: string;
14
+ model: string;
15
+ type: string;
16
+ relation: string;
17
+ ondelete: string;
18
+ required: string;
19
+ readonly: string;
20
+ stored: string;
21
+ computed: string;
22
+ default: string;
23
+ translated: string;
24
+ indexed: string;
25
+ selection: string;
26
+ module: string;
27
+ button: string;
28
+ states: string;
29
+ guard: string;
30
+ requires: string;
31
+ action: string;
32
+ domain: string;
33
+ extendedBy: string;
34
+ out_one: string;
35
+ out_other: string;
36
+ in_one: string;
37
+ in_other: string;
38
+ };
6
39
  app: {
7
40
  name: string;
8
41
  loading: string;
@@ -130,6 +163,7 @@ export declare const en: {
130
163
  leaveConfirm: string;
131
164
  transitionDone: string;
132
165
  deleted: string;
166
+ duplicated: string;
133
167
  breadcrumbs: string;
134
168
  saving: string;
135
169
  unsaved: string;
@@ -154,6 +188,8 @@ export declare const en: {
154
188
  discard: string;
155
189
  edit: string;
156
190
  delete: string;
191
+ duplicate: string;
192
+ actions: string;
157
193
  confirmDelete: string;
158
194
  saved: string;
159
195
  total: string;
@@ -3,6 +3,39 @@
3
3
  * Modules ship their own namespaces; labels from model metadata come translated by the server (`Accept-Language`).
4
4
  */
5
5
  export const en = {
6
+ explain: {
7
+ developerMode: 'Developer mode',
8
+ loading: 'Loading…',
9
+ unknown: 'Not a field of this model.',
10
+ yes: 'yes',
11
+ no: 'no',
12
+ label: 'Label',
13
+ field: 'Field',
14
+ model: 'Model',
15
+ type: 'Type',
16
+ relation: 'Relation',
17
+ ondelete: 'On delete',
18
+ required: 'Required',
19
+ readonly: 'Read-only',
20
+ stored: 'Stored',
21
+ computed: 'Computed from',
22
+ default: 'Default',
23
+ translated: 'Translated',
24
+ indexed: 'Indexed',
25
+ selection: 'Values',
26
+ module: 'Module',
27
+ button: 'Button',
28
+ states: 'States',
29
+ guard: 'Guard',
30
+ requires: 'Requires',
31
+ action: 'Action',
32
+ domain: 'Domain',
33
+ extendedBy: 'Extended by',
34
+ out_one: '{{count}} relation out',
35
+ out_other: '{{count}} relations out',
36
+ in_one: '{{count}} relation in',
37
+ in_other: '{{count}} relations in',
38
+ },
6
39
  app: {
7
40
  name: 'Shutro ERP',
8
41
  loading: 'Loading…',
@@ -127,6 +160,7 @@ export const en = {
127
160
  leaveConfirm: 'You have unsaved changes. Leave without saving?',
128
161
  transitionDone: '{{action}}: done',
129
162
  deleted: 'Deleted',
163
+ duplicated: 'Duplicated: this is the copy',
130
164
  breadcrumbs: 'Breadcrumbs',
131
165
  saving: 'Saving…',
132
166
  unsaved: 'Unsaved changes',
@@ -151,6 +185,8 @@ export const en = {
151
185
  discard: 'Discard',
152
186
  edit: 'Edit',
153
187
  delete: 'Delete',
188
+ duplicate: 'Duplicate',
189
+ actions: 'Actions',
154
190
  confirmDelete: 'Delete this record?',
155
191
  saved: 'Saved',
156
192
  total: 'Total',
@@ -337,6 +373,39 @@ export const en = {
337
373
  },
338
374
  };
339
375
  export const bn = {
376
+ explain: {
377
+ developerMode: 'ডেভেলপার মোড',
378
+ loading: 'লোড হচ্ছে…',
379
+ unknown: 'এই মডেলের ফিল্ড নয়।',
380
+ yes: 'হ্যাঁ',
381
+ no: 'না',
382
+ label: 'লেবেল',
383
+ field: 'ফিল্ড',
384
+ model: 'মডেল',
385
+ type: 'ধরন',
386
+ relation: 'সম্পর্ক',
387
+ ondelete: 'মুছলে',
388
+ required: 'আবশ্যক',
389
+ readonly: 'শুধু পড়া যায়',
390
+ stored: 'সংরক্ষিত',
391
+ computed: 'যা থেকে হিসাব হয়',
392
+ default: 'ডিফল্ট',
393
+ translated: 'অনূদিত',
394
+ indexed: 'ইনডেক্সড',
395
+ selection: 'মান',
396
+ module: 'মডিউল',
397
+ button: 'বাটন',
398
+ states: 'অবস্থা',
399
+ guard: 'শর্ত',
400
+ requires: 'প্রয়োজন',
401
+ action: 'অ্যাকশন',
402
+ domain: 'ডোমেইন',
403
+ extendedBy: 'যা বাড়িয়েছে',
404
+ out_one: '{{count}}টি বাইরের সম্পর্ক',
405
+ out_other: '{{count}}টি বাইরের সম্পর্ক',
406
+ in_one: '{{count}}টি ভেতরের সম্পর্ক',
407
+ in_other: '{{count}}টি ভেতরের সম্পর্ক',
408
+ },
340
409
  app: {
341
410
  name: 'কোষ',
342
411
  loading: 'লোড হচ্ছে…',
@@ -461,6 +530,7 @@ export const bn = {
461
530
  leaveConfirm: 'পরিবর্তন সংরক্ষণ করা হয়নি। সংরক্ষণ না করেই চলে যাবেন?',
462
531
  transitionDone: '{{action}}: সম্পন্ন',
463
532
  deleted: 'মুছে ফেলা হয়েছে',
533
+ duplicated: 'অনুলিপি হয়েছে: এটি অনুলিপি',
464
534
  breadcrumbs: 'অবস্থান',
465
535
  saving: 'সংরক্ষণ হচ্ছে…',
466
536
  unsaved: 'অসংরক্ষিত পরিবর্তন',
@@ -485,6 +555,8 @@ export const bn = {
485
555
  discard: 'বাতিল',
486
556
  edit: 'সম্পাদনা',
487
557
  delete: 'মুছুন',
558
+ duplicate: 'অনুলিপি করুন',
559
+ actions: 'কাজ',
488
560
  confirmDelete: 'এই রেকর্ডটি মুছবেন?',
489
561
  saved: 'সংরক্ষিত',
490
562
  total: 'মোট',
@@ -11,6 +11,7 @@ export { ApiError, type ApiOptions, type AppEntry, type CurrentUser, createKoshA
11
11
  export { KoshApp, type KoshAppProps, useLanguage } from './app.js';
12
12
  export { AppIcon } from './components/AppIcon.js';
13
13
  export * from './components/Avatar.js';
14
+ export { Explain, type Explained, type ExplainedField, type ExplainTarget, useExplain, } from './components/Explain.js';
14
15
  export * from './components/primitives.js';
15
16
  export { type KoshContextValue, KoshProvider, type ThemeChoice, useKosh, useTheme, } from './context.js';
16
17
  export { type DesignContextValue, DesignProvider, type DesignSpot, useDesign, } from './design.js';
@@ -26,7 +27,7 @@ export { type Prefill, setPrefill, takePrefill } from './prefill.js';
26
27
  export { registerServiceWorker } from './pwa/register.js';
27
28
  export { serviceWorkerSource, type WorkerConfig } from './pwa/worker.js';
28
29
  export { type ChangeEvent, createRealtimeClient, type PresenceUser, type RealtimeClient, type RealtimeOptions, } from './realtime.js';
29
- export { type ChatterAssistProps, type CreateAssistProps, type FormProps, type HeaderItemProps, type NodeComponentProps, type PageProps, Registry, RegistryError, type SearchAssistProps, type ViewProps, type WidgetProps, } from './registry.js';
30
+ export { type ChatterAssistProps, type CreateAssistProps, type FormProps, type HeaderItemProps, type NodeComponentProps, type PageProps, Registry, RegistryError, type SearchAssistProps, type SelectionActionProps, type ViewProps, type WidgetProps, } from './registry.js';
30
31
  export { SearchBar, type SearchBarProps } from './search/SearchBar.js';
31
32
  export { Login } from './shell/Login.js';
32
33
  export { FormView } from './views/FormView.js';
package/dist/ui/index.js CHANGED
@@ -15,6 +15,7 @@ export { ApiError, createKoshApi, NetworkError, } from './api.js';
15
15
  export { KoshApp, useLanguage } from './app.js';
16
16
  export { AppIcon } from './components/AppIcon.js';
17
17
  export * from './components/Avatar.js';
18
+ export { Explain, useExplain, } from './components/Explain.js';
18
19
  export * from './components/primitives.js';
19
20
  export { KoshProvider, useKosh, useTheme, } from './context.js';
20
21
  export { DesignProvider, useDesign, } from './design.js';
@@ -93,6 +93,14 @@ export interface CreateAssistProps {
93
93
  /** Opens a new record with these values, `proposed` marked as proposals. */
94
94
  readonly onCreate: (values: Readonly<Record<string, unknown>>, proposed: readonly string[]) => void;
95
95
  }
96
+ /** Props of a selection action: a control in a list's bar of selected rows (Send by email). */
97
+ export interface SelectionActionProps {
98
+ readonly api: KoshApi;
99
+ readonly model: string;
100
+ readonly ids: readonly number[];
101
+ /** Clears the selection, refreshes the list and says `message`. */
102
+ readonly done: (message: string, tone?: 'info' | 'danger') => void;
103
+ }
96
104
  /** Props of a page: what a client action opens (`{ type: 'client', page: 'settings.Apps' }`). */
97
105
  export interface PageProps {
98
106
  readonly api: KoshApi;
@@ -177,6 +185,12 @@ export declare class Registry {
177
185
  }): this;
178
186
  /** The create assistants, in registration order. */
179
187
  createAssists(): readonly ComponentType<CreateAssistProps>[];
188
+ /** Controls in every list's bar of selected rows; each decides whether it applies to the model. */
189
+ registerSelectionAction(name: string, component: ComponentType<SelectionActionProps>, options?: {
190
+ readonly replace?: boolean;
191
+ }): this;
192
+ /** The selection actions, in registration order. */
193
+ selectionActions(): readonly ComponentType<SelectionActionProps>[];
180
194
  page(name: string): ComponentType<PageProps> | undefined;
181
195
  /** A copy, for an app that changes entries without touching the defaults. */
182
196
  clone(): Registry;
@@ -16,6 +16,7 @@ export class Registry {
16
16
  searchAssist: new Map(),
17
17
  chatterAssist: new Map(),
18
18
  createAssist: new Map(),
19
+ selectionAction: new Map(),
19
20
  };
20
21
  #add(kind, name, component, replace) {
21
22
  if (this.#entries[kind].has(name) && !replace)
@@ -118,6 +119,14 @@ export class Registry {
118
119
  createAssists() {
119
120
  return [...this.#entries.createAssist.values()];
120
121
  }
122
+ /** Controls in every list's bar of selected rows; each decides whether it applies to the model. */
123
+ registerSelectionAction(name, component, options = {}) {
124
+ return this.#add('selectionAction', name, component, options.replace === true);
125
+ }
126
+ /** The selection actions, in registration order. */
127
+ selectionActions() {
128
+ return [...this.#entries.selectionAction.values()];
129
+ }
121
130
  page(name) {
122
131
  return this.#entries.page.get(name);
123
132
  }
@@ -133,6 +142,7 @@ export class Registry {
133
142
  'searchAssist',
134
143
  'chatterAssist',
135
144
  'createAssist',
145
+ 'selectionAction',
136
146
  ])
137
147
  for (const [name, c] of this.#entries[kind])
138
148
  copy.#entries[kind].set(name, c);
@@ -1,3 +1,9 @@
1
+ /**
2
+ * The form renderer (RFC 0007 §5): statusbar and transition buttons from the served view (only what the user may
3
+ * run, from the current state), groups, notebooks, editable lines, registered components (escape hatches), onchange
4
+ * assistance, and saves with compare-and-set (a record changed by someone else since it was opened is not
5
+ * overwritten: the user reloads). Conditions only decide display; the server re-checks every write.
6
+ */
1
7
  import { type ReactElement } from 'react';
2
8
  import type { FormProps } from '../registry.js';
3
9
  /** The default form renderer. */