shutro-erp 0.3.3 → 0.3.5

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 (412) hide show
  1. package/dist/account_portal/.kosh/bindings.js +1 -1
  2. package/dist/account_portal/.kosh/schema.d.ts +181 -3
  3. package/dist/account_portal/module.d.ts +359 -6
  4. package/dist/accounting/.kosh/bindings.js +1 -1
  5. package/dist/accounting/.kosh/schema.d.ts +181 -3
  6. package/dist/accounting/index.js +214 -2
  7. package/dist/accounting/module.d.ts +217 -5
  8. package/dist/accounting/module.js +23 -2
  9. package/dist/calendar/.kosh/bindings.d.ts +22 -0
  10. package/dist/calendar/.kosh/bindings.js +15 -0
  11. package/dist/calendar/.kosh/schema.d.ts +795 -0
  12. package/dist/calendar/demo.d.ts +6 -0
  13. package/dist/calendar/demo.js +24 -0
  14. package/dist/calendar/index.d.ts +3 -0
  15. package/dist/calendar/index.js +291 -0
  16. package/dist/calendar/module.d.ts +1705 -0
  17. package/dist/calendar/module.js +180 -0
  18. package/dist/cli/init.js +48 -0
  19. package/dist/cli/templates.d.ts +1 -1
  20. package/dist/cli/templates.js +137 -0
  21. package/dist/contacts/.kosh/bindings.js +1 -1
  22. package/dist/contacts/.kosh/schema.d.ts +205 -3
  23. package/dist/contacts/demo.js +30 -1
  24. package/dist/contacts/index.d.ts +1 -1
  25. package/dist/contacts/index.js +155 -9
  26. package/dist/contacts/module.d.ts +338 -2
  27. package/dist/contacts/module.js +82 -5
  28. package/dist/crm/.kosh/bindings.d.ts +22 -0
  29. package/dist/crm/.kosh/bindings.js +15 -0
  30. package/dist/crm/.kosh/schema.d.ts +799 -0
  31. package/dist/crm/demo.d.ts +6 -0
  32. package/dist/crm/demo.js +45 -0
  33. package/dist/crm/index.d.ts +3 -0
  34. package/dist/crm/index.js +361 -0
  35. package/dist/crm/module.d.ts +1843 -0
  36. package/dist/crm/module.js +207 -0
  37. package/dist/event/.kosh/bindings.d.ts +22 -0
  38. package/dist/event/.kosh/bindings.js +15 -0
  39. package/dist/event/.kosh/schema.d.ts +843 -0
  40. package/dist/event/demo.d.ts +6 -0
  41. package/dist/event/demo.js +65 -0
  42. package/dist/event/index.d.ts +14 -0
  43. package/dist/event/index.js +333 -0
  44. package/dist/event/mails.d.ts +15 -0
  45. package/dist/event/mails.js +112 -0
  46. package/dist/event/module.d.ts +2800 -0
  47. package/dist/event/module.js +323 -0
  48. package/dist/event/web/CheckInBox.d.ts +9 -0
  49. package/dist/event/web/CheckInBox.js +87 -0
  50. package/dist/event/web/index.d.ts +11 -0
  51. package/dist/event/web/index.js +16 -0
  52. package/dist/event/web/messages.d.ts +2 -0
  53. package/dist/event/web/messages.js +23 -0
  54. package/dist/event_account/.kosh/bindings.d.ts +22 -0
  55. package/dist/event_account/.kosh/bindings.js +15 -0
  56. package/dist/event_account/.kosh/schema.d.ts +1639 -0
  57. package/dist/event_account/index.d.ts +3 -0
  58. package/dist/event_account/index.js +28 -0
  59. package/dist/event_account/module.d.ts +6968 -0
  60. package/dist/event_account/module.js +90 -0
  61. package/dist/hr/.kosh/bindings.d.ts +22 -0
  62. package/dist/hr/.kosh/bindings.js +15 -0
  63. package/dist/hr/.kosh/schema.d.ts +878 -0
  64. package/dist/hr/demo.d.ts +6 -0
  65. package/dist/hr/demo.js +60 -0
  66. package/dist/hr/index.d.ts +3 -0
  67. package/dist/hr/index.js +483 -0
  68. package/dist/hr/module.d.ts +2611 -0
  69. package/dist/hr/module.js +350 -0
  70. package/dist/integrations/index.js +12 -0
  71. package/dist/integrations/web/OAuthAppsPage.d.ts +9 -0
  72. package/dist/integrations/web/OAuthAppsPage.js +79 -0
  73. package/dist/integrations/web/index.d.ts +1 -0
  74. package/dist/integrations/web/index.js +3 -0
  75. package/dist/integrations/web/messages.js +58 -0
  76. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  77. package/dist/l10n_bd/.kosh/schema.d.ts +181 -3
  78. package/dist/l10n_bd/module.d.ts +359 -6
  79. package/dist/l10n_in/.kosh/bindings.js +1 -1
  80. package/dist/l10n_in/.kosh/schema.d.ts +181 -3
  81. package/dist/l10n_in/module.d.ts +380 -7
  82. package/dist/maintenance/.kosh/bindings.d.ts +22 -0
  83. package/dist/maintenance/.kosh/bindings.js +15 -0
  84. package/dist/maintenance/.kosh/schema.d.ts +911 -0
  85. package/dist/maintenance/demo.d.ts +6 -0
  86. package/dist/maintenance/demo.js +60 -0
  87. package/dist/maintenance/index.d.ts +3 -0
  88. package/dist/maintenance/index.js +422 -0
  89. package/dist/maintenance/module.d.ts +3545 -0
  90. package/dist/maintenance/module.js +446 -0
  91. package/dist/maintenance_stock/.kosh/bindings.d.ts +22 -0
  92. package/dist/maintenance_stock/.kosh/bindings.js +15 -0
  93. package/dist/maintenance_stock/.kosh/schema.d.ts +1371 -0
  94. package/dist/maintenance_stock/index.d.ts +9 -0
  95. package/dist/maintenance_stock/index.js +52 -0
  96. package/dist/maintenance_stock/module.d.ts +6953 -0
  97. package/dist/maintenance_stock/module.js +192 -0
  98. package/dist/messaging/web/index.js +1 -1
  99. package/dist/modules-sdk/index.d.ts +1 -1
  100. package/dist/modules-sdk/manifest.d.ts +70 -0
  101. package/dist/modules-sdk/manifest.js +35 -1
  102. package/dist/mrp/.kosh/bindings.d.ts +22 -0
  103. package/dist/mrp/.kosh/bindings.js +15 -0
  104. package/dist/mrp/.kosh/schema.d.ts +1378 -0
  105. package/dist/mrp/demo.d.ts +7 -0
  106. package/dist/mrp/demo.js +42 -0
  107. package/dist/mrp/index.d.ts +3 -0
  108. package/dist/mrp/index.js +392 -0
  109. package/dist/mrp/module.d.ts +8608 -0
  110. package/dist/mrp/module.js +695 -0
  111. package/dist/mrp_account/.kosh/bindings.d.ts +22 -0
  112. package/dist/mrp_account/.kosh/bindings.js +15 -0
  113. package/dist/mrp_account/.kosh/schema.d.ts +2106 -0
  114. package/dist/mrp_account/index.d.ts +3 -0
  115. package/dist/mrp_account/index.js +22 -0
  116. package/dist/mrp_account/module.d.ts +20840 -0
  117. package/dist/mrp_account/module.js +123 -0
  118. package/dist/notify/web/index.js +1 -1
  119. package/dist/payment/.kosh/bindings.js +1 -1
  120. package/dist/payment/.kosh/schema.d.ts +181 -3
  121. package/dist/payment/module.d.ts +359 -6
  122. package/dist/portal/.kosh/bindings.js +1 -1
  123. package/dist/portal/.kosh/schema.d.ts +205 -3
  124. package/dist/portal/module.d.ts +166 -2
  125. package/dist/pos/.kosh/bindings.d.ts +22 -0
  126. package/dist/pos/.kosh/bindings.js +15 -0
  127. package/dist/pos/.kosh/schema.d.ts +1690 -0
  128. package/dist/pos/accounting.d.ts +10 -0
  129. package/dist/pos/accounting.js +149 -0
  130. package/dist/pos/demo.d.ts +6 -0
  131. package/dist/pos/demo.js +90 -0
  132. package/dist/pos/index.d.ts +9 -0
  133. package/dist/pos/index.js +349 -0
  134. package/dist/pos/module.d.ts +9636 -0
  135. package/dist/pos/module.js +423 -0
  136. package/dist/pos/routes.d.ts +39 -0
  137. package/dist/pos/routes.js +368 -0
  138. package/dist/pos/web/Register.d.ts +9 -0
  139. package/dist/pos/web/Register.js +252 -0
  140. package/dist/pos/web/index.d.ts +11 -0
  141. package/dist/pos/web/index.js +16 -0
  142. package/dist/pos/web/messages.d.ts +2 -0
  143. package/dist/pos/web/messages.js +87 -0
  144. package/dist/pos_stock/.kosh/bindings.d.ts +22 -0
  145. package/dist/pos_stock/.kosh/bindings.js +15 -0
  146. package/dist/pos_stock/.kosh/schema.d.ts +2015 -0
  147. package/dist/pos_stock/index.d.ts +9 -0
  148. package/dist/pos_stock/index.js +35 -0
  149. package/dist/pos_stock/module.d.ts +11935 -0
  150. package/dist/pos_stock/module.js +115 -0
  151. package/dist/product/.kosh/bindings.js +1 -1
  152. package/dist/product/.kosh/schema.d.ts +178 -1
  153. package/dist/product/index.js +81 -4
  154. package/dist/product/module.d.ts +43 -1
  155. package/dist/product/module.js +9 -2
  156. package/dist/project/.kosh/bindings.js +1 -1
  157. package/dist/project/.kosh/schema.d.ts +181 -3
  158. package/dist/project/index.js +147 -7
  159. package/dist/project/module.d.ts +210 -2
  160. package/dist/project/module.js +52 -5
  161. package/dist/project_portal/.kosh/bindings.js +1 -1
  162. package/dist/project_portal/.kosh/schema.d.ts +181 -3
  163. package/dist/project_portal/module.d.ts +353 -4
  164. package/dist/purchase/.kosh/bindings.js +1 -1
  165. package/dist/purchase/.kosh/schema.d.ts +181 -3
  166. package/dist/purchase/index.js +163 -3
  167. package/dist/purchase/module.d.ts +215 -3
  168. package/dist/purchase/module.js +21 -3
  169. package/dist/purchase_account/.kosh/bindings.js +1 -1
  170. package/dist/purchase_account/.kosh/schema.d.ts +182 -3
  171. package/dist/purchase_account/index.js +26 -1
  172. package/dist/purchase_account/module.d.ts +393 -7
  173. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  174. package/dist/purchase_portal/.kosh/schema.d.ts +181 -3
  175. package/dist/purchase_portal/module.d.ts +366 -5
  176. package/dist/purchase_stock/.kosh/bindings.d.ts +22 -0
  177. package/dist/purchase_stock/.kosh/bindings.js +15 -0
  178. package/dist/purchase_stock/.kosh/schema.d.ts +1310 -0
  179. package/dist/purchase_stock/index.d.ts +7 -0
  180. package/dist/purchase_stock/index.js +91 -0
  181. package/dist/purchase_stock/module.d.ts +6763 -0
  182. package/dist/purchase_stock/module.js +144 -0
  183. package/dist/purchase_stock_account/.kosh/bindings.d.ts +22 -0
  184. package/dist/purchase_stock_account/.kosh/bindings.js +15 -0
  185. package/dist/purchase_stock_account/.kosh/schema.d.ts +1959 -0
  186. package/dist/purchase_stock_account/index.d.ts +3 -0
  187. package/dist/purchase_stock_account/index.js +24 -0
  188. package/dist/purchase_stock_account/module.d.ts +35366 -0
  189. package/dist/purchase_stock_account/module.js +162 -0
  190. package/dist/recruitment/.kosh/bindings.d.ts +22 -0
  191. package/dist/recruitment/.kosh/bindings.js +15 -0
  192. package/dist/recruitment/.kosh/schema.d.ts +990 -0
  193. package/dist/recruitment/demo.d.ts +6 -0
  194. package/dist/recruitment/demo.js +45 -0
  195. package/dist/recruitment/index.d.ts +3 -0
  196. package/dist/recruitment/index.js +385 -0
  197. package/dist/recruitment/module.d.ts +3247 -0
  198. package/dist/recruitment/module.js +193 -0
  199. package/dist/recruitment/web/HireButton.d.ts +9 -0
  200. package/dist/recruitment/web/HireButton.js +32 -0
  201. package/dist/recruitment/web/index.d.ts +11 -0
  202. package/dist/recruitment/web/index.js +16 -0
  203. package/dist/recruitment/web/messages.d.ts +2 -0
  204. package/dist/recruitment/web/messages.js +19 -0
  205. package/dist/reporting/documents.d.ts +5 -0
  206. package/dist/reporting/documents.js +28 -1
  207. package/dist/reporting/index.d.ts +1 -1
  208. package/dist/reporting/index.js +4 -2
  209. package/dist/reporting/models.js +9 -0
  210. package/dist/reporting/overviews.d.ts +16 -0
  211. package/dist/reporting/overviews.js +56 -0
  212. package/dist/reporting/routes-documents.js +1 -1
  213. package/dist/reporting/routes.js +138 -80
  214. package/dist/reporting/web/DashboardView.d.ts +11 -0
  215. package/dist/reporting/web/DashboardView.js +2 -2
  216. package/dist/reporting/web/DesignerView.js +5 -0
  217. package/dist/reporting/web/Overview.d.ts +9 -0
  218. package/dist/reporting/web/Overview.js +53 -0
  219. package/dist/reporting/web/index.d.ts +1 -0
  220. package/dist/reporting/web/index.js +4 -1
  221. package/dist/reporting/web/messages.js +9 -0
  222. package/dist/sale_account/.kosh/bindings.js +1 -1
  223. package/dist/sale_account/.kosh/schema.d.ts +186 -3
  224. package/dist/sale_account/index.js +22 -1
  225. package/dist/sale_account/module.d.ts +461 -7
  226. package/dist/sale_portal/.kosh/bindings.js +1 -1
  227. package/dist/sale_portal/.kosh/schema.d.ts +185 -3
  228. package/dist/sale_portal/module.d.ts +434 -5
  229. package/dist/sale_project/.kosh/bindings.js +1 -1
  230. package/dist/sale_project/.kosh/schema.d.ts +187 -3
  231. package/dist/sale_project/module.d.ts +476 -6
  232. package/dist/sale_stock/.kosh/bindings.d.ts +22 -0
  233. package/dist/sale_stock/.kosh/bindings.js +15 -0
  234. package/dist/sale_stock/.kosh/schema.d.ts +1228 -0
  235. package/dist/sale_stock/index.d.ts +7 -0
  236. package/dist/sale_stock/index.js +84 -0
  237. package/dist/sale_stock/module.d.ts +6791 -0
  238. package/dist/sale_stock/module.js +146 -0
  239. package/dist/sales/.kosh/bindings.js +1 -1
  240. package/dist/sales/.kosh/schema.d.ts +185 -3
  241. package/dist/sales/index.js +191 -4
  242. package/dist/sales/module.d.ts +355 -3
  243. package/dist/sales/module.js +78 -3
  244. package/dist/server/api/metadata.d.ts +5 -0
  245. package/dist/server/api/metadata.js +5 -0
  246. package/dist/server/api/rest.js +64 -1
  247. package/dist/server/api/views.js +1 -0
  248. package/dist/server/app-settings.d.ts +7 -0
  249. package/dist/server/app-settings.js +10 -0
  250. package/dist/server/auth/base.js +85 -0
  251. package/dist/server/auth/oauth.d.ts +21 -0
  252. package/dist/server/auth/oauth.js +579 -0
  253. package/dist/server/auth/service.d.ts +4 -0
  254. package/dist/server/auth/service.js +17 -0
  255. package/dist/server/identity.d.ts +2 -0
  256. package/dist/server/images.d.ts +12 -0
  257. package/dist/server/images.js +139 -0
  258. package/dist/server/index.d.ts +2 -0
  259. package/dist/server/index.js +2 -0
  260. package/dist/server/server.d.ts +4 -0
  261. package/dist/server/server.js +9 -1
  262. package/dist/settings/app-settings.d.ts +2 -0
  263. package/dist/settings/app-settings.js +518 -0
  264. package/dist/settings/company.js +3 -1
  265. package/dist/settings/index.d.ts +1 -0
  266. package/dist/settings/index.js +15 -0
  267. package/dist/settings/people.js +32 -6
  268. package/dist/settings/web/AppSettingsPage.d.ts +11 -0
  269. package/dist/settings/web/AppSettingsPage.js +210 -0
  270. package/dist/settings/web/CompaniesPage.js +2 -2
  271. package/dist/settings/web/CompanyPage.js +13 -2
  272. package/dist/settings/web/ConnectedAppsPage.d.ts +7 -0
  273. package/dist/settings/web/ConnectedAppsPage.js +33 -0
  274. package/dist/settings/web/OverviewPage.js +28 -4
  275. package/dist/settings/web/PeoplePage.js +23 -18
  276. package/dist/settings/web/ProfilePage.js +9 -7
  277. package/dist/settings/web/index.d.ts +2 -0
  278. package/dist/settings/web/index.js +8 -0
  279. package/dist/settings/web/messages.js +146 -2
  280. package/dist/stock/.kosh/bindings.d.ts +22 -0
  281. package/dist/stock/.kosh/bindings.js +15 -0
  282. package/dist/stock/.kosh/schema.d.ts +1147 -0
  283. package/dist/stock/demo.d.ts +7 -0
  284. package/dist/stock/demo.js +55 -0
  285. package/dist/stock/index.d.ts +3 -0
  286. package/dist/stock/index.js +674 -0
  287. package/dist/stock/module.d.ts +6330 -0
  288. package/dist/stock/module.js +1325 -0
  289. package/dist/stock/web/ScanBox.d.ts +8 -0
  290. package/dist/stock/web/ScanBox.js +90 -0
  291. package/dist/stock/web/index.d.ts +11 -0
  292. package/dist/stock/web/index.js +16 -0
  293. package/dist/stock/web/messages.d.ts +2 -0
  294. package/dist/stock/web/messages.js +25 -0
  295. package/dist/stock_account/.kosh/bindings.d.ts +22 -0
  296. package/dist/stock_account/.kosh/bindings.js +15 -0
  297. package/dist/stock_account/.kosh/schema.d.ts +1875 -0
  298. package/dist/stock_account/index.d.ts +3 -0
  299. package/dist/stock_account/index.js +130 -0
  300. package/dist/stock_account/module.d.ts +10655 -0
  301. package/dist/stock_account/module.js +339 -0
  302. package/dist/storage/attachments.d.ts +5 -0
  303. package/dist/storage/attachments.js +12 -1
  304. package/dist/storage/models.js +3 -0
  305. package/dist/storage/routes.js +13 -2
  306. package/dist/todo/.kosh/bindings.d.ts +22 -0
  307. package/dist/todo/.kosh/bindings.js +15 -0
  308. package/dist/todo/.kosh/schema.d.ts +732 -0
  309. package/dist/todo/demo.d.ts +6 -0
  310. package/dist/todo/demo.js +35 -0
  311. package/dist/todo/index.d.ts +3 -0
  312. package/dist/todo/index.js +187 -0
  313. package/dist/todo/module.d.ts +1180 -0
  314. package/dist/todo/module.js +130 -0
  315. package/dist/trade_finance/.kosh/bindings.d.ts +22 -0
  316. package/dist/trade_finance/.kosh/bindings.js +15 -0
  317. package/dist/trade_finance/.kosh/schema.d.ts +884 -0
  318. package/dist/trade_finance/demo.d.ts +6 -0
  319. package/dist/trade_finance/demo.js +63 -0
  320. package/dist/trade_finance/index.d.ts +3 -0
  321. package/dist/trade_finance/index.js +413 -0
  322. package/dist/trade_finance/module.d.ts +3779 -0
  323. package/dist/trade_finance/module.js +505 -0
  324. package/dist/trade_finance_account/.kosh/bindings.d.ts +22 -0
  325. package/dist/trade_finance_account/.kosh/bindings.js +15 -0
  326. package/dist/trade_finance_account/.kosh/schema.d.ts +1711 -0
  327. package/dist/trade_finance_account/index.d.ts +3 -0
  328. package/dist/trade_finance_account/index.js +92 -0
  329. package/dist/trade_finance_account/module.d.ts +7928 -0
  330. package/dist/trade_finance_account/module.js +244 -0
  331. package/dist/trade_finance_purchase/.kosh/bindings.d.ts +22 -0
  332. package/dist/trade_finance_purchase/.kosh/bindings.js +15 -0
  333. package/dist/trade_finance_purchase/.kosh/schema.d.ts +1153 -0
  334. package/dist/trade_finance_purchase/index.d.ts +8 -0
  335. package/dist/trade_finance_purchase/index.js +50 -0
  336. package/dist/trade_finance_purchase/module.d.ts +4252 -0
  337. package/dist/trade_finance_purchase/module.js +44 -0
  338. package/dist/trade_finance_sale/.kosh/bindings.d.ts +22 -0
  339. package/dist/trade_finance_sale/.kosh/bindings.js +15 -0
  340. package/dist/trade_finance_sale/.kosh/schema.d.ts +1071 -0
  341. package/dist/trade_finance_sale/index.d.ts +8 -0
  342. package/dist/trade_finance_sale/index.js +50 -0
  343. package/dist/trade_finance_sale/module.d.ts +4280 -0
  344. package/dist/trade_finance_sale/module.js +44 -0
  345. package/dist/ui/api.d.ts +6 -1
  346. package/dist/ui/api.js +2 -1
  347. package/dist/ui/app.js +51 -17
  348. package/dist/ui/components/AppIcon.js +33 -1
  349. package/dist/ui/components/Avatar.d.ts +21 -0
  350. package/dist/ui/components/Avatar.js +71 -0
  351. package/dist/ui/components/primitives.d.ts +2 -0
  352. package/dist/ui/components/primitives.js +7 -1
  353. package/dist/ui/i18n/messages.d.ts +53 -0
  354. package/dist/ui/i18n/messages.js +98 -0
  355. package/dist/ui/index.d.ts +2 -0
  356. package/dist/ui/index.js +2 -0
  357. package/dist/ui/offline/queue.d.ts +5 -1
  358. package/dist/ui/offline/queue.js +2 -0
  359. package/dist/ui/registry.d.ts +12 -1
  360. package/dist/ui/registry.js +10 -1
  361. package/dist/ui/search/ViewTabs.d.ts +14 -0
  362. package/dist/ui/search/ViewTabs.js +42 -0
  363. package/dist/ui/shell/Consent.d.ts +5 -0
  364. package/dist/ui/shell/Consent.js +35 -0
  365. package/dist/ui/shell/Home.js +136 -16
  366. package/dist/ui/shell/Sidebar.js +15 -22
  367. package/dist/ui/views/FormView.js +98 -17
  368. package/dist/ui/views/KanbanView.d.ts +2 -0
  369. package/dist/ui/views/KanbanView.js +32 -3
  370. package/dist/ui/views/ListView.js +155 -31
  371. package/dist/ui/views/StatsRow.d.ts +14 -0
  372. package/dist/ui/views/StatsRow.js +88 -0
  373. package/dist/ui/views/widgets.d.ts +2 -1
  374. package/dist/ui/views/widgets.js +194 -1
  375. package/dist/views/builders.d.ts +19 -2
  376. package/dist/views/builders.js +21 -1
  377. package/dist/views/condition.d.ts +6 -0
  378. package/dist/views/condition.js +20 -0
  379. package/dist/views/documents.d.ts +8 -0
  380. package/dist/views/extend.d.ts +2 -2
  381. package/dist/views/extend.js +11 -1
  382. package/dist/views/index.d.ts +2 -2
  383. package/dist/views/index.js +2 -2
  384. package/dist/views/types.d.ts +52 -5
  385. package/dist/views/validate.js +39 -1
  386. package/dist/website/.kosh/bindings.d.ts +22 -0
  387. package/dist/website/.kosh/bindings.js +15 -0
  388. package/dist/website/.kosh/schema.d.ts +881 -0
  389. package/dist/website/demo.d.ts +6 -0
  390. package/dist/website/demo.js +115 -0
  391. package/dist/website/index.d.ts +9 -0
  392. package/dist/website/index.js +250 -0
  393. package/dist/website/module.d.ts +2987 -0
  394. package/dist/website/module.js +281 -0
  395. package/dist/website/render.d.ts +45 -0
  396. package/dist/website/render.js +102 -0
  397. package/dist/website/routes.d.ts +12 -0
  398. package/dist/website/routes.js +246 -0
  399. package/dist/website/web/PagePreview.d.ts +7 -0
  400. package/dist/website/web/PagePreview.js +33 -0
  401. package/dist/website/web/index.d.ts +11 -0
  402. package/dist/website/web/index.js +16 -0
  403. package/dist/website/web/messages.d.ts +2 -0
  404. package/dist/website/web/messages.js +15 -0
  405. package/dist/website_crm/.kosh/bindings.d.ts +22 -0
  406. package/dist/website_crm/.kosh/bindings.js +15 -0
  407. package/dist/website_crm/.kosh/schema.d.ts +966 -0
  408. package/dist/website_crm/index.d.ts +3 -0
  409. package/dist/website_crm/index.js +39 -0
  410. package/dist/website_crm/module.d.ts +2955 -0
  411. package/dist/website_crm/module.js +44 -0
  412. package/package.json +118 -1
@@ -5,7 +5,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
5
5
  * invitation, a two-factor reset, deactivation and reactivation, and their recent activity. The server decides
6
6
  * what a People manager may do (not administrators, not their own roles) and audits it all.
7
7
  */
8
- import { Alert, ApiError, Badge, Button, Dialog, EmptyState, Input, Label, useKosh, } from '../../ui/index.js';
8
+ import { Alert, ApiError, Avatar, Badge, Button, Dialog, EmptyState, Input, imageUrl, Label, useKosh, } from '../../ui/index.js';
9
9
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
10
10
  import { Check, Copy, Search, ShieldCheck, UserPlus } from 'lucide-react';
11
11
  import { useEffect, useId, useState } from 'react';
@@ -13,15 +13,6 @@ import { useTranslation } from 'react-i18next';
13
13
  import { RolesEditor } from './RolesEditor.js';
14
14
  const P = '/api/v1/settings/people';
15
15
  const message = (error) => (error instanceof ApiError ? error.message : String(error));
16
- const initials = (name) => name
17
- .split(/\s+/)
18
- .map((w) => w.slice(0, 1))
19
- .join('')
20
- .slice(0, 2)
21
- .toUpperCase();
22
- function Avatar({ name }) {
23
- return (_jsx("span", { "aria-hidden": true, className: "grid size-8 shrink-0 place-items-center rounded-full bg-accent text-xs font-semibold text-accent-foreground", children: initials(name) }));
24
- }
25
16
  function StateBadge({ person }) {
26
17
  const { t } = useTranslation('settings');
27
18
  return person.state === 'deactivated' ? (_jsx(Badge, { tone: "neutral", children: t('people.deactivated') })) : person.state === 'invited' ? (_jsx(Badge, { tone: "warning", children: t('people.invited') })) : (_jsx(Badge, { tone: "success", children: t('people.active') }));
@@ -34,31 +25,45 @@ function InvitationLink({ url, emailed, to, }) {
34
25
  void navigator.clipboard?.writeText(url).then(() => setCopied(true));
35
26
  }, children: [copied ? _jsx(Check, { "aria-hidden": true }) : _jsx(Copy, { "aria-hidden": true }), copied ? t('people.copied') : t('people.copy')] })] })] }));
36
27
  }
28
+ /** Invite someone (they choose their password from a link), or add them directly with a password you pass on. */
37
29
  function InviteDialog({ api, catalogue, open, onOpenChange, }) {
38
30
  const { t } = useTranslation('settings');
39
31
  const id = useId();
40
32
  const queryClient = useQueryClient();
33
+ const [mode, setMode] = useState('invite');
41
34
  const [name, setName] = useState('');
42
35
  const [email, setEmail] = useState('');
36
+ const [login, setLogin] = useState('');
37
+ const [password, setPassword] = useState('');
38
+ const [repeat, setRepeat] = useState('');
43
39
  const [assignments, setAssignments] = useState([]);
44
40
  const invite = useMutation({
45
- mutationFn: () => api.call('POST', P, {
46
- name,
47
- email,
48
- assignments,
49
- }),
41
+ mutationFn: () => api.call('POST', P, mode === 'invite'
42
+ ? { name, email, assignments }
43
+ : { name, email, login: login.trim() === '' ? email : login, password, assignments }),
50
44
  onSuccess: () => void queryClient.invalidateQueries({ queryKey: ['settings', 'people'] }),
51
45
  });
52
46
  useEffect(() => {
53
47
  if (!open) {
48
+ setMode('invite');
54
49
  setName('');
55
50
  setEmail('');
51
+ setLogin('');
52
+ setPassword('');
53
+ setRepeat('');
56
54
  setAssignments([]);
57
55
  invite.reset();
58
56
  }
59
57
  }, [open, invite.reset]);
60
58
  const done = invite.data;
61
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, title: t('people.inviteTitle'), description: t('people.inviteHint'), wide: true, footer: done === undefined ? (_jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => onOpenChange(false), children: t('profile.cancel') }), _jsx(Button, { variant: "primary", busy: invite.isPending, disabled: name.trim() === '' || !email.includes('@'), onClick: () => invite.mutate(), children: t('people.send') })] })) : (_jsx(Button, { variant: "primary", onClick: () => onOpenChange(false), children: t('people.done') })), children: done !== undefined ? (_jsx(InvitationLink, { url: done.activationUrl, emailed: done.emailed, to: done.login })) : (_jsxs("div", { className: "grid gap-4", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-name`, children: t('profile.name') }), _jsx(Input, { id: `${id}-name`, value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-email`, children: t('profile.email') }), _jsx(Input, { id: `${id}-email`, type: "email", value: email, onChange: (e) => setEmail(e.target.value) })] })] }), _jsxs("div", { className: "grid gap-2", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.roles') }), _jsx(RolesEditor, { catalogue: catalogue, value: assignments, onChange: setAssignments })] }), invite.error === null ? null : _jsx(Alert, { tone: "danger", children: message(invite.error) })] })) }));
59
+ const mismatch = repeat !== '' && repeat !== password;
60
+ const ready = name.trim() !== '' &&
61
+ (mode === 'invite'
62
+ ? email.includes('@')
63
+ : (login.trim() !== '' || email.includes('@')) &&
64
+ password.length >= 12 &&
65
+ repeat === password);
66
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, title: mode === 'invite' ? t('people.inviteTitle') : t('people.addTitle'), description: mode === 'invite' ? t('people.inviteHint') : t('people.addHint'), wide: true, footer: done === undefined ? (_jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => onOpenChange(false), children: t('profile.cancel') }), _jsx(Button, { variant: "primary", busy: invite.isPending, disabled: !ready, onClick: () => invite.mutate(), children: mode === 'invite' ? t('people.send') : t('people.add') })] })) : (_jsx(Button, { variant: "primary", onClick: () => onOpenChange(false), children: t('people.done') })), children: done !== undefined ? (done.activationUrl === null ? (_jsx(Alert, { tone: "info", children: t('people.added', { login: done.login }) })) : (_jsx(InvitationLink, { url: done.activationUrl, emailed: done.emailed, to: done.login }))) : (_jsxs("div", { className: "grid gap-4", children: [_jsxs("fieldset", { className: "grid gap-2 sm:grid-cols-2", children: [_jsx("legend", { className: "sr-only", children: t('people.how') }), ['invite', 'password'].map((m) => (_jsxs("label", { className: `flex cursor-pointer items-start gap-2 rounded-lg border p-3 text-sm ${mode === m ? 'border-primary bg-accent/40' : ''}`, children: [_jsx("input", { type: "radio", name: `${id}-mode`, className: "mt-1", checked: mode === m, onChange: () => setMode(m) }), _jsxs("span", { children: [_jsx("span", { className: "font-medium", children: t(`people.mode.${m}`) }), _jsx("span", { className: "block text-muted-foreground", children: t(`people.mode.${m}Hint`) })] })] }, m)))] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-name`, children: t('profile.name') }), _jsx(Input, { id: `${id}-name`, value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-email`, children: mode === 'invite' ? t('profile.email') : t('people.emailOptional') }), _jsx(Input, { id: `${id}-email`, type: "email", value: email, onChange: (e) => setEmail(e.target.value) })] }), mode === 'password' ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-login`, children: t('people.login') }), _jsx(Input, { id: `${id}-login`, autoComplete: "off", placeholder: email === '' ? 'rahim' : email, value: login, onChange: (e) => setLogin(e.target.value) })] }), _jsx("div", {}), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-password`, children: t('people.password') }), _jsx(Input, { id: `${id}-password`, type: "password", autoComplete: "new-password", value: password, onChange: (e) => setPassword(e.target.value) }), _jsx("p", { className: "text-xs text-muted-foreground", children: t('people.passwordHint') })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-repeat`, children: t('people.repeat') }), _jsx(Input, { id: `${id}-repeat`, type: "password", autoComplete: "new-password", "aria-invalid": mismatch ? true : undefined, value: repeat, onChange: (e) => setRepeat(e.target.value) }), mismatch ? _jsx("p", { className: "text-xs text-danger", children: t('people.mismatch') }) : null] })] })) : null] }), _jsxs("div", { className: "grid gap-2", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.roles') }), _jsx(RolesEditor, { catalogue: catalogue, value: assignments, onChange: setAssignments })] }), invite.error === null ? null : _jsx(Alert, { tone: "danger", children: message(invite.error) })] })) }));
62
67
  }
63
68
  /** What a person can do, computed by the server as them (administrators only). */
64
69
  function Effective({ api, personId }) {
@@ -130,7 +135,7 @@ function PersonDialog({ api, catalogue, personId, onClose, }) {
130
135
  const p = person.data;
131
136
  const error = saveDetails.error ?? saveRoles.error ?? setActive.error ?? resend.error ?? reset.error;
132
137
  const self = personId === uid;
133
- return (_jsx(Dialog, { open: true, onOpenChange: (open) => !open && onClose(), title: p?.name ?? '…', wide: true, children: p === undefined ? null : (_jsxs("div", { className: "grid gap-5", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Avatar, { name: p.name }), _jsx("span", { className: "text-muted-foreground", children: p.login }), _jsx(StateBadge, { person: p }), p.administrator ? _jsx(Badge, { tone: "info", children: t('people.administrator') }) : null, p.twoFactor ? (_jsxs(Badge, { tone: "success", children: [_jsx(ShieldCheck, { className: "size-3", "aria-hidden": true }), t('people.twoFactor')] })) : null] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.details') }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-[1fr_1fr_auto] sm:items-end", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-name`, children: t('profile.name') }), _jsx(Input, { id: `${id}-name`, value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-email`, children: t('profile.email') }), _jsx(Input, { id: `${id}-email`, type: "email", value: email, onChange: (e) => setEmail(e.target.value) })] }), _jsx(Button, { variant: "secondary", busy: saveDetails.isPending, onClick: () => saveDetails.mutate(), children: t('profile.save') })] })] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.roles') }), self && !catalogue.manager.administrator ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('people.notYourOwn') })) : (_jsxs(_Fragment, { children: [_jsx(RolesEditor, { catalogue: catalogue, value: assignments, onChange: setAssignments }), _jsx("div", { children: _jsx(Button, { variant: "primary", busy: saveRoles.isPending, onClick: () => saveRoles.mutate(), children: t('people.saveRoles') }) })] }))] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.access') }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [p.state === 'invited' || p.state === 'active' ? (_jsx(Button, { variant: "secondary", busy: resend.isPending, onClick: () => resend.mutate(), children: p.state === 'invited' ? t('people.resend') : t('people.newLink') })) : null, p.twoFactor ? (_jsx(Button, { variant: "secondary", onClick: () => setConfirm('reset'), children: t('people.reset2fa') })) : null, self ? null : p.active ? (_jsx(Button, { variant: "danger", onClick: () => setConfirm('deactivate'), children: t('people.deactivate') })) : (_jsx(Button, { variant: "secondary", busy: setActive.isPending, onClick: () => setActive.mutate(true), children: t('people.reactivate') }))] }), link === null ? null : (_jsx(InvitationLink, { url: link.url, emailed: link.emailed, to: p.login })), confirm === null ? null : (_jsx(Alert, { tone: "warning", action: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", onClick: () => setConfirm(null), children: t('profile.cancel') }), _jsx(Button, { size: "sm", variant: "danger", busy: setActive.isPending || reset.isPending, onClick: () => confirm === 'reset' ? reset.mutate() : setActive.mutate(false), children: confirm === 'reset' ? t('people.reset2fa') : t('people.deactivate') })] }), children: confirm === 'reset' ? t('people.resetConfirm') : t('people.deactivateConfirm') }))] }), error === null ? null : _jsx(Alert, { tone: "danger", children: message(error) }), catalogue.manager.administrator ? _jsx(Effective, { api: api, personId: personId }) : null, _jsxs("section", { className: "grid gap-2", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.activity') }), p.activity.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('people.noActivity') })) : (_jsx("ol", { className: "grid gap-1.5 text-sm", children: p.activity.map((a, i) => (_jsxs("li", { className: "flex gap-3", children: [_jsx("span", { className: "w-40 shrink-0 text-xs text-muted-foreground", children: a.at === null ? '' : format.datetime(a.at) }), _jsx("span", { children: a.summary })] }, i))) }))] })] })) }));
138
+ return (_jsx(Dialog, { open: true, onOpenChange: (open) => !open && onClose(), title: p?.name ?? '…', wide: true, children: p === undefined ? null : (_jsxs("div", { className: "grid gap-5", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Avatar, { name: p.name, src: imageUrl('user', p.id, p.avatar), className: "size-8" }), _jsx("span", { className: "text-muted-foreground", children: p.login }), _jsx(StateBadge, { person: p }), p.administrator ? _jsx(Badge, { tone: "info", children: t('people.administrator') }) : null, p.twoFactor ? (_jsxs(Badge, { tone: "success", children: [_jsx(ShieldCheck, { className: "size-3", "aria-hidden": true }), t('people.twoFactor')] })) : null] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.details') }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-[1fr_1fr_auto] sm:items-end", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-name`, children: t('profile.name') }), _jsx(Input, { id: `${id}-name`, value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: `${id}-email`, children: t('profile.email') }), _jsx(Input, { id: `${id}-email`, type: "email", value: email, onChange: (e) => setEmail(e.target.value) })] }), _jsx(Button, { variant: "secondary", busy: saveDetails.isPending, onClick: () => saveDetails.mutate(), children: t('profile.save') })] })] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.roles') }), self && !catalogue.manager.administrator ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('people.notYourOwn') })) : (_jsxs(_Fragment, { children: [_jsx(RolesEditor, { catalogue: catalogue, value: assignments, onChange: setAssignments }), _jsx("div", { children: _jsx(Button, { variant: "primary", busy: saveRoles.isPending, onClick: () => saveRoles.mutate(), children: t('people.saveRoles') }) })] }))] }), _jsxs("section", { className: "grid gap-3", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.access') }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [p.state === 'invited' || p.state === 'active' ? (_jsx(Button, { variant: "secondary", busy: resend.isPending, onClick: () => resend.mutate(), children: p.state === 'invited' ? t('people.resend') : t('people.newLink') })) : null, p.twoFactor ? (_jsx(Button, { variant: "secondary", onClick: () => setConfirm('reset'), children: t('people.reset2fa') })) : null, self ? null : p.active ? (_jsx(Button, { variant: "danger", onClick: () => setConfirm('deactivate'), children: t('people.deactivate') })) : (_jsx(Button, { variant: "secondary", busy: setActive.isPending, onClick: () => setActive.mutate(true), children: t('people.reactivate') }))] }), link === null ? null : (_jsx(InvitationLink, { url: link.url, emailed: link.emailed, to: p.login })), confirm === null ? null : (_jsx(Alert, { tone: "warning", action: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", onClick: () => setConfirm(null), children: t('profile.cancel') }), _jsx(Button, { size: "sm", variant: "danger", busy: setActive.isPending || reset.isPending, onClick: () => confirm === 'reset' ? reset.mutate() : setActive.mutate(false), children: confirm === 'reset' ? t('people.reset2fa') : t('people.deactivate') })] }), children: confirm === 'reset' ? t('people.resetConfirm') : t('people.deactivateConfirm') }))] }), error === null ? null : _jsx(Alert, { tone: "danger", children: message(error) }), catalogue.manager.administrator ? _jsx(Effective, { api: api, personId: personId }) : null, _jsxs("section", { className: "grid gap-2", children: [_jsx("h3", { className: "text-sm font-semibold", children: t('people.activity') }), p.activity.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('people.noActivity') })) : (_jsx("ol", { className: "grid gap-1.5 text-sm", children: p.activity.map((a, i) => (_jsxs("li", { className: "flex gap-3", children: [_jsx("span", { className: "w-40 shrink-0 text-xs text-muted-foreground", children: a.at === null ? '' : format.datetime(a.at) }), _jsx("span", { children: a.summary })] }, i))) }))] })] })) }));
134
139
  }
135
140
  export function PeoplePage({ api }) {
136
141
  const { t } = useTranslation('settings');
@@ -152,7 +157,7 @@ export function PeoplePage({ api }) {
152
157
  return _jsx(Alert, { tone: "danger", children: message(catalogue.error) });
153
158
  const list = people.data?.people ?? [];
154
159
  const statuses = ['all', 'active', 'invited', 'deactivated'];
155
- return (_jsxs("div", { className: "mx-auto grid max-w-5xl gap-5", children: [_jsxs("header", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: t('people.title') }), _jsx("p", { className: "text-sm text-muted-foreground", children: t('people.intro') })] }), _jsxs(Button, { variant: "primary", onClick: () => setInviting(true), disabled: catalogue.data === undefined, children: [_jsx(UserPlus, { "aria-hidden": true }), t('people.invite')] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("div", { className: "relative min-w-60 flex-1", children: [_jsx(Search, { className: "pointer-events-none absolute start-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": true }), _jsx("label", { htmlFor: `${id}-q`, className: "sr-only", children: t('people.search') }), _jsx(Input, { id: `${id}-q`, type: "search", className: "ps-9", placeholder: t('people.search'), value: q, onChange: (e) => setQ(e.target.value) })] }), _jsxs("fieldset", { className: "flex rounded-md border p-0.5", children: [_jsx("legend", { className: "sr-only", children: t('people.status') }), statuses.map((s) => (_jsx("button", { type: "button", "aria-pressed": status === s, onClick: () => setStatus(s), className: "rounded px-3 py-1 text-sm aria-pressed:bg-accent aria-pressed:font-medium aria-pressed:text-accent-foreground", children: t(`people.filter.${s}`) }, s)))] })] }), people.isSuccess && list.length === 0 ? (_jsx(EmptyState, { title: t('people.empty') })) : (_jsx("ul", { className: "divide-y rounded-lg border bg-surface", "aria-label": t('people.title'), children: list.map((p) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => setOpen(p.id), className: "flex w-full flex-wrap items-center gap-3 px-4 py-3 text-start hover:bg-muted/50", children: [_jsx(Avatar, { name: p.name }), _jsxs("span", { className: "grid min-w-48 flex-1", children: [_jsx("span", { className: "font-medium", children: p.name }), _jsx("span", { className: "text-sm text-muted-foreground", children: p.login })] }), _jsxs("span", { className: "flex min-w-48 flex-1 flex-wrap gap-1", children: [p.administrator ? _jsx(Badge, { tone: "info", children: t('people.administrator') }) : null, p.assignments
160
+ return (_jsxs("div", { className: "mx-auto grid max-w-5xl gap-5", children: [_jsxs("header", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: t('people.title') }), _jsx("p", { className: "text-sm text-muted-foreground", children: t('people.intro') })] }), _jsxs(Button, { variant: "primary", onClick: () => setInviting(true), disabled: catalogue.data === undefined, children: [_jsx(UserPlus, { "aria-hidden": true }), t('people.invite')] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("div", { className: "relative min-w-60 flex-1", children: [_jsx(Search, { className: "pointer-events-none absolute start-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": true }), _jsx("label", { htmlFor: `${id}-q`, className: "sr-only", children: t('people.search') }), _jsx(Input, { id: `${id}-q`, type: "search", className: "ps-9", placeholder: t('people.search'), value: q, onChange: (e) => setQ(e.target.value) })] }), _jsxs("fieldset", { className: "flex rounded-md border p-0.5", children: [_jsx("legend", { className: "sr-only", children: t('people.status') }), statuses.map((s) => (_jsx("button", { type: "button", "aria-pressed": status === s, onClick: () => setStatus(s), className: "rounded px-3 py-1 text-sm aria-pressed:bg-accent aria-pressed:font-medium aria-pressed:text-accent-foreground", children: t(`people.filter.${s}`) }, s)))] })] }), people.isSuccess && list.length === 0 ? (_jsx(EmptyState, { title: t('people.empty') })) : (_jsx("ul", { className: "divide-y rounded-lg border bg-surface", "aria-label": t('people.title'), children: list.map((p) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => setOpen(p.id), className: "flex w-full flex-wrap items-center gap-3 px-4 py-3 text-start hover:bg-muted/50", children: [_jsx(Avatar, { name: p.name, src: imageUrl('user', p.id, p.avatar), className: "size-8" }), _jsxs("span", { className: "grid min-w-48 flex-1", children: [_jsx("span", { className: "font-medium", children: p.name }), _jsx("span", { className: "text-sm text-muted-foreground", children: p.login })] }), _jsxs("span", { className: "flex min-w-48 flex-1 flex-wrap gap-1", children: [p.administrator ? _jsx(Badge, { tone: "info", children: t('people.administrator') }) : null, p.assignments
156
161
  .filter((a) => !a.group.startsWith('base.'))
157
162
  .slice(0, 3)
158
163
  .map((a) => (_jsx(Badge, { tone: "neutral", children: a.label }, `${a.group}-${a.company}`))), p.assignments.length > 3 ? (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["+", p.assignments.length - 3] })) : null] }), _jsxs("span", { className: "flex items-center gap-2", children: [p.twoFactor ? (_jsx(ShieldCheck, { className: "size-4 text-success", "aria-label": t('people.twoFactor') })) : null, _jsx(StateBadge, { person: p })] }), _jsx("span", { className: "w-40 text-end text-xs text-muted-foreground", children: p.state === 'invited' && p.invitationExpiresAt !== null
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * your password, two-factor sign-in (set up with an authenticator app, recovery codes, turn off) and the devices
5
5
  * signed in as you (sign one out, or all the others). The server checks and audits every change.
6
6
  */
7
- import { Alert, ApiError, Badge, Button, Input, LANGUAGES, Label, Select, useKosh, useLanguage, } from '../../ui/index.js';
7
+ import { Alert, ApiError, Badge, Button, ImagePicker, Input, imageUrl, LANGUAGES, Label, Select, useKosh, useLanguage, } from '../../ui/index.js';
8
8
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
9
9
  import { Laptop, Monitor, Smartphone } from 'lucide-react';
10
10
  import { useEffect, useId, useState } from 'react';
@@ -142,6 +142,13 @@ export function ProfilePage({ api }) {
142
142
  setLang(saved.lang);
143
143
  },
144
144
  });
145
+ const photo = useMutation({
146
+ mutationFn: (image) => image === null
147
+ ? api.call('DELETE', '/api/v1/auth/profile/avatar')
148
+ : api.call('PUT', '/api/v1/auth/profile/avatar', { image }),
149
+ // The shell shows the photo from the user's details.
150
+ onSuccess: () => void queryClient.invalidateQueries({ queryKey: ['me'] }),
151
+ });
145
152
  const [current, setCurrent] = useState('');
146
153
  const [next, setNext] = useState('');
147
154
  const [repeat, setRepeat] = useState('');
@@ -169,12 +176,7 @@ export function ProfilePage({ api }) {
169
176
  if (draft === null || me.data === undefined)
170
177
  return _jsx("p", { className: "text-sm text-muted-foreground", children: "\u2026" });
171
178
  const set = (patch) => setDraft({ ...draft, ...patch });
172
- return (_jsxs("div", { className: "mx-auto grid max-w-3xl gap-6", children: [_jsxs("header", { className: "flex items-center gap-4", children: [_jsx("span", { "aria-hidden": true, className: "grid size-14 place-items-center rounded-full bg-primary text-lg font-semibold text-primary-foreground", children: draft.name
173
- .split(/\s+/)
174
- .map((w) => w.slice(0, 1))
175
- .join('')
176
- .slice(0, 2)
177
- .toUpperCase() }), _jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: t('profile.title') }), _jsx("p", { className: "text-sm text-muted-foreground", children: t('profile.signedInAs', { login: draft.login }) })] })] }), _jsxs("form", { className: "grid gap-6", onSubmit: (e) => {
179
+ return (_jsxs("div", { className: "mx-auto grid max-w-3xl gap-6", children: [_jsxs("header", { className: "grid gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: t('profile.title') }), _jsx("p", { className: "text-sm text-muted-foreground", children: t('profile.signedInAs', { login: draft.login }) })] }), _jsxs("section", { "aria-label": t('profile.photo'), className: "rounded-lg border bg-surface p-5", children: [_jsx(ImagePicker, { name: draft.name, src: imageUrl('user', me.data.id, me.data.avatar), fit: "photo", busy: photo.isPending, onChoose: (image) => photo.mutate(image), onRemove: () => photo.mutate(null) }), photo.error === null ? null : (_jsx("div", { className: "mt-3", children: _jsx(Alert, { tone: "danger", children: message(photo.error) }) }))] })] }), _jsxs("form", { className: "grid gap-6", onSubmit: (e) => {
178
180
  e.preventDefault();
179
181
  save.mutate({
180
182
  name: draft.name,
@@ -7,10 +7,12 @@ import { type Registry } from '../../ui/index.js';
7
7
  import type { i18n } from 'i18next';
8
8
  import { messages } from './messages.js';
9
9
  export { ApiKeysPage } from './ApiKeysPage.js';
10
+ export { AppSettingsPage } from './AppSettingsPage.js';
10
11
  export { AppsPage } from './AppsPage.js';
11
12
  export { AuditPage } from './AuditPage.js';
12
13
  export { CompaniesPage } from './CompaniesPage.js';
13
14
  export { CompanyPage } from './CompanyPage.js';
15
+ export { ConnectedAppsPage } from './ConnectedAppsPage.js';
14
16
  export { OverviewPage } from './OverviewPage.js';
15
17
  export { PeoplePage } from './PeoplePage.js';
16
18
  export { deviceOf, ProfilePage } from './ProfilePage.js';
@@ -5,10 +5,12 @@
5
5
  */
6
6
  import { addMessages } from '../../ui/index.js';
7
7
  import { ApiKeysPage } from './ApiKeysPage.js';
8
+ import { AppSettingsPage } from './AppSettingsPage.js';
8
9
  import { AppsPage } from './AppsPage.js';
9
10
  import { AuditPage } from './AuditPage.js';
10
11
  import { CompaniesPage } from './CompaniesPage.js';
11
12
  import { CompanyPage } from './CompanyPage.js';
13
+ import { ConnectedAppsPage } from './ConnectedAppsPage.js';
12
14
  import { messages } from './messages.js';
13
15
  import { OverviewPage } from './OverviewPage.js';
14
16
  import { PeoplePage } from './PeoplePage.js';
@@ -16,10 +18,12 @@ import { ProfilePage } from './ProfilePage.js';
16
18
  import { RolesPage } from './RolesPage.js';
17
19
  import { SecurityPage } from './SecurityPage.js';
18
20
  export { ApiKeysPage } from './ApiKeysPage.js';
21
+ export { AppSettingsPage } from './AppSettingsPage.js';
19
22
  export { AppsPage } from './AppsPage.js';
20
23
  export { AuditPage } from './AuditPage.js';
21
24
  export { CompaniesPage } from './CompaniesPage.js';
22
25
  export { CompanyPage } from './CompanyPage.js';
26
+ export { ConnectedAppsPage } from './ConnectedAppsPage.js';
23
27
  export { OverviewPage } from './OverviewPage.js';
24
28
  export { PeoplePage } from './PeoplePage.js';
25
29
  export { deviceOf, ProfilePage } from './ProfilePage.js';
@@ -30,6 +34,7 @@ export { SecurityPage } from './SecurityPage.js';
30
34
  export function registerSettingsWeb(registry, i18n) {
31
35
  registry.registerPage('settings.Overview', OverviewPage);
32
36
  registry.registerPage('settings.Apps', AppsPage);
37
+ registry.registerPage('settings.AppSettings', AppSettingsPage);
33
38
  registry.registerPage('settings.People', PeoplePage);
34
39
  registry.registerPage('settings.Roles', RolesPage);
35
40
  registry.registerPage('settings.Company', CompanyPage);
@@ -39,6 +44,9 @@ export function registerSettingsWeb(registry, i18n) {
39
44
  // Every signed-in user's own profile (RFC 0019) and keys (RFC 0017 §5.1): in the user menu, not in Settings.
40
45
  registry.registerUserPage('settings.Profile', ProfilePage, { label: 'settings:profile.title' });
41
46
  registry.registerUserPage('settings.ApiKeys', ApiKeysPage, { label: 'settings:apiKeys.title' });
47
+ registry.registerUserPage('settings.ConnectedApps', ConnectedAppsPage, {
48
+ label: 'settings:connected.title',
49
+ });
42
50
  if (i18n !== undefined)
43
51
  addMessages(i18n, 'settings', messages);
44
52
  return registry;
@@ -1,6 +1,56 @@
1
1
  /** Messages of the Settings app (namespace `settings`). */
2
2
  export const messages = {
3
3
  en: {
4
+ appSettings: {
5
+ title: 'App settings',
6
+ intro: 'Each app’s own settings, in one place. Who may change them is set by the app; every change is in the audit log.',
7
+ apps: 'Apps',
8
+ none: 'No installed app you may open has settings yet.',
9
+ perCompany: 'For this company',
10
+ everywhere: 'For every company',
11
+ changed: 'Changed',
12
+ reset: 'Reset',
13
+ resetOne: 'Reset {{setting}} to its default',
14
+ defaultIs: 'Default: {{value}}',
15
+ save: 'Save',
16
+ discard: 'Discard',
17
+ saved: 'Saved.',
18
+ readOnly: 'You may see these settings; changing them needs another role.',
19
+ notSet: 'Not set',
20
+ history: 'History',
21
+ historyOf: 'History of {{setting}}',
22
+ neverChanged: 'Never changed: the default applies.',
23
+ system: 'System',
24
+ how: { changed: 'changed', copied: 'copied from another company', imported: 'imported' },
25
+ copyTo: 'Copy to another company…',
26
+ copyTitle: 'Copy settings to another company',
27
+ copyIntro: 'This company’s settings for each app, written to the company you choose. What would change is shown first; nothing is written until you confirm.',
28
+ toCompany: 'To company',
29
+ chooseCompany: 'Choose a company',
30
+ copyNow: 'Copy the settings',
31
+ copied: 'Settings copied ({{count}} sections changed).',
32
+ nothingToChange: 'Nothing would change: the settings are the same already.',
33
+ export: 'Export',
34
+ import: 'Import…',
35
+ importFile: 'Settings file to import',
36
+ importTitle: 'Import settings',
37
+ importIntro: 'A settings file exported from Shutro ERP, checked against the installed apps. What would change is shown first; unknown settings are skipped.',
38
+ importNow: 'Import the settings',
39
+ imported: 'Settings imported ({{count}} sections changed).',
40
+ skipped: 'Skipped (not in this installation): {{what}}',
41
+ notJson: 'That file is not a settings export.',
42
+ },
43
+ connected: {
44
+ title: 'Connected apps',
45
+ intro: 'Apps you allowed to act for you. They can never do more than you may; remove one and its access ends at once.',
46
+ none: 'You have not allowed any app.',
47
+ since: 'allowed {{when}}',
48
+ lastUsed: 'last used {{when}}',
49
+ neverUsed: 'not used yet',
50
+ revoke: 'Remove access',
51
+ revokeApp: 'Remove the access of {{app}}',
52
+ homepage: 'About {{app}}',
53
+ },
4
54
  roles: {
5
55
  title: 'Roles & permissions',
6
56
  intro: 'What each role lets people open and do. Changes are previewed before they are saved.',
@@ -62,9 +112,26 @@ export const messages = {
62
112
  people: {
63
113
  title: 'People',
64
114
  intro: 'Who works here, what they can open, and how they sign in.',
65
- invite: 'Invite',
115
+ invite: 'Add or invite',
66
116
  inviteTitle: 'Invite someone',
67
117
  inviteHint: 'They get a link to choose their password; it works for 7 days.',
118
+ addTitle: 'Add someone',
119
+ addHint: 'You set their password and pass it on; they can change it in their profile.',
120
+ add: 'Add the person',
121
+ added: '{{login}} can sign in now with the password you set. Pass it on safely.',
122
+ how: 'How they get in',
123
+ mode: {
124
+ invite: 'Send an invitation',
125
+ inviteHint: 'An email with a link; they choose their own password.',
126
+ password: 'Add with a password',
127
+ passwordHint: 'They can sign in at once; no email needed.',
128
+ },
129
+ emailOptional: 'Email (optional)',
130
+ login: 'Login',
131
+ password: 'Password',
132
+ passwordHint: 'At least 12 characters.',
133
+ repeat: 'Repeat the password',
134
+ mismatch: 'The passwords differ.',
68
135
  send: 'Send the invitation',
69
136
  done: 'Done',
70
137
  emailed: 'The invitation is on its way to {{to}}. You can also pass on the link:',
@@ -129,10 +196,18 @@ export const messages = {
129
196
  description: 'Sign-ins, permission changes, exports and sensitive actions; filtered and exported.',
130
197
  keywords: 'audit log history events who did what logins export csv',
131
198
  },
199
+ 'settings.action_app_settings': {
200
+ description: 'Each app’s own settings: quotations, purchase orders, fiscal year and lock dates, and more.',
201
+ keywords: 'app settings configuration defaults',
202
+ },
132
203
  'settings.action_companies': {
133
204
  description: 'Every company, its currency and people; switch between them or add one.',
134
205
  keywords: 'companies multi-company branches new company switch',
135
206
  },
207
+ 'settings.action_people': {
208
+ description: 'Invite people, give them roles per app and company, deactivate them, reset their two-factor sign-in.',
209
+ keywords: 'people users employees invite invitation roles deactivate 2fa reset',
210
+ },
136
211
  'settings.action_roles': {
137
212
  description: 'What each role opens and allows, rights per model, record rules; previewed before saving.',
138
213
  keywords: 'roles permissions access rights groups record rules field security acl',
@@ -184,6 +259,7 @@ export const messages = {
184
259
  turnOff: 'Turn off two-factor sign-in',
185
260
  password: 'Password',
186
261
  recoveryCodes: 'Your recovery codes: each signs you in once if you lose your phone. Keep them somewhere safe; they are shown only now.',
262
+ photo: 'Photo',
187
263
  sessions: 'Signed-in devices',
188
264
  sessionsHint: 'Where you are signed in now. Sign out a device you do not recognise.',
189
265
  thisDevice: 'This device',
@@ -368,6 +444,56 @@ export const messages = {
368
444
  version: 'Version {{version}}',
369
445
  },
370
446
  bn: {
447
+ appSettings: {
448
+ title: 'অ্যাপ সেটিংস',
449
+ intro: 'প্রতিটি অ্যাপের নিজস্ব সেটিংস, এক জায়গায়। কে বদলাতে পারবেন তা অ্যাপ ঠিক করে; প্রতিটি পরিবর্তন অডিট লগে থাকে।',
450
+ apps: 'অ্যাপস',
451
+ none: 'আপনি খুলতে পারেন এমন কোনো অ্যাপের এখনো সেটিংস নেই।',
452
+ perCompany: 'এই প্রতিষ্ঠানের জন্য',
453
+ everywhere: 'সব প্রতিষ্ঠানের জন্য',
454
+ changed: 'পরিবর্তিত',
455
+ reset: 'ডিফল্টে ফিরিয়ে দিন',
456
+ resetOne: '{{setting}} ডিফল্টে ফিরিয়ে দিন',
457
+ defaultIs: 'ডিফল্ট: {{value}}',
458
+ save: 'সংরক্ষণ করুন',
459
+ discard: 'বাদ দিন',
460
+ saved: 'সংরক্ষিত।',
461
+ readOnly: 'আপনি এই সেটিংস দেখতে পারেন; বদলাতে অন্য রোল লাগে।',
462
+ notSet: 'নির্ধারিত নয়',
463
+ history: 'ইতিহাস',
464
+ historyOf: '{{setting}}-এর ইতিহাস',
465
+ neverChanged: 'কখনো বদলানো হয়নি: ডিফল্ট প্রযোজ্য।',
466
+ system: 'সিস্টেম',
467
+ how: { changed: 'বদলানো হয়েছে', copied: 'অন্য প্রতিষ্ঠান থেকে কপি', imported: 'ইমপোর্ট' },
468
+ copyTo: 'অন্য প্রতিষ্ঠানে কপি করুন…',
469
+ copyTitle: 'সেটিংস অন্য প্রতিষ্ঠানে কপি করুন',
470
+ copyIntro: 'এই প্রতিষ্ঠানের প্রতিটি অ্যাপের সেটিংস আপনার বেছে নেওয়া প্রতিষ্ঠানে লেখা হবে। কী বদলাবে তা আগে দেখানো হয়; নিশ্চিত না করা পর্যন্ত কিছু লেখা হয় না।',
471
+ toCompany: 'যে প্রতিষ্ঠানে',
472
+ chooseCompany: 'প্রতিষ্ঠান বেছে নিন',
473
+ copyNow: 'সেটিংস কপি করুন',
474
+ copied: 'সেটিংস কপি হয়েছে ({{count}}টি অংশ বদলেছে)।',
475
+ nothingToChange: 'কিছু বদলাবে না: সেটিংস আগে থেকেই এক।',
476
+ export: 'এক্সপোর্ট',
477
+ import: 'ইমপোর্ট…',
478
+ importFile: 'ইমপোর্টের সেটিংস ফাইল',
479
+ importTitle: 'সেটিংস ইমপোর্ট',
480
+ importIntro: 'Shutro ERP থেকে এক্সপোর্ট করা সেটিংস ফাইল, ইনস্টল করা অ্যাপের সাথে মিলিয়ে দেখা। কী বদলাবে তা আগে দেখানো হয়; অজানা সেটিংস বাদ যায়।',
481
+ importNow: 'সেটিংস ইমপোর্ট করুন',
482
+ imported: 'সেটিংস ইমপোর্ট হয়েছে ({{count}}টি অংশ বদলেছে)।',
483
+ skipped: 'বাদ গেছে (এই ইনস্টলেশনে নেই): {{what}}',
484
+ notJson: 'ফাইলটি সেটিংস এক্সপোর্ট নয়।',
485
+ },
486
+ connected: {
487
+ title: 'সংযুক্ত অ্যাপস',
488
+ intro: 'যে অ্যাপগুলোকে আপনি আপনার হয়ে কাজ করতে দিয়েছেন। সরিয়ে দিলে সাথে সাথে প্রবেশাধিকার শেষ।',
489
+ none: 'আপনি কোনো অ্যাপকে অনুমতি দেননি।',
490
+ since: '{{when}} থেকে অনুমতি',
491
+ lastUsed: 'সর্বশেষ ব্যবহার {{when}}',
492
+ neverUsed: 'এখনো ব্যবহার হয়নি',
493
+ revoke: 'প্রবেশাধিকার সরান',
494
+ revokeApp: '{{app}}-এর প্রবেশাধিকার সরান',
495
+ homepage: '{{app}} সম্পর্কে',
496
+ },
371
497
  roles: {
372
498
  title: 'রোল ও অনুমতি',
373
499
  intro: 'প্রতিটি রোল মানুষকে কী খুলতে ও করতে দেয়। সংরক্ষণের আগে পরিবর্তন দেখানো হয়।',
@@ -429,9 +555,26 @@ export const messages = {
429
555
  people: {
430
556
  title: 'মানুষ',
431
557
  intro: 'এখানে কারা কাজ করেন, কী খুলতে পারেন এবং কীভাবে সাইন ইন করেন।',
432
- invite: 'আমন্ত্রণ',
558
+ invite: 'যোগ বা আমন্ত্রণ',
433
559
  inviteTitle: 'কাউকে আমন্ত্রণ জানান',
434
560
  inviteHint: 'তাঁরা পাসওয়ার্ড বেছে নেওয়ার একটি লিংক পাবেন; এটি ৭ দিন কাজ করে।',
561
+ addTitle: 'কাউকে যোগ করুন',
562
+ addHint: 'আপনি পাসওয়ার্ড ঠিক করে দিন; তাঁরা প্রোফাইলে বদলাতে পারেন।',
563
+ add: 'যোগ করুন',
564
+ added: '{{login}} এখনই আপনার ঠিক করা পাসওয়ার্ড দিয়ে সাইন ইন করতে পারেন। নিরাপদে জানিয়ে দিন।',
565
+ how: 'কীভাবে প্রবেশ করবেন',
566
+ mode: {
567
+ invite: 'আমন্ত্রণ পাঠান',
568
+ inviteHint: 'একটি ইমেইলে লিংক; তাঁরা নিজের পাসওয়ার্ড বেছে নেন।',
569
+ password: 'পাসওয়ার্ড দিয়ে যোগ করুন',
570
+ passwordHint: 'সাথে সাথে সাইন ইন করতে পারেন; ইমেইল লাগে না।',
571
+ },
572
+ emailOptional: 'ইমেইল (ঐচ্ছিক)',
573
+ login: 'লগইন',
574
+ password: 'পাসওয়ার্ড',
575
+ passwordHint: 'অন্তত ১২ অক্ষর।',
576
+ repeat: 'পাসওয়ার্ড আবার দিন',
577
+ mismatch: 'পাসওয়ার্ড মিলছে না।',
435
578
  send: 'আমন্ত্রণ পাঠান',
436
579
  done: 'সম্পন্ন',
437
580
  emailed: 'আমন্ত্রণ {{to}}-এ যাচ্ছে। লিংকটি আপনিও পাঠাতে পারেন:',
@@ -555,6 +698,7 @@ export const messages = {
555
698
  turnOff: 'দুই-ধাপের সাইন ইন বন্ধ করুন',
556
699
  password: 'পাসওয়ার্ড',
557
700
  recoveryCodes: 'আপনার রিকভারি কোড: ফোন হারালে প্রতিটি একবার সাইন ইন করায়। নিরাপদে রাখুন; শুধু এখনই দেখানো হচ্ছে।',
701
+ photo: 'ছবি',
558
702
  sessions: 'সাইন ইন করা ডিভাইস',
559
703
  sessionsHint: 'এখন যেখানে আপনি সাইন ইন আছেন। অচেনা ডিভাইস সাইন আউট করুন।',
560
704
  thisDevice: 'এই ডিভাইস',
@@ -0,0 +1,22 @@
1
+ export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
2
+ import { type DefinitionHelpers } from '../../server/orm.js';
3
+ import type { DefaultLoaded, Env as CoreEnv, RecordSet as CoreRecordSet, Shutro as CoreShutro } from '../../server/orm.js';
4
+ import type { SchemaView } from './schema.js';
5
+ export type { SchemaView };
6
+ /** Every model visible in this view. */
7
+ export type ModelName = keyof SchemaView & string;
8
+ /** `Env` typed to this view. */
9
+ export type Env = CoreEnv<SchemaView>;
10
+ /** `Shutro` typed to this view. */
11
+ export type Shutro = CoreShutro<SchemaView>;
12
+ /** A recordset of `M`, with the default loaded shape unless `L` is given. */
13
+ export type Records<M extends ModelName, L = DefaultLoaded<SchemaView, M>> = CoreRecordSet<SchemaView, M, L>;
14
+ export declare const compute: DefinitionHelpers<SchemaView>['compute'];
15
+ export declare const check: DefinitionHelpers<SchemaView>['check'];
16
+ export declare const onchange: DefinitionHelpers<SchemaView>['onchange'];
17
+ export declare const records: DefinitionHelpers<SchemaView>['records'];
18
+ export declare const method: DefinitionHelpers<SchemaView>['method'];
19
+ /** Module data (RFC 0017): records, overrides of dependencies' records, and references, typed like creates. */
20
+ export declare const record: DefinitionHelpers<SchemaView>['record'];
21
+ export declare const override: DefinitionHelpers<SchemaView>['override'];
22
+ export declare const ref: DefinitionHelpers<SchemaView>['ref'];
@@ -0,0 +1,15 @@
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 8b53af7578c6a801
2
+ // Bindings of module `stock`: import the definition API from here to get types scoped to what it can see.
3
+ export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
4
+ import { definitions } from '../../server/orm.js';
5
+ /** Definition callbacks typed against this module's view: no casts in computes, checks, onchange, methods. */
6
+ const helpers = definitions();
7
+ export const compute = helpers.compute;
8
+ export const check = helpers.check;
9
+ export const onchange = helpers.onchange;
10
+ export const records = helpers.records;
11
+ export const method = helpers.method;
12
+ /** Module data (RFC 0017): records, overrides of dependencies' records, and references, typed like creates. */
13
+ export const record = helpers.record;
14
+ export const override = helpers.override;
15
+ export const ref = helpers.ref;