shutro-erp 0.3.5 → 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 (768) hide show
  1. package/dist/account_asset/.kosh/bindings.js +15 -0
  2. package/dist/{mrp_account → account_asset}/.kosh/schema.d.ts +785 -614
  3. package/dist/account_asset/board.d.ts +61 -0
  4. package/dist/account_asset/board.js +86 -0
  5. package/dist/account_asset/books.d.ts +42 -0
  6. package/dist/account_asset/books.js +398 -0
  7. package/dist/account_asset/demo.d.ts +7 -0
  8. package/dist/account_asset/demo.js +72 -0
  9. package/dist/account_asset/i18n/bn.d.ts +2 -0
  10. package/dist/account_asset/i18n/bn.js +97 -0
  11. package/dist/account_asset/index.d.ts +9 -0
  12. package/dist/account_asset/index.js +337 -0
  13. package/dist/account_asset/module.d.ts +11076 -0
  14. package/dist/account_asset/module.js +230 -0
  15. package/dist/account_budget/.kosh/bindings.js +15 -0
  16. package/dist/account_budget/.kosh/schema.d.ts +2841 -0
  17. package/dist/account_budget/budget.d.ts +5 -0
  18. package/dist/account_budget/budget.js +142 -0
  19. package/dist/account_budget/demo.d.ts +6 -0
  20. package/dist/account_budget/demo.js +30 -0
  21. package/dist/account_budget/i18n/bn.d.ts +2 -0
  22. package/dist/account_budget/i18n/bn.js +63 -0
  23. package/dist/account_budget/index.d.ts +4 -0
  24. package/dist/account_budget/index.js +237 -0
  25. package/dist/account_budget/module.d.ts +27289 -0
  26. package/dist/account_budget/module.js +182 -0
  27. package/dist/account_portal/.kosh/bindings.js +1 -1
  28. package/dist/account_portal/.kosh/schema.d.ts +651 -10
  29. package/dist/account_portal/i18n/bn.d.ts +2 -0
  30. package/dist/account_portal/i18n/bn.js +6 -0
  31. package/dist/account_portal/index.js +2 -0
  32. package/dist/account_portal/module.d.ts +5212 -1592
  33. package/dist/accounting/.kosh/bindings.js +1 -1
  34. package/dist/accounting/.kosh/schema.d.ts +651 -10
  35. package/dist/accounting/closing.js +1 -0
  36. package/dist/accounting/fiscal.d.ts +578 -0
  37. package/dist/accounting/fiscal.js +401 -0
  38. package/dist/accounting/followups.d.ts +618 -0
  39. package/dist/accounting/followups.js +420 -0
  40. package/dist/accounting/i18n/bn.d.ts +2 -0
  41. package/dist/accounting/i18n/bn.js +425 -0
  42. package/dist/accounting/index.d.ts +3 -1
  43. package/dist/accounting/index.js +780 -5
  44. package/dist/accounting/module.d.ts +5386 -1543
  45. package/dist/accounting/module.js +155 -18
  46. package/dist/accounting/statements.d.ts +878 -0
  47. package/dist/accounting/statements.js +728 -0
  48. package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
  49. package/dist/accounting/web/BankReconcilePage.js +138 -0
  50. package/dist/accounting/web/FollowupsPage.d.ts +8 -0
  51. package/dist/accounting/web/FollowupsPage.js +54 -0
  52. package/dist/accounting/web/PostingPreview.d.ts +8 -0
  53. package/dist/accounting/web/PostingPreview.js +26 -0
  54. package/dist/accounting/web/index.d.ts +3 -0
  55. package/dist/accounting/web/index.js +9 -0
  56. package/dist/accounting/web/messages.js +140 -0
  57. package/dist/approvals/.kosh/bindings.d.ts +22 -0
  58. package/dist/approvals/.kosh/bindings.js +15 -0
  59. package/dist/approvals/.kosh/schema.d.ts +879 -0
  60. package/dist/approvals/demo.d.ts +7 -0
  61. package/dist/approvals/demo.js +41 -0
  62. package/dist/approvals/i18n/bn.d.ts +2 -0
  63. package/dist/approvals/i18n/bn.js +133 -0
  64. package/dist/approvals/index.d.ts +36 -0
  65. package/dist/approvals/index.js +772 -0
  66. package/dist/approvals/mails.d.ts +30 -0
  67. package/dist/approvals/mails.js +87 -0
  68. package/dist/approvals/module.d.ts +2930 -0
  69. package/dist/approvals/module.js +473 -0
  70. package/dist/approvals/web/Config.d.ts +12 -0
  71. package/dist/approvals/web/Config.js +60 -0
  72. package/dist/approvals/web/History.d.ts +4 -0
  73. package/dist/approvals/web/History.js +13 -0
  74. package/dist/approvals/web/Inbox.d.ts +9 -0
  75. package/dist/approvals/web/Inbox.js +114 -0
  76. package/dist/approvals/web/Matrix.d.ts +9 -0
  77. package/dist/approvals/web/Matrix.js +26 -0
  78. package/dist/approvals/web/Mine.d.ts +7 -0
  79. package/dist/approvals/web/Mine.js +27 -0
  80. package/dist/approvals/web/index.d.ts +15 -0
  81. package/dist/approvals/web/index.js +29 -0
  82. package/dist/approvals/web/messages.d.ts +2 -0
  83. package/dist/approvals/web/messages.js +211 -0
  84. package/dist/approvals/web/shared.d.ts +59 -0
  85. package/dist/approvals/web/shared.js +46 -0
  86. package/dist/approvals_purchase/.kosh/bindings.d.ts +22 -0
  87. package/dist/approvals_purchase/.kosh/bindings.js +15 -0
  88. package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
  89. package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
  90. package/dist/approvals_purchase/i18n/bn.js +5 -0
  91. package/dist/approvals_purchase/index.d.ts +3 -0
  92. package/dist/approvals_purchase/index.js +47 -0
  93. package/dist/approvals_purchase/module.d.ts +12670 -0
  94. package/dist/approvals_purchase/module.js +84 -0
  95. package/dist/attendance/.kosh/bindings.d.ts +22 -0
  96. package/dist/attendance/.kosh/bindings.js +15 -0
  97. package/dist/attendance/.kosh/schema.d.ts +1106 -0
  98. package/dist/attendance/days.d.ts +96 -0
  99. package/dist/attendance/days.js +430 -0
  100. package/dist/attendance/demo.d.ts +7 -0
  101. package/dist/attendance/demo.js +58 -0
  102. package/dist/attendance/i18n/bn.d.ts +2 -0
  103. package/dist/attendance/i18n/bn.js +147 -0
  104. package/dist/attendance/index.d.ts +4 -0
  105. package/dist/attendance/index.js +515 -0
  106. package/dist/attendance/module.d.ts +4413 -0
  107. package/dist/attendance/module.js +412 -0
  108. package/dist/attendance/routes.d.ts +16 -0
  109. package/dist/attendance/routes.js +266 -0
  110. package/dist/attendance/web/Check.d.ts +8 -0
  111. package/dist/attendance/web/Check.js +40 -0
  112. package/dist/attendance/web/Kiosk.d.ts +8 -0
  113. package/dist/attendance/web/Kiosk.js +62 -0
  114. package/dist/attendance/web/PinButton.d.ts +7 -0
  115. package/dist/attendance/web/PinButton.js +29 -0
  116. package/dist/attendance/web/index.d.ts +13 -0
  117. package/dist/attendance/web/index.js +22 -0
  118. package/dist/attendance/web/messages.d.ts +2 -0
  119. package/dist/attendance/web/messages.js +61 -0
  120. package/dist/automation/engine.js +1 -1
  121. package/dist/calendar/.kosh/bindings.js +1 -1
  122. package/dist/calendar/.kosh/schema.d.ts +2 -1
  123. package/dist/calendar/i18n/bn.d.ts +2 -0
  124. package/dist/calendar/i18n/bn.js +80 -0
  125. package/dist/calendar/index.js +77 -0
  126. package/dist/calendar/module.d.ts +26 -0
  127. package/dist/calendar/module.js +14 -4
  128. package/dist/cli/apps.js +25 -5
  129. package/dist/cli/init.js +46 -4
  130. package/dist/cli/templates.d.ts +1 -1
  131. package/dist/cli/templates.js +123 -5
  132. package/dist/contacts/.kosh/bindings.js +1 -1
  133. package/dist/contacts/.kosh/schema.d.ts +2 -1
  134. package/dist/contacts/i18n/bn.d.ts +2 -0
  135. package/dist/contacts/i18n/bn.js +67 -0
  136. package/dist/contacts/index.js +3 -0
  137. package/dist/contacts/module.d.ts +42 -0
  138. package/dist/contacts/module.js +19 -3
  139. package/dist/crm/.kosh/bindings.js +1 -1
  140. package/dist/crm/.kosh/schema.d.ts +3 -1
  141. package/dist/crm/i18n/bn.d.ts +2 -0
  142. package/dist/crm/i18n/bn.js +80 -0
  143. package/dist/crm/index.js +22 -0
  144. package/dist/crm/module.d.ts +22 -0
  145. package/dist/crm/module.js +6 -3
  146. package/dist/documents/.kosh/bindings.d.ts +22 -0
  147. package/dist/documents/.kosh/bindings.js +15 -0
  148. package/dist/documents/.kosh/schema.d.ts +863 -0
  149. package/dist/documents/demo.d.ts +6 -0
  150. package/dist/documents/demo.js +22 -0
  151. package/dist/documents/documents.d.ts +98 -0
  152. package/dist/documents/documents.js +318 -0
  153. package/dist/documents/i18n/bn.d.ts +2 -0
  154. package/dist/documents/i18n/bn.js +83 -0
  155. package/dist/documents/index.d.ts +30 -0
  156. package/dist/documents/index.js +569 -0
  157. package/dist/documents/module.d.ts +2801 -0
  158. package/dist/documents/module.js +215 -0
  159. package/dist/documents/web/Versions.d.ts +7 -0
  160. package/dist/documents/web/Versions.js +45 -0
  161. package/dist/documents/web/index.d.ts +11 -0
  162. package/dist/documents/web/index.js +16 -0
  163. package/dist/documents/web/messages.d.ts +2 -0
  164. package/dist/documents/web/messages.js +21 -0
  165. package/dist/event/.kosh/bindings.js +1 -1
  166. package/dist/event/.kosh/schema.d.ts +2 -1
  167. package/dist/event/i18n/bn.d.ts +2 -0
  168. package/dist/event/i18n/bn.js +101 -0
  169. package/dist/event/index.js +66 -0
  170. package/dist/event/module.d.ts +20 -0
  171. package/dist/event/module.js +8 -1
  172. package/dist/event_account/.kosh/bindings.js +1 -1
  173. package/dist/event_account/.kosh/schema.d.ts +651 -10
  174. package/dist/event_account/i18n/bn.d.ts +2 -0
  175. package/dist/event_account/i18n/bn.js +5 -0
  176. package/dist/event_account/index.js +2 -0
  177. package/dist/event_account/module.d.ts +5133 -1513
  178. package/dist/expense/.kosh/bindings.d.ts +22 -0
  179. package/dist/expense/.kosh/bindings.js +15 -0
  180. package/dist/expense/.kosh/schema.d.ts +1620 -0
  181. package/dist/expense/demo.d.ts +7 -0
  182. package/dist/expense/demo.js +69 -0
  183. package/dist/expense/i18n/bn.d.ts +2 -0
  184. package/dist/expense/i18n/bn.js +155 -0
  185. package/dist/expense/index.d.ts +3 -0
  186. package/dist/expense/index.js +502 -0
  187. package/dist/expense/module.d.ts +6768 -0
  188. package/dist/expense/module.js +649 -0
  189. package/dist/expense_account/.kosh/bindings.d.ts +22 -0
  190. package/dist/expense_account/.kosh/bindings.js +15 -0
  191. package/dist/expense_account/.kosh/schema.d.ts +2515 -0
  192. package/dist/expense_account/i18n/bn.d.ts +2 -0
  193. package/dist/expense_account/i18n/bn.js +15 -0
  194. package/dist/expense_account/index.d.ts +3 -0
  195. package/dist/expense_account/index.js +76 -0
  196. package/dist/expense_account/module.d.ts +14628 -0
  197. package/dist/expense_account/module.js +318 -0
  198. package/dist/helpdesk/.kosh/bindings.d.ts +22 -0
  199. package/dist/helpdesk/.kosh/bindings.js +15 -0
  200. package/dist/helpdesk/.kosh/schema.d.ts +886 -0
  201. package/dist/helpdesk/demo.d.ts +7 -0
  202. package/dist/helpdesk/demo.js +65 -0
  203. package/dist/helpdesk/hours.d.ts +17 -0
  204. package/dist/helpdesk/hours.js +94 -0
  205. package/dist/helpdesk/i18n/bn.d.ts +2 -0
  206. package/dist/helpdesk/i18n/bn.js +127 -0
  207. package/dist/helpdesk/index.d.ts +10 -0
  208. package/dist/helpdesk/index.js +463 -0
  209. package/dist/helpdesk/module.d.ts +2960 -0
  210. package/dist/helpdesk/module.js +326 -0
  211. package/dist/helpdesk/routes.d.ts +12 -0
  212. package/dist/helpdesk/routes.js +132 -0
  213. package/dist/helpdesk/sla.d.ts +37 -0
  214. package/dist/helpdesk/sla.js +226 -0
  215. package/dist/hr/.kosh/bindings.js +1 -1
  216. package/dist/hr/.kosh/schema.d.ts +59 -1
  217. package/dist/hr/demo.js +11 -1
  218. package/dist/hr/i18n/bn.d.ts +2 -0
  219. package/dist/hr/i18n/bn.js +126 -0
  220. package/dist/hr/index.d.ts +1 -1
  221. package/dist/hr/index.js +158 -12
  222. package/dist/hr/module.d.ts +932 -59
  223. package/dist/hr/module.js +114 -17
  224. package/dist/indent/.kosh/bindings.d.ts +22 -0
  225. package/dist/indent/.kosh/bindings.js +15 -0
  226. package/dist/indent/.kosh/schema.d.ts +2084 -0
  227. package/dist/indent/demo.d.ts +7 -0
  228. package/dist/indent/demo.js +48 -0
  229. package/dist/indent/i18n/bn.d.ts +2 -0
  230. package/dist/indent/i18n/bn.js +143 -0
  231. package/dist/indent/index.d.ts +3 -0
  232. package/dist/indent/index.js +450 -0
  233. package/dist/indent/module.d.ts +13424 -0
  234. package/dist/indent/module.js +792 -0
  235. package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
  236. package/dist/indent_purchase/.kosh/bindings.js +15 -0
  237. package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
  238. package/dist/indent_purchase/i18n/bn.d.ts +2 -0
  239. package/dist/indent_purchase/i18n/bn.js +13 -0
  240. package/dist/indent_purchase/index.d.ts +3 -0
  241. package/dist/indent_purchase/index.js +61 -0
  242. package/dist/indent_purchase/module.d.ts +27950 -0
  243. package/dist/indent_purchase/module.js +163 -0
  244. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  245. package/dist/l10n_bd/.kosh/schema.d.ts +651 -10
  246. package/dist/l10n_bd/i18n/bn.d.ts +2 -0
  247. package/dist/l10n_bd/i18n/bn.js +69 -0
  248. package/dist/l10n_bd/index.js +2 -0
  249. package/dist/l10n_bd/module.d.ts +5212 -1592
  250. package/dist/l10n_bd_payroll/.kosh/bindings.d.ts +22 -0
  251. package/dist/l10n_bd_payroll/.kosh/bindings.js +15 -0
  252. package/dist/l10n_bd_payroll/.kosh/schema.d.ts +2891 -0
  253. package/dist/l10n_bd_payroll/data.d.ts +47 -0
  254. package/dist/l10n_bd_payroll/data.js +347 -0
  255. package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
  256. package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
  257. package/dist/l10n_bd_payroll/index.d.ts +4 -0
  258. package/dist/l10n_bd_payroll/index.js +26 -0
  259. package/dist/l10n_bd_payroll/module.d.ts +17294 -0
  260. package/dist/l10n_bd_payroll/module.js +86 -0
  261. package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
  262. package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
  263. package/dist/l10n_bd_pos/.kosh/schema.d.ts +2341 -0
  264. package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
  265. package/dist/l10n_bd_pos/i18n/bn.js +32 -0
  266. package/dist/l10n_bd_pos/index.d.ts +3 -0
  267. package/dist/l10n_bd_pos/index.js +111 -0
  268. package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +9047 -6981
  269. package/dist/l10n_bd_pos/module.js +43 -0
  270. package/dist/l10n_in/.kosh/bindings.js +1 -1
  271. package/dist/l10n_in/.kosh/schema.d.ts +651 -10
  272. package/dist/l10n_in/i18n/bn.d.ts +2 -0
  273. package/dist/l10n_in/i18n/bn.js +95 -0
  274. package/dist/l10n_in/index.js +2 -0
  275. package/dist/l10n_in/module.d.ts +6778 -1580
  276. package/dist/l10n_in/module.js +25 -5
  277. package/dist/l10n_in/web/GstSettings.js +2 -2
  278. package/dist/mail/inbound/handle.js +8 -5
  279. package/dist/mail/inbound/models.js +5 -3
  280. package/dist/mail/index.d.ts +12 -1
  281. package/dist/mail/index.js +139 -2
  282. package/dist/mail/send.d.ts +56 -0
  283. package/dist/mail/send.js +394 -0
  284. package/dist/mail/web/SendButton.d.ts +9 -0
  285. package/dist/mail/web/SendButton.js +71 -0
  286. package/dist/mail/web/SendSelected.d.ts +8 -0
  287. package/dist/mail/web/SendSelected.js +33 -0
  288. package/dist/mail/web/index.d.ts +2 -0
  289. package/dist/mail/web/index.js +6 -0
  290. package/dist/mail/web/messages.js +36 -0
  291. package/dist/maintenance/.kosh/bindings.js +1 -1
  292. package/dist/maintenance/.kosh/schema.d.ts +2 -1
  293. package/dist/maintenance/i18n/bn.d.ts +2 -0
  294. package/dist/maintenance/i18n/bn.js +132 -0
  295. package/dist/maintenance/index.js +85 -0
  296. package/dist/maintenance/module.d.ts +25 -0
  297. package/dist/maintenance/module.js +27 -9
  298. package/dist/maintenance_stock/.kosh/bindings.js +1 -1
  299. package/dist/maintenance_stock/.kosh/schema.d.ts +374 -3
  300. package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
  301. package/dist/maintenance_stock/i18n/bn.js +21 -0
  302. package/dist/maintenance_stock/index.js +2 -0
  303. package/dist/maintenance_stock/module.d.ts +6095 -1327
  304. package/dist/maintenance_stock/module.js +1 -0
  305. package/dist/modules-sdk/apps.d.ts +10 -0
  306. package/dist/modules-sdk/apps.js +32 -0
  307. package/dist/modules-sdk/index.d.ts +1 -1
  308. package/dist/modules-sdk/manifest.d.ts +105 -2
  309. package/dist/payment/.kosh/bindings.js +1 -1
  310. package/dist/payment/.kosh/schema.d.ts +653 -11
  311. package/dist/payment/i18n/bn.d.ts +2 -0
  312. package/dist/payment/i18n/bn.js +59 -0
  313. package/dist/payment/index.d.ts +41 -0
  314. package/dist/payment/index.js +216 -74
  315. package/dist/payment/module.d.ts +5353 -1675
  316. package/dist/payment/module.js +36 -6
  317. package/dist/payment/settle.js +11 -1
  318. package/dist/payroll/.kosh/bindings.d.ts +22 -0
  319. package/dist/payroll/.kosh/bindings.js +15 -0
  320. package/dist/payroll/.kosh/schema.d.ts +1448 -0
  321. package/dist/payroll/compute.d.ts +35 -0
  322. package/dist/payroll/compute.js +398 -0
  323. package/dist/payroll/demo.d.ts +55 -0
  324. package/dist/payroll/demo.js +121 -0
  325. package/dist/payroll/formula.d.ts +62 -0
  326. package/dist/payroll/formula.js +320 -0
  327. package/dist/payroll/i18n/bn.d.ts +2 -0
  328. package/dist/payroll/i18n/bn.js +206 -0
  329. package/dist/payroll/index.d.ts +230 -0
  330. package/dist/payroll/index.js +715 -0
  331. package/dist/{mrp → payroll}/module.d.ts +4294 -2624
  332. package/dist/payroll/module.js +606 -0
  333. package/dist/payroll/routes.d.ts +10 -0
  334. package/dist/payroll/routes.js +112 -0
  335. package/dist/payroll_account/.kosh/bindings.d.ts +22 -0
  336. package/dist/payroll_account/.kosh/bindings.js +15 -0
  337. package/dist/payroll_account/.kosh/schema.d.ts +2887 -0
  338. package/dist/payroll_account/i18n/bn.d.ts +2 -0
  339. package/dist/payroll_account/i18n/bn.js +10 -0
  340. package/dist/payroll_account/index.d.ts +3 -0
  341. package/dist/payroll_account/index.js +42 -0
  342. package/dist/payroll_account/module.d.ts +16738 -0
  343. package/dist/payroll_account/module.js +256 -0
  344. package/dist/permissions/approvals.d.ts +227 -12
  345. package/dist/permissions/approvals.js +1421 -67
  346. package/dist/permissions/index.d.ts +1 -1
  347. package/dist/permissions/index.js +2 -2
  348. package/dist/permissions/models.js +364 -13
  349. package/dist/permissions/routes.d.ts +9 -1
  350. package/dist/permissions/routes.js +72 -5
  351. package/dist/permissions/web/ApprovalPanel.d.ts +5 -4
  352. package/dist/permissions/web/ApprovalPanel.js +75 -11
  353. package/dist/permissions/web/index.d.ts +6 -4
  354. package/dist/permissions/web/index.js +13 -4
  355. package/dist/permissions/web/messages.d.ts +2 -0
  356. package/dist/permissions/web/messages.js +95 -0
  357. package/dist/portal/.kosh/bindings.js +1 -1
  358. package/dist/portal/.kosh/schema.d.ts +2 -1
  359. package/dist/portal/documents.d.ts +3 -0
  360. package/dist/portal/documents.js +21 -1
  361. package/dist/portal/i18n/bn.d.ts +2 -0
  362. package/dist/portal/i18n/bn.js +33 -0
  363. package/dist/portal/index.js +3 -1
  364. package/dist/portal/module.d.ts +20 -0
  365. package/dist/portal/routes-documents.js +76 -0
  366. package/dist/pos/.kosh/bindings.js +1 -1
  367. package/dist/pos/.kosh/schema.d.ts +652 -10
  368. package/dist/pos/i18n/bn.d.ts +2 -0
  369. package/dist/pos/i18n/bn.js +133 -0
  370. package/dist/pos/index.js +87 -1
  371. package/dist/pos/module.d.ts +6967 -1709
  372. package/dist/pos/module.js +49 -5
  373. package/dist/pos/routes.js +80 -7
  374. package/dist/pos/web/Register.js +2 -5
  375. package/dist/pos_stock/.kosh/bindings.js +1 -1
  376. package/dist/pos_stock/.kosh/schema.d.ts +822 -12
  377. package/dist/pos_stock/i18n/bn.d.ts +2 -0
  378. package/dist/pos_stock/i18n/bn.js +6 -0
  379. package/dist/pos_stock/index.js +2 -0
  380. package/dist/pos_stock/module.d.ts +11241 -2851
  381. package/dist/product/.kosh/bindings.js +1 -1
  382. package/dist/product/.kosh/schema.d.ts +203 -1
  383. package/dist/product/i18n/bn.d.ts +2 -0
  384. package/dist/product/i18n/bn.js +175 -0
  385. package/dist/product/index.d.ts +1 -0
  386. package/dist/product/index.js +301 -1
  387. package/dist/product/module.d.ts +1727 -0
  388. package/dist/product/module.js +67 -6
  389. package/dist/product/pricelist.d.ts +575 -0
  390. package/dist/product/pricelist.js +257 -0
  391. package/dist/product/variants.d.ts +908 -0
  392. package/dist/product/variants.js +251 -0
  393. package/dist/production/.kosh/bindings.d.ts +22 -0
  394. package/dist/production/.kosh/bindings.js +15 -0
  395. package/dist/production/.kosh/schema.d.ts +2345 -0
  396. package/dist/{mrp → production}/demo.d.ts +1 -1
  397. package/dist/{mrp → production}/demo.js +5 -5
  398. package/dist/production/depth.d.ts +790 -0
  399. package/dist/production/depth.js +262 -0
  400. package/dist/production/i18n/bn.d.ts +2 -0
  401. package/dist/production/i18n/bn.js +350 -0
  402. package/dist/production/index.d.ts +6 -0
  403. package/dist/production/index.js +1256 -0
  404. package/dist/production/module.d.ts +17327 -0
  405. package/dist/production/module.js +1333 -0
  406. package/dist/production/plan.d.ts +921 -0
  407. package/dist/production/plan.js +511 -0
  408. package/dist/production/schedule.d.ts +656 -0
  409. package/dist/production/schedule.js +309 -0
  410. package/dist/production_account/.kosh/bindings.d.ts +22 -0
  411. package/dist/production_account/.kosh/bindings.js +15 -0
  412. package/dist/production_account/.kosh/schema.d.ts +3496 -0
  413. package/dist/production_account/i18n/bn.d.ts +2 -0
  414. package/dist/production_account/i18n/bn.js +93 -0
  415. package/dist/production_account/index.d.ts +4 -0
  416. package/dist/production_account/index.js +246 -0
  417. package/dist/production_account/module.d.ts +1192 -0
  418. package/dist/{mrp_account → production_account}/module.js +72 -18
  419. package/dist/production_account/overhead.d.ts +1195 -0
  420. package/dist/production_account/overhead.js +554 -0
  421. package/dist/project/.kosh/bindings.js +1 -1
  422. package/dist/project/.kosh/schema.d.ts +735 -1
  423. package/dist/project/i18n/bn.d.ts +2 -0
  424. package/dist/project/i18n/bn.js +383 -0
  425. package/dist/project/index.d.ts +3 -1
  426. package/dist/project/index.js +1024 -14
  427. package/dist/project/module.d.ts +9912 -390
  428. package/dist/project/module.js +1590 -14
  429. package/dist/project/routes.d.ts +44 -0
  430. package/dist/project/routes.js +314 -0
  431. package/dist/project/schedule.d.ts +72 -0
  432. package/dist/project/schedule.js +192 -0
  433. package/dist/project/web/Refresh.d.ts +8 -0
  434. package/dist/project/web/Refresh.js +29 -0
  435. package/dist/project/web/Schedule.d.ts +9 -0
  436. package/dist/project/web/Schedule.js +93 -0
  437. package/dist/project/web/Structure.d.ts +8 -0
  438. package/dist/project/web/Structure.js +86 -0
  439. package/dist/project/web/Workload.d.ts +8 -0
  440. package/dist/project/web/Workload.js +43 -0
  441. package/dist/project/web/index.d.ts +14 -0
  442. package/dist/project/web/index.js +25 -0
  443. package/dist/project/web/messages.d.ts +2 -0
  444. package/dist/project/web/messages.js +85 -0
  445. package/dist/project_account/.kosh/bindings.d.ts +22 -0
  446. package/dist/project_account/.kosh/bindings.js +15 -0
  447. package/dist/project_account/.kosh/schema.d.ts +2763 -0
  448. package/dist/project_account/i18n/bn.d.ts +2 -0
  449. package/dist/project_account/i18n/bn.js +6 -0
  450. package/dist/project_account/index.d.ts +3 -0
  451. package/dist/project_account/index.js +29 -0
  452. package/dist/project_account/module.d.ts +15013 -0
  453. package/dist/project_account/module.js +76 -0
  454. package/dist/project_portal/.kosh/bindings.js +1 -1
  455. package/dist/project_portal/.kosh/schema.d.ts +735 -1
  456. package/dist/project_portal/i18n/bn.d.ts +2 -0
  457. package/dist/project_portal/i18n/bn.js +6 -0
  458. package/dist/project_portal/index.js +2 -0
  459. package/dist/project_portal/module.d.ts +4796 -87
  460. package/dist/project_purchase/.kosh/bindings.d.ts +22 -0
  461. package/dist/project_purchase/.kosh/bindings.js +15 -0
  462. package/dist/project_purchase/.kosh/schema.d.ts +3393 -0
  463. package/dist/project_purchase/i18n/bn.d.ts +2 -0
  464. package/dist/project_purchase/i18n/bn.js +4 -0
  465. package/dist/project_purchase/index.d.ts +9 -0
  466. package/dist/project_purchase/index.js +24 -0
  467. package/dist/project_purchase/module.d.ts +38613 -0
  468. package/dist/project_purchase/module.js +56 -0
  469. package/dist/purchase/.kosh/bindings.js +1 -1
  470. package/dist/purchase/.kosh/schema.d.ts +908 -5
  471. package/dist/purchase/comparison.d.ts +993 -0
  472. package/dist/purchase/comparison.js +415 -0
  473. package/dist/purchase/extras.d.ts +1509 -0
  474. package/dist/purchase/extras.js +445 -0
  475. package/dist/purchase/i18n/bn.d.ts +2 -0
  476. package/dist/purchase/i18n/bn.js +413 -0
  477. package/dist/purchase/index.d.ts +5 -0
  478. package/dist/purchase/index.js +1280 -4
  479. package/dist/purchase/module.d.ts +7147 -395
  480. package/dist/purchase/module.js +303 -10
  481. package/dist/purchase/request.d.ts +696 -0
  482. package/dist/purchase/request.js +446 -0
  483. package/dist/purchase/tender.d.ts +1208 -0
  484. package/dist/purchase/tender.js +507 -0
  485. package/dist/purchase/vendorprice.d.ts +340 -0
  486. package/dist/purchase/vendorprice.js +153 -0
  487. package/dist/purchase_account/.kosh/bindings.js +1 -1
  488. package/dist/purchase_account/.kosh/schema.d.ts +1209 -16
  489. package/dist/purchase_account/i18n/bn.d.ts +2 -0
  490. package/dist/purchase_account/i18n/bn.js +22 -0
  491. package/dist/purchase_account/index.js +20 -0
  492. package/dist/purchase_account/module.d.ts +12232 -2028
  493. package/dist/purchase_account/module.js +252 -9
  494. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  495. package/dist/purchase_portal/.kosh/schema.d.ts +908 -5
  496. package/dist/purchase_portal/i18n/bn.d.ts +2 -0
  497. package/dist/purchase_portal/i18n/bn.js +5 -0
  498. package/dist/purchase_portal/index.js +2 -0
  499. package/dist/purchase_portal/module.d.ts +6853 -352
  500. package/dist/purchase_stock/.kosh/bindings.js +1 -1
  501. package/dist/purchase_stock/.kosh/schema.d.ts +1096 -21
  502. package/dist/purchase_stock/i18n/bn.d.ts +2 -0
  503. package/dist/purchase_stock/i18n/bn.js +19 -0
  504. package/dist/purchase_stock/index.d.ts +2 -2
  505. package/dist/purchase_stock/index.js +38 -2
  506. package/dist/purchase_stock/module.d.ts +12930 -1612
  507. package/dist/purchase_stock/module.js +317 -9
  508. package/dist/purchase_stock/scorecard.d.ts +22 -0
  509. package/dist/purchase_stock/scorecard.js +77 -0
  510. package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
  511. package/dist/purchase_stock/web/Scorecard.js +22 -0
  512. package/dist/purchase_stock/web/index.d.ts +11 -0
  513. package/dist/purchase_stock/web/index.js +16 -0
  514. package/dist/purchase_stock/web/messages.d.ts +2 -0
  515. package/dist/purchase_stock/web/messages.js +27 -0
  516. package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
  517. package/dist/purchase_stock_account/.kosh/schema.d.ts +1444 -20
  518. package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
  519. package/dist/purchase_stock_account/i18n/bn.js +8 -0
  520. package/dist/purchase_stock_account/index.js +18 -0
  521. package/dist/purchase_stock_account/module.d.ts +7 -35346
  522. package/dist/purchase_stock_account/module.js +35 -8
  523. package/dist/recruitment/.kosh/bindings.js +1 -1
  524. package/dist/recruitment/.kosh/schema.d.ts +60 -1
  525. package/dist/recruitment/i18n/bn.d.ts +2 -0
  526. package/dist/recruitment/i18n/bn.js +93 -0
  527. package/dist/recruitment/index.js +64 -0
  528. package/dist/recruitment/module.d.ts +460 -8
  529. package/dist/recruitment/module.js +13 -4
  530. package/dist/reporting/documents.d.ts +5 -0
  531. package/dist/reporting/documents.js +11 -1
  532. package/dist/reporting/index.d.ts +1 -1
  533. package/dist/reporting/index.js +1 -1
  534. package/dist/reporting/web/CalendarView.d.ts +18 -5
  535. package/dist/reporting/web/CalendarView.js +163 -29
  536. package/dist/reporting/web/messages.js +18 -0
  537. package/dist/sale_account/.kosh/bindings.js +1 -1
  538. package/dist/sale_account/.kosh/schema.d.ts +763 -18
  539. package/dist/sale_account/i18n/bn.d.ts +2 -0
  540. package/dist/sale_account/i18n/bn.js +48 -0
  541. package/dist/sale_account/index.d.ts +1 -1
  542. package/dist/sale_account/index.js +102 -4
  543. package/dist/sale_account/module.d.ts +8241 -2052
  544. package/dist/sale_account/module.js +535 -46
  545. package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
  546. package/dist/sale_crm/.kosh/bindings.js +15 -0
  547. package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +391 -494
  548. package/dist/sale_crm/i18n/bn.d.ts +2 -0
  549. package/dist/sale_crm/i18n/bn.js +9 -0
  550. package/dist/sale_crm/index.d.ts +7 -0
  551. package/dist/sale_crm/index.js +104 -0
  552. package/dist/sale_crm/module.d.ts +5609 -0
  553. package/dist/sale_crm/module.js +73 -0
  554. package/dist/sale_portal/.kosh/bindings.js +1 -1
  555. package/dist/sale_portal/.kosh/schema.d.ts +292 -4
  556. package/dist/sale_portal/i18n/bn.d.ts +2 -0
  557. package/dist/sale_portal/i18n/bn.js +7 -0
  558. package/dist/sale_portal/index.js +10 -0
  559. package/dist/sale_portal/module.d.ts +2563 -292
  560. package/dist/sale_project/.kosh/bindings.js +1 -1
  561. package/dist/sale_project/.kosh/schema.d.ts +1025 -4
  562. package/dist/sale_project/i18n/bn.d.ts +2 -0
  563. package/dist/sale_project/i18n/bn.js +12 -0
  564. package/dist/sale_project/index.js +2 -0
  565. package/dist/sale_project/module.d.ts +9280 -762
  566. package/dist/sale_project/module.js +17 -1
  567. package/dist/sale_stock/.kosh/bindings.js +1 -1
  568. package/dist/sale_stock/.kosh/schema.d.ts +463 -6
  569. package/dist/sale_stock/i18n/bn.d.ts +2 -0
  570. package/dist/sale_stock/i18n/bn.js +15 -0
  571. package/dist/sale_stock/index.js +2 -0
  572. package/dist/sale_stock/module.d.ts +8355 -1334
  573. package/dist/sale_stock/module.js +20 -3
  574. package/dist/sales/.kosh/bindings.js +1 -1
  575. package/dist/sales/.kosh/schema.d.ts +292 -4
  576. package/dist/sales/i18n/bn.d.ts +2 -0
  577. package/dist/sales/i18n/bn.js +128 -0
  578. package/dist/sales/index.js +124 -5
  579. package/dist/sales/module.d.ts +3568 -633
  580. package/dist/sales/module.js +306 -11
  581. package/dist/server/api/duplicate.d.ts +14 -0
  582. package/dist/server/api/duplicate.js +75 -0
  583. package/dist/server/api/explain.d.ts +70 -0
  584. package/dist/server/api/explain.js +111 -0
  585. package/dist/server/api/metadata.d.ts +2 -0
  586. package/dist/server/api/metadata.js +9 -0
  587. package/dist/server/api/openapi.js +15 -0
  588. package/dist/server/api/rest.d.ts +1 -0
  589. package/dist/server/api/rest.js +76 -12
  590. package/dist/server/api/views.js +1 -1
  591. package/dist/server/apps.d.ts +16 -1
  592. package/dist/server/apps.js +164 -2
  593. package/dist/server/auth/base.js +2 -0
  594. package/dist/server/auth/service.d.ts +8 -0
  595. package/dist/server/auth/service.js +19 -0
  596. package/dist/server/events.d.ts +13 -0
  597. package/dist/server/events.js +22 -0
  598. package/dist/server/i18n.d.ts +27 -0
  599. package/dist/server/i18n.js +143 -0
  600. package/dist/server/index.d.ts +2 -0
  601. package/dist/server/index.js +2 -0
  602. package/dist/server/server.js +6 -0
  603. package/dist/settings/company.d.ts +3 -1
  604. package/dist/settings/company.js +26 -5
  605. package/dist/settings/routes.d.ts +10 -0
  606. package/dist/settings/routes.js +19 -3
  607. package/dist/settings/web/AppsPage.d.ts +3 -2
  608. package/dist/settings/web/AppsPage.js +26 -8
  609. package/dist/settings/web/CompaniesPage.js +91 -6
  610. package/dist/settings/web/messages.js +64 -0
  611. package/dist/sign/.kosh/bindings.d.ts +22 -0
  612. package/dist/{mrp → sign}/.kosh/bindings.js +2 -2
  613. package/dist/sign/.kosh/schema.d.ts +991 -0
  614. package/dist/sign/i18n/bn.d.ts +2 -0
  615. package/dist/sign/i18n/bn.js +97 -0
  616. package/dist/sign/index.d.ts +29 -0
  617. package/dist/sign/index.js +478 -0
  618. package/dist/sign/module.d.ts +4518 -0
  619. package/dist/sign/module.js +167 -0
  620. package/dist/sign/sign.d.ts +82 -0
  621. package/dist/sign/sign.js +474 -0
  622. package/dist/stock/.kosh/bindings.js +1 -1
  623. package/dist/stock/.kosh/schema.d.ts +374 -3
  624. package/dist/stock/demo.d.ts +2 -1
  625. package/dist/stock/demo.js +28 -1
  626. package/dist/stock/i18n/bn.d.ts +2 -0
  627. package/dist/stock/i18n/bn.js +311 -0
  628. package/dist/stock/index.d.ts +4 -1
  629. package/dist/stock/index.js +674 -6
  630. package/dist/stock/ledger.d.ts +78 -0
  631. package/dist/stock/ledger.js +582 -0
  632. package/dist/stock/module.d.ts +6142 -1380
  633. package/dist/stock/module.js +780 -26
  634. package/dist/stock/replenish.d.ts +38 -0
  635. package/dist/stock/replenish.js +191 -0
  636. package/dist/stock/returns.d.ts +157 -0
  637. package/dist/stock/returns.js +163 -0
  638. package/dist/stock/web/Ledger.d.ts +9 -0
  639. package/dist/stock/web/Ledger.js +108 -0
  640. package/dist/stock/web/Operations.d.ts +8 -0
  641. package/dist/stock/web/Operations.js +33 -0
  642. package/dist/stock/web/Replenishment.d.ts +8 -0
  643. package/dist/stock/web/Replenishment.js +84 -0
  644. package/dist/stock/web/ReturnButton.d.ts +7 -0
  645. package/dist/stock/web/ReturnButton.js +62 -0
  646. package/dist/stock/web/index.d.ts +7 -2
  647. package/dist/stock/web/index.js +15 -2
  648. package/dist/stock/web/messages.js +206 -0
  649. package/dist/stock_account/.kosh/bindings.js +1 -1
  650. package/dist/stock_account/.kosh/schema.d.ts +878 -12
  651. package/dist/stock_account/i18n/bn.d.ts +2 -0
  652. package/dist/stock_account/i18n/bn.js +73 -0
  653. package/dist/stock_account/index.d.ts +1 -0
  654. package/dist/stock_account/index.js +141 -3
  655. package/dist/stock_account/landed.d.ts +429 -0
  656. package/dist/stock_account/landed.js +335 -0
  657. package/dist/stock_account/module.d.ts +12143 -3391
  658. package/dist/stock_account/module.js +135 -6
  659. package/dist/stock_account/web/LandedPreview.d.ts +7 -0
  660. package/dist/stock_account/web/LandedPreview.js +23 -0
  661. package/dist/stock_account/web/index.d.ts +11 -0
  662. package/dist/stock_account/web/index.js +16 -0
  663. package/dist/stock_account/web/messages.d.ts +2 -0
  664. package/dist/stock_account/web/messages.js +27 -0
  665. package/dist/todo/i18n/bn.d.ts +2 -0
  666. package/dist/todo/i18n/bn.js +66 -0
  667. package/dist/todo/index.js +59 -0
  668. package/dist/todo/module.d.ts +5 -0
  669. package/dist/todo/module.js +5 -3
  670. package/dist/trade_finance/.kosh/bindings.js +1 -1
  671. package/dist/trade_finance/.kosh/schema.d.ts +2 -1
  672. package/dist/trade_finance/i18n/bn.d.ts +2 -0
  673. package/dist/trade_finance/i18n/bn.js +162 -0
  674. package/dist/trade_finance/index.js +95 -0
  675. package/dist/trade_finance/module.d.ts +26 -0
  676. package/dist/trade_finance/module.js +29 -8
  677. package/dist/trade_finance_account/.kosh/bindings.js +1 -1
  678. package/dist/trade_finance_account/.kosh/schema.d.ts +651 -10
  679. package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
  680. package/dist/trade_finance_account/i18n/bn.js +27 -0
  681. package/dist/trade_finance_account/index.js +3 -0
  682. package/dist/trade_finance_account/module.d.ts +5129 -1509
  683. package/dist/trade_finance_account/module.js +2 -0
  684. package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
  685. package/dist/trade_finance_purchase/.kosh/schema.d.ts +908 -5
  686. package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
  687. package/dist/trade_finance_purchase/i18n/bn.js +6 -0
  688. package/dist/trade_finance_purchase/index.js +2 -0
  689. package/dist/trade_finance_purchase/module.d.ts +6909 -408
  690. package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
  691. package/dist/trade_finance_sale/.kosh/schema.d.ts +292 -4
  692. package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
  693. package/dist/trade_finance_sale/i18n/bn.js +6 -0
  694. package/dist/trade_finance_sale/index.js +2 -0
  695. package/dist/trade_finance_sale/module.d.ts +2602 -331
  696. package/dist/ui/api.d.ts +2 -0
  697. package/dist/ui/app.d.ts +9 -0
  698. package/dist/ui/app.js +47 -15
  699. package/dist/ui/components/AppIcon.js +9 -2
  700. package/dist/ui/components/Explain.d.ts +69 -0
  701. package/dist/ui/components/Explain.js +62 -0
  702. package/dist/ui/context.d.ts +8 -1
  703. package/dist/ui/context.js +34 -1
  704. package/dist/ui/i18n/messages.d.ts +40 -0
  705. package/dist/ui/i18n/messages.js +80 -0
  706. package/dist/ui/index.d.ts +2 -1
  707. package/dist/ui/index.js +1 -0
  708. package/dist/ui/registry.d.ts +14 -0
  709. package/dist/ui/registry.js +10 -0
  710. package/dist/ui/views/FormView.d.ts +6 -0
  711. package/dist/ui/views/FormView.js +51 -12
  712. package/dist/ui/views/KanbanView.js +9 -1
  713. package/dist/ui/views/ListView.d.ts +8 -0
  714. package/dist/ui/views/ListView.js +14 -5
  715. package/dist/ui/views/StatsRow.js +2 -1
  716. package/dist/ui/views/widgets.js +7 -1
  717. package/dist/views/extend.js +12 -0
  718. package/dist/views/types.d.ts +13 -2
  719. package/dist/views/validate.js +8 -1
  720. package/dist/website/.kosh/bindings.js +1 -1
  721. package/dist/website/.kosh/schema.d.ts +2 -1
  722. package/dist/website/i18n/bn.d.ts +2 -0
  723. package/dist/website/i18n/bn.js +113 -0
  724. package/dist/website/index.js +37 -0
  725. package/dist/website/module.d.ts +20 -0
  726. package/dist/website/module.js +30 -5
  727. package/dist/website_crm/.kosh/bindings.js +1 -1
  728. package/dist/website_crm/.kosh/schema.d.ts +3 -1
  729. package/dist/website_crm/i18n/bn.d.ts +2 -0
  730. package/dist/website_crm/i18n/bn.js +5 -0
  731. package/dist/website_crm/index.js +2 -0
  732. package/dist/website_crm/module.d.ts +41 -0
  733. package/dist/website_sale/.kosh/bindings.d.ts +22 -0
  734. package/dist/website_sale/.kosh/bindings.js +15 -0
  735. package/dist/website_sale/.kosh/schema.d.ts +2909 -0
  736. package/dist/website_sale/couriers.d.ts +50 -0
  737. package/dist/website_sale/couriers.js +59 -0
  738. package/dist/website_sale/demo.d.ts +7 -0
  739. package/dist/website_sale/demo.js +90 -0
  740. package/dist/website_sale/growth.d.ts +31 -0
  741. package/dist/website_sale/growth.js +163 -0
  742. package/dist/website_sale/i18n/bn.d.ts +2 -0
  743. package/dist/website_sale/i18n/bn.js +132 -0
  744. package/dist/website_sale/index.d.ts +49 -0
  745. package/dist/website_sale/index.js +620 -0
  746. package/dist/website_sale/module.d.ts +35182 -0
  747. package/dist/website_sale/module.js +419 -0
  748. package/dist/website_sale/shipments.d.ts +16 -0
  749. package/dist/website_sale/shipments.js +113 -0
  750. package/dist/website_sale/shop.d.ts +81 -0
  751. package/dist/website_sale/shop.js +662 -0
  752. package/dist/website_sale_stock/.kosh/bindings.d.ts +22 -0
  753. package/dist/website_sale_stock/.kosh/bindings.js +15 -0
  754. package/dist/website_sale_stock/.kosh/schema.d.ts +3400 -0
  755. package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
  756. package/dist/website_sale_stock/i18n/bn.js +4 -0
  757. package/dist/website_sale_stock/index.d.ts +9 -0
  758. package/dist/website_sale_stock/index.js +22 -0
  759. package/dist/website_sale_stock/module.d.ts +11 -0
  760. package/dist/website_sale_stock/module.js +32 -0
  761. package/package.json +117 -8
  762. package/dist/mrp/index.d.ts +0 -3
  763. package/dist/mrp/index.js +0 -392
  764. package/dist/mrp/module.js +0 -695
  765. package/dist/mrp_account/index.d.ts +0 -3
  766. package/dist/mrp_account/index.js +0 -22
  767. /package/dist/{mrp → account_asset}/.kosh/bindings.d.ts +0 -0
  768. /package/dist/{mrp_account → account_budget}/.kosh/bindings.d.ts +0 -0
@@ -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…',
@@ -48,6 +81,9 @@ export const en = {
48
81
  home: 'Home',
49
82
  appNamed: '{{app}} app',
50
83
  switchCompany: 'Company: {{name}} (switch)',
84
+ companyMenu: 'Company: {{name}}',
85
+ manageCompanies: 'Companies…',
86
+ addCompany: 'Add a company…',
51
87
  sidebar: 'Sidebar',
52
88
  collapseSidebar: 'Collapse the sidebar',
53
89
  expandSidebar: 'Expand the sidebar',
@@ -92,6 +128,7 @@ export const en = {
92
128
  exportFailed: 'The export failed: {{reason}}',
93
129
  columns: 'Columns',
94
130
  pinned: 'Pinned at the start',
131
+ pinColumn: 'Pin {{name}}',
95
132
  resetWidths: 'Reset column widths',
96
133
  resize: 'Resize {{column}}',
97
134
  density: 'Density',
@@ -123,6 +160,7 @@ export const en = {
123
160
  leaveConfirm: 'You have unsaved changes. Leave without saving?',
124
161
  transitionDone: '{{action}}: done',
125
162
  deleted: 'Deleted',
163
+ duplicated: 'Duplicated: this is the copy',
126
164
  breadcrumbs: 'Breadcrumbs',
127
165
  saving: 'Saving…',
128
166
  unsaved: 'Unsaved changes',
@@ -147,6 +185,8 @@ export const en = {
147
185
  discard: 'Discard',
148
186
  edit: 'Edit',
149
187
  delete: 'Delete',
188
+ duplicate: 'Duplicate',
189
+ actions: 'Actions',
150
190
  confirmDelete: 'Delete this record?',
151
191
  saved: 'Saved',
152
192
  total: 'Total',
@@ -333,6 +373,39 @@ export const en = {
333
373
  },
334
374
  };
335
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
+ },
336
409
  app: {
337
410
  name: 'কোষ',
338
411
  loading: 'লোড হচ্ছে…',
@@ -378,6 +451,9 @@ export const bn = {
378
451
  home: 'হোম',
379
452
  appNamed: '{{app}} অ্যাপ',
380
453
  switchCompany: 'প্রতিষ্ঠান: {{name}} (বদলান)',
454
+ companyMenu: 'প্রতিষ্ঠান: {{name}}',
455
+ manageCompanies: 'প্রতিষ্ঠানসমূহ…',
456
+ addCompany: 'প্রতিষ্ঠান যোগ করুন…',
381
457
  sidebar: 'সাইডবার',
382
458
  collapseSidebar: 'সাইডবার ছোট করুন',
383
459
  expandSidebar: 'সাইডবার বড় করুন',
@@ -422,6 +498,7 @@ export const bn = {
422
498
  exportFailed: 'এক্সপোর্ট ব্যর্থ: {{reason}}',
423
499
  columns: 'কলাম',
424
500
  pinned: 'শুরুতে আটকানো',
501
+ pinColumn: '{{name}} আটকান',
425
502
  resetWidths: 'কলামের প্রস্থ মুছুন',
426
503
  resize: '{{column}} প্রস্থ বদলান',
427
504
  density: 'ঘনত্ব',
@@ -453,6 +530,7 @@ export const bn = {
453
530
  leaveConfirm: 'পরিবর্তন সংরক্ষণ করা হয়নি। সংরক্ষণ না করেই চলে যাবেন?',
454
531
  transitionDone: '{{action}}: সম্পন্ন',
455
532
  deleted: 'মুছে ফেলা হয়েছে',
533
+ duplicated: 'অনুলিপি হয়েছে: এটি অনুলিপি',
456
534
  breadcrumbs: 'অবস্থান',
457
535
  saving: 'সংরক্ষণ হচ্ছে…',
458
536
  unsaved: 'অসংরক্ষিত পরিবর্তন',
@@ -477,6 +555,8 @@ export const bn = {
477
555
  discard: 'বাতিল',
478
556
  edit: 'সম্পাদনা',
479
557
  delete: 'মুছুন',
558
+ duplicate: 'অনুলিপি করুন',
559
+ actions: 'কাজ',
480
560
  confirmDelete: 'এই রেকর্ডটি মুছবেন?',
481
561
  saved: 'সংরক্ষিত',
482
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. */
@@ -5,18 +5,20 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
5
5
  * assistance, and saves with compare-and-set (a record changed by someone else since it was opened is not
6
6
  * overwritten: the user reloads). Conditions only decide display; the server re-checks every write.
7
7
  */
8
- import { evaluate, holds, } from '../../views/index.js';
8
+ import { evaluate, holds, resolveRecord, } from '../../views/index.js';
9
9
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
10
- import { useBlocker, useParams } from '@tanstack/react-router';
11
- import { ArrowLeft, Check, ChevronLeft, ChevronRight, CircleDot, MoreHorizontal, PanelRight, Plus, Trash2, } from 'lucide-react';
10
+ import { useBlocker, useNavigate, useParams } from '@tanstack/react-router';
11
+ import { ArrowLeft, Check, ChevronLeft, ChevronRight, CircleDot, Copy, MoreHorizontal, PanelRight, Plus, Trash2, } from 'lucide-react';
12
12
  import { useEffect, useId, useMemo, useRef, useState } from 'react';
13
13
  import { useTranslation } from 'react-i18next';
14
14
  import { ApiError, NetworkError, } from '../api.js';
15
+ import { Explain } from '../components/Explain.js';
15
16
  import { Alert, Button, Dialog, Label, Menu, MenuContent, MenuItem, MenuTrigger, Spinner, Tabs, TabsContent, TabsList, TabsTrigger, } from '../components/primitives.js';
16
17
  import { useKosh } from '../context.js';
17
18
  import { useDesign } from '../design.js';
18
19
  import { cn } from '../lib/cn.js';
19
20
  import { useLiveRecord } from '../live.js';
21
+ import { setPrefill } from '../prefill.js';
20
22
  import { useToast } from '../shell/toast.js';
21
23
  import { StatsRow } from './StatsRow.js';
22
24
  import { StatusChip } from './StatusChip.js';
@@ -128,7 +130,7 @@ lineFields) {
128
130
  return out;
129
131
  }
130
132
  function Lines({ node, served, ids, readonly, state, onState, }) {
131
- const { api, registry } = useKosh();
133
+ const { api, registry, uid, companyId } = useKosh();
132
134
  const { t } = useTranslation();
133
135
  const field = served.fields[served.view.model]?.[node.field];
134
136
  const target = field?.target ?? '';
@@ -157,7 +159,9 @@ function Lines({ node, served, ids, readonly, state, onState, }) {
157
159
  return (_jsx(PrefetchedNames.Provider, { value: names, children: _jsxs("div", { className: "col-span-full overflow-x-auto", children: [_jsxs("table", { className: "w-full text-sm", children: [_jsx("caption", { className: "sr-only", children: node.id }), _jsx("thead", { children: _jsxs("tr", { className: "border-b", children: [columns.map((c) => (_jsx("th", { scope: "col", className: "px-2 py-1.5 text-start font-medium text-muted-foreground", children: c.label ?? columnFields[c.field]?.label ?? c.field }, c.id))), _jsx("th", { className: "w-10", children: _jsx("span", { className: "sr-only", children: t('views.removeLine') }) })] }) }), _jsx("tbody", { children: rows.map((row, index) => (_jsxs("tr", { className: "border-b", children: [columns.map((c) => {
158
160
  const meta = columnFields[c.field];
159
161
  const Widget = registry.widget(c, meta);
160
- return (_jsx("td", { className: "px-2 py-1", children: _jsx(Widget, { id: `${row.key}-${c.id}`, node: c, field: meta, value: row.values[c.field], record: row.values, readonly: readonly || meta.readonly, onChange: (value) => set(rows.map((r, i) => i === index
162
+ return (_jsx("td", { className: "px-2 py-1", children: _jsx(Widget, { id: `${row.key}-${c.id}`, node: c, field: meta, value: row.values[c.field], record: row.values, readonly: readonly ||
163
+ meta.readonly ||
164
+ holds(c.readonlyWhen, row.values, { uid, companyId }), onChange: (value) => set(rows.map((r, i) => i === index
161
165
  ? {
162
166
  ...r,
163
167
  values: { ...r.values, [c.field]: value },
@@ -186,6 +190,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
186
190
  const design = useDesign();
187
191
  const toast = useToast();
188
192
  const queryClient = useQueryClient();
193
+ const navigateTo = useNavigate();
189
194
  const formId = useId();
190
195
  const [railOpen, setRailOpen] = useRail();
191
196
  const route = useParams({ strict: false });
@@ -378,6 +383,16 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
378
383
  },
379
384
  onError: fail,
380
385
  });
386
+ // Duplicate (RFC 0023 R1): a copy made by the server as the user; the form opens it.
387
+ const duplicate = useMutation({
388
+ mutationFn: () => api.call('POST', `/api/v1/models/${model}/${String(recordId)}/duplicate`, {}),
389
+ onSuccess: async (copy) => {
390
+ await queryClient.invalidateQueries({ queryKey: ['list', model] });
391
+ toast({ title: t('views.duplicated') });
392
+ onSaved(copy.id);
393
+ },
394
+ onError: fail,
395
+ });
381
396
  const remove = useMutation({
382
397
  mutationFn: () => api.remove(model, recordId),
383
398
  onSuccess: async () => {
@@ -445,7 +460,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
445
460
  const readonly = locked || field.readonly || holds(node.readonlyWhen, values, env);
446
461
  const id = `${formId}-${node.id}`;
447
462
  const invalid = problem?.problem.detail.includes(node.field) === true;
448
- return (_jsxs("div", { className: cn('grid gap-1', (field.kind === 'text' || field.kind === 'html') && 'col-span-full'), children: [_jsxs(Label, { htmlFor: id, children: [node.label ?? field.label, (field.required || holds(node.requiredWhen, values, env)) && !readonly ? (_jsxs("span", { "aria-hidden": true, className: "text-danger", children: [' ', "*"] })) : null, recordId === 'new' && proposed?.includes(node.field) === true ? (_jsx("span", { className: "ms-2 rounded bg-accent px-1.5 py-0.5 text-[10px] font-medium text-accent-foreground", children: t('views.proposed') })) : null] }), _jsx("div", { className: "min-h-9 py-1.5 text-sm", children: _jsx(Widget, { id: id, node: node, field: field, value: values[node.field], record: values, model: model, readonly: readonly, onChange: (v) => change(node.field, v), invalid: invalid }) }), (node.help ?? field.help) === undefined ? null : (_jsx("p", { className: "text-xs text-muted-foreground", children: node.help ?? field.help }))] }, node.id));
463
+ return (_jsxs("div", { className: cn('grid gap-1', (field.kind === 'text' || field.kind === 'html') && 'col-span-full'), children: [_jsxs(Label, { htmlFor: id, children: [_jsx(Explain, { model: model, target: { field: node.field }, children: node.label ?? field.label }), (field.required || holds(node.requiredWhen, values, env)) && !readonly ? (_jsxs("span", { "aria-hidden": true, className: "text-danger", children: [' ', "*"] })) : null, recordId === 'new' && proposed?.includes(node.field) === true ? (_jsx("span", { className: "ms-2 rounded bg-accent px-1.5 py-0.5 text-[10px] font-medium text-accent-foreground", children: t('views.proposed') })) : null] }), _jsx("div", { className: "min-h-9 py-1.5 text-sm", children: _jsx(Widget, { id: id, node: node, field: field, value: values[node.field], record: values, model: model, readonly: readonly, onChange: (v) => change(node.field, v), invalid: invalid }) }), (node.help ?? field.help) === undefined ? null : (_jsx("p", { className: "text-xs text-muted-foreground", children: node.help ?? field.help }))] }, node.id));
449
464
  };
450
465
  const renderNodes = (nodes) => nodes.map((node) => {
451
466
  switch (node.kind) {
@@ -516,9 +531,27 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
516
531
  (v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0)));
517
532
  })
518
533
  .map((n) => n.field);
534
+ // A button that opens a new record of another model, filled from this one (RFC 0028 §3.4).
535
+ const openNew = (open) => {
536
+ void api.routes().then((routes) => {
537
+ const route = routes[open.model];
538
+ const action = open.action ?? route?.action;
539
+ if (action === undefined || route?.app === undefined)
540
+ return;
541
+ const filled = resolveRecord(open.values, values);
542
+ setPrefill(action, { values: filled, proposed: [] });
543
+ void navigateTo({
544
+ to: '/$app/a/$action/$id',
545
+ params: { app: route.app, action, id: 'new' },
546
+ });
547
+ });
548
+ };
519
549
  // RFC 0022 §3.5: the record's document templates as a Print menu, when reporting's web is registered.
520
550
  const Print = registry.component('reporting.Documents');
551
+ const Send = registry.component('mail.Send');
521
552
  const buttons = view.header.buttons.filter((b) => {
553
+ if (b.open !== undefined)
554
+ return !isNew && visible(b.visibleWhen);
522
555
  const spec = served.transitions.find((tr) => tr.name === b.transition);
523
556
  return (!isNew &&
524
557
  spec !== undefined &&
@@ -598,7 +631,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
598
631
  e.preventDefault();
599
632
  if (dirty && !locked)
600
633
  save.mutate();
601
- }, children: [_jsxs("div", { className: "sticky top-12 z-20 -mx-4 flex flex-wrap items-center justify-between gap-2 border-b bg-background/95 px-4 py-2 backdrop-blur", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.back'), "data-kosh-back": true, onClick: onBack, children: _jsx(ArrowLeft, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2.5", children: [_jsx("h1", { className: "truncate text-xl font-semibold", children: title }), statusbar === undefined || fields[statusbar] === undefined || isNew ? null : (_jsx(StatusChip, { field: fields[statusbar], value: state, transitions: served.transitions.filter((tr) => tr.field === statusbar) })), locked && !isNew ? (_jsx("span", { className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground", children: t('views.readonly') })) : null] }), facts.length === 0 ? null : (_jsx("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 text-sm text-muted-foreground", children: facts.map((node, i) => {
634
+ }, children: [_jsxs("div", { className: "sticky top-12 z-20 -mx-4 flex flex-wrap items-center justify-between gap-2 border-b bg-background/95 px-4 py-2 backdrop-blur", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.back'), "data-kosh-back": true, onClick: onBack, children: _jsx(ArrowLeft, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2.5", children: [_jsx("h1", { className: "truncate text-xl font-semibold", children: _jsx(Explain, { model: model, target: { model: true }, children: title }) }), statusbar === undefined || fields[statusbar] === undefined || isNew ? null : (_jsx(StatusChip, { field: fields[statusbar], value: state, transitions: served.transitions.filter((tr) => tr.field === statusbar) })), locked && !isNew ? (_jsx("span", { className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground", children: t('views.readonly') })) : null] }), facts.length === 0 ? null : (_jsx("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 text-sm text-muted-foreground", children: facts.map((node, i) => {
602
635
  const field = fields[node.field];
603
636
  const Widget = registry.widget(node, field);
604
637
  return (_jsxs("span", { className: "flex items-center gap-2", title: field.label, children: [i === 0 ? null : _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsxs("span", { className: "sr-only", children: [field.label, ": "] }), _jsx(Widget, { id: `${formId}-fact-${node.id}`, node: node, field: field, value: values[node.field], record: values, readonly: true })] }, node.id));
@@ -612,7 +645,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
612
645
  setChanges({});
613
646
  setLines(new Map());
614
647
  setProblem(null);
615
- }, children: t('views.discard') }), _jsx(Button, { type: "submit", variant: "primary", busy: save.isPending, "data-kosh-save": true, children: t('views.save') })] })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "hidden xl:inline-flex", "aria-pressed": railOpen, "aria-label": railOpen ? t('views.hidePanel') : t('views.showPanel'), title: railOpen ? t('views.hidePanel') : t('views.showPanel'), onClick: () => setRailOpen(!railOpen), children: _jsx(PanelRight, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), !isNew && served.operations.unlink ? (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": "Actions", children: _jsx(MoreHorizontal, { "aria-hidden": true }) }) }), _jsx(MenuContent, { children: _jsxs(MenuItem, { onSelect: () => setDeleting(true), children: [_jsx(Trash2, { className: "size-4", "aria-hidden": true }), t('views.delete')] }) })] })) : null] })] }), _jsxs("div", { className: cn('grid gap-4', showRail && 'xl:grid-cols-[minmax(0,1fr)_20rem] xl:items-start'), children: [_jsxs("div", { className: "grid min-w-0 content-start gap-4", children: [live.changedByOther ? (_jsx(Alert, { tone: "warning", action: _jsx(Button, { type: "button", size: "sm", onClick: () => {
648
+ }, children: t('views.discard') }), _jsx(Button, { type: "submit", variant: "primary", busy: save.isPending, "data-kosh-save": true, children: t('views.save') })] })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "hidden xl:inline-flex", "aria-pressed": railOpen, "aria-label": railOpen ? t('views.hidePanel') : t('views.showPanel'), title: railOpen ? t('views.hidePanel') : t('views.showPanel'), onClick: () => setRailOpen(!railOpen), children: _jsx(PanelRight, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), !isNew && (served.operations.unlink || served.operations.create) ? (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.actions'), children: _jsx(MoreHorizontal, { "aria-hidden": true }) }) }), _jsxs(MenuContent, { children: [served.operations.create ? (_jsxs(MenuItem, { disabled: duplicate.isPending, onSelect: () => duplicate.mutate(), children: [_jsx(Copy, { className: "size-4", "aria-hidden": true }), t('views.duplicate')] })) : null, served.operations.unlink ? (_jsxs(MenuItem, { onSelect: () => setDeleting(true), children: [_jsx(Trash2, { className: "size-4", "aria-hidden": true }), t('views.delete')] })) : null] })] })) : null] })] }), _jsxs("div", { className: cn('grid gap-4', showRail && 'xl:grid-cols-[minmax(0,1fr)_20rem] xl:items-start'), children: [_jsxs("div", { className: "grid min-w-0 content-start gap-4", children: [live.changedByOther ? (_jsx(Alert, { tone: "warning", action: _jsx(Button, { type: "button", size: "sm", onClick: () => {
616
649
  setChanges({});
617
650
  setLines(new Map());
618
651
  live.dismiss();
@@ -623,12 +656,18 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
623
656
  void loaded.refetch();
624
657
  }, children: t('views.reload') })) : undefined, children: problem.kind === 'stale-record' ? t('views.stale') : problem.message })), warnings.map((w) => (_jsx(Alert, { tone: "info", children: w }, w))), nextStep === undefined || nextButton === undefined || locked ? null : (_jsx(Alert, { tone: nextStep.allowed ? 'info' : 'warning', children: nextStep.allowed
625
658
  ? t('views.nextStep.ready', { step: nextButton.label ?? nextButton.transition })
626
- : `${t('views.nextStep.before', { step: nextButton.label ?? nextButton.transition })} ${nextStep.message ?? ''}`.trim() })), buttons.length === 0 && (isNew || Print === undefined) ? null : (_jsxs("div", { role: "toolbar", "aria-label": t('views.recordActions'), className: "flex flex-wrap gap-2", children: [isNew || Print === undefined ? null : (_jsx(Print, { node: { kind: 'component', id: 'print', component: 'reporting.Documents' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), _jsx("div", { className: "contents", children: buttons.map((b, i) => (_jsx(Button, { type: "button", size: "sm", variant: b.primary === true || (i === 0 && !buttons.some((x) => x.primary === true))
627
- ? 'primary'
628
- : 'secondary', busy: transition.isPending && transition.variables === b.transition, onClick: () => b.confirm === undefined ? transition.mutate(b.transition) : setConfirming(b), children: b.label ?? b.transition }, b.id))) })] })), sections.map((section) => section.nodes[0]?.kind === 'stats' ? (_jsx("div", { className: "grid", children: renderNodes(section.nodes) }, section.key)) : (_jsx("section", { className: "rounded-lg border bg-surface p-5", children: _jsx("div", { className: "grid gap-x-6 gap-y-4 sm:grid-cols-2", children: renderNodes(section.nodes) }) }, section.key))), showRail ? null : rail] }), showRail ? (_jsx("aside", { "aria-label": t('views.recordPanel'),
659
+ : `${t('views.nextStep.before', { step: nextButton.label ?? nextButton.transition })} ${nextStep.message ?? ''}`.trim() })), buttons.length === 0 &&
660
+ (isNew || (Print === undefined && Send === undefined)) ? null : (_jsxs("div", { role: "toolbar", "aria-label": t('views.recordActions'), className: "flex flex-wrap gap-2", children: [isNew || Print === undefined ? null : (_jsx(Print, { node: { kind: 'component', id: 'print', component: 'reporting.Documents' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), isNew || Send === undefined ? null : (_jsx(Send, { node: { kind: 'component', id: 'send', component: 'mail.Send' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), _jsx("div", { className: "contents", children: buttons.map((b, i) => (_jsx(Explain, { model: model, asChild: true, target: b.transition === undefined ? { action: b.id } : { transition: b.transition }, children: _jsx(Button, { type: "button", size: "sm", variant: b.primary === true ||
661
+ (i === 0 && !buttons.some((x) => x.primary === true))
662
+ ? 'primary'
663
+ : 'secondary', busy: transition.isPending && transition.variables === b.transition, onClick: () => b.open !== undefined
664
+ ? openNew(b.open)
665
+ : b.confirm === undefined
666
+ ? transition.mutate(b.transition ?? '')
667
+ : setConfirming(b), children: b.label ?? b.transition ?? b.id }) }, b.id))) })] })), sections.map((section) => section.nodes[0]?.kind === 'stats' ? (_jsx("div", { className: "grid", children: renderNodes(section.nodes) }, section.key)) : (_jsx("section", { className: "rounded-lg border bg-surface p-5", children: _jsx("div", { className: "grid gap-x-6 gap-y-4 sm:grid-cols-2", children: renderNodes(section.nodes) }) }, section.key))), showRail ? null : rail] }), showRail ? (_jsx("aside", { "aria-label": t('views.recordPanel'),
629
668
  // Beside the record when wide; under it otherwise (one grid column).
630
669
  className: "grid content-start gap-4 xl:sticky xl:top-28", children: rail })) : null] })] }), _jsx(Dialog, { open: confirming !== null, onOpenChange: (open) => !open && setConfirming(null), title: confirming?.label ?? confirming?.transition ?? '', description: confirming?.confirm ?? '', footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => setConfirming(null), children: t('views.no') }), _jsx(Button, { variant: "primary", onClick: () => {
631
- if (confirming !== null)
670
+ if (confirming?.transition !== undefined)
632
671
  transition.mutate(confirming.transition);
633
672
  setConfirming(null);
634
673
  }, children: t('views.yes') })] }) }), _jsx(Dialog, { open: deleting, onOpenChange: setDeleting, title: t('views.confirmDelete'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => setDeleting(false), children: t('views.no') }), _jsx(Button, { variant: "danger", busy: remove.isPending, onClick: () => remove.mutate(), children: t('views.delete') })] }) })] }));
@@ -56,6 +56,14 @@ function Card({ row, served, onOpen, }) {
56
56
  if (view.type !== 'kanban')
57
57
  throw new Error('kanban');
58
58
  const fields = served.fields[view.model] ?? {};
59
+ // A number, or a decimal's string ("75.0").
60
+ const rawProgress = view.card.progress === undefined ? undefined : row[view.card.progress];
61
+ const progressValue = typeof rawProgress === 'number' || (typeof rawProgress === 'string' && rawProgress !== '')
62
+ ? Number(rawProgress)
63
+ : Number.NaN;
64
+ const progress = Number.isFinite(progressValue)
65
+ ? Math.max(0, Math.min(100, progressValue))
66
+ : null;
59
67
  const show = (node) => {
60
68
  const field = fields[node.field];
61
69
  if (field === undefined)
@@ -81,7 +89,7 @@ function Card({ row, served, onOpen, }) {
81
89
  : nameOfValue(row[view.card.avatar])) ?? ''), src: fields[view.card.avatar]?.target === 'storage.attachment' &&
82
90
  idOfValue(row[view.card.avatar]) !== null
83
91
  ? `/api/v1/attachments/${idOfValue(row[view.card.avatar])}/download?inline=true&w=256`
84
- : null, className: "mt-0.5" })), _jsx("button", { type: "button", className: "text-start font-medium hover:underline", onClick: () => onOpen(row.id), children: text(view.card.title) }), _jsx("button", { type: "button", className: "cursor-grab rounded px-1 text-muted-foreground hover:bg-muted", "aria-label": `Move ${String(row['displayName'] ?? row[view.card.title] ?? row.id)}`, ...attributes, ...listeners, children: "\u283F" })] }), view.card.subtitle === undefined ? null : (_jsx("div", { className: "text-muted-foreground", children: text(view.card.subtitle) })), (view.card.badges ?? []).length === 0 ? null : (_jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: (view.card.badges ?? []).map(show) })), (view.card.footer ?? []).length === 0 ? null : (_jsx("div", { className: "mt-2 flex flex-wrap justify-between gap-2 text-xs text-muted-foreground", children: (view.card.footer ?? []).map(show) })), view.card.progress === undefined || typeof row[view.card.progress] !== 'number' ? null : (_jsx("div", { role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": row[view.card.progress], className: "mt-2 h-1.5 w-full overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary", style: { width: `${Math.max(0, Math.min(100, row[view.card.progress]))}%` } }) }))] }));
92
+ : null, className: "mt-0.5" })), _jsx("button", { type: "button", className: "text-start font-medium hover:underline", onClick: () => onOpen(row.id), children: text(view.card.title) }), _jsx("button", { type: "button", className: "cursor-grab rounded px-1 text-muted-foreground hover:bg-muted", "aria-label": `Move ${String(row['displayName'] ?? row[view.card.title] ?? row.id)}`, ...attributes, ...listeners, children: "\u283F" })] }), view.card.subtitle === undefined ? null : (_jsx("div", { className: "text-muted-foreground", children: text(view.card.subtitle) })), (view.card.badges ?? []).length === 0 ? null : (_jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: (view.card.badges ?? []).map(show) })), (view.card.footer ?? []).length === 0 ? null : (_jsx("div", { className: "mt-2 flex flex-wrap justify-between gap-2 text-xs text-muted-foreground", children: (view.card.footer ?? []).map(show) })), progress === null ? null : (_jsx("div", { role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": progress, className: "mt-2 h-1.5 w-full overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary", style: { width: `${progress}%` } }) }))] }));
85
93
  }
86
94
  function ColumnView({ column, props, keys, groupField, stats, folded, onUnfold, }) {
87
95
  const { api, format } = useKosh();
@@ -1,3 +1,11 @@
1
+ /**
2
+ * The list renderer (RFC 0007 §5, RFC 0010 §3.5): server-side order, paging and totals, grouping (one level,
3
+ * expandable), inline edit of `inlineEdit` columns with compare-and-set, row virtualization (TanStack Virtual) so
4
+ * large pages scroll smoothly, selection with a bulk bar (archive and delete with Undo, export, the transitions every
5
+ * selected record allows), export to CSV and Excel, a column chooser and density remembered per user, skeleton rows
6
+ * while loading and an empty state that offers the next step. Rows are a semantic table: keyboard users move with
7
+ * Tab and open with Enter. Every bulk action is one request per record to the existing, permission-checked routes.
8
+ */
1
9
  import { type ReactElement } from 'react';
2
10
  import type { ViewProps } from '../registry.js';
3
11
  /** The default list renderer. */
@@ -15,6 +15,7 @@ import { Archive, ArrowDown, ArrowUp, ChevronRight, Columns3, Download, Inbox, P
15
15
  import { useEffect, useMemo, useRef, useState, } from 'react';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { ApiError } from '../api.js';
18
+ import { Explain } from '../components/Explain.js';
18
19
  import { Alert, Button, Checkbox, Dialog, EmptyState, Menu, MenuCheckboxItem, MenuContent, MenuItem, MenuLabel, MenuSeparator, MenuTrigger, Skeleton, } from '../components/primitives.js';
19
20
  import { useKosh } from '../context.js';
20
21
  import { useDesign } from '../design.js';
@@ -78,7 +79,7 @@ const SELECT_WIDTH = 40;
78
79
  */
79
80
  function ResizeHandle({ label, width, onResize, onReset, }) {
80
81
  const drag = useRef(null);
81
- return (_jsx("span", { role: "separator", "aria-orientation": "vertical", "aria-label": label, "aria-valuenow": width ?? undefined, tabIndex: 0, className: "absolute inset-y-0 end-0 w-2 cursor-col-resize touch-none select-none hover:bg-primary/30 focus-visible:bg-primary/40 focus-visible:outline-none", onPointerDown: (e) => {
82
+ return (_jsx("span", { role: "separator", "aria-orientation": "vertical", "aria-label": label, "aria-valuenow": width ?? DEFAULT_WIDTH, "aria-valuemin": MIN_WIDTH, "aria-valuemax": MAX_WIDTH, tabIndex: 0, className: "absolute inset-y-0 end-0 w-2 cursor-col-resize touch-none select-none hover:bg-primary/30 focus-visible:bg-primary/40 focus-visible:outline-none", onPointerDown: (e) => {
82
83
  const cell = e.currentTarget.parentElement;
83
84
  if (cell === null)
84
85
  return;
@@ -603,7 +604,7 @@ function Rows({ props, where, columns, fields, offset, limit, height, selection,
603
604
  ? 'ascending'
604
605
  : direction === 'desc'
605
606
  ? 'descending'
606
- : 'none', className: cn('relative px-3 py-2 text-start font-medium text-muted-foreground', pinnedClass(node.id)), children: [_jsxs("button", { type: "button", className: "inline-flex items-center gap-1", onClick: () => toggleOrder(node.field), children: [_jsx(table.FlexRender, { header: header }), direction === 'asc' ? (_jsx(ArrowUp, { className: "size-3", "aria-hidden": true })) : direction === 'desc' ? (_jsx(ArrowDown, { className: "size-3", "aria-hidden": true })) : null] }), _jsx(ResizeHandle, { label: t('views.resize', {
607
+ : 'none', className: cn('relative px-3 py-2 text-start font-medium text-muted-foreground', pinnedClass(node.id)), children: [_jsx(Explain, { model: model, target: { field: node.field }, asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex items-center gap-1", onClick: () => toggleOrder(node.field), children: [_jsx(table.FlexRender, { header: header }), direction === 'asc' ? (_jsx(ArrowUp, { className: "size-3", "aria-hidden": true })) : direction === 'desc' ? (_jsx(ArrowDown, { className: "size-3", "aria-hidden": true })) : null] }) }), _jsx(ResizeHandle, { label: t('views.resize', {
607
608
  column: node.label ?? fields[node.field]?.label ?? node.field,
608
609
  }), width: widths[node.id] ?? null, onResize: (w) => setWidth(node.id, w), onReset: () => setWidth(node.id, null) })] }, header.id));
609
610
  })] }, group.id))) }), _jsxs("tbody", { children: [top > 0 ? (_jsx("tr", { "aria-hidden": true, children: _jsx("td", { style: { height: top }, colSpan: span }) })) : null, virtual.map((v) => {
@@ -759,7 +760,7 @@ export function totalLabel(word, label) {
759
760
  : `${word} ${label}`;
760
761
  }
761
762
  export function ListView(props) {
762
- const { api, uid } = useKosh();
763
+ const { api, uid, registry } = useKosh();
763
764
  const { t } = useTranslation();
764
765
  const toast = useToast();
765
766
  const queryClient = useQueryClient();
@@ -934,7 +935,13 @@ export function ListView(props) {
934
935
  }),
935
936
  });
936
937
  // Selected rows: a floating bar at the bottom of the screen (RFC 0018 §4.3); the list's own toolbar stays put.
937
- const floating = ids.length > 0 ? (_jsxs("div", { role: "toolbar", "aria-label": t('views.selected', { count: ids.length }), "data-kosh-selection-bar": true, className: "fixed inset-x-0 bottom-4 z-30 mx-auto flex w-fit max-w-[calc(100vw-2rem)] flex-wrap items-center gap-2 rounded-xl border bg-surface px-3 py-2 text-sm shadow-lg", children: [_jsx("span", { className: "font-medium", children: t('views.selected', { count: ids.length }) }), _jsx(Button, { size: "sm", variant: "ghost", "aria-label": t('views.clearSelection'), onClick: () => setSelected(new Set()), children: _jsx(X, { "aria-hidden": true }) }), _jsx("span", { className: "flex-1" }), transitions.map((tr) => (_jsx(Button, { size: "sm", busy: transition.isPending && transition.variables?.name === tr.name, onClick: () => transition.mutate({ name: tr.name, what: ids }), children: tr.name.charAt(0).toUpperCase() + tr.name.slice(1).replace(/_/g, ' ') }, tr.name))), archivable ? (_jsxs(Button, { size: "sm", busy: archive.isPending, onClick: () => archive.mutate(ids), children: [_jsx(Archive, { "aria-hidden": true }), t('views.archive')] })) : null, served.operations.unlink ? (_jsxs(Button, { size: "sm", variant: "danger", onClick: () => setConfirmingDelete(true), children: [_jsx(Trash2, { "aria-hidden": true }), t('views.delete')] })) : null, canExport ? (_jsxs(Button, { size: "sm", busy: exportAs.isPending, onClick: () => exportAs.mutate('csv'), children: [_jsx(Download, { "aria-hidden": true }), t('views.export')] })) : null] })) : null;
938
+ const floating = ids.length > 0 ? (_jsxs("div", { role: "toolbar", "aria-label": t('views.selected', { count: ids.length }), "data-kosh-selection-bar": true, className: "fixed inset-x-0 bottom-4 z-30 mx-auto flex w-fit max-w-[calc(100vw-2rem)] flex-wrap items-center gap-2 rounded-xl border bg-surface px-3 py-2 text-sm shadow-lg", children: [_jsx("span", { className: "font-medium", children: t('views.selected', { count: ids.length }) }), _jsx(Button, { size: "sm", variant: "ghost", "aria-label": t('views.clearSelection'), onClick: () => setSelected(new Set()), children: _jsx(X, { "aria-hidden": true }) }), _jsx("span", { className: "flex-1" }), transitions.map((tr) => (_jsx(Button, { size: "sm", busy: transition.isPending && transition.variables?.name === tr.name, onClick: () => transition.mutate({ name: tr.name, what: ids }), children: tr.name.charAt(0).toUpperCase() + tr.name.slice(1).replace(/_/g, ' ') }, tr.name))), registry.selectionActions().map((Action, i) => (_jsx(Action
939
+ // biome-ignore lint/suspicious/noArrayIndexKey: registered once, in a fixed order
940
+ , { api: api, model: model, ids: ids, done: (message, tone) => {
941
+ setSelected(new Set());
942
+ void refresh();
943
+ toast({ title: message, tone: tone ?? 'info' });
944
+ } }, i))), archivable ? (_jsxs(Button, { size: "sm", busy: archive.isPending, onClick: () => archive.mutate(ids), children: [_jsx(Archive, { "aria-hidden": true }), t('views.archive')] })) : null, served.operations.unlink ? (_jsxs(Button, { size: "sm", variant: "danger", onClick: () => setConfirmingDelete(true), children: [_jsx(Trash2, { "aria-hidden": true }), t('views.delete')] })) : null, canExport ? (_jsxs(Button, { size: "sm", busy: exportAs.isPending, onClick: () => exportAs.mutate('csv'), children: [_jsx(Download, { "aria-hidden": true }), t('views.export')] })) : null] })) : null;
938
945
  const toolbar = (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b px-3 py-1.5 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: count === null ? (_jsx(Skeleton, { className: "inline-block h-4 w-20" })) : (t('views.records', { count })) }), _jsx("span", { className: "flex-1" }), design.active ? (_jsxs(Button, { size: "sm", variant: "ghost", className: "border border-dashed border-primary/50 text-primary", onClick: () => design.choose({
939
946
  kind: 'list',
940
947
  view: view.id,
@@ -952,7 +959,9 @@ export function ListView(props) {
952
959
  next.add(c.id);
953
960
  setHidden(next);
954
961
  stored.set(columnsKey, [...next]);
955
- }, children: c.label ?? fields[c.field]?.label ?? c.field }, c.id))), _jsx(MenuSeparator, {}), _jsx(MenuLabel, { children: t('views.pinned') }), columns.map((c) => (_jsx(MenuCheckboxItem, { checked: pinned.includes(c.id), onCheckedChange: () => togglePin(c.id), children: c.label ?? fields[c.field]?.label ?? c.field }, `pin-${c.id}`))), Object.keys(widths).length === 0 ? null : (_jsxs(_Fragment, { children: [_jsx(MenuSeparator, {}), _jsx(MenuItem, { onSelect: () => {
962
+ }, children: c.label ?? fields[c.field]?.label ?? c.field }, c.id))), _jsx(MenuSeparator, {}), _jsx(MenuLabel, { children: t('views.pinned') }), columns.map((c) => (_jsx(MenuCheckboxItem, { "aria-label": t('views.pinColumn', {
963
+ name: c.label ?? fields[c.field]?.label ?? c.field,
964
+ }), checked: pinned.includes(c.id), onCheckedChange: () => togglePin(c.id), children: c.label ?? fields[c.field]?.label ?? c.field }, `pin-${c.id}`))), Object.keys(widths).length === 0 ? null : (_jsxs(_Fragment, { children: [_jsx(MenuSeparator, {}), _jsx(MenuItem, { onSelect: () => {
956
965
  setWidths({});
957
966
  stored.set(widthsKey, {});
958
967
  }, children: t('views.resetWidths') })] }))] })] }), canExport ? (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsx(Button, { size: "sm", variant: "ghost", "aria-label": t('views.export'), busy: exportAs.isPending, children: _jsx(Download, { "aria-hidden": true }) }) }), _jsxs(MenuContent, { align: "end", children: [_jsx(MenuLabel, { children: t('views.export') }), _jsx(MenuItem, { onSelect: () => exportAs.mutate('csv'), children: t('views.exportCsv') }), _jsx(MenuItem, { onSelect: () => exportAs.mutate('xlsx'), children: t('views.exportXlsx') }), _jsx(MenuItem, { onSelect: () => exportAs.mutate('pdf'), children: t('views.exportPdf') })] })] })) : null] }), floating] }));
@@ -7,6 +7,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
7
7
  import { holds, resolveRecord, } from '../../views/index.js';
8
8
  import { useQueries, useQuery } from '@tanstack/react-query';
9
9
  import { useNavigate } from '@tanstack/react-router';
10
+ import { Explain } from '../components/Explain.js';
10
11
  import { useKosh } from '../context.js';
11
12
  import { cn } from '../lib/cn.js';
12
13
  // The badge's tones (primitives), on the figure only.
@@ -81,7 +82,7 @@ export function StatsRow({ node, values, env, version, }) {
81
82
  const result = results[i];
82
83
  const value = textOf(result?.data, format);
83
84
  const clickable = routes.data?.[tile.model]?.app !== undefined;
84
- const body = (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: tile.label }), _jsxs("span", { className: cn('text-xl font-semibold tabular-nums leading-tight', TONES[tile.tone ?? 'neutral']), children: [result?.isPending === true ? '…' : value.text, value.currency === undefined ? null : (_jsx("span", { className: "ms-1 text-xs font-normal text-muted-foreground", children: value.currency }))] })] }));
85
+ const body = (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: _jsx(Explain, { model: tile.model, focusable: false, target: { action: tile.id, domain: wheres[i] }, children: tile.label }) }), _jsxs("span", { className: cn('text-xl font-semibold tabular-nums leading-tight', TONES[tile.tone ?? 'neutral']), children: [result?.isPending === true ? '…' : value.text, value.currency === undefined ? null : (_jsx("span", { className: "ms-1 text-xs font-normal text-muted-foreground", children: value.currency }))] })] }));
85
86
  const className = 'grid gap-0.5 rounded-lg border bg-surface px-3 py-2 text-start transition-colors';
86
87
  return clickable ? (_jsx("button", { type: "button", className: cn(className, 'hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring'), onClick: () => open(i), children: body }, tile.id)) : (_jsx("div", { className: className, children: body }, tile.id));
87
88
  }) }));
@@ -272,7 +272,13 @@ function ProgressWidget(props) {
272
272
  const { format } = useKosh();
273
273
  if (props.onChange !== undefined && !props.readonly)
274
274
  return _jsx(IntegerWidget, { ...props });
275
- const n = typeof props.value === 'number' ? Math.max(0, Math.min(100, props.value)) : null;
275
+ // Decimals arrive as strings ("75.0"), integers as numbers.
276
+ const raw = typeof props.value === 'number'
277
+ ? props.value
278
+ : typeof props.value === 'string' && props.value.trim() !== ''
279
+ ? Number(props.value)
280
+ : Number.NaN;
281
+ const n = Number.isFinite(raw) ? Math.max(0, Math.min(100, raw)) : null;
276
282
  if (n === null)
277
283
  return _jsx("span", {});
278
284
  return (_jsxs("span", { className: "inline-flex w-full max-w-40 items-center gap-2", children: [_jsx("span", { role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": n, "aria-label": props.field.label, className: "h-1.5 flex-1 overflow-hidden rounded-full bg-muted", children: _jsx("span", { className: "block h-full rounded-full bg-primary", style: { width: `${n}%` } }) }), _jsxs("span", { className: "tabular-nums text-xs text-muted-foreground", children: [format.number(n), "%"] })] }));
@@ -153,6 +153,18 @@ function apply(view, op) {
153
153
  break;
154
154
  }
155
155
  case 'form': {
156
+ // `append: 'header'` adds buttons to the header, which may have none yet (RFC 0028 §3.4).
157
+ if ('append' in op && op.append === 'header') {
158
+ next = {
159
+ ...view,
160
+ header: {
161
+ ...view.header,
162
+ buttons: [...view.header.buttons, ...op.nodes],
163
+ },
164
+ };
165
+ done = true;
166
+ break;
167
+ }
156
168
  const [buttons, inHeader] = applyIn(view.header.buttons, op);
157
169
  if (inHeader)
158
170
  [next, done] = [
@@ -99,7 +99,18 @@ export type FormNode = FieldNode | GroupNode | NotebookNode | LinesNode | Compon
99
99
  export interface ButtonNode {
100
100
  readonly kind: 'button';
101
101
  readonly id: string;
102
- readonly transition: string;
102
+ /** The transition it runs (a button runs a transition, or opens a new record: `open`). */
103
+ readonly transition?: string;
104
+ /**
105
+ * Opens a new record of another model, filled from this one (RFC 0028 §3.4: "New quotation" on a deal): `values`
106
+ * may refer to the record (`{ $record: 'partner' }`); `action` defaults to the model's own. Saved like any new
107
+ * record: the server checks the rights then.
108
+ */
109
+ readonly open?: {
110
+ readonly model: string;
111
+ readonly action?: string;
112
+ readonly values: Readonly<Record<string, unknown>>;
113
+ };
103
114
  readonly label?: string;
104
115
  readonly primary?: boolean;
105
116
  readonly visibleWhen?: Condition;
@@ -213,7 +224,7 @@ export interface CalendarView extends ViewBase {
213
224
  readonly title: string;
214
225
  /** A field whose value colours the events. */
215
226
  readonly color?: string;
216
- readonly mode?: 'month' | 'week';
227
+ readonly mode?: 'month' | 'week' | 'day';
217
228
  }
218
229
  /** Records as bars on a timeline. */
219
230
  export interface GanttView extends ViewBase {