@multiplatform.one/frappe-ui 7.28.1 → 7.29.0

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 (325) hide show
  1. package/dist/cjs/FrappeCalendar.cjs +3 -2
  2. package/dist/cjs/FrappeCalendar.native.js +3 -2
  3. package/dist/cjs/FrappeCalendar.native.js.map +1 -1
  4. package/dist/cjs/FrappeForm.cjs +148 -464
  5. package/dist/cjs/FrappeForm.native.js +152 -633
  6. package/dist/cjs/FrappeForm.native.js.map +1 -1
  7. package/dist/cjs/FrappeListView.cjs +5 -27
  8. package/dist/cjs/FrappeListView.native.js +11 -32
  9. package/dist/cjs/FrappeListView.native.js.map +1 -1
  10. package/dist/cjs/FrappeReportBuilder.cjs +523 -309
  11. package/dist/cjs/FrappeReportBuilder.native.js +658 -353
  12. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  13. package/dist/cjs/FrappeReportView.cjs +35 -234
  14. package/dist/cjs/FrappeReportView.native.js +39 -283
  15. package/dist/cjs/FrappeReportView.native.js.map +1 -1
  16. package/dist/cjs/dependsOn.cjs +2 -2
  17. package/dist/cjs/dependsOn.native.js +1 -2
  18. package/dist/cjs/dependsOn.native.js.map +1 -1
  19. package/dist/cjs/fields/shared/EditorPreviewPanes.cjs +2 -2
  20. package/dist/cjs/fields/shared/EditorPreviewPanes.native.js +2 -2
  21. package/dist/cjs/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  22. package/dist/cjs/formEngine/docPermissions.cjs +20 -0
  23. package/dist/cjs/formEngine/docPermissions.native.js +69 -0
  24. package/dist/cjs/formEngine/docPermissions.native.js.map +1 -1
  25. package/dist/cjs/formEngine/index.cjs +2 -0
  26. package/dist/cjs/formEngine/index.native.js +2 -0
  27. package/dist/cjs/formEngine/index.native.js.map +1 -1
  28. package/dist/cjs/index.cjs +67 -7
  29. package/dist/cjs/index.native.js +67 -7
  30. package/dist/cjs/index.native.js.map +1 -1
  31. package/dist/cjs/liveErrors.cjs +8 -2
  32. package/dist/cjs/liveErrors.native.js +8 -2
  33. package/dist/cjs/liveErrors.native.js.map +1 -1
  34. package/dist/cjs/measures.cjs +31 -0
  35. package/dist/cjs/measures.native.js +34 -0
  36. package/dist/cjs/measures.native.js.map +1 -0
  37. package/dist/cjs/recordShape.cjs +103 -0
  38. package/dist/cjs/recordShape.native.js +115 -0
  39. package/dist/cjs/recordShape.native.js.map +1 -0
  40. package/dist/cjs/report/ReportGrid.cjs +453 -0
  41. package/dist/cjs/report/ReportGrid.native.js +510 -0
  42. package/dist/cjs/report/ReportGrid.native.js.map +1 -0
  43. package/dist/cjs/report/ReportViewToolbar.cjs +253 -0
  44. package/dist/cjs/report/ReportViewToolbar.native.js +303 -0
  45. package/dist/cjs/report/ReportViewToolbar.native.js.map +1 -0
  46. package/dist/cjs/report/queryReport.cjs +444 -0
  47. package/dist/cjs/report/queryReport.native.js +588 -0
  48. package/dist/cjs/report/queryReport.native.js.map +1 -0
  49. package/dist/cjs/report/queryReportColumns.cjs +131 -0
  50. package/dist/cjs/report/queryReportColumns.native.js +159 -0
  51. package/dist/cjs/report/queryReportColumns.native.js.map +1 -0
  52. package/dist/cjs/report/reportViewModel.cjs +386 -0
  53. package/dist/cjs/report/reportViewModel.native.js +657 -0
  54. package/dist/cjs/report/reportViewModel.native.js.map +1 -0
  55. package/dist/cjs/report/savedReports.cjs +137 -0
  56. package/dist/cjs/report/savedReports.native.js +169 -0
  57. package/dist/cjs/report/savedReports.native.js.map +1 -0
  58. package/dist/cjs/report/useFrappeReport.cjs +184 -0
  59. package/dist/cjs/report/useFrappeReport.native.js +214 -0
  60. package/dist/cjs/report/useFrappeReport.native.js.map +1 -0
  61. package/dist/cjs/report/useQueryReport.cjs +201 -0
  62. package/dist/cjs/report/useQueryReport.native.js +233 -0
  63. package/dist/cjs/report/useQueryReport.native.js.map +1 -0
  64. package/dist/cjs/useFrappeForm.cjs +558 -0
  65. package/dist/cjs/useFrappeForm.native.js +714 -0
  66. package/dist/cjs/useFrappeForm.native.js.map +1 -0
  67. package/dist/esm/FrappeCalendar.mjs +4 -3
  68. package/dist/esm/FrappeCalendar.mjs.map +1 -1
  69. package/dist/esm/FrappeCalendar.native.js +4 -3
  70. package/dist/esm/FrappeCalendar.native.js.map +1 -1
  71. package/dist/esm/FrappeForm.mjs +151 -467
  72. package/dist/esm/FrappeForm.mjs.map +1 -1
  73. package/dist/esm/FrappeForm.native.js +155 -636
  74. package/dist/esm/FrappeForm.native.js.map +1 -1
  75. package/dist/esm/FrappeListView.mjs +6 -28
  76. package/dist/esm/FrappeListView.mjs.map +1 -1
  77. package/dist/esm/FrappeListView.native.js +12 -33
  78. package/dist/esm/FrappeListView.native.js.map +1 -1
  79. package/dist/esm/FrappeReportBuilder.mjs +526 -312
  80. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  81. package/dist/esm/FrappeReportBuilder.native.js +661 -356
  82. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  83. package/dist/esm/FrappeReportView.mjs +30 -229
  84. package/dist/esm/FrappeReportView.mjs.map +1 -1
  85. package/dist/esm/FrappeReportView.native.js +34 -278
  86. package/dist/esm/FrappeReportView.native.js.map +1 -1
  87. package/dist/esm/dependsOn.mjs +2 -2
  88. package/dist/esm/dependsOn.mjs.map +1 -1
  89. package/dist/esm/dependsOn.native.js +1 -2
  90. package/dist/esm/dependsOn.native.js.map +1 -1
  91. package/dist/esm/fields/shared/EditorPreviewPanes.mjs +2 -2
  92. package/dist/esm/fields/shared/EditorPreviewPanes.mjs.map +1 -1
  93. package/dist/esm/fields/shared/EditorPreviewPanes.native.js +2 -2
  94. package/dist/esm/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  95. package/dist/esm/formEngine/docPermissions.mjs +19 -1
  96. package/dist/esm/formEngine/docPermissions.mjs.map +1 -1
  97. package/dist/esm/formEngine/docPermissions.native.js +68 -1
  98. package/dist/esm/formEngine/docPermissions.native.js.map +1 -1
  99. package/dist/esm/formEngine/index.mjs +2 -2
  100. package/dist/esm/formEngine/index.mjs.map +1 -1
  101. package/dist/esm/formEngine/index.native.js +2 -2
  102. package/dist/esm/formEngine/index.native.js.map +1 -1
  103. package/dist/esm/index.mjs +16 -4
  104. package/dist/esm/index.mjs.map +1 -1
  105. package/dist/esm/index.native.js +16 -4
  106. package/dist/esm/index.native.js.map +1 -1
  107. package/dist/esm/liveErrors.mjs +8 -3
  108. package/dist/esm/liveErrors.mjs.map +1 -1
  109. package/dist/esm/liveErrors.native.js +8 -3
  110. package/dist/esm/liveErrors.native.js.map +1 -1
  111. package/dist/esm/measures.mjs +5 -0
  112. package/dist/esm/measures.mjs.map +1 -0
  113. package/dist/esm/measures.native.js +5 -0
  114. package/dist/esm/measures.native.js.map +1 -0
  115. package/dist/esm/recordShape.mjs +74 -0
  116. package/dist/esm/recordShape.mjs.map +1 -0
  117. package/dist/esm/recordShape.native.js +83 -0
  118. package/dist/esm/recordShape.native.js.map +1 -0
  119. package/dist/esm/report/ReportGrid.mjs +428 -0
  120. package/dist/esm/report/ReportGrid.mjs.map +1 -0
  121. package/dist/esm/report/ReportGrid.native.js +471 -0
  122. package/dist/esm/report/ReportGrid.native.js.map +1 -0
  123. package/dist/esm/report/ReportViewToolbar.mjs +228 -0
  124. package/dist/esm/report/ReportViewToolbar.mjs.map +1 -0
  125. package/dist/esm/report/ReportViewToolbar.native.js +264 -0
  126. package/dist/esm/report/ReportViewToolbar.native.js.map +1 -0
  127. package/dist/esm/report/queryReport.mjs +404 -0
  128. package/dist/esm/report/queryReport.mjs.map +1 -0
  129. package/dist/esm/report/queryReport.native.js +545 -0
  130. package/dist/esm/report/queryReport.native.js.map +1 -0
  131. package/dist/esm/report/queryReportColumns.mjs +105 -0
  132. package/dist/esm/report/queryReportColumns.mjs.map +1 -0
  133. package/dist/esm/report/queryReportColumns.native.js +119 -0
  134. package/dist/esm/report/queryReportColumns.native.js.map +1 -0
  135. package/dist/esm/report/reportViewModel.mjs +343 -0
  136. package/dist/esm/report/reportViewModel.mjs.map +1 -0
  137. package/dist/esm/report/reportViewModel.native.js +611 -0
  138. package/dist/esm/report/reportViewModel.native.js.map +1 -0
  139. package/dist/esm/report/savedReports.mjs +112 -0
  140. package/dist/esm/report/savedReports.mjs.map +1 -0
  141. package/dist/esm/report/savedReports.native.js +141 -0
  142. package/dist/esm/report/savedReports.native.js.map +1 -0
  143. package/dist/esm/report/useFrappeReport.mjs +158 -0
  144. package/dist/esm/report/useFrappeReport.mjs.map +1 -0
  145. package/dist/esm/report/useFrappeReport.native.js +185 -0
  146. package/dist/esm/report/useFrappeReport.native.js.map +1 -0
  147. package/dist/esm/report/useQueryReport.mjs +176 -0
  148. package/dist/esm/report/useQueryReport.mjs.map +1 -0
  149. package/dist/esm/report/useQueryReport.native.js +205 -0
  150. package/dist/esm/report/useQueryReport.native.js.map +1 -0
  151. package/dist/esm/useFrappeForm.mjs +533 -0
  152. package/dist/esm/useFrappeForm.mjs.map +1 -0
  153. package/dist/esm/useFrappeForm.native.js +686 -0
  154. package/dist/esm/useFrappeForm.native.js.map +1 -0
  155. package/dist/jsx/FrappeCalendar.mjs +4 -3
  156. package/dist/jsx/FrappeCalendar.mjs.map +1 -1
  157. package/dist/jsx/FrappeCalendar.native.js +3 -2
  158. package/dist/jsx/FrappeCalendar.native.js.map +1 -1
  159. package/dist/jsx/FrappeForm.mjs +151 -467
  160. package/dist/jsx/FrappeForm.mjs.map +1 -1
  161. package/dist/jsx/FrappeForm.native.js +152 -633
  162. package/dist/jsx/FrappeForm.native.js.map +1 -1
  163. package/dist/jsx/FrappeListView.mjs +6 -28
  164. package/dist/jsx/FrappeListView.mjs.map +1 -1
  165. package/dist/jsx/FrappeListView.native.js +11 -32
  166. package/dist/jsx/FrappeListView.native.js.map +1 -1
  167. package/dist/jsx/FrappeReportBuilder.mjs +526 -312
  168. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  169. package/dist/jsx/FrappeReportBuilder.native.js +658 -353
  170. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  171. package/dist/jsx/FrappeReportView.mjs +30 -229
  172. package/dist/jsx/FrappeReportView.mjs.map +1 -1
  173. package/dist/jsx/FrappeReportView.native.js +39 -283
  174. package/dist/jsx/FrappeReportView.native.js.map +1 -1
  175. package/dist/jsx/dependsOn.mjs +2 -2
  176. package/dist/jsx/dependsOn.mjs.map +1 -1
  177. package/dist/jsx/dependsOn.native.js +1 -2
  178. package/dist/jsx/dependsOn.native.js.map +1 -1
  179. package/dist/jsx/fields/shared/EditorPreviewPanes.mjs +2 -2
  180. package/dist/jsx/fields/shared/EditorPreviewPanes.mjs.map +1 -1
  181. package/dist/jsx/fields/shared/EditorPreviewPanes.native.js +2 -2
  182. package/dist/jsx/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  183. package/dist/jsx/formEngine/docPermissions.mjs +19 -1
  184. package/dist/jsx/formEngine/docPermissions.mjs.map +1 -1
  185. package/dist/jsx/formEngine/docPermissions.native.js +69 -0
  186. package/dist/jsx/formEngine/docPermissions.native.js.map +1 -1
  187. package/dist/jsx/formEngine/index.mjs +2 -2
  188. package/dist/jsx/formEngine/index.mjs.map +1 -1
  189. package/dist/jsx/formEngine/index.native.js +2 -0
  190. package/dist/jsx/formEngine/index.native.js.map +1 -1
  191. package/dist/jsx/index.js +16 -4
  192. package/dist/jsx/index.js.map +1 -1
  193. package/dist/jsx/index.mjs +16 -4
  194. package/dist/jsx/index.mjs.map +1 -1
  195. package/dist/jsx/index.native.js +67 -7
  196. package/dist/jsx/index.native.js.map +1 -1
  197. package/dist/jsx/liveErrors.mjs +8 -3
  198. package/dist/jsx/liveErrors.mjs.map +1 -1
  199. package/dist/jsx/liveErrors.native.js +8 -2
  200. package/dist/jsx/liveErrors.native.js.map +1 -1
  201. package/dist/jsx/measures.mjs +5 -0
  202. package/dist/jsx/measures.mjs.map +1 -0
  203. package/dist/jsx/measures.native.js +34 -0
  204. package/dist/jsx/measures.native.js.map +1 -0
  205. package/dist/jsx/recordShape.mjs +74 -0
  206. package/dist/jsx/recordShape.mjs.map +1 -0
  207. package/dist/jsx/recordShape.native.js +115 -0
  208. package/dist/jsx/recordShape.native.js.map +1 -0
  209. package/dist/jsx/report/ReportGrid.mjs +428 -0
  210. package/dist/jsx/report/ReportGrid.mjs.map +1 -0
  211. package/dist/jsx/report/ReportGrid.native.js +510 -0
  212. package/dist/jsx/report/ReportGrid.native.js.map +1 -0
  213. package/dist/jsx/report/ReportViewToolbar.mjs +228 -0
  214. package/dist/jsx/report/ReportViewToolbar.mjs.map +1 -0
  215. package/dist/jsx/report/ReportViewToolbar.native.js +303 -0
  216. package/dist/jsx/report/ReportViewToolbar.native.js.map +1 -0
  217. package/dist/jsx/report/queryReport.mjs +404 -0
  218. package/dist/jsx/report/queryReport.mjs.map +1 -0
  219. package/dist/jsx/report/queryReport.native.js +588 -0
  220. package/dist/jsx/report/queryReport.native.js.map +1 -0
  221. package/dist/jsx/report/queryReportColumns.mjs +105 -0
  222. package/dist/jsx/report/queryReportColumns.mjs.map +1 -0
  223. package/dist/jsx/report/queryReportColumns.native.js +159 -0
  224. package/dist/jsx/report/queryReportColumns.native.js.map +1 -0
  225. package/dist/jsx/report/reportViewModel.mjs +343 -0
  226. package/dist/jsx/report/reportViewModel.mjs.map +1 -0
  227. package/dist/jsx/report/reportViewModel.native.js +657 -0
  228. package/dist/jsx/report/reportViewModel.native.js.map +1 -0
  229. package/dist/jsx/report/savedReports.mjs +112 -0
  230. package/dist/jsx/report/savedReports.mjs.map +1 -0
  231. package/dist/jsx/report/savedReports.native.js +169 -0
  232. package/dist/jsx/report/savedReports.native.js.map +1 -0
  233. package/dist/jsx/report/useFrappeReport.mjs +158 -0
  234. package/dist/jsx/report/useFrappeReport.mjs.map +1 -0
  235. package/dist/jsx/report/useFrappeReport.native.js +214 -0
  236. package/dist/jsx/report/useFrappeReport.native.js.map +1 -0
  237. package/dist/jsx/report/useQueryReport.mjs +176 -0
  238. package/dist/jsx/report/useQueryReport.mjs.map +1 -0
  239. package/dist/jsx/report/useQueryReport.native.js +233 -0
  240. package/dist/jsx/report/useQueryReport.native.js.map +1 -0
  241. package/dist/jsx/useFrappeForm.mjs +533 -0
  242. package/dist/jsx/useFrappeForm.mjs.map +1 -0
  243. package/dist/jsx/useFrappeForm.native.js +714 -0
  244. package/dist/jsx/useFrappeForm.native.js.map +1 -0
  245. package/package.json +16 -16
  246. package/src/FrappeCalendar.tsx +8 -2
  247. package/src/FrappeForm.stories.tsx +52 -0
  248. package/src/FrappeForm.tsx +176 -565
  249. package/src/FrappeListView.cards.stories.tsx +3 -6
  250. package/src/FrappeListView.tsx +15 -55
  251. package/src/FrappeReportBuilder.stories.tsx +34 -7
  252. package/src/FrappeReportBuilder.tsx +790 -380
  253. package/src/FrappeReportView.spec.tsx +10 -6
  254. package/src/FrappeReportView.stories.tsx +20 -1
  255. package/src/FrappeReportView.tsx +89 -415
  256. package/src/dependsOn.ts +4 -1
  257. package/src/fields/shared/EditorPreviewPanes.tsx +2 -2
  258. package/src/formEngine/docPermissions.spec.ts +36 -1
  259. package/src/formEngine/docPermissions.ts +34 -0
  260. package/src/formEngine/index.ts +8 -1
  261. package/src/frappeRemainder.designLaw.spec.ts +9 -1
  262. package/src/frappeRoutes.spec.tsx +9 -0
  263. package/src/frappeViews.designLaw.spec.ts +15 -2
  264. package/src/guestFallback.spec.tsx +236 -0
  265. package/src/index.ts +117 -16
  266. package/src/liveErrors.spec.ts +10 -0
  267. package/src/liveErrors.ts +16 -3
  268. package/src/measures.ts +11 -0
  269. package/src/recordShape.spec.ts +100 -0
  270. package/src/recordShape.ts +133 -0
  271. package/src/report/ReportGrid.spec.tsx +175 -0
  272. package/src/report/ReportGrid.tsx +530 -0
  273. package/src/report/ReportViewToolbar.spec.tsx +90 -0
  274. package/src/report/ReportViewToolbar.tsx +314 -0
  275. package/src/report/queryReport.spec.ts +483 -0
  276. package/src/report/queryReport.ts +722 -0
  277. package/src/report/queryReportColumns.tsx +123 -0
  278. package/src/report/reportViewModel.spec.ts +393 -0
  279. package/src/report/reportViewModel.ts +617 -0
  280. package/src/report/savedReports.ts +172 -0
  281. package/src/report/seam.spec.ts +216 -0
  282. package/src/report/useFrappeReport.ts +241 -0
  283. package/src/report/useQueryReport.spec.tsx +131 -0
  284. package/src/report/useQueryReport.ts +309 -0
  285. package/src/useFrappeForm.spec.tsx +209 -0
  286. package/src/useFrappeForm.ts +778 -0
  287. package/types/FrappeCalendar.d.ts.map +1 -1
  288. package/types/FrappeForm.d.ts +21 -1
  289. package/types/FrappeForm.d.ts.map +1 -1
  290. package/types/FrappeListView.d.ts.map +1 -1
  291. package/types/FrappeReportBuilder.d.ts +66 -16
  292. package/types/FrappeReportBuilder.d.ts.map +1 -1
  293. package/types/FrappeReportView.d.ts +9 -127
  294. package/types/FrappeReportView.d.ts.map +1 -1
  295. package/types/dependsOn.d.ts.map +1 -1
  296. package/types/formEngine/docPermissions.d.ts +14 -0
  297. package/types/formEngine/docPermissions.d.ts.map +1 -1
  298. package/types/formEngine/index.d.ts +1 -1
  299. package/types/formEngine/index.d.ts.map +1 -1
  300. package/types/index.d.ts +15 -3
  301. package/types/index.d.ts.map +1 -1
  302. package/types/liveErrors.d.ts +9 -1
  303. package/types/liveErrors.d.ts.map +1 -1
  304. package/types/measures.d.ts +3 -0
  305. package/types/measures.d.ts.map +1 -0
  306. package/types/recordShape.d.ts +45 -0
  307. package/types/recordShape.d.ts.map +1 -0
  308. package/types/report/ReportGrid.d.ts +20 -0
  309. package/types/report/ReportGrid.d.ts.map +1 -0
  310. package/types/report/ReportViewToolbar.d.ts +31 -0
  311. package/types/report/ReportViewToolbar.d.ts.map +1 -0
  312. package/types/report/queryReport.d.ts +181 -0
  313. package/types/report/queryReport.d.ts.map +1 -0
  314. package/types/report/queryReportColumns.d.ts +12 -0
  315. package/types/report/queryReportColumns.d.ts.map +1 -0
  316. package/types/report/reportViewModel.d.ts +146 -0
  317. package/types/report/reportViewModel.d.ts.map +1 -0
  318. package/types/report/savedReports.d.ts +27 -0
  319. package/types/report/savedReports.d.ts.map +1 -0
  320. package/types/report/useFrappeReport.d.ts +60 -0
  321. package/types/report/useFrappeReport.d.ts.map +1 -0
  322. package/types/report/useQueryReport.d.ts +37 -0
  323. package/types/report/useQueryReport.d.ts.map +1 -0
  324. package/types/useFrappeForm.d.ts +142 -0
  325. package/types/useFrappeForm.d.ts.map +1 -0
@@ -14,8 +14,10 @@
14
14
  * server-appended total row (`add_total_row`) is a plain array — rows are
15
15
  * therefore re-keyed defensively here (`normalizeReportRows`).
16
16
  *
17
- * Transport rides the existing whitelisted-method caller (`CallModule` from
18
- * `@multiplatform.one/frappe`) — no bespoke fetch path.
17
+ * The payload, filter and column shapes are the one query-report model in
18
+ * `./report/queryReport` (MPO-15, GL-28), and the transport is
19
+ * `./report/useFrappeReport`, the same caller the desk's QueryReportScreen
20
+ * runs its reports through. This file owns rendering only.
19
21
  *
20
22
  * Filter bar: built from the report's DB-defined filters (the Report doc's
21
23
  * `filters` child table, fetched via `frappe.desk.query_report.get_script`).
@@ -37,8 +39,7 @@
37
39
  * (no new export machinery), capability-gated like FrappeReportBuilder (B12):
38
40
  * hidden where the web download pipeline does not exist.
39
41
  */
40
- import { AsyncDebouncer, CallModule, HttpClient, type AuthConfig } from "@multiplatform.one/frappe";
41
- import { AsyncBoundary } from "@multiplatform.one/components";
42
+ import { AsyncBoundary, EmptyState } from "@multiplatform.one/components";
42
43
  import { Button, DatePicker, Spinner, formCommonColors } from "@multiplatform.one/forms";
43
44
  import {
44
45
  DataTable,
@@ -57,177 +58,54 @@ import { useFrappeConfig } from "./FrappeProvider";
57
58
  import { Check } from "./fields/Check";
58
59
  import { Data } from "./fields/Data";
59
60
  import { Select } from "./fields/Select";
60
- import { toLiveLoadError } from "./liveErrors";
61
-
62
- // ---------------------------------------------------------------------------
63
- // Types
64
- // ---------------------------------------------------------------------------
65
-
66
- /** A report column definition as returned by `query_report.run`. */
67
- export interface FrappeReportColumn {
68
- fieldname: string;
69
- label: string;
61
+ import { isPermissionError, refusalReason, toLiveLoadError } from "./liveErrors";
62
+ import {
63
+ humanizeFrappeError,
64
+ normalizeFilterMeta,
65
+ scrubFieldname,
66
+ type FrappeReportColumn,
67
+ type FrappeReportFilterDef,
68
+ type FrappeReportRow,
69
+ type FrappeReportValues,
70
+ type QueryReportFilterMeta,
71
+ } from "./report/queryReport";
72
+ import {
73
+ useFrappeReport,
74
+ type FrappeReportConnection,
75
+ type FrappeReportFixture,
76
+ } from "./report/useFrappeReport";
77
+
78
+ export {
79
+ compactFilterValues,
80
+ normalizeReportColumn,
81
+ normalizeReportPayload,
82
+ normalizeReportRows,
83
+ scrubFieldname,
84
+ type FrappeReportColumn,
85
+ type FrappeReportFilterDef,
86
+ type FrappeReportPayload,
87
+ type FrappeReportRow,
88
+ type FrappeReportRunResponse,
89
+ type FrappeReportValues,
90
+ } from "./report/queryReport";
91
+ export {
92
+ useFrappeReport,
93
+ type FrappeReportConnection,
94
+ type FrappeReportFixture,
95
+ type UseFrappeReportOptions,
96
+ type UseFrappeReportResult,
97
+ } from "./report/useFrappeReport";
98
+
99
+ /** A column as the render helpers take it: normalized, or with the wire's string width. */
100
+ type RenderableReportColumn = Omit<FrappeReportColumn, "fieldtype" | "width"> & {
70
101
  fieldtype?: string;
71
- /** Link/Select target or option list (Frappe semantics per fieldtype). */
72
- options?: string;
73
- /** Column width in px (the server sends numbers or numeric strings). */
74
102
  width?: number | string;
75
- precision?: number;
76
- }
77
-
78
- /** One row of report data, keyed by column fieldname. */
79
- export type FrappeReportRow = Record<string, unknown>;
103
+ };
80
104
 
81
105
  // Generic JSX (`<DataTable<FrappeReportRow> …/>`) breaks one-dev's source
82
106
  // annotation transform; instantiate the type argument outside JSX instead.
83
107
  const ReportDataTable = DataTable<FrappeReportRow>;
84
108
 
85
- /** Current filter values, keyed by filter fieldname. */
86
- export type FrappeReportValues = Record<string, unknown>;
87
-
88
- /**
89
- * A report filter definition — the Report doctype's `filters` child table
90
- * shape (Report Filter rows), also the shape of the `filterFields` prop.
91
- */
92
- export interface FrappeReportFilterDef {
93
- fieldname: string;
94
- label: string;
95
- /** "Data" | "Select" | "Date" | "Datetime" | "Check" | "Int" | … */
96
- fieldtype: string;
97
- /** Newline-separated choices for Select, Link target for Link. */
98
- options?: string;
99
- default?: unknown;
100
- mandatory?: number | boolean;
101
- wildcard_filter?: number | boolean;
102
- }
103
-
104
- /** Raw `frappe.desk.query_report.run` response body (`message`). */
105
- export interface FrappeReportRunResponse {
106
- columns?: Array<FrappeReportColumn | string>;
107
- result?: Array<FrappeReportRow | unknown[]>;
108
- message?: string | string[] | null;
109
- chart?: unknown;
110
- report_summary?: unknown;
111
- add_total_row?: number | boolean;
112
- skip_total_row?: number | boolean;
113
- status?: string | null;
114
- execution_time?: number;
115
- /**
116
- * Fixture extension: report filter definitions. The live endpoint does not
117
- * include filters in `run`; fixtures may carry them so fixture-backed
118
- * stories/tests get a filter bar without a second fixture surface.
119
- */
120
- filters?: FrappeReportFilterDef[];
121
- }
122
-
123
- /** Normalized report payload consumed by the table. */
124
- export interface FrappeReportPayload {
125
- columns: FrappeReportColumn[];
126
- rows: FrappeReportRow[];
127
- /** Server-side report message (already user-facing). */
128
- message?: string;
129
- /** True when the last row is the server-computed total row. */
130
- addTotalRow: boolean;
131
- /** Fixture-provided filter definitions (see FrappeReportRunResponse). */
132
- filters?: FrappeReportFilterDef[];
133
- /** Untouched response for chart / report_summary consumers. */
134
- raw: FrappeReportRunResponse;
135
- }
136
-
137
- /** Fixture payload or loader — renders the report without any network. */
138
- export type FrappeReportFixture =
139
- | FrappeReportRunResponse
140
- | ((args: {
141
- reportName: string;
142
- filters: FrappeReportValues;
143
- }) => FrappeReportRunResponse | Promise<FrappeReportRunResponse>);
144
-
145
- // ---------------------------------------------------------------------------
146
- // Pure helpers (unit-tested)
147
- // ---------------------------------------------------------------------------
148
-
149
- /** Frappe's `scrub`: label → fieldname (lowercase, spaces/dashes → "_"). */
150
- export function scrubFieldname(label: string): string {
151
- return label
152
- .trim()
153
- .replace(/[\s-]+/g, "_")
154
- .toLowerCase();
155
- }
156
-
157
- /**
158
- * Normalize a report column to the dict shape. Mirrors the server's
159
- * `get_column_as_dict`: legacy string columns are
160
- * `"Label:Fieldtype/Options:Width"`, dict columns may lack `fieldname`.
161
- */
162
- export function normalizeReportColumn(col: FrappeReportColumn | string): FrappeReportColumn {
163
- if (typeof col === "string") {
164
- const parts = col.split(":");
165
- const label = parts[0] ?? "";
166
- const out: FrappeReportColumn = { label, fieldname: scrubFieldname(label) };
167
- if (parts.length > 1 && parts[1]) {
168
- const [fieldtype, options] = parts[1].split("/");
169
- if (fieldtype) out.fieldtype = fieldtype;
170
- if (options) out.options = options;
171
- }
172
- if (parts.length === 3 && parts[2]) out.width = parts[2];
173
- return out;
174
- }
175
- return {
176
- ...col,
177
- fieldname: col.fieldname || scrubFieldname(col.label ?? ""),
178
- label: col.label ?? col.fieldname,
179
- };
180
- }
181
-
182
- /**
183
- * Re-key report rows by column fieldname. The server normalizes rows to
184
- * dicts, but the appended total row (and legacy prepared payloads) are
185
- * arrays — both shapes must render (mixed within one result).
186
- */
187
- export function normalizeReportRows(
188
- columns: FrappeReportColumn[],
189
- result: Array<FrappeReportRow | unknown[]> | undefined,
190
- ): FrappeReportRow[] {
191
- if (!result?.length) return [];
192
- return result.map((row) => {
193
- if (Array.isArray(row)) {
194
- const obj: FrappeReportRow = {};
195
- columns.forEach((col, idx) => {
196
- obj[col.fieldname] = row[idx];
197
- });
198
- return obj;
199
- }
200
- return row;
201
- });
202
- }
203
-
204
- /** Normalize the raw `run` response into the payload the table consumes. */
205
- export function normalizeReportPayload(raw: FrappeReportRunResponse): FrappeReportPayload {
206
- const columns = (raw.columns ?? []).map(normalizeReportColumn);
207
- const rows = normalizeReportRows(columns, raw.result);
208
- const message = Array.isArray(raw.message)
209
- ? raw.message.filter(Boolean).join(" ")
210
- : (raw.message ?? undefined);
211
- return {
212
- columns,
213
- rows,
214
- message: message || undefined,
215
- addTotalRow: Boolean(raw.add_total_row) && !raw.skip_total_row,
216
- filters: raw.filters,
217
- raw,
218
- };
219
- }
220
-
221
- /** Drop empty filter values so cleared fields never reach the API. */
222
- export function compactFilterValues(values: FrappeReportValues | undefined): FrappeReportValues {
223
- const out: FrappeReportValues = {};
224
- for (const [key, value] of Object.entries(values ?? {})) {
225
- if (value === undefined || value === null || value === "") continue;
226
- out[key] = value;
227
- }
228
- return out;
229
- }
230
-
231
109
  /** Parse a Select column/filter option string (newline-separated). */
232
110
  function parseSelectOptions(options: string | undefined): Array<{ label: string; value: string }> {
233
111
  return (options ?? "")
@@ -242,7 +120,7 @@ function parseSelectOptions(options: string | undefined): Array<{ label: string;
242
120
  * forms `FieldDisplay` pipeline formats the value and DG-TBL-01
243
121
  * align-by-type defaults apply (numerics → right, Check → center).
244
122
  */
245
- export function reportFieldtypeToTableField(column: FrappeReportColumn): {
123
+ export function reportFieldtypeToTableField(column: RenderableReportColumn): {
246
124
  field: DataTableField;
247
125
  fieldProps?: Record<string, unknown>;
248
126
  } {
@@ -283,7 +161,7 @@ export function reportFieldtypeToTableField(column: FrappeReportColumn): {
283
161
  * renderers included (DataTable's aligned cell wrapper reads it).
284
162
  */
285
163
  export function reportColumnToDataTableColumn(
286
- column: FrappeReportColumn,
164
+ column: RenderableReportColumn,
287
165
  ): DataTableColumn<FrappeReportRow> {
288
166
  const { field, fieldProps } = reportFieldtypeToTableField(column);
289
167
  const width = column.width != null ? Number(column.width) : undefined;
@@ -331,237 +209,19 @@ function canDownloadFiles(): boolean {
331
209
  );
332
210
  }
333
211
 
334
- // ---------------------------------------------------------------------------
335
- // Data hook
336
- // ---------------------------------------------------------------------------
337
-
338
- export interface FrappeReportConnection {
339
- baseURL: string;
340
- auth?: {
341
- useToken?: boolean;
342
- token?: string | (() => string | Promise<string>);
343
- type?: string;
344
- };
345
- }
346
-
347
- // One whitelisted-method caller per connection — report views sharing a
348
- // bench share it (same pattern as useFrappeAggregate's DbModule cache).
349
- const callCache = new Map<string, CallModule>();
350
-
351
- function getCall(connection: FrappeReportConnection): CallModule {
352
- const key = `${connection.baseURL}:${connection.auth?.useToken ? "t" : ""}:${connection.auth?.token ?? ""}:${connection.auth?.type ?? ""}`;
353
- let call = callCache.get(key);
354
- if (!call) {
355
- const authConfig: AuthConfig | undefined = connection.auth
356
- ? {
357
- useToken: connection.auth.useToken,
358
- token: connection.auth.token,
359
- type: connection.auth.type as AuthConfig["type"],
360
- }
361
- : undefined;
362
- call = new CallModule(new HttpClient(connection.baseURL, authConfig));
363
- callCache.set(key, call);
364
- }
365
- return call;
366
- }
367
-
368
- const DEFAULT_DEBOUNCE_MS = 400;
369
-
370
- export interface UseFrappeReportOptions {
371
- reportName: string;
372
- /** Current filter values (already compacted values are fine too). */
373
- filters?: FrappeReportValues;
374
- /** Fixture payload / loader — no network is touched when set. */
375
- fixture?: FrappeReportFixture;
376
- /**
377
- * Fetch the report's DB-defined filter definitions (`get_script`).
378
- * Off when the consumer supplies `filterFields` explicitly.
379
- */
380
- fetchFilterDefs?: boolean;
381
- /** Bypass the prepared-report cache and execute the report now. */
382
- ignorePreparedReport?: boolean;
383
- /** Debounce for filter-change refetches in ms (default 400). */
384
- debounceMs?: number;
385
- enabled?: boolean;
386
- }
387
-
388
- export interface UseFrappeReportResult {
389
- payload: FrappeReportPayload | undefined;
390
- /** DB-defined filter defs (`get_script`); undefined while unknown. */
391
- scriptFilters: FrappeReportFilterDef[] | undefined;
392
- /** First run in flight — nothing to show yet. */
393
- isLoading: boolean;
394
- /** Any run in flight (filter-change / refresh refetches included). */
395
- isFetching: boolean;
396
- error: Error | undefined;
397
- /** Immediate re-run (skips the debounce window). */
398
- refresh: () => void;
399
- }
400
-
401
- /**
402
- * Run a named server-side report (`frappe.desk.query_report.run`) with the
403
- * given filters. Filter-value changes are debounced; report changes and
404
- * explicit `refresh()` run immediately.
405
- */
406
- export function useFrappeReport(
407
- connection: FrappeReportConnection | undefined,
408
- {
409
- reportName,
410
- filters,
411
- fixture,
412
- fetchFilterDefs = false,
413
- ignorePreparedReport = false,
414
- debounceMs = DEFAULT_DEBOUNCE_MS,
415
- enabled = true,
416
- }: UseFrappeReportOptions,
417
- ): UseFrappeReportResult {
418
- const isEnabled = enabled && !!reportName && (!!connection || !!fixture);
419
-
420
- const [payload, setPayload] = useState<FrappeReportPayload | undefined>(undefined);
421
- const [scriptFilters, setScriptFilters] = useState<FrappeReportFilterDef[] | undefined>(
422
- undefined,
423
- );
424
- const [isLoading, setIsLoading] = useState(isEnabled);
425
- const [isFetching, setIsFetching] = useState(false);
426
- const [error, setError] = useState<Error | undefined>(undefined);
427
-
428
- const compactedFilters = useMemo(() => compactFilterValues(filters), [filters]);
429
- const filtersKey = JSON.stringify(compactedFilters);
430
- const runKey = JSON.stringify([
431
- connection?.baseURL,
432
- !!fixture,
433
- reportName,
434
- filtersKey,
435
- ignorePreparedReport,
436
- ]);
437
-
438
- const fetchSeq = useRef(0);
439
- const argsRef = useRef({ reportName, filters: compactedFilters, fixture, ignorePreparedReport });
440
- argsRef.current = { reportName, filters: compactedFilters, fixture, ignorePreparedReport };
441
- const connectionRef = useRef(connection);
442
- connectionRef.current = connection;
443
-
444
- const runFetch = useCallback(async () => {
445
- const {
446
- reportName: name,
447
- filters: values,
448
- fixture: fx,
449
- ignorePreparedReport: skipPrepared,
450
- } = argsRef.current;
451
- const conn = connectionRef.current;
452
- if (!name || (!conn && !fx)) return;
453
- const seq = ++fetchSeq.current;
454
- setIsFetching(true);
455
- try {
456
- let raw: FrappeReportRunResponse | undefined;
457
- if (fx) {
458
- raw = typeof fx === "function" ? await fx({ reportName: name, filters: values }) : fx;
459
- } else if (conn) {
460
- const res = await getCall(conn).post<{ message: FrappeReportRunResponse }>(
461
- "frappe.desk.query_report.run",
462
- {
463
- report_name: name,
464
- filters: values,
465
- ignore_prepared_report: skipPrepared ? 1 : 0,
466
- // Desk parity: only let the server substitute saved custom
467
- // filters when the caller sent no filter values at all.
468
- are_default_filters: Object.keys(values).length ? 0 : 1,
469
- },
470
- );
471
- raw = res.payload.message;
472
- }
473
- if (seq !== fetchSeq.current) return; // stale response — a newer run won
474
- setPayload(normalizeReportPayload(raw ?? {}));
475
- setError(undefined);
476
- } catch (err) {
477
- if (seq !== fetchSeq.current) return;
478
- setError(err instanceof Error ? err : new Error(String(err)));
479
- } finally {
480
- if (seq === fetchSeq.current) {
481
- setIsLoading(false);
482
- setIsFetching(false);
483
- }
484
- }
485
- }, []);
486
-
487
- // Debouncer coalescing filter keystrokes into one refetch.
488
- const debouncerRef = useRef<AsyncDebouncer<() => Promise<void>> | undefined>(undefined);
489
- if (!debouncerRef.current) {
490
- debouncerRef.current = new AsyncDebouncer(() => runFetch(), {
491
- wait: debounceMs,
492
- });
493
- }
494
- useEffect(() => {
495
- debouncerRef.current?.setOptions({ wait: debounceMs });
496
- }, [debounceMs]);
497
- useEffect(() => () => debouncerRef.current?.cancel(), []);
498
-
499
- // Report identity changes (and first mount) run immediately; filter-value
500
- // changes ride the debouncer so per-keystroke Data filters cost one run.
501
- // The run key guards actual query changes; captured args ride argsRef.
502
- const lastRunKeyRef = useRef<string | undefined>(undefined);
503
- const lastReportRef = useRef<string | undefined>(undefined);
504
- useEffect(() => {
505
- if (!isEnabled || lastRunKeyRef.current === runKey) return;
506
- lastRunKeyRef.current = runKey;
507
- const reportChanged = lastReportRef.current !== argsRef.current.reportName;
508
- lastReportRef.current = argsRef.current.reportName;
509
- setError(undefined);
510
- if (reportChanged) {
511
- setIsLoading(true);
512
- debouncerRef.current?.cancel();
513
- void runFetch();
514
- } else if (debounceMs <= 0) {
515
- void runFetch();
516
- } else {
517
- void debouncerRef.current?.maybeExecute();
518
- }
519
- }, [isEnabled, runKey, debounceMs, runFetch]);
520
-
521
- // DB-defined filter definitions (Report doc `filters` child table) via
522
- // get_script — live mode only; fixtures carry defs on the payload itself.
523
- useEffect(() => {
524
- if (!isEnabled || !fetchFilterDefs || fixture || !connection) {
525
- return;
526
- }
527
- let cancelled = false;
528
- void (async () => {
529
- try {
530
- const res = await getCall(connection).get<{
531
- message: { filters?: FrappeReportFilterDef[] };
532
- }>("frappe.desk.query_report.get_script", { report_name: reportName });
533
- if (!cancelled) setScriptFilters(res.payload.message?.filters ?? []);
534
- } catch {
535
- // Filter defs are progressive enhancement — a failing get_script
536
- // must not take the report down (run() surfaces real errors).
537
- if (!cancelled) setScriptFilters([]);
538
- }
539
- })();
540
- return () => {
541
- cancelled = true;
542
- };
543
- }, [isEnabled, fetchFilterDefs, fixture, connection, reportName]);
544
-
545
- const refresh = useCallback(() => {
546
- debouncerRef.current?.cancel();
547
- void runFetch();
548
- }, [runFetch]);
549
-
550
- return { payload, scriptFilters, isLoading, isFetching, error, refresh };
551
- }
552
-
553
212
  // ---------------------------------------------------------------------------
554
213
  // Filter bar
555
214
  // ---------------------------------------------------------------------------
556
215
 
557
216
  interface ReportFilterFieldProps {
558
- def: FrappeReportFilterDef;
217
+ def: QueryReportFilterMeta;
559
218
  value: unknown;
560
219
  onChange: (value: unknown) => void;
561
220
  }
562
221
 
563
222
  function ReportFilterField({ def, value, onChange }: ReportFilterFieldProps) {
564
223
  const { t } = useTranslation();
224
+ const label = def.label || def.fieldname;
565
225
  switch (def.fieldtype) {
566
226
  case "Select": {
567
227
  const options = parseSelectOptions(def.options).map((opt) =>
@@ -569,7 +229,7 @@ function ReportFilterField({ def, value, onChange }: ReportFilterFieldProps) {
569
229
  );
570
230
  return (
571
231
  <Select
572
- label={def.label}
232
+ label={label}
573
233
  compact
574
234
  options={options}
575
235
  value={value == null ? "" : String(value)}
@@ -581,7 +241,7 @@ function ReportFilterField({ def, value, onChange }: ReportFilterFieldProps) {
581
241
  case "Datetime":
582
242
  return (
583
243
  <DatePicker
584
- label={def.label}
244
+ label={label}
585
245
  compact
586
246
  value={value == null ? null : String(value)}
587
247
  onChange={(date) => onChange(date ? formatCalendarDate(date) : "")}
@@ -590,7 +250,7 @@ function ReportFilterField({ def, value, onChange }: ReportFilterFieldProps) {
590
250
  case "Check":
591
251
  return (
592
252
  <Check
593
- label={def.label}
253
+ label={label}
594
254
  compact
595
255
  value={Boolean(value)}
596
256
  // Wire shape parity with desk: checkboxes travel as 1 / 0.
@@ -601,11 +261,11 @@ function ReportFilterField({ def, value, onChange }: ReportFilterFieldProps) {
601
261
  // Data / Link / Dynamic Link / Int / Float / …: free-text entry.
602
262
  return (
603
263
  <Data
604
- label={def.label}
264
+ label={label}
605
265
  compact
606
266
  value={value == null ? "" : String(value)}
607
267
  onChange={onChange}
608
- placeholder={def.label}
268
+ placeholder={label}
609
269
  />
610
270
  );
611
271
  }
@@ -726,11 +386,14 @@ export function FrappeReportView({
726
386
  },
727
387
  );
728
388
 
729
- // Filter bar definitions: explicit prop > fixture payload > get_script.
389
+ // Filter bar definitions: explicit prop > fixture payload > get_script,
390
+ // normalized through the one filter model (hidden filters apply their
391
+ // defaults and never render, desk parity).
730
392
  const filterDefs = useMemo(
731
- () => filterFields ?? payload?.filters ?? scriptFilters ?? [],
393
+ () => normalizeFilterMeta(filterFields ?? payload?.filters ?? scriptFilters ?? []),
732
394
  [filterFields, payload?.filters, scriptFilters],
733
395
  );
396
+ const shownFilterDefs = useMemo(() => filterDefs.filter((def) => def.hidden !== 1), [filterDefs]);
734
397
 
735
398
  // Seed DB-defined defaults once per report (uncontrolled mode only —
736
399
  // controlled callers own their values).
@@ -741,7 +404,7 @@ export function FrappeReportView({
741
404
  setInternalFilters((prev) => {
742
405
  const seeded: FrappeReportValues = {};
743
406
  for (const def of filterDefs) {
744
- if (def.default != null && def.default !== "" && prev[def.fieldname] == null) {
407
+ if (def.default !== undefined && def.default !== "" && prev[def.fieldname] == null) {
745
408
  seeded[def.fieldname] = def.default;
746
409
  }
747
410
  }
@@ -766,27 +429,32 @@ export function FrappeReportView({
766
429
  );
767
430
 
768
431
  const exportEnabled = showExport && canDownloadFiles();
769
- const hasToolbar = filterDefs.length > 0 || showRefresh || exportEnabled;
432
+ const refused = error !== undefined && isPermissionError(error);
433
+ const refreshShown = showRefresh && !refused;
434
+ const hasToolbar = shownFilterDefs.length > 0 || refreshShown || exportEnabled;
770
435
 
771
436
  if (error && errorRenderer) {
772
437
  return <>{errorRenderer(error)}</>;
773
438
  }
774
439
 
775
- const normalizedError = error
776
- ? toLiveLoadError(error, {
777
- permissionMessage: t("You do not have permission to run {{reportName}}", { reportName }),
778
- genericMessage: t("Error running {{reportName}}", { reportName }),
779
- })
780
- : null;
440
+ const normalizedError =
441
+ error && !refused
442
+ ? toLiveLoadError(error, {
443
+ permissionMessage: t("You do not have permission to run {{reportName}}", { reportName }),
444
+ genericMessage: t("Error running {{reportName}}", { reportName }),
445
+ })
446
+ : null;
781
447
 
782
448
  // Honest states via AsyncBoundary (DG-ST-01: error > loading > empty).
783
- const boundaryState = normalizedError
784
- ? { error: normalizedError }
785
- : isLoading
786
- ? { loading: loading ?? true }
787
- : rows.length === 0
788
- ? { empty: true }
789
- : null;
449
+ const boundaryState = refused
450
+ ? null
451
+ : normalizedError
452
+ ? { error: normalizedError }
453
+ : isLoading
454
+ ? { loading: loading ?? true }
455
+ : rows.length === 0
456
+ ? { empty: true }
457
+ : null;
790
458
 
791
459
  return (
792
460
  <YStack {...knobProps.gap} flex={1} {...stackProps}>
@@ -794,7 +462,7 @@ export function FrappeReportView({
794
462
  bad filter can always be corrected. */}
795
463
  {hasToolbar && (
796
464
  <XStack {...knobProps.gap} alignItems="flex-end" flexWrap="wrap">
797
- {filterDefs.map((def) => (
465
+ {shownFilterDefs.map((def) => (
798
466
  <YStack key={def.fieldname} minWidth={180} maxWidth={280} flexShrink={1}>
799
467
  <ReportFilterField
800
468
  def={def}
@@ -812,7 +480,7 @@ export function FrappeReportView({
812
480
  </Text>
813
481
  </XStack>
814
482
  )}
815
- {showRefresh && (
483
+ {refreshShown && (
816
484
  <Button
817
485
  size="$2"
818
486
  icon={ArrowClockwiseIcon}
@@ -859,7 +527,13 @@ export function FrappeReportView({
859
527
  </Text>
860
528
  )}
861
529
 
862
- {boundaryState ? (
530
+ {refused ? (
531
+ <EmptyState
532
+ testID="frappe-report-not-permitted"
533
+ title={t("You can't run {{reportName}}", { reportName })}
534
+ description={refusalReason(humanizeFrappeError(error))}
535
+ />
536
+ ) : boundaryState ? (
863
537
  <AsyncBoundary
864
538
  layout="table"
865
539
  errorTitle={t("Error running {{reportName}}", { reportName })}
package/src/dependsOn.ts CHANGED
@@ -164,7 +164,10 @@ const COERCE_FUNCTIONS: Record<string, (value: unknown) => unknown> = {
164
164
 
165
165
  class Parser {
166
166
  private pos = 0;
167
- constructor(private readonly tokens: Token[]) {}
167
+ private readonly tokens: Token[];
168
+ constructor(tokens: Token[]) {
169
+ this.tokens = tokens;
170
+ }
168
171
 
169
172
  parse(): DependsEvaluator | undefined {
170
173
  const node = this.parseOr();
@@ -9,10 +9,10 @@
9
9
  * a narrow column stays tabbed on a wide screen.
10
10
  */
11
11
 
12
- import { Tabs } from "@multiplatform.one/components";
12
+ import { Tabs, ScrollView } from "@multiplatform.one/components";
13
13
  import { layoutBreakpoints, useResolvedKnobs } from "@multiplatform.one/theme";
14
14
  import { useState, type ReactNode } from "react";
15
- import { ScrollView, XStack, YStack } from "tamagui";
15
+ import { XStack, YStack } from "tamagui";
16
16
 
17
17
  export interface PreviewSurfaceProps {
18
18
  compact?: boolean;