@multiplatform.one/backoffice 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 (269) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/desk/DeskSurface.native.js.map +1 -1
  3. package/dist/cjs/form/DocFormScreen.cjs +167 -224
  4. package/dist/cjs/form/DocFormScreen.native.js +182 -259
  5. package/dist/cjs/form/DocFormScreen.native.js.map +1 -1
  6. package/dist/cjs/i18n/en.cjs +1 -0
  7. package/dist/cjs/i18n/en.native.js +1 -0
  8. package/dist/cjs/i18n/en.native.js.map +1 -1
  9. package/dist/cjs/list/ListBulkActionsBar.cjs +30 -18
  10. package/dist/cjs/list/ListBulkActionsBar.native.js +43 -31
  11. package/dist/cjs/list/ListBulkActionsBar.native.js.map +1 -1
  12. package/dist/cjs/list/sidebar-section.cjs +15 -7
  13. package/dist/cjs/list/sidebar-section.native.js +16 -7
  14. package/dist/cjs/list/sidebar-section.native.js.map +1 -1
  15. package/dist/cjs/report/DoctypeReportView.cjs +20 -374
  16. package/dist/cjs/report/DoctypeReportView.native.js +23 -455
  17. package/dist/cjs/report/DoctypeReportView.native.js.map +1 -1
  18. package/dist/cjs/report/QueryReportScreen.cjs +33 -23
  19. package/dist/cjs/report/QueryReportScreen.native.js +33 -23
  20. package/dist/cjs/report/QueryReportScreen.native.js.map +1 -1
  21. package/dist/cjs/report/queryReportColumns.cjs +3 -105
  22. package/dist/cjs/report/queryReportColumns.native.js +2 -129
  23. package/dist/cjs/report/queryReportColumns.native.js.map +1 -1
  24. package/dist/cjs/report/queryReportFilterBar.cjs +3 -4
  25. package/dist/cjs/report/queryReportFilterBar.native.js +3 -4
  26. package/dist/cjs/report/queryReportFilterBar.native.js.map +1 -1
  27. package/dist/cjs/report/queryReportUrlState.cjs +2 -2
  28. package/dist/cjs/report/queryReportUrlState.native.js +2 -2
  29. package/dist/cjs/report/queryReportUrlState.native.js.map +1 -1
  30. package/dist/cjs/report/report-grid.cjs +2 -426
  31. package/dist/cjs/report/report-grid.native.js +1 -479
  32. package/dist/cjs/report/report-grid.native.js.map +1 -1
  33. package/dist/cjs/report/report-toolbar.cjs +2 -228
  34. package/dist/cjs/report/report-toolbar.native.js +1 -274
  35. package/dist/cjs/report/report-toolbar.native.js.map +1 -1
  36. package/dist/cjs/report/reportShapes.cjs +12 -383
  37. package/dist/cjs/report/reportShapes.native.js +12 -501
  38. package/dist/cjs/report/reportShapes.native.js.map +1 -1
  39. package/dist/cjs/report/reportViewModel.cjs +20 -360
  40. package/dist/cjs/report/reportViewModel.native.js +19 -627
  41. package/dist/cjs/report/reportViewModel.native.js.map +1 -1
  42. package/dist/cjs/report/savedReports.cjs +2 -106
  43. package/dist/cjs/report/savedReports.native.js +1 -132
  44. package/dist/cjs/report/savedReports.native.js.map +1 -1
  45. package/dist/cjs/report/useQueryReport.cjs +11 -219
  46. package/dist/cjs/report/useQueryReport.native.js +11 -244
  47. package/dist/cjs/report/useQueryReport.native.js.map +1 -1
  48. package/dist/cjs/shared/measures.cjs +3 -5
  49. package/dist/cjs/shared/measures.native.js +3 -5
  50. package/dist/cjs/shared/measures.native.js.map +1 -1
  51. package/dist/cjs/views/ReportView.cjs +3 -256
  52. package/dist/cjs/views/ReportView.native.js +3 -382
  53. package/dist/cjs/views/ReportView.native.js.map +1 -1
  54. package/dist/cjs/views/report-controls.cjs +6 -6
  55. package/dist/cjs/views/report-controls.native.js +6 -6
  56. package/dist/cjs/views/report-controls.native.js.map +1 -1
  57. package/dist/esm/desk/DeskSurface.mjs.map +1 -1
  58. package/dist/esm/desk/DeskSurface.native.js.map +1 -1
  59. package/dist/esm/form/DocFormScreen.mjs +169 -226
  60. package/dist/esm/form/DocFormScreen.mjs.map +1 -1
  61. package/dist/esm/form/DocFormScreen.native.js +184 -261
  62. package/dist/esm/form/DocFormScreen.native.js.map +1 -1
  63. package/dist/esm/i18n/en.mjs +1 -0
  64. package/dist/esm/i18n/en.mjs.map +1 -1
  65. package/dist/esm/i18n/en.native.js +1 -0
  66. package/dist/esm/i18n/en.native.js.map +1 -1
  67. package/dist/esm/list/ListBulkActionsBar.mjs +31 -19
  68. package/dist/esm/list/ListBulkActionsBar.mjs.map +1 -1
  69. package/dist/esm/list/ListBulkActionsBar.native.js +37 -25
  70. package/dist/esm/list/ListBulkActionsBar.native.js.map +1 -1
  71. package/dist/esm/list/sidebar-section.mjs +16 -8
  72. package/dist/esm/list/sidebar-section.mjs.map +1 -1
  73. package/dist/esm/list/sidebar-section.native.js +17 -8
  74. package/dist/esm/list/sidebar-section.native.js.map +1 -1
  75. package/dist/esm/report/DoctypeReportView.mjs +21 -375
  76. package/dist/esm/report/DoctypeReportView.mjs.map +1 -1
  77. package/dist/esm/report/DoctypeReportView.native.js +24 -456
  78. package/dist/esm/report/DoctypeReportView.native.js.map +1 -1
  79. package/dist/esm/report/QueryReportScreen.mjs +26 -16
  80. package/dist/esm/report/QueryReportScreen.mjs.map +1 -1
  81. package/dist/esm/report/QueryReportScreen.native.js +26 -16
  82. package/dist/esm/report/QueryReportScreen.native.js.map +1 -1
  83. package/dist/esm/report/queryReportColumns.mjs +1 -103
  84. package/dist/esm/report/queryReportColumns.mjs.map +1 -1
  85. package/dist/esm/report/queryReportColumns.native.js +1 -117
  86. package/dist/esm/report/queryReportColumns.native.js.map +1 -1
  87. package/dist/esm/report/queryReportFilterBar.mjs +1 -2
  88. package/dist/esm/report/queryReportFilterBar.mjs.map +1 -1
  89. package/dist/esm/report/queryReportFilterBar.native.js +1 -2
  90. package/dist/esm/report/queryReportFilterBar.native.js.map +1 -1
  91. package/dist/esm/report/queryReportUrlState.mjs +1 -1
  92. package/dist/esm/report/queryReportUrlState.native.js +1 -1
  93. package/dist/esm/report/report-grid.mjs +1 -425
  94. package/dist/esm/report/report-grid.mjs.map +1 -1
  95. package/dist/esm/report/report-grid.native.js +1 -468
  96. package/dist/esm/report/report-grid.native.js.map +1 -1
  97. package/dist/esm/report/report-toolbar.mjs +2 -228
  98. package/dist/esm/report/report-toolbar.mjs.map +1 -1
  99. package/dist/esm/report/report-toolbar.native.js +2 -264
  100. package/dist/esm/report/report-toolbar.native.js.map +1 -1
  101. package/dist/esm/report/reportShapes.mjs +2 -373
  102. package/dist/esm/report/reportShapes.mjs.map +1 -1
  103. package/dist/esm/report/reportShapes.native.js +2 -491
  104. package/dist/esm/report/reportShapes.native.js.map +1 -1
  105. package/dist/esm/report/reportViewModel.mjs +2 -342
  106. package/dist/esm/report/reportViewModel.mjs.map +1 -1
  107. package/dist/esm/report/reportViewModel.native.js +2 -610
  108. package/dist/esm/report/reportViewModel.native.js.map +1 -1
  109. package/dist/esm/report/savedReports.mjs +1 -105
  110. package/dist/esm/report/savedReports.mjs.map +1 -1
  111. package/dist/esm/report/savedReports.native.js +1 -132
  112. package/dist/esm/report/savedReports.native.js.map +1 -1
  113. package/dist/esm/report/useQueryReport.mjs +2 -210
  114. package/dist/esm/report/useQueryReport.mjs.map +1 -1
  115. package/dist/esm/report/useQueryReport.native.js +2 -235
  116. package/dist/esm/report/useQueryReport.native.js.map +1 -1
  117. package/dist/esm/shared/measures.mjs +1 -3
  118. package/dist/esm/shared/measures.mjs.map +1 -1
  119. package/dist/esm/shared/measures.native.js +1 -3
  120. package/dist/esm/shared/measures.native.js.map +1 -1
  121. package/dist/esm/views/ReportView.mjs +3 -256
  122. package/dist/esm/views/ReportView.mjs.map +1 -1
  123. package/dist/esm/views/ReportView.native.js +3 -382
  124. package/dist/esm/views/ReportView.native.js.map +1 -1
  125. package/dist/esm/views/report-controls.mjs +3 -3
  126. package/dist/esm/views/report-controls.mjs.map +1 -1
  127. package/dist/esm/views/report-controls.native.js +3 -3
  128. package/dist/esm/views/report-controls.native.js.map +1 -1
  129. package/dist/jsx/desk/DeskSurface.mjs.map +1 -1
  130. package/dist/jsx/desk/DeskSurface.native.js.map +1 -1
  131. package/dist/jsx/form/DocFormScreen.mjs +169 -226
  132. package/dist/jsx/form/DocFormScreen.mjs.map +1 -1
  133. package/dist/jsx/form/DocFormScreen.native.js +182 -259
  134. package/dist/jsx/form/DocFormScreen.native.js.map +1 -1
  135. package/dist/jsx/i18n/en.mjs +1 -0
  136. package/dist/jsx/i18n/en.mjs.map +1 -1
  137. package/dist/jsx/i18n/en.native.js +1 -0
  138. package/dist/jsx/i18n/en.native.js.map +1 -1
  139. package/dist/jsx/list/ListBulkActionsBar.mjs +31 -19
  140. package/dist/jsx/list/ListBulkActionsBar.mjs.map +1 -1
  141. package/dist/jsx/list/ListBulkActionsBar.native.js +43 -31
  142. package/dist/jsx/list/ListBulkActionsBar.native.js.map +1 -1
  143. package/dist/jsx/list/sidebar-section.mjs +16 -8
  144. package/dist/jsx/list/sidebar-section.mjs.map +1 -1
  145. package/dist/jsx/list/sidebar-section.native.js +16 -7
  146. package/dist/jsx/list/sidebar-section.native.js.map +1 -1
  147. package/dist/jsx/report/DoctypeReportView.mjs +21 -375
  148. package/dist/jsx/report/DoctypeReportView.mjs.map +1 -1
  149. package/dist/jsx/report/DoctypeReportView.native.js +23 -455
  150. package/dist/jsx/report/DoctypeReportView.native.js.map +1 -1
  151. package/dist/jsx/report/QueryReportScreen.mjs +26 -16
  152. package/dist/jsx/report/QueryReportScreen.mjs.map +1 -1
  153. package/dist/jsx/report/QueryReportScreen.native.js +33 -23
  154. package/dist/jsx/report/QueryReportScreen.native.js.map +1 -1
  155. package/dist/jsx/report/queryReportColumns.mjs +1 -103
  156. package/dist/jsx/report/queryReportColumns.mjs.map +1 -1
  157. package/dist/jsx/report/queryReportColumns.native.js +2 -129
  158. package/dist/jsx/report/queryReportColumns.native.js.map +1 -1
  159. package/dist/jsx/report/queryReportFilterBar.mjs +1 -2
  160. package/dist/jsx/report/queryReportFilterBar.mjs.map +1 -1
  161. package/dist/jsx/report/queryReportFilterBar.native.js +3 -4
  162. package/dist/jsx/report/queryReportFilterBar.native.js.map +1 -1
  163. package/dist/jsx/report/queryReportUrlState.mjs +1 -1
  164. package/dist/jsx/report/queryReportUrlState.native.js +2 -2
  165. package/dist/jsx/report/queryReportUrlState.native.js.map +1 -1
  166. package/dist/jsx/report/report-grid.mjs +1 -425
  167. package/dist/jsx/report/report-grid.mjs.map +1 -1
  168. package/dist/jsx/report/report-grid.native.js +1 -479
  169. package/dist/jsx/report/report-grid.native.js.map +1 -1
  170. package/dist/jsx/report/report-toolbar.mjs +2 -228
  171. package/dist/jsx/report/report-toolbar.mjs.map +1 -1
  172. package/dist/jsx/report/report-toolbar.native.js +1 -274
  173. package/dist/jsx/report/report-toolbar.native.js.map +1 -1
  174. package/dist/jsx/report/reportShapes.mjs +2 -373
  175. package/dist/jsx/report/reportShapes.mjs.map +1 -1
  176. package/dist/jsx/report/reportShapes.native.js +12 -501
  177. package/dist/jsx/report/reportShapes.native.js.map +1 -1
  178. package/dist/jsx/report/reportViewModel.mjs +2 -342
  179. package/dist/jsx/report/reportViewModel.mjs.map +1 -1
  180. package/dist/jsx/report/reportViewModel.native.js +19 -627
  181. package/dist/jsx/report/reportViewModel.native.js.map +1 -1
  182. package/dist/jsx/report/savedReports.mjs +1 -105
  183. package/dist/jsx/report/savedReports.mjs.map +1 -1
  184. package/dist/jsx/report/savedReports.native.js +1 -132
  185. package/dist/jsx/report/savedReports.native.js.map +1 -1
  186. package/dist/jsx/report/useQueryReport.mjs +2 -210
  187. package/dist/jsx/report/useQueryReport.mjs.map +1 -1
  188. package/dist/jsx/report/useQueryReport.native.js +11 -244
  189. package/dist/jsx/report/useQueryReport.native.js.map +1 -1
  190. package/dist/jsx/shared/measures.mjs +1 -3
  191. package/dist/jsx/shared/measures.mjs.map +1 -1
  192. package/dist/jsx/shared/measures.native.js +3 -5
  193. package/dist/jsx/shared/measures.native.js.map +1 -1
  194. package/dist/jsx/views/ReportView.mjs +3 -256
  195. package/dist/jsx/views/ReportView.mjs.map +1 -1
  196. package/dist/jsx/views/ReportView.native.js +3 -382
  197. package/dist/jsx/views/ReportView.native.js.map +1 -1
  198. package/dist/jsx/views/report-controls.mjs +3 -3
  199. package/dist/jsx/views/report-controls.mjs.map +1 -1
  200. package/dist/jsx/views/report-controls.native.js +6 -6
  201. package/dist/jsx/views/report-controls.native.js.map +1 -1
  202. package/package.json +12 -12
  203. package/src/backofficeScreens.designLaw.spec.ts +0 -5
  204. package/src/desk/DeskSurface.tsx +4 -7
  205. package/src/form/DocFormScreen.chrome.spec.ts +77 -0
  206. package/src/form/DocFormScreen.guest.screen.spec.tsx +175 -0
  207. package/src/form/DocFormScreen.rights.spec.tsx +7 -3
  208. package/src/form/DocFormScreen.tsx +214 -315
  209. package/src/i18n/en.ts +1 -0
  210. package/src/list/ListBulkActionsBar.rights.spec.tsx +134 -0
  211. package/src/list/ListBulkActionsBar.screen.spec.tsx +7 -1
  212. package/src/list/ListBulkActionsBar.tsx +76 -57
  213. package/src/list/ListFilterBar.screen.spec.tsx +14 -13
  214. package/src/list/sidebar-section.tsx +11 -3
  215. package/src/report/DoctypeReportView.tsx +28 -550
  216. package/src/report/QueryReportScreen.spec.tsx +75 -1
  217. package/src/report/QueryReportScreen.tsx +38 -22
  218. package/src/report/queryReportColumns.tsx +4 -123
  219. package/src/report/queryReportFilterBar.tsx +3 -5
  220. package/src/report/queryReportUrlState.ts +1 -1
  221. package/src/report/report-grid.tsx +4 -529
  222. package/src/report/report-toolbar.tsx +4 -308
  223. package/src/report/reportShapes.ts +25 -613
  224. package/src/report/reportShim.spec.ts +162 -0
  225. package/src/report/reportViewModel.ts +32 -605
  226. package/src/report/savedReports.ts +4 -161
  227. package/src/report/useQueryReport.ts +9 -347
  228. package/src/shared/measures.ts +3 -11
  229. package/src/views/ReportView.screen.spec.tsx +25 -20
  230. package/src/views/ReportView.tsx +7 -439
  231. package/src/views/report-controls.tsx +12 -20
  232. package/types/desk/DeskSurface.d.ts.map +1 -1
  233. package/types/form/DocFormScreen.d.ts +2 -2
  234. package/types/form/DocFormScreen.d.ts.map +1 -1
  235. package/types/i18n/en.d.ts +1 -0
  236. package/types/i18n/en.d.ts.map +1 -1
  237. package/types/list/ListBulkActionsBar.d.ts.map +1 -1
  238. package/types/list/sidebar-section.d.ts.map +1 -1
  239. package/types/report/DoctypeReportView.d.ts.map +1 -1
  240. package/types/report/QueryReportScreen.d.ts +1 -1
  241. package/types/report/QueryReportScreen.d.ts.map +1 -1
  242. package/types/report/queryReportColumns.d.ts +2 -11
  243. package/types/report/queryReportColumns.d.ts.map +1 -1
  244. package/types/report/queryReportFilterBar.d.ts +1 -1
  245. package/types/report/queryReportFilterBar.d.ts.map +1 -1
  246. package/types/report/queryReportUrlState.d.ts +1 -1
  247. package/types/report/queryReportUrlState.d.ts.map +1 -1
  248. package/types/report/report-grid.d.ts +2 -19
  249. package/types/report/report-grid.d.ts.map +1 -1
  250. package/types/report/report-toolbar.d.ts +2 -29
  251. package/types/report/report-toolbar.d.ts.map +1 -1
  252. package/types/report/reportShapes.d.ts +2 -115
  253. package/types/report/reportShapes.d.ts.map +1 -1
  254. package/types/report/reportViewModel.d.ts +2 -135
  255. package/types/report/reportViewModel.d.ts.map +1 -1
  256. package/types/report/savedReports.d.ts +2 -18
  257. package/types/report/savedReports.d.ts.map +1 -1
  258. package/types/report/useQueryReport.d.ts +2 -35
  259. package/types/report/useQueryReport.d.ts.map +1 -1
  260. package/types/shared/measures.d.ts +1 -2
  261. package/types/shared/measures.d.ts.map +1 -1
  262. package/types/views/ReportView.d.ts +3 -22
  263. package/types/views/ReportView.d.ts.map +1 -1
  264. package/types/views/report-controls.d.ts +2 -5
  265. package/types/views/report-controls.d.ts.map +1 -1
  266. package/src/report/report-grid.spec.tsx +0 -175
  267. package/src/report/report-toolbar.spec.tsx +0 -90
  268. package/src/report/reportShapes.spec.ts +0 -391
  269. package/src/report/reportViewModel.spec.ts +0 -393
@@ -5,7 +5,7 @@
5
5
  import { renderWithProviders } from "@multiplatform.one/test-utils";
6
6
  import { fireEvent, screen, waitFor } from "@testing-library/react";
7
7
  import React from "react";
8
- import { describe, expect, it } from "vitest";
8
+ import { afterEach, describe, expect, it, vi } from "vitest";
9
9
  import { BackofficeProvider } from "../config/BackofficeProvider";
10
10
  import { createMemoryNavigator } from "../navigation/navigator";
11
11
  import { QueryReportScreen } from "./QueryReportScreen";
@@ -72,3 +72,77 @@ describe("QueryReportScreen filter URL round-trip", () => {
72
72
  expect(screen.getByRole("button", { name: /export csv/i })).toBeTruthy();
73
73
  });
74
74
  });
75
+
76
+ // LC-96: a report the session may not run is a permission state, not an error
77
+ // whose retry cannot succeed. The bench refuses the Report doc, its script and
78
+ // the run the way Frappe refuses a user without the report's role.
79
+ describe("QueryReportScreen refused run", () => {
80
+ afterEach(() => {
81
+ vi.unstubAllGlobals();
82
+ });
83
+
84
+ function stubRefusingBench(message = "You don't have access to Report: Team Workload") {
85
+ vi.stubGlobal(
86
+ "fetch",
87
+ async () =>
88
+ new Response(
89
+ JSON.stringify({
90
+ exc_type: "PermissionError",
91
+ _server_messages: JSON.stringify([JSON.stringify({ message })]),
92
+ }),
93
+ { status: 403, headers: { "content-type": "application/json" } },
94
+ ),
95
+ );
96
+ }
97
+
98
+ let run = 0;
99
+ function renderRefused() {
100
+ run += 1;
101
+ const navigation = createMemoryNavigator("/backoffice/query-report/Team%20Workload");
102
+ return renderWithProviders(
103
+ <BackofficeProvider
104
+ frappe={{ baseURL: `https://backoffice-query-report-refused-${run}.mock.test` }}
105
+ navigation={navigation}
106
+ >
107
+ <QueryReportScreen reportName="Team Workload" />
108
+ </BackofficeProvider>,
109
+ );
110
+ }
111
+
112
+ it("says the reader can't run the report, with the server's reason and no retry", async () => {
113
+ stubRefusingBench();
114
+ renderRefused();
115
+
116
+ const state = await screen.findByTestId("frappe-report-not-permitted", {}, { timeout: 8000 });
117
+ expect(state.textContent).toContain(`You can't run "Team Workload"`);
118
+ expect(state.textContent).toContain("You don't have access to Report: Team Workload");
119
+ expect(screen.queryByRole("button", { name: /retry|refresh/i })).toBeNull();
120
+ });
121
+
122
+ // MPO-473: a refused run has nothing to export, and never will.
123
+ it("offers no Export CSV", async () => {
124
+ stubRefusingBench();
125
+ renderRefused();
126
+
127
+ await screen.findByTestId("frappe-report-not-permitted", {}, { timeout: 8000 });
128
+ expect(screen.queryByRole("button", { name: /export csv/i })).toBeNull();
129
+ expect(screen.queryByText("Export CSV")).toBeNull();
130
+ });
131
+
132
+ // Verbatim from pokemon's bench signed out: is_whitelisted refuses Guest with
133
+ // one message, a <details> summary and body, which rendered glued as
134
+ // "Login to accessFunction frappe.desk.query_report.run …".
135
+ it("renders each line of the server's reason on its own", async () => {
136
+ stubRefusingBench(
137
+ "<details><summary>You are not permitted to access this resource. Login to access</summary>Function <strong>frappe.desk.query_report.run</strong> is not whitelisted.</details>",
138
+ );
139
+ renderRefused();
140
+
141
+ const state = await screen.findByTestId("frappe-report-not-permitted", {}, { timeout: 8000 });
142
+ const lines = Array.from(state.querySelectorAll("p")).map((node) => node.textContent);
143
+ expect(lines).toEqual([
144
+ "You are not permitted to access this resource. Login to access",
145
+ "Function frappe.desk.query_report.run is not whitelisted.",
146
+ ]);
147
+ });
148
+ });
@@ -31,22 +31,23 @@ import {
31
31
  useBackofficeNavigator,
32
32
  useBackofficePaths,
33
33
  } from "../config/BackofficeProvider";
34
+ import {
35
+ buildQueryReportColumns,
36
+ buildQueryReportCsv,
37
+ defaultFilterValues,
38
+ isEmptyFilterValue,
39
+ scrubFieldname,
40
+ stripReportHtml as stripHtml,
41
+ useQueryReport,
42
+ type QueryReportFilters,
43
+ type QueryReportFixture,
44
+ } from "@multiplatform.one/frappe-ui";
34
45
  import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
35
- import { buildQueryReportColumns, buildQueryReportCsv } from "./queryReportColumns";
36
46
  import { QueryReportFilterBar, queryReportFilterLabel } from "./queryReportFilterBar";
37
47
  import {
38
48
  parseQueryReportFiltersParam,
39
49
  serializeQueryReportFiltersParam,
40
50
  } from "./queryReportUrlState";
41
- import {
42
- defaultFilterValues,
43
- isEmptyFilterValue,
44
- type QueryReportFilters,
45
- type QueryReportFixture,
46
- scrubFieldname,
47
- stripHtml,
48
- useQueryReport,
49
- } from "./useQueryReport";
50
51
 
51
52
  export interface QueryReportScreenProps {
52
53
  /** Report document name (proper-cased, e.g. "Permitted Documents For User"). */
@@ -217,6 +218,17 @@ export function QueryReportScreen({
217
218
  )}
218
219
  />
219
220
  );
221
+ } else if (report.error && report.refused) {
222
+ body = (
223
+ <EmptyState
224
+ testID="frappe-report-not-permitted"
225
+ title={t("queryReport.notPermitted", {
226
+ defaultValue: 'You can\'t run "{{report}}"',
227
+ report: title,
228
+ })}
229
+ description={report.error.message}
230
+ />
231
+ );
220
232
  } else if (report.error) {
221
233
  body = (
222
234
  <YStack flex={1} gap="$2">
@@ -303,18 +315,22 @@ export function QueryReportScreen({
303
315
  actions={
304
316
  <XStack gap="$2" alignItems="center">
305
317
  {report.running && !report.loading ? <Spinner size="small" /> : null}
306
- <Button size="$2" chromeless onPress={report.reload} disabled={report.loading}>
307
- {t("queryReport.refresh", "Refresh")}
308
- </Button>
309
- <Button
310
- size="$2"
311
- chromeless
312
- icon={DownloadSimpleIcon}
313
- onPress={handleExport}
314
- disabled={report.loading || report.rows.length === 0}
315
- >
316
- {t("queryReport.exportCsv", "Export CSV")}
317
- </Button>
318
+ {report.refused ? null : (
319
+ <>
320
+ <Button size="$2" chromeless onPress={report.reload} disabled={report.loading}>
321
+ {t("queryReport.refresh", "Refresh")}
322
+ </Button>
323
+ <Button
324
+ size="$2"
325
+ chromeless
326
+ icon={DownloadSimpleIcon}
327
+ onPress={handleExport}
328
+ disabled={report.loading || report.rows.length === 0}
329
+ >
330
+ {t("queryReport.exportCsv", "Export CSV")}
331
+ </Button>
332
+ </>
333
+ )}
318
334
  </XStack>
319
335
  }
320
336
  />
@@ -1,123 +1,4 @@
1
- // Query-report column meta → DataTable columns with fieldtype-aware cells:
2
- // numerics right-aligned, Date/Datetime trimmed like desk lists, Link cells
3
- // navigable to the target doc form, HTML values (desk anchor markup)
4
- // flattened to text.
5
- import React from "react";
6
- import { Text } from "@multiplatform.one/components";
7
- import type { DataTableColumn } from "@multiplatform.one/table";
8
- import { formatDateCell } from "@multiplatform.one/frappe-ui";
9
- import { type QueryReportColumn, type QueryReportRow, stripHtml } from "./useQueryReport";
10
-
11
- const NUMERIC_FIELDTYPES = new Set(["Currency", "Float", "Int", "Percent", "Duration"]);
12
-
13
- export interface BuildQueryReportColumnsArgs {
14
- columns: readonly QueryReportColumn[];
15
- /** Open a Link cell's target document (doctype comes from column options). */
16
- onOpenLink?: (doctype: string, name: string) => void;
17
- }
18
-
19
- function queryReportCell(
20
- column: QueryReportColumn,
21
- onOpenLink?: (doctype: string, name: string) => void,
22
- ) {
23
- return ({ getValue }: { getValue: () => unknown }) => {
24
- const raw = getValue();
25
- if (raw === null || raw === undefined || raw === "") {
26
- return (
27
- <Text fontSize="$3" color="$color8">
28
- —
29
- </Text>
30
- );
31
- }
32
- if (column.fieldtype === "Check") {
33
- return (
34
- <Text fontSize="$3" color={raw ? "$green11" : "$color8"}>
35
- {raw ? "✓" : "—"}
36
- </Text>
37
- );
38
- }
39
- const value = String(raw);
40
- if (NUMERIC_FIELDTYPES.has(column.fieldtype)) {
41
- return (
42
- <Text fontSize="$3" color="$color12" textAlign="right">
43
- {value}
44
- </Text>
45
- );
46
- }
47
- switch (column.fieldtype) {
48
- case "Date":
49
- case "Datetime":
50
- return (
51
- <Text fontSize="$3" color="$color11">
52
- {formatDateCell(value)}
53
- </Text>
54
- );
55
- case "Link": {
56
- const doctype = column.options;
57
- if (doctype && onOpenLink) {
58
- return (
59
- <Text
60
- fontSize="$3"
61
- color="$color11"
62
- textDecorationLine="underline"
63
- cursor="pointer"
64
- numberOfLines={1}
65
- role="link"
66
- onPress={(event) => {
67
- event?.stopPropagation?.();
68
- onOpenLink(doctype, value);
69
- }}
70
- >
71
- {value}
72
- </Text>
73
- );
74
- }
75
- return (
76
- <Text fontSize="$3" color="$color11" numberOfLines={1}>
77
- {value}
78
- </Text>
79
- );
80
- }
81
- default:
82
- return (
83
- <Text fontSize="$3" color="$color11" numberOfLines={1}>
84
- {stripHtml(value)}
85
- </Text>
86
- );
87
- }
88
- };
89
- }
90
-
91
- /** Build DataTable columns for a query-report run result. */
92
- export function buildQueryReportColumns({
93
- columns,
94
- onOpenLink,
95
- }: BuildQueryReportColumnsArgs): DataTableColumn<QueryReportRow>[] {
96
- return columns.map((column) => ({
97
- id: column.fieldname,
98
- header: column.label,
99
- // accessorFn (not accessorKey): report fieldnames may contain path-y
100
- // characters like "assigned_to/owner" that key-based access mangles.
101
- accessorFn: (row: QueryReportRow) => row[column.fieldname],
102
- ...(NUMERIC_FIELDTYPES.has(column.fieldtype) ? { align: "right" as const } : {}),
103
- ...(column.width ? { width: column.width } : {}),
104
- cell: queryReportCell(column, onOpenLink),
105
- }));
106
- }
107
-
108
- function escapeCsvCell(value: unknown): string {
109
- if (value === null || value === undefined) return "";
110
- const text = stripHtml(String(value));
111
- return /[",\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
112
- }
113
-
114
- /** CSV over the full run result (Desk Export, not just the current page). */
115
- export function buildQueryReportCsv(
116
- columns: readonly QueryReportColumn[],
117
- rows: readonly QueryReportRow[],
118
- ): string {
119
- return [
120
- columns.map((column) => escapeCsvCell(column.label)).join(","),
121
- ...rows.map((row) => columns.map((column) => escapeCsvCell(row[column.fieldname])).join(",")),
122
- ].join("\n");
123
- }
1
+ // Query-report columns live in @multiplatform.one/frappe-ui (MPO-15, GL-28);
2
+ // this path keeps handing out the same names.
3
+ export { buildQueryReportColumns, buildQueryReportCsv } from "@multiplatform.one/frappe-ui";
4
+ export type { BuildQueryReportColumnsArgs } from "@multiplatform.one/frappe-ui";
@@ -25,18 +25,16 @@ import { useCallback, useEffect, useRef, useState } from "react";
25
25
  import { useTranslation } from "react-i18next";
26
26
  import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
27
27
  import {
28
+ compactQueryReportFilters,
28
29
  Date as DateField,
29
30
  fieldKind,
30
31
  fieldLabelFor,
32
+ isEmptyFilterValue,
31
33
  Link as LinkField,
32
34
  selectOptionsFromField,
33
- } from "@multiplatform.one/frappe-ui";
34
- import {
35
- compactQueryReportFilters,
36
- isEmptyFilterValue,
37
35
  type QueryReportFilterMeta,
38
36
  type QueryReportFilters,
39
- } from "./reportShapes";
37
+ } from "@multiplatform.one/frappe-ui";
40
38
 
41
39
  export function queryReportFilterLabel(filter: QueryReportFilterMeta): string {
42
40
  return filter.label || fieldLabelFor([], filter.fieldname);
@@ -12,7 +12,7 @@
12
12
  * `setParams` (history REPLACE, no remount) and adopts inbound param changes
13
13
  * (deep links, back/forward), so reload and shared links reproduce the run.
14
14
  */
15
- import { isEmptyFilterValue, type QueryReportFilters } from "./reportShapes";
15
+ import { isEmptyFilterValue, type QueryReportFilters } from "@multiplatform.one/frappe-ui";
16
16
 
17
17
  /**
18
18
  * Parse the `?filters=` deep-link value. The router usually decodes the