@multiplatform.one/backoffice 7.28.1 → 7.29.1

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
@@ -1,393 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import type { DoctypeMeta } from "../shared/useDoctypeMeta";
3
- import {
4
- buildGridRows,
5
- buildReportCsv,
6
- columnFilterTuple,
7
- columnFilterTuples,
8
- computeTotals,
9
- defaultReportFieldnames,
10
- fromDeskReportSettings,
11
- orderReportRows,
12
- parseDeskOrderBy,
13
- parseReportFiltersParam,
14
- reportColumnsFromMeta,
15
- resolveSelectedColumns,
16
- toDeskReportSettings,
17
- type ReportColumnDef,
18
- type ReportRow,
19
- } from "./reportViewModel";
20
-
21
- const userMeta: DoctypeMeta = {
22
- name: "User",
23
- title_field: "full_name",
24
- sort_field: "modified",
25
- sort_order: "DESC",
26
- fields: [
27
- { fieldname: "basic_section", fieldtype: "Section Break" },
28
- { fieldname: "email", label: "Email", fieldtype: "Data", in_list_view: 1 },
29
- { fieldname: "first_name", label: "First Name", fieldtype: "Data", in_standard_filter: 1 },
30
- { fieldname: "full_name", label: "Full Name", fieldtype: "Data", in_list_view: 1 },
31
- { fieldname: "enabled", label: "Enabled", fieldtype: "Check", in_standard_filter: 1 },
32
- {
33
- fieldname: "user_type",
34
- label: "User Type",
35
- fieldtype: "Select",
36
- options: "System User\nWebsite User",
37
- in_list_view: 1,
38
- in_standard_filter: 1,
39
- },
40
- {
41
- fieldname: "api_secret",
42
- label: "API Secret",
43
- fieldtype: "Data",
44
- in_list_view: 1,
45
- report_hide: 1,
46
- },
47
- {
48
- fieldname: "roles",
49
- label: "Roles",
50
- fieldtype: "Table",
51
- options: "Has Role",
52
- in_list_view: 1,
53
- },
54
- { fieldname: "bio", label: "Bio", fieldtype: "Small Text" },
55
- { fieldname: "points", label: "Points", fieldtype: "Int" },
56
- {
57
- fieldname: "role_profile",
58
- label: "Role Profile",
59
- fieldtype: "Link",
60
- options: "Role Profile",
61
- },
62
- ],
63
- };
64
-
65
- function column(fieldname: string, overrides: Partial<ReportColumnDef> = {}): ReportColumnDef {
66
- return {
67
- fieldname,
68
- label: fieldname,
69
- fieldtype: "Data",
70
- kind: "text",
71
- width: 160,
72
- align: "left",
73
- ...overrides,
74
- };
75
- }
76
-
77
- describe("defaultReportFieldnames", () => {
78
- it("seeds desk defaults: name, title field, in_list_view/in_standard_filter, modified", () => {
79
- expect(defaultReportFieldnames(userMeta)).toEqual([
80
- "name",
81
- "full_name",
82
- "email",
83
- "first_name",
84
- "enabled",
85
- "user_type",
86
- "modified",
87
- ]);
88
- });
89
-
90
- it("excludes report_hide, layout and table fields, dedupes the title field", () => {
91
- const fields = defaultReportFieldnames(userMeta);
92
- expect(fields).not.toContain("api_secret");
93
- expect(fields).not.toContain("roles");
94
- expect(fields).not.toContain("basic_section");
95
- expect(fields.filter((field) => field === "full_name")).toHaveLength(1);
96
- });
97
-
98
- it("degrades to name + modified without meta", () => {
99
- expect(defaultReportFieldnames(undefined)).toEqual(["name", "modified"]);
100
- });
101
-
102
- it("includes the image_field after the title field (desk set_default_fields)", () => {
103
- const meta: DoctypeMeta = {
104
- ...userMeta,
105
- image_field: "user_image",
106
- fields: [
107
- ...userMeta.fields,
108
- { fieldname: "user_image", label: "User Image", fieldtype: "Attach Image" },
109
- ],
110
- };
111
- const fields = defaultReportFieldnames(meta);
112
- expect(fields.indexOf("user_image")).toBe(fields.indexOf("full_name") + 1);
113
- });
114
-
115
- it("seeds an unflagged status docfield right after name", () => {
116
- const meta: DoctypeMeta = {
117
- name: "ToDo",
118
- fields: [
119
- { fieldname: "status", label: "Status", fieldtype: "Select", options: "Open\nClosed" },
120
- { fieldname: "description", label: "Description", fieldtype: "Text", in_list_view: 1 },
121
- ],
122
- };
123
- expect(defaultReportFieldnames(meta)).toEqual(["name", "status", "description", "modified"]);
124
- });
125
-
126
- it("pulls the currency-source field referenced by a flagged Currency column", () => {
127
- const meta: DoctypeMeta = {
128
- name: "Quote",
129
- fields: [
130
- {
131
- fieldname: "amount",
132
- label: "Amount",
133
- fieldtype: "Currency",
134
- options: "currency",
135
- in_list_view: 1,
136
- },
137
- { fieldname: "currency", label: "Currency", fieldtype: "Link", options: "Currency" },
138
- {
139
- fieldname: "converted",
140
- label: "Converted",
141
- fieldtype: "Currency",
142
- options: "Company:company:default_currency",
143
- in_list_view: 1,
144
- },
145
- ],
146
- };
147
- expect(defaultReportFieldnames(meta)).toEqual([
148
- "name",
149
- "amount",
150
- "converted",
151
- "currency",
152
- "company",
153
- "modified",
154
- ]);
155
- });
156
- });
157
-
158
- describe("reportColumnsFromMeta", () => {
159
- it("offers ID first, all value-type meta fields, then standard doc fields", () => {
160
- const columns = reportColumnsFromMeta(userMeta);
161
- expect(columns[0].fieldname).toBe("name");
162
- const names = columns.map((entry) => entry.fieldname);
163
- expect(names).toContain("bio");
164
- expect(names).toContain("points");
165
- expect(names).toContain("owner");
166
- expect(names).toContain("modified");
167
- expect(names).not.toContain("roles");
168
- expect(names).not.toContain("basic_section");
169
- });
170
-
171
- it("derives kind, width and alignment from the fieldtype", () => {
172
- const columns = reportColumnsFromMeta(userMeta);
173
- const points = columns.find((entry) => entry.fieldname === "points");
174
- expect(points).toMatchObject({ kind: "number", align: "right" });
175
- const enabled = columns.find((entry) => entry.fieldname === "enabled");
176
- expect(enabled).toMatchObject({ kind: "check", align: "center" });
177
- const userType = columns.find((entry) => entry.fieldname === "user_type");
178
- expect(userType).toMatchObject({ kind: "select", options: "System User\nWebsite User" });
179
- });
180
- });
181
-
182
- describe("resolveSelectedColumns", () => {
183
- it("keeps selection order and drops unknown fieldnames", () => {
184
- const all = reportColumnsFromMeta(userMeta);
185
- const resolved = resolveSelectedColumns(all, ["user_type", "nope", "name"]);
186
- expect(resolved.map((entry) => entry.fieldname)).toEqual(["user_type", "name"]);
187
- });
188
- });
189
-
190
- describe("columnFilterTuple", () => {
191
- it("wraps text in contains-like (user wildcards win)", () => {
192
- expect(columnFilterTuple(column("email"), "test")).toEqual(["email", "like", "%test%"]);
193
- expect(columnFilterTuple(column("email"), "test%")).toEqual(["email", "like", "test%"]);
194
- expect(columnFilterTuple(column("email"), " ")).toBeNull();
195
- });
196
-
197
- it("equals exact select options (case-insensitive), likes partials", () => {
198
- const select = column("user_type", {
199
- fieldtype: "Select",
200
- kind: "select",
201
- options: "System User\nWebsite User",
202
- });
203
- expect(columnFilterTuple(select, "system user")).toEqual(["user_type", "=", "System User"]);
204
- expect(columnFilterTuple(select, "Sys")).toEqual(["user_type", "like", "%Sys%"]);
205
- });
206
-
207
- it("parses check values, rejects unparseable input", () => {
208
- const check = column("enabled", { fieldtype: "Check", kind: "check" });
209
- expect(columnFilterTuple(check, "yes")).toEqual(["enabled", "=", 1]);
210
- expect(columnFilterTuple(check, "0")).toEqual(["enabled", "=", 0]);
211
- expect(columnFilterTuple(check, "maybe")).toBeNull();
212
- });
213
-
214
- it("supports comparison prefixes on numbers and dates", () => {
215
- const points = column("points", { fieldtype: "Int", kind: "number" });
216
- expect(columnFilterTuple(points, ">= 10")).toEqual(["points", ">=", "10"]);
217
- expect(columnFilterTuple(points, "5")).toEqual(["points", "=", "5"]);
218
- expect(columnFilterTuple(points, ">")).toBeNull();
219
- const modified = column("modified", { fieldtype: "Datetime", kind: "date" });
220
- expect(columnFilterTuple(modified, ">2026-01-01")).toEqual(["modified", ">", "2026-01-01"]);
221
- });
222
- });
223
-
224
- describe("columnFilterTuples", () => {
225
- it("collects only parseable inputs, keyed by fieldname", () => {
226
- const columns = [column("email"), column("enabled", { fieldtype: "Check", kind: "check" })];
227
- expect(columnFilterTuples(columns, { email: "a", enabled: "??", other: "x" })).toEqual([
228
- ["email", "like", "%a%"],
229
- ]);
230
- });
231
- });
232
-
233
- describe("desk report settings round trip", () => {
234
- it("serializes fields/filters/order_by/group_by in desk shape", () => {
235
- const settings = toDeskReportSettings("User", {
236
- fieldnames: ["name", "email"],
237
- filters: [["enabled", "=", 1]],
238
- sort: { field: "creation", order: "asc" },
239
- pageSize: 100,
240
- groupBy: "user_type",
241
- addTotals: true,
242
- });
243
- expect(settings.fields).toEqual([
244
- ["name", "User"],
245
- ["email", "User"],
246
- ]);
247
- expect(settings.filters).toEqual([["User", "enabled", "=", 1]]);
248
- expect(settings.order_by).toBe("`tabUser`.`creation` asc");
249
- expect(settings.add_totals_row).toBe(1);
250
- expect(settings.page_length).toBe(100);
251
- expect(settings.group_by).toEqual({
252
- group_by: "`tabUser`.`user_type`",
253
- aggregate_function: "count",
254
- aggregate_on: null,
255
- });
256
- });
257
-
258
- it("parses desk json back (dropping child-doctype fields and filters)", () => {
259
- const parsed = fromDeskReportSettings("User", {
260
- fields: [["name", "User"], ["role", "Has Role"], "email"],
261
- filters: [
262
- ["User", "enabled", "=", 1],
263
- ["Has Role", "role", "=", "System Manager"],
264
- ["user_type", "=", "System User"],
265
- ],
266
- order_by: "`tabUser`.`modified` desc",
267
- add_totals_row: 1,
268
- page_length: 500,
269
- group_by: { group_by: "`tabUser`.`user_type`", aggregate_function: "count" },
270
- });
271
- expect(parsed).toEqual({
272
- fieldnames: ["name", "email"],
273
- filters: [
274
- ["enabled", "=", 1],
275
- ["user_type", "=", "System User"],
276
- ],
277
- sort: { field: "modified", order: "desc" },
278
- pageSize: 500,
279
- groupBy: "user_type",
280
- addTotals: true,
281
- });
282
- });
283
-
284
- it("round-trips through its own serialization", () => {
285
- const config = {
286
- fieldnames: ["name", "points"],
287
- filters: [["points", ">", "5"]] as Array<[string, string, unknown]>,
288
- sort: { field: "points", order: "asc" as const },
289
- pageSize: 20,
290
- groupBy: null,
291
- addTotals: false,
292
- };
293
- const parsed = fromDeskReportSettings("User", toDeskReportSettings("User", config));
294
- expect(parsed).toEqual(config);
295
- });
296
-
297
- it("tolerates garbage", () => {
298
- expect(fromDeskReportSettings("User", null)).toBeUndefined();
299
- expect(fromDeskReportSettings("User", "{}")).toBeUndefined();
300
- expect(fromDeskReportSettings("User", {})).toMatchObject({ fieldnames: [], filters: [] });
301
- });
302
- });
303
-
304
- describe("parseDeskOrderBy", () => {
305
- it("parses backticked and bare expressions", () => {
306
- expect(parseDeskOrderBy("`tabUser`.`modified` desc")).toEqual({
307
- field: "modified",
308
- order: "desc",
309
- });
310
- expect(parseDeskOrderBy("creation asc")).toEqual({ field: "creation", order: "asc" });
311
- expect(parseDeskOrderBy("")).toBeUndefined();
312
- expect(parseDeskOrderBy(42)).toBeUndefined();
313
- });
314
- });
315
-
316
- describe("orderReportRows / buildGridRows", () => {
317
- const rows: ReportRow[] = [
318
- { name: "c", status: "Open", points: 3 },
319
- { name: "a", status: "Closed", points: 1 },
320
- { name: "b", status: "Open", points: 2 },
321
- { name: "d", status: "Open", points: null },
322
- ];
323
-
324
- it("orders by sort field with name tiebreak, nulls last", () => {
325
- const ordered = orderReportRows(rows, { field: "points", order: "desc" });
326
- expect(ordered.map((row) => row.name)).toEqual(["c", "b", "a", "d"]);
327
- });
328
-
329
- it("groups first when grouping, then sorts inside groups", () => {
330
- const ordered = orderReportRows(rows, { field: "points", order: "asc" }, "status");
331
- expect(ordered.map((row) => row.name)).toEqual(["a", "b", "c", "d"]);
332
- });
333
-
334
- it("injects group headers with full-result counts inside the page", () => {
335
- const ordered = orderReportRows(rows, { field: "points", order: "asc" }, "status");
336
- const page = buildGridRows(ordered, 0, 2, "status");
337
- expect(page).toHaveLength(4);
338
- expect(page[0]).toMatchObject({ kind: "group", value: "Closed", count: 1 });
339
- expect(page[1]).toMatchObject({ kind: "row", key: "a", index: 1 });
340
- expect(page[2]).toMatchObject({ kind: "group", value: "Open", count: 3 });
341
- expect(page[3]).toMatchObject({ kind: "row", key: "b", index: 2 });
342
- });
343
-
344
- it("numbers rows across pages without grouping", () => {
345
- const ordered = orderReportRows(rows, { field: "name", order: "asc" });
346
- const page = buildGridRows(ordered, 2, 2);
347
- expect(page).toEqual([
348
- { kind: "row", key: "c", row: ordered[2], index: 3 },
349
- { kind: "row", key: "d", row: ordered[3], index: 4 },
350
- ]);
351
- });
352
- });
353
-
354
- describe("computeTotals", () => {
355
- it("sums numeric visible columns over all rows", () => {
356
- const columns = [column("name"), column("points", { fieldtype: "Int", kind: "number" })];
357
- const totals = computeTotals(columns, [
358
- { name: "a", points: 1 },
359
- { name: "b", points: 2 },
360
- { name: "c", points: "x" },
361
- ]);
362
- expect(totals).toEqual([{ fieldname: "points", fieldtype: "Int", value: 3 }]);
363
- });
364
-
365
- it("is empty without rows", () => {
366
- expect(computeTotals([column("points", { fieldtype: "Int", kind: "number" })], [])).toEqual([]);
367
- });
368
- });
369
-
370
- describe("buildReportCsv", () => {
371
- it("escapes quotes, commas and newlines", () => {
372
- const csv = buildReportCsv(
373
- [column("name", { label: "ID" }), column("bio", { label: "Bio, or so" })],
374
- [{ name: "a", bio: 'say "hi"\nplease' }],
375
- );
376
- expect(csv).toBe('ID,"Bio, or so"\na,"say ""hi""\nplease"');
377
- });
378
- });
379
-
380
- describe("parseReportFiltersParam", () => {
381
- it("parses raw and urlencoded JSON tuples", () => {
382
- expect(parseReportFiltersParam('[["enabled","=",1]]')).toEqual([["enabled", "=", 1]]);
383
- expect(
384
- parseReportFiltersParam(encodeURIComponent('[["user_type","=","System User"]]')),
385
- ).toEqual([["user_type", "=", "System User"]]);
386
- });
387
-
388
- it("degrades to undefined on malformed input", () => {
389
- expect(parseReportFiltersParam("not json")).toBeUndefined();
390
- expect(parseReportFiltersParam("")).toBeUndefined();
391
- expect(parseReportFiltersParam(42)).toBeUndefined();
392
- });
393
- });