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
@@ -594,6 +594,10 @@ export class AuthService {
594
594
  twoFactorEnabled,
595
595
  administrator,
596
596
  administratorNeedsSecondFactor: administrator && !(session.secondFactor && twoFactorEnabled),
597
+ developer: administrator ||
598
+ (await model(env, 'auth.user_group').search({
599
+ where: { user: session.user, group: 'base.developer' },
600
+ })).length > 0,
597
601
  twoFactorSetupRequired: !twoFactorEnabled && (await this.policy()).twoFactor === 'everyone',
598
602
  };
599
603
  });
@@ -702,6 +706,21 @@ export class AuthService {
702
706
  });
703
707
  }
704
708
  /** Turns 2FA off (password and a current code required). */
709
+ /**
710
+ * A step-up check (RFC 0008 §5.4): the user's current authenticator code, asked again for a dangerous action
711
+ * (removing an app with its data). Recovery codes do not count. @throws {HttpProblem} 409 when two-factor is off,
712
+ * 422 when the code does not match
713
+ */
714
+ async confirmSecondFactor(user, code) {
715
+ await this.#system('2fa step-up', async (env) => {
716
+ const credentials = await model(env, 'auth.credential').search({ where: { user } });
717
+ const [row] = await fetch(credentials, ['totpSecret', 'totpEnabled']);
718
+ if (row?.['totpEnabled'] !== true || typeof row['totpSecret'] !== 'string')
719
+ throw new HttpProblem(409, 'two-factor-off', 'Two-factor authentication is off', 'This needs a code from your authenticator app.', 'Turn on two-factor sign-in in Settings › Your profile first.');
720
+ if (!verifyTotp(row['totpSecret'], code.trim()))
721
+ throw new HttpProblem(422, 'invalid-code', 'Invalid code', 'The code does not match.', 'Use the current code of the authenticator app.');
722
+ });
723
+ }
705
724
  async disableTwoFactor(session, password, code) {
706
725
  if ((await this.policy()).twoFactor === 'everyone')
707
726
  throw new HttpProblem(409, 'two-factor-required', 'Two-factor sign-in is required', 'This installation requires two-factor sign-in of everyone: it cannot be turned off.');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Named events of state transitions (RFC 0023 E1, RFC 0006): `emitting(topic, transition)` returns the transition
3
+ * with an `after` hook that emits `topic` with `{ id }` for each record, once its own `after` ran — in the same
4
+ * transaction, through the outbox, so notifications, automations and webhooks take it by name. The module declares
5
+ * the topic in its manifest's `events`.
6
+ *
7
+ * ```ts
8
+ * transitions: {
9
+ * validate: emitting('stock.picking.done', { from: ['assigned'], to: 'done', after: … }),
10
+ * }
11
+ * ```
12
+ */
13
+ export declare function emitting<const T extends object>(topic: string, transition: T): T;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Named events of state transitions (RFC 0023 E1, RFC 0006): `emitting(topic, transition)` returns the transition
3
+ * with an `after` hook that emits `topic` with `{ id }` for each record, once its own `after` ran — in the same
4
+ * transaction, through the outbox, so notifications, automations and webhooks take it by name. The module declares
5
+ * the topic in its manifest's `events`.
6
+ *
7
+ * ```ts
8
+ * transitions: {
9
+ * validate: emitting('stock.picking.done', { from: ['assigned'], to: 'done', after: … }),
10
+ * }
11
+ * ```
12
+ */
13
+ export function emitting(topic, transition) {
14
+ const own = transition.after;
15
+ const after = async (records) => {
16
+ await own?.(records);
17
+ const { env, ids } = records;
18
+ for (const id of ids)
19
+ await env.emit(topic, { id });
20
+ };
21
+ return { ...transition, after };
22
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Translated metadata (RFC 0023 §3.1): modules ship dictionaries keyed by the English text (`i18n: { bn: () =>
3
+ * import('./i18n/bn.js') }`, each `export const bn = { 'Customer': 'গ্রাহক', … }`). The server merges every installed
4
+ * module's dictionaries at start and translates what it serves to the request's language (`Accept-Language`): the
5
+ * labels, help, descriptions, titles and options of views, menus, actions, apps, model metadata, searches, overviews
6
+ * and settings, and the message of a problem. English stays the key, so code never changes; a string without a
7
+ * translation is served in English.
8
+ */
9
+ import type { FastifyInstance } from 'fastify';
10
+ /** language → English text → translation. */
11
+ export type Dictionaries = ReadonlyMap<string, ReadonlyMap<string, string>>;
12
+ /** Merges the modules' dictionaries (`i18n` loaders) per language; a module's own entries never lose to an empty one. */
13
+ export declare function loadDictionaries(modules: readonly {
14
+ readonly i18n?: Readonly<Record<string, () => Promise<unknown>>>;
15
+ }[]): Promise<Dictionaries>;
16
+ /** The dictionary of a Shutro language code (`bn_BD`, then `bn`), or none for English. */
17
+ export declare function dictionaryFor(dictionaries: Dictionaries, lang: string | null): ReadonlyMap<string, string> | null;
18
+ /**
19
+ * A copy of `value` with the people-facing strings translated (and `[value, label]` options' labels). A field's own
20
+ * label may have a context key, `<model>.<field>` (`res.partner.state` → রাজ্য where "State" is a region), looked up
21
+ * before the English text: in a served view's `fields` (model → field → description) and a model's metadata.
22
+ */
23
+ export declare function translateValue(value: unknown, dict: ReadonlyMap<string, string>, key?: string, field?: string): unknown;
24
+ /** A problem's detail with the known messages in it translated (`project.project: A project …`). */
25
+ export declare function translateDetail(detail: string, dict: ReadonlyMap<string, string>): string;
26
+ /** Translates metadata responses and problems to the request's language. */
27
+ export declare function registerTranslation(app: FastifyInstance, dictionaries: Dictionaries): void;
@@ -0,0 +1,143 @@
1
+ /** The keys whose string values people read (as `pnpm i18n:extract` collects them). */
2
+ const TEXT_KEYS = new Set([
3
+ 'label',
4
+ 'description',
5
+ 'help',
6
+ 'title',
7
+ 'summary',
8
+ 'confirm',
9
+ 'message',
10
+ 'placeholder',
11
+ 'category',
12
+ 'text',
13
+ 'header',
14
+ 'footer',
15
+ 'successMessage',
16
+ 'name',
17
+ ]);
18
+ /** Merges the modules' dictionaries (`i18n` loaders) per language; a module's own entries never lose to an empty one. */
19
+ export async function loadDictionaries(modules) {
20
+ const out = new Map();
21
+ for (const m of modules)
22
+ for (const [lang, load] of Object.entries(m.i18n ?? {})) {
23
+ const loaded = (await load());
24
+ const dict = (loaded?.[lang] ?? loaded?.['default'] ?? loaded);
25
+ const target = out.get(lang) ?? new Map();
26
+ for (const [source, text] of Object.entries(dict ?? {}))
27
+ if (typeof text === 'string' && text !== '' && !target.has(source))
28
+ target.set(source, text);
29
+ out.set(lang, target);
30
+ }
31
+ return out;
32
+ }
33
+ /** The dictionary of a Shutro language code (`bn_BD`, then `bn`), or none for English. */
34
+ export function dictionaryFor(dictionaries, lang) {
35
+ if (lang === null || lang === '' || lang.startsWith('en'))
36
+ return null;
37
+ return dictionaries.get(lang) ?? dictionaries.get(lang.split(/[_-]/)[0] ?? '') ?? null;
38
+ }
39
+ /** A model name (`sale.order`): what keys a served view's `fields` map by. */
40
+ const MODEL = /^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/;
41
+ /**
42
+ * A copy of `value` with the people-facing strings translated (and `[value, label]` options' labels). A field's own
43
+ * label may have a context key, `<model>.<field>` (`res.partner.state` → রাজ্য where "State" is a region), looked up
44
+ * before the English text: in a served view's `fields` (model → field → description) and a model's metadata.
45
+ */
46
+ export function translateValue(value, dict, key, field) {
47
+ if (typeof value === 'string') {
48
+ if (key === undefined || !TEXT_KEYS.has(key))
49
+ return value;
50
+ return ((key === 'label' && field !== undefined ? dict.get(field) : undefined) ??
51
+ dict.get(value) ??
52
+ value);
53
+ }
54
+ if (Array.isArray(value)) {
55
+ // A selection's options: [value, label] pairs.
56
+ if (key === 'options' &&
57
+ value.every((o) => Array.isArray(o) && o.length === 2 && typeof o[1] === 'string'))
58
+ return value.map((o) => [o[0], dict.get(o[1]) ?? o[1]]);
59
+ return value.map((v) => translateValue(v, dict, key === 'options' ? undefined : key));
60
+ }
61
+ if (value !== null && typeof value === 'object') {
62
+ if (value instanceof Date)
63
+ return value;
64
+ const o = value;
65
+ const out = {};
66
+ // A model's metadata: `{ name: 'res.partner', fields: [{ key, label, … }] }`.
67
+ const model = typeof o['name'] === 'string' && MODEL.test(o['name']) ? o['name'] : null;
68
+ for (const [k, v] of Object.entries(o)) {
69
+ if (k === 'fields' && v !== null && typeof v === 'object' && !Array.isArray(v)) {
70
+ // A served view's fields: model → field → description.
71
+ const byModel = {};
72
+ for (const [m, fields] of Object.entries(v)) {
73
+ if (!MODEL.test(m) || fields === null || typeof fields !== 'object') {
74
+ byModel[m] = translateValue(fields, dict, m);
75
+ continue;
76
+ }
77
+ const translated = {};
78
+ for (const [f, d] of Object.entries(fields))
79
+ translated[f] = translateValue(d, dict, f, `${m}.${f}`);
80
+ byModel[m] = translated;
81
+ }
82
+ out[k] = byModel;
83
+ }
84
+ else if (k === 'fields' && Array.isArray(v) && model !== null)
85
+ out[k] = v.map((d) => d !== null &&
86
+ typeof d === 'object' &&
87
+ typeof d['key'] === 'string'
88
+ ? translateValue(d, dict, undefined, `${model}.${String(d['key'])}`)
89
+ : translateValue(d, dict, k));
90
+ else
91
+ out[k] = translateValue(v, dict, k, k === 'label' ? field : undefined);
92
+ }
93
+ return out;
94
+ }
95
+ return value;
96
+ }
97
+ /** A problem's detail with the known messages in it translated (`project.project: A project …`). */
98
+ export function translateDetail(detail, dict) {
99
+ let out = detail;
100
+ for (const [source, text] of dict)
101
+ if (source.length >= 12 && out.includes(source))
102
+ out = out.split(source).join(text);
103
+ return out;
104
+ }
105
+ /** The routes that serve metadata, translated as a whole. */
106
+ const METADATA = [
107
+ '/api/v1/apps',
108
+ '/api/v1/menus',
109
+ '/api/v1/actions/',
110
+ '/api/v1/views',
111
+ '/api/v1/search/',
112
+ '/api/v1/meta/',
113
+ '/api/v1/reports/overview',
114
+ '/api/v1/settings/',
115
+ '/api/v1/models/', // only `/next` (transitions and their messages), below
116
+ ];
117
+ /** `bn-BD,bn;q=0.9` → `bn_BD`. */
118
+ function languageOf(request) {
119
+ const header = request.headers['accept-language'];
120
+ const first = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.split(';')[0]?.trim();
121
+ return first === undefined || first === '' ? null : first.replace('-', '_');
122
+ }
123
+ /** Translates metadata responses and problems to the request's language. */
124
+ export function registerTranslation(app, dictionaries) {
125
+ if (dictionaries.size === 0)
126
+ return;
127
+ app.addHook('preSerialization', async (request, reply, payload) => {
128
+ const dict = dictionaryFor(dictionaries, languageOf(request));
129
+ if (dict === null || payload === null || typeof payload !== 'object')
130
+ return payload;
131
+ const url = request.url.split('?')[0] ?? '';
132
+ if (reply.statusCode >= 400) {
133
+ const p = payload;
134
+ return typeof p['detail'] === 'string'
135
+ ? { ...p, detail: translateDetail(p['detail'], dict) }
136
+ : payload;
137
+ }
138
+ const metadata = request.method === 'GET' &&
139
+ METADATA.some((prefix) => url.startsWith(prefix)) &&
140
+ (!url.startsWith('/api/v1/models/') || url.endsWith('/next'));
141
+ return metadata ? translateValue(payload, dict) : payload;
142
+ });
143
+ }
@@ -23,7 +23,9 @@ export { type AuthOptions, AuthService, cookieOf, SESSION_COOKIE, type SecurityP
23
23
  export { DEMO_PASSWORD, type DemoResult, installDemo } from './demo.js';
24
24
  export { applyEnvironmentNames } from './env-names.js';
25
25
  export { HttpProblem, type Problem, problemOf, ServerConfigError } from './errors.js';
26
+ export { emitting } from './events.js';
26
27
  export { type AppHost, type AppHostOptions, createAppHost, startAppHost } from './host.js';
28
+ export { type Dictionaries, dictionaryFor, loadDictionaries, translateDetail, translateValue, } from './i18n.js';
27
29
  export { type Authenticator, denyAll, isSuperuser, languageOf, type RequestIdentity, type RequestRunOptions, runOptionsOf, } from './identity.js';
28
30
  export { imageVersions, registerImageRoutes } from './images.js';
29
31
  export { migrate, orm, pg } from './orm.js';
@@ -23,7 +23,9 @@ export { AuthService, cookieOf, SESSION_COOKIE, timeOf, } from './auth/service.j
23
23
  export { DEMO_PASSWORD, installDemo } from './demo.js';
24
24
  export { applyEnvironmentNames } from './env-names.js';
25
25
  export { HttpProblem, problemOf, ServerConfigError } from './errors.js';
26
+ export { emitting } from './events.js';
26
27
  export { createAppHost, startAppHost } from './host.js';
28
+ export { dictionaryFor, loadDictionaries, translateDetail, translateValue, } from './i18n.js';
27
29
  export { denyAll, isSuperuser, languageOf, runOptionsOf, } from './identity.js';
28
30
  export { imageVersions, registerImageRoutes } from './images.js';
29
31
  export { migrate, orm, pg } from './orm.js';
@@ -6,6 +6,7 @@
6
6
  import rateLimit from '@fastify/rate-limit';
7
7
  import Fastify, {} from 'fastify';
8
8
  import { Valkey } from 'iovalkey';
9
+ import { registerExplain } from './api/explain.js';
9
10
  import { idempotencyTableStatements } from './api/idempotency.js';
10
11
  import { publicApiModels } from './api/metadata.js';
11
12
  import { Navigation } from './api/navigation.js';
@@ -19,6 +20,7 @@ import { enforceScopes } from './auth/scopes.js';
19
20
  import { AuthService } from './auth/service.js';
20
21
  import { applyEnvironmentNames } from './env-names.js';
21
22
  import { HttpProblem, problemOf, ServerConfigError } from './errors.js';
23
+ import { loadDictionaries, registerTranslation } from './i18n.js';
22
24
  import { denyAll, runOptionsOf } from './identity.js';
23
25
  import { registerImageRoutes } from './images.js';
24
26
  import { orm, pg } from './orm.js';
@@ -218,6 +220,8 @@ export async function createServer(options) {
218
220
  baseUrl: options.oauth?.baseUrl ?? process.env['KOSH_BASE_URL'] ?? 'http://localhost:5173',
219
221
  });
220
222
  }
223
+ // Metadata and problems in the request's language, from the modules' dictionaries (RFC 0023 §3.1).
224
+ registerTranslation(app, await loadDictionaries(registry.loaded.modules));
221
225
  // The generated REST API and its OpenAPI document (RFC 0002 §6.3–6.4).
222
226
  for (const statement of idempotencyTableStatements())
223
227
  await driver.query(statement);
@@ -235,6 +239,8 @@ export async function createServer(options) {
235
239
  return openapi;
236
240
  },
237
241
  });
242
+ // What models, fields and buttons are, for Developer mode (RFC 0031 §3.1).
243
+ registerExplain(app, { registry, models });
238
244
  new Navigation(registry.loaded, models).register(app);
239
245
  views.register(app);
240
246
  // Module routes (admin APIs, custom endpoints), in dependency order.
@@ -8,7 +8,9 @@
8
8
  * - `PATCH /api/v1/settings/company` `{ name?, numberGrouping?, accentColor?, details? }` (`accentColor`:
9
9
  * `#rrggbb` or null; `details`: `{ field: value }`)
10
10
  * - `GET /api/v1/settings/companies` every company with its currency and people, the currencies
11
- * - `POST /api/v1/settings/companies` `{ name, currency }`: a new company (administrators)
11
+ * - `GET /api/v1/settings/companies` … and the details a new company may be given (`fields`)
12
+ * - `POST /api/v1/settings/companies` `{ name, currency, numberGrouping?, accentColor?, details? }`: a new company
13
+ * (administrators), with what each app set up for it (`defaults`)
12
14
  */
13
15
  import { type ModuleContext } from '../server/index.js';
14
16
  /** One of the company's details: a field an installed app adds. */
@@ -8,7 +8,9 @@
8
8
  * - `PATCH /api/v1/settings/company` `{ name?, numberGrouping?, accentColor?, details? }` (`accentColor`:
9
9
  * `#rrggbb` or null; `details`: `{ field: value }`)
10
10
  * - `GET /api/v1/settings/companies` every company with its currency and people, the currencies
11
- * - `POST /api/v1/settings/companies` `{ name, currency }`: a new company (administrators)
11
+ * - `GET /api/v1/settings/companies` … and the details a new company may be given (`fields`)
12
+ * - `POST /api/v1/settings/companies` `{ name, currency, numberGrouping?, accentColor?, details? }`: a new company
13
+ * (administrators), with what each app set up for it (`defaults`)
12
14
  */
13
15
  import { audit, HttpProblem, imageVersions, installDefaults, publicApiModels, } from '../server/index.js';
14
16
  const model = (env, name) => env.model(name);
@@ -64,9 +66,11 @@ export function registerCompanyRoutes(context) {
64
66
  },
65
67
  // The superuser scope is audited: even a read writes its audit record.
66
68
  { write: true });
67
- app.get('/api/v1/settings/company', async (request) => guarded(request, (su, company) => read(su, company)));
68
- app.patch('/api/v1/settings/company', async (request) => {
69
- const body = (request.body ?? {});
69
+ /**
70
+ * The company values of a body (`name`, `numberGrouping`, `accentColor`, `details`), checked: the same rules for a
71
+ * new company and a change.
72
+ */
73
+ const companyValues = (body) => {
70
74
  const values = {};
71
75
  const invalid = (code, title, detail) => new HttpProblem(422, code, title, detail);
72
76
  if (body['name'] !== undefined) {
@@ -109,6 +113,12 @@ export function registerCompanyRoutes(context) {
109
113
  values[key] = typeof value === 'string' && value.trim() === '' ? null : value;
110
114
  }
111
115
  }
116
+ return values;
117
+ };
118
+ app.get('/api/v1/settings/company', async (request) => guarded(request, (su, company) => read(su, company)));
119
+ app.patch('/api/v1/settings/company', async (request) => {
120
+ const body = (request.body ?? {});
121
+ const values = companyValues(body);
112
122
  return guarded(request, async (su, company) => {
113
123
  if (Object.keys(values).length > 0)
114
124
  await model(su, 'res.company').browse([company]).write(values);
@@ -122,6 +132,16 @@ export function registerCompanyRoutes(context) {
122
132
  const currencyName = new Map(currencies.map((c) => [c['id'], String(c['name'])]));
123
133
  return {
124
134
  canCreate: env.administrator,
135
+ // What a new company may be given: the details a person changes (not those an app's own flow sets).
136
+ fields: detailFields()
137
+ .filter((f) => !f.readonly && !SHOWN_ONLY.has(f.key))
138
+ .map((f) => ({
139
+ key: f.key,
140
+ label: f.label,
141
+ kind: f.kind,
142
+ help: f.help,
143
+ options: f.options?.map((o) => ({ value: String(o[0]), label: String(o[1]) })) ?? null,
144
+ })),
125
145
  companies: (await Promise.all(all.map(async (c) => ({
126
146
  id: c['id'],
127
147
  name: String(c['name']),
@@ -145,6 +165,7 @@ export function registerCompanyRoutes(context) {
145
165
  const body = (request.body ?? {});
146
166
  const name = String(body['name'] ?? '').trim();
147
167
  const currency = Number(body['currency']);
168
+ const values = companyValues({ ...body, name });
148
169
  if (name === '' || name.length > 200)
149
170
  throw new HttpProblem(422, 'invalid-name', 'Invalid name', 'The company needs a name.');
150
171
  if (!Number.isSafeInteger(currency) || currency <= 0)
@@ -155,7 +176,7 @@ export function registerCompanyRoutes(context) {
155
176
  return env.asSuperuser({ reason: 'new company' }, async (su) => {
156
177
  if ((await find(su, 'res.currency', { id: currency }, ['name'])).length === 0)
157
178
  throw new HttpProblem(422, 'invalid-currency', 'Invalid currency', 'Choose its currency.');
158
- const company = (await model(su, 'res.company').create([{ name, currency }]))
179
+ const company = (await model(su, 'res.company').create([{ ...values, name, currency }]))
159
180
  .ids[0];
160
181
  // The administrators and the person who made it can switch to it at once.
161
182
  const admins = [...su.access.administratorGroups()];
@@ -40,6 +40,16 @@ export interface PlanInfo {
40
40
  readonly unchanged: readonly string[];
41
41
  readonly statements: readonly string[];
42
42
  readonly empty: boolean;
43
+ /** Apps removed with their data (RFC 0008 §5.4), and what goes: each table or column with its rows. */
44
+ readonly uninstall: readonly {
45
+ readonly name: string;
46
+ readonly cascade: boolean;
47
+ }[];
48
+ readonly drops: readonly {
49
+ readonly table: string;
50
+ readonly column: string | null;
51
+ readonly rows: number;
52
+ }[];
43
53
  }
44
54
  /** Registers the App manager's routes. */
45
55
  export declare function registerAppRoutes(context: ModuleContext): void;
@@ -17,7 +17,7 @@ const NAME = /^[a-z][a-z0-9_]{0,63}$/;
17
17
  function changeOf(body) {
18
18
  const b = (body ?? {});
19
19
  const out = {};
20
- for (const key of ['install', 'enable', 'disable', 'upgrade']) {
20
+ for (const key of ['install', 'enable', 'disable', 'upgrade', 'uninstall']) {
21
21
  const value = b[key];
22
22
  if (value === undefined)
23
23
  continue;
@@ -30,9 +30,10 @@ function changeOf(body) {
30
30
  if ((out.install?.length ?? 0) +
31
31
  (out.enable?.length ?? 0) +
32
32
  (out.disable?.length ?? 0) +
33
- (out.upgrade?.length ?? 0) ===
33
+ (out.upgrade?.length ?? 0) +
34
+ (out.uninstall?.length ?? 0) ===
34
35
  0)
35
- throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'Name at least one app to install, enable, disable or upgrade.');
36
+ throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'Name at least one app to install, enable, disable, upgrade or uninstall.');
36
37
  return out;
37
38
  }
38
39
  /** Stable for the same change against the same installed set and schema. */
@@ -54,6 +55,8 @@ function planInfo(change, prepared) {
54
55
  enable: plan.enable,
55
56
  disable: plan.disable,
56
57
  upgrade: plan.upgrade,
58
+ uninstall: plan.uninstall,
59
+ drops: prepared.drops,
57
60
  unchanged: plan.unchanged,
58
61
  statements: prepared.migration.statements.map((s) => s.sql),
59
62
  empty: prepared.empty,
@@ -135,6 +138,17 @@ export function registerAppRoutes(context) {
135
138
  throw new HttpProblem(409, 'plan-changed', 'The plan changed', 'The installed apps or the schema changed since this plan was made.', 'Review the new plan, then apply it.');
136
139
  if (prepared.empty)
137
140
  return { installed: [], enabled: [], disabled: [], migration: null };
141
+ // Removing data (RFC 0008 §5.4): the apps' names typed back, and a fresh code from the authenticator app.
142
+ if ((change.uninstall ?? []).length > 0) {
143
+ const expected = (change.uninstall ?? []).join(' ');
144
+ if (typeof body.confirm !== 'string' || body.confirm.trim() !== expected)
145
+ throw new HttpProblem(422, 'confirm-name', 'Type the app’s name', `Removing data needs the app’s name typed: ${expected}.`);
146
+ if (typeof body.code !== 'string' || body.code.trim() === '')
147
+ throw new HttpProblem(422, 'code-required', 'A code is needed', 'Removing data needs a code from your authenticator app.');
148
+ if (context.auth === undefined)
149
+ throw new HttpProblem(503, 'auth-unavailable', 'Sign-in unavailable', 'No sign-in here.');
150
+ await context.auth.confirmSecondFactor(uid, body.code);
151
+ }
138
152
  const result = await applyApps(prepared, {
139
153
  driver,
140
154
  dir: apps.migrationsDir,
@@ -147,6 +161,8 @@ export function registerAppRoutes(context) {
147
161
  installed: result.installed,
148
162
  enabled: result.enabled,
149
163
  disabled: result.disabled,
164
+ uninstalled: result.uninstalled,
165
+ snapshot: result.snapshot,
150
166
  migration: result.migration === null
151
167
  ? null
152
168
  : `${result.migration.version}_${result.migration.name}.sql`,
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Settings → Apps (RFC 0008 §5.5): the App manager. A card per app with its icon, state and what it needs; search,
3
- * category and state filters; Install, Enable and Disable open the server's plan (what comes along, what goes, the
4
- * database changes and their SQL) and apply it after confirmation. The server decides and checks everything; this
3
+ * category and state filters; Install, Enable, Disable, Upgrade and Uninstall open the server's plan (what comes
4
+ * along, what goes, the database changes and their SQL) and apply it after confirmation — an uninstall, which removes
5
+ * the data, after the app's name is typed back and a code from the authenticator app is given. The server decides and checks everything; this
5
6
  * page only shows what it says. After a change every cached query is refreshed: the menus and the launcher follow.
6
7
  */
7
8
  import { type PageProps } from '../../ui/index.js';
@@ -1,8 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * Settings → Apps (RFC 0008 §5.5): the App manager. A card per app with its icon, state and what it needs; search,
4
- * category and state filters; Install, Enable and Disable open the server's plan (what comes along, what goes, the
5
- * database changes and their SQL) and apply it after confirmation. The server decides and checks everything; this
4
+ * category and state filters; Install, Enable, Disable, Upgrade and Uninstall open the server's plan (what comes
5
+ * along, what goes, the database changes and their SQL) and apply it after confirmation — an uninstall, which removes
6
+ * the data, after the app's name is typed back and a code from the authenticator app is given. The server decides and checks everything; this
6
7
  * page only shows what it says. After a change every cached query is refreshed: the menus and the launcher follow.
7
8
  */
8
9
  import { Alert, ApiError, AppIcon, Badge, Button, Card, Checkbox, Dialog, Input, Select, Spinner, } from '../../ui/index.js';
@@ -42,7 +43,12 @@ export function AppsPage({ api, label }) {
42
43
  },
43
44
  });
44
45
  const apply = useMutation({
45
- mutationFn: (p) => api.call('POST', '/api/v1/settings/apps/apply', { change: { [p.kind]: [p.app.name] }, planId: p.plan.planId }),
46
+ mutationFn: ({ p, confirm, code }) => api.call('POST', '/api/v1/settings/apps/apply', {
47
+ change: { [p.kind]: [p.app.name] },
48
+ planId: p.plan.planId,
49
+ ...(confirm === undefined ? {} : { confirm }),
50
+ ...(code === undefined ? {} : { code }),
51
+ }),
46
52
  onSuccess: async (result) => {
47
53
  const labelOf = (name) => catalogue.data?.apps.find((a) => a.name === name)?.label ?? name;
48
54
  const parts = [
@@ -50,6 +56,7 @@ export function AppsPage({ api, label }) {
50
56
  ...result.enabled.map((n) => t('doneEnabled', { name: labelOf(n) })),
51
57
  ...result.disabled.map((n) => t('doneDisabled', { name: labelOf(n) })),
52
58
  ...(result.upgraded ?? []).map((n) => t('doneUpgraded', { name: labelOf(n) })),
59
+ ...(result.uninstalled ?? []).map((n) => t('doneUninstalled', { name: labelOf(n) })),
53
60
  ];
54
61
  setPending(null);
55
62
  setDone(parts.length === 0 ? t('nothingToDo') : t('done', { list: parts.join(', ') }));
@@ -99,26 +106,35 @@ export function AppsPage({ api, label }) {
99
106
  ? ''
100
107
  : t('needs', { list: a.depends.map(labelOf).join(', ') }) }), a.installedVersion === null || a.state !== 'installed' ? null : (_jsx(Button, { size: "sm", variant: "primary", busy: plan.isPending &&
101
108
  plan.variables?.kind === 'upgrade' &&
102
- plan.variables.app.name === a.name, "aria-label": `${t('upgrade')} ${a.label}`, onClick: () => plan.mutate({ kind: 'upgrade', app: a }), children: t('upgrade') })), kind === null ? null : (_jsx(Button, { size: "sm", variant: kind === 'disable' ? 'secondary' : 'primary', busy: busy, "aria-label": `${t(kind)} ${a.label}`, onClick: () => plan.mutate({ kind, app: a }), children: t(kind) }))] })] }) }, a.name));
109
+ plan.variables.app.name === a.name, "aria-label": `${t('upgrade')} ${a.label}`, onClick: () => plan.mutate({ kind: 'upgrade', app: a }), children: t('upgrade') })), kind === null ? null : (_jsx(Button, { size: "sm", variant: kind === 'disable' ? 'secondary' : 'primary', busy: busy, "aria-label": `${t(kind)} ${a.label}`, onClick: () => plan.mutate({ kind, app: a }), children: t(kind) })), a.state === 'available' || a.protected ? null : (_jsx(Button, { size: "sm", variant: "ghost", busy: plan.isPending &&
110
+ plan.variables?.kind === 'uninstall' &&
111
+ plan.variables.app.name === a.name, "aria-label": `${t('uninstall')} ${a.label}`, onClick: () => plan.mutate({ kind: 'uninstall', app: a }), children: t('uninstall') }))] })] }) }, a.name));
103
112
  }) })), pending === null ? null : (_jsx(PlanDialog, { pending: pending, labelOf: labelOf, busy: apply.isPending, error: apply.error === null ? null : message(apply.error), onCancel: () => {
104
113
  apply.reset();
105
114
  setPending(null);
106
- }, onConfirm: () => apply.mutate(pending) }))] }));
115
+ }, onConfirm: (confirm, code) => apply.mutate(confirm === undefined ? { p: pending } : { p: pending, confirm, code: code ?? '' }) }))] }));
107
116
  }
108
117
  function PlanDialog({ pending, labelOf, busy, error, onCancel, onConfirm, }) {
109
118
  const { t } = useTranslation('settings');
110
119
  const { kind, app, plan } = pending;
120
+ const formId = useId();
121
+ const [typed, setTyped] = useState('');
122
+ const [code, setCode] = useState('');
123
+ const removing = kind === 'uninstall';
124
+ const ready = !removing || (typed.trim() === app.name && code.trim() !== '');
111
125
  const title = t(kind === 'install'
112
126
  ? 'planTitleInstall'
113
127
  : kind === 'enable'
114
128
  ? 'planTitleEnable'
115
129
  : kind === 'upgrade'
116
130
  ? 'planTitleUpgrade'
117
- : 'planTitleDisable', { name: app.label });
131
+ : kind === 'uninstall'
132
+ ? 'planTitleUninstall'
133
+ : 'planTitleDisable', { name: app.label });
118
134
  return (_jsx(Dialog, { open: true, onOpenChange: (open) => {
119
135
  if (!open && !busy)
120
136
  onCancel();
121
- }, title: title, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "secondary", onClick: onCancel, disabled: busy, children: t('cancel') }), _jsx(Button, { variant: kind === 'disable' ? 'danger' : 'primary', busy: busy, disabled: plan.empty, onClick: onConfirm, children: busy
137
+ }, title: title, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "secondary", onClick: onCancel, disabled: busy, children: t('cancel') }), _jsx(Button, { variant: kind === 'disable' || removing ? 'danger' : 'primary', busy: busy, disabled: plan.empty || !ready, onClick: () => (removing ? onConfirm(typed.trim(), code.trim()) : onConfirm()), children: busy
122
138
  ? t('applying')
123
139
  : t(kind === 'install'
124
140
  ? 'confirmInstall'
@@ -126,7 +142,9 @@ function PlanDialog({ pending, labelOf, busy, error, onCancel, onConfirm, }) {
126
142
  ? 'confirmEnable'
127
143
  : kind === 'upgrade'
128
144
  ? 'confirmUpgrade'
129
- : 'confirmDisable') })] }), children: _jsxs("div", { className: "grid gap-3 text-sm", children: [plan.empty ? _jsx("p", { children: t('nothingToDo') }) : null, plan.install.length === 0 ? null : (_jsx(PlanList, { title: t('planInstall'), children: plan.install.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.reason === 'dependency' ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planNeeded')] })) : null] }, m.name))) })), plan.enable.length === 0 ? null : (_jsx(PlanList, { title: t('planEnable'), children: plan.enable.map((name) => (_jsx("li", { children: labelOf(name) }, name))) })), plan.disable.length === 0 ? null : (_jsx(PlanList, { title: t('planDisable'), children: plan.disable.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.cascade ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planCascade')] })) : null] }, m.name))) })), plan.upgrade.length === 0 ? null : (_jsx(PlanList, { title: t('planUpgrade'), children: plan.upgrade.map((u) => (_jsxs("li", { children: [labelOf(u.name), ' ', _jsxs("span", { className: "text-muted-foreground", children: [u.from, " \u2192 ", u.to] })] }, u.name))) })), kind === 'disable' ? _jsx(Alert, { tone: "warning", children: t('planKeepsData') }) : null, kind === 'install' ? _jsx("p", { className: "text-muted-foreground", children: t('planAccess') }) : null, _jsx("p", { className: "text-muted-foreground", children: plan.statements.length === 0
145
+ : removing
146
+ ? 'confirmUninstall'
147
+ : 'confirmDisable') })] }), children: _jsxs("div", { className: "grid gap-3 text-sm", children: [plan.empty ? _jsx("p", { children: t('nothingToDo') }) : null, plan.install.length === 0 ? null : (_jsx(PlanList, { title: t('planInstall'), children: plan.install.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.reason === 'dependency' ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planNeeded')] })) : null] }, m.name))) })), plan.enable.length === 0 ? null : (_jsx(PlanList, { title: t('planEnable'), children: plan.enable.map((name) => (_jsx("li", { children: labelOf(name) }, name))) })), plan.disable.length === 0 ? null : (_jsx(PlanList, { title: t('planDisable'), children: plan.disable.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.cascade ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planCascade')] })) : null] }, m.name))) })), plan.upgrade.length === 0 ? null : (_jsx(PlanList, { title: t('planUpgrade'), children: plan.upgrade.map((u) => (_jsxs("li", { children: [labelOf(u.name), ' ', _jsxs("span", { className: "text-muted-foreground", children: [u.from, " \u2192 ", u.to] })] }, u.name))) })), plan.uninstall.length === 0 ? null : (_jsx(PlanList, { title: t('planUninstall'), children: plan.uninstall.map((m) => (_jsxs("li", { children: [labelOf(m.name), m.cascade ? (_jsxs("span", { className: "text-muted-foreground", children: [" \u00B7 ", t('planCascade')] })) : null] }, m.name))) })), plan.drops.length === 0 ? null : (_jsxs("div", { children: [_jsx("h3", { className: "mb-1 font-medium", children: t('planDrops') }), _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-muted-foreground", children: [_jsx("th", { className: "text-start font-normal", children: t('planDropWhat') }), _jsx("th", { className: "text-end font-normal", children: t('planDropRows') })] }) }), _jsx("tbody", { children: plan.drops.map((d) => (_jsxs("tr", { children: [_jsx("td", { dir: "ltr", className: "text-start", children: d.column === null ? d.table : `${d.table}.${d.column}` }), _jsx("td", { className: "text-end tabular-nums", children: d.rows })] }, `${d.table}.${d.column ?? ''}`))) })] })] })), removing ? (_jsxs(_Fragment, { children: [_jsx(Alert, { children: t('planRemovesData') }), _jsxs("label", { htmlFor: `${formId}-name`, className: "grid gap-1", children: [_jsx("span", { children: t('typeName', { name: app.name }) }), _jsx(Input, { id: `${formId}-name`, autoComplete: "off", value: typed, onChange: (e) => setTyped(e.target.value) })] }), _jsxs("label", { htmlFor: `${formId}-code`, className: "grid gap-1", children: [_jsx("span", { children: t('authCode') }), _jsx(Input, { id: `${formId}-code`, inputMode: "numeric", autoComplete: "one-time-code", value: code, onChange: (e) => setCode(e.target.value) })] })] })) : null, kind === 'disable' ? _jsx(Alert, { tone: "warning", children: t('planKeepsData') }) : null, kind === 'install' ? _jsx("p", { className: "text-muted-foreground", children: t('planAccess') }) : null, _jsx("p", { className: "text-muted-foreground", children: plan.statements.length === 0
130
148
  ? t('planNoSchema')
131
149
  : t('planSchema', { count: plan.statements.length }) }), plan.statements.length === 0 ? null : (_jsxs("details", { children: [_jsx("summary", { className: "cursor-pointer text-muted-foreground", children: t('planShowSql') }), _jsx("pre", { className: "mt-2 max-h-48 overflow-auto rounded-md bg-muted p-2 text-xs", dir: "ltr", children: plan.statements.map((sql) => `${sql};`).join('\n') })] })), error === null ? null : _jsx(Alert, { children: error })] }) }));
132
150
  }