@multiplatform.one/backoffice 7.2.2 → 7.3.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 (511) hide show
  1. package/dist/cjs/chrome/BackofficeAwesomebar.native.js +1 -1
  2. package/dist/cjs/chrome/BackofficeAwesomebar.native.js.map +1 -1
  3. package/dist/cjs/chrome/CommandPalette.native.js +1 -1
  4. package/dist/cjs/chrome/CommandPalette.native.js.map +1 -1
  5. package/dist/cjs/chrome/HelpMenu.native.js +1 -1
  6. package/dist/cjs/chrome/HelpMenu.native.js.map +1 -1
  7. package/dist/cjs/chrome/NotificationsButton.native.js +1 -1
  8. package/dist/cjs/chrome/NotificationsButton.native.js.map +1 -1
  9. package/dist/cjs/chrome/UserMenu.native.js +1 -1
  10. package/dist/cjs/chrome/UserMenu.native.js.map +1 -1
  11. package/dist/cjs/chrome/awesomebar-data.native.js.map +1 -1
  12. package/dist/cjs/chrome/command-palette-model.native.js +1 -1
  13. package/dist/cjs/chrome/command-palette-model.native.js.map +1 -1
  14. package/dist/cjs/chrome/help-about-dialog.native.js +1 -1
  15. package/dist/cjs/chrome/help-about-dialog.native.js.map +1 -1
  16. package/dist/cjs/chrome/help-shortcuts-dialog.native.js +1 -1
  17. package/dist/cjs/chrome/help-shortcuts-dialog.native.js.map +1 -1
  18. package/dist/cjs/chrome/notifications-data.native.js.map +1 -1
  19. package/dist/cjs/chrome/notifications-panel.native.js +1 -1
  20. package/dist/cjs/chrome/notifications-panel.native.js.map +1 -1
  21. package/dist/cjs/chrome/notifications-utils.native.js.map +1 -1
  22. package/dist/cjs/chrome/shortcuts.native.js.map +1 -1
  23. package/dist/cjs/chrome/user-session.native.js.map +1 -1
  24. package/dist/cjs/config/BackofficeProvider.cjs +4 -10
  25. package/dist/cjs/config/BackofficeProvider.native.js +10 -30
  26. package/dist/cjs/config/BackofficeProvider.native.js.map +1 -1
  27. package/dist/cjs/config/capabilities.native.js.map +1 -1
  28. package/dist/cjs/config/events.native.js.map +1 -1
  29. package/dist/cjs/config/slots.native.js.map +1 -1
  30. package/dist/cjs/desk/Desk.cjs +187 -0
  31. package/dist/cjs/desk/Desk.native.js +214 -0
  32. package/dist/cjs/desk/Desk.native.js.map +1 -0
  33. package/dist/cjs/desk/DeskSurface.cjs +123 -0
  34. package/dist/cjs/desk/DeskSurface.native.js +130 -0
  35. package/dist/cjs/desk/DeskSurface.native.js.map +1 -0
  36. package/dist/cjs/desk/resolveDeskPath.cjs +118 -0
  37. package/dist/cjs/desk/resolveDeskPath.native.js +123 -0
  38. package/dist/cjs/desk/resolveDeskPath.native.js.map +1 -0
  39. package/dist/cjs/desk/scope.cjs +54 -0
  40. package/dist/cjs/desk/scope.native.js +61 -0
  41. package/dist/cjs/desk/scope.native.js.map +1 -0
  42. package/dist/cjs/desk/target.cjs +174 -0
  43. package/dist/cjs/desk/target.native.js +178 -0
  44. package/dist/cjs/desk/target.native.js.map +1 -0
  45. package/dist/cjs/form/DocFormScreen.native.js +1 -1
  46. package/dist/cjs/form/DocFormScreen.native.js.map +1 -1
  47. package/dist/cjs/form/FormConnections.native.js +1 -1
  48. package/dist/cjs/form/FormConnections.native.js.map +1 -1
  49. package/dist/cjs/form/FormDialogs.native.js +1 -1
  50. package/dist/cjs/form/FormDialogs.native.js.map +1 -1
  51. package/dist/cjs/form/FormErrorBoundary.native.js +1 -1
  52. package/dist/cjs/form/FormErrorBoundary.native.js.map +1 -1
  53. package/dist/cjs/form/FormHeaderCluster.native.js +1 -1
  54. package/dist/cjs/form/FormHeaderCluster.native.js.map +1 -1
  55. package/dist/cjs/form/FormSidebarPanel.native.js +1 -1
  56. package/dist/cjs/form/FormSidebarPanel.native.js.map +1 -1
  57. package/dist/cjs/form/FormTimeline.native.js +1 -1
  58. package/dist/cjs/form/FormTimeline.native.js.map +1 -1
  59. package/dist/cjs/form/FormToolbar.native.js +1 -1
  60. package/dist/cjs/form/FormToolbar.native.js.map +1 -1
  61. package/dist/cjs/form/connections-data.native.js.map +1 -1
  62. package/dist/cjs/form/createPrefill.native.js.map +1 -1
  63. package/dist/cjs/form/dependsOn.native.js.map +1 -1
  64. package/dist/cjs/form/dirtyTracking.native.js.map +1 -1
  65. package/dist/cjs/form/docinfo.native.js.map +1 -1
  66. package/dist/cjs/form/fetchFrom.native.js.map +1 -1
  67. package/dist/cjs/form/fieldPermissions.native.js.map +1 -1
  68. package/dist/cjs/form/formActions.native.js.map +1 -1
  69. package/dist/cjs/form/formLayout.native.js.map +1 -1
  70. package/dist/cjs/form/platformHooks.native.js.map +1 -1
  71. package/dist/cjs/form/sidebar-attachments.native.js +1 -1
  72. package/dist/cjs/form/sidebar-attachments.native.js.map +1 -1
  73. package/dist/cjs/form/sidebar-dialogs.native.js +1 -1
  74. package/dist/cjs/form/sidebar-dialogs.native.js.map +1 -1
  75. package/dist/cjs/form/sidebar-people.native.js +1 -1
  76. package/dist/cjs/form/sidebar-people.native.js.map +1 -1
  77. package/dist/cjs/form/sidebar-rpc.native.js.map +1 -1
  78. package/dist/cjs/form/sidebar-utils.native.js.map +1 -1
  79. package/dist/cjs/form/timeline-entries.native.js.map +1 -1
  80. package/dist/cjs/form/timeline-utils.native.js.map +1 -1
  81. package/dist/cjs/form/useFormEngine.native.js.map +1 -1
  82. package/dist/cjs/i18n/en.native.js.map +1 -1
  83. package/dist/cjs/i18n/index.native.js.map +1 -1
  84. package/dist/cjs/index.cjs +13 -0
  85. package/dist/cjs/index.native.js +14 -1
  86. package/dist/cjs/index.native.js.map +1 -1
  87. package/dist/cjs/list/AddTagsDialog.native.js +1 -1
  88. package/dist/cjs/list/AddTagsDialog.native.js.map +1 -1
  89. package/dist/cjs/list/AssignToDialog.native.js +1 -1
  90. package/dist/cjs/list/AssignToDialog.native.js.map +1 -1
  91. package/dist/cjs/list/DoctypeListScreen.cjs +3 -1
  92. package/dist/cjs/list/DoctypeListScreen.native.js +4 -2
  93. package/dist/cjs/list/DoctypeListScreen.native.js.map +1 -1
  94. package/dist/cjs/list/ListBulkActionsBar.native.js +1 -1
  95. package/dist/cjs/list/ListBulkActionsBar.native.js.map +1 -1
  96. package/dist/cjs/list/ListFilterBar.native.js +1 -1
  97. package/dist/cjs/list/ListFilterBar.native.js.map +1 -1
  98. package/dist/cjs/list/ListSidebar.native.js +1 -1
  99. package/dist/cjs/list/ListSidebar.native.js.map +1 -1
  100. package/dist/cjs/list/bulk-edit-dialog.native.js +1 -1
  101. package/dist/cjs/list/bulk-edit-dialog.native.js.map +1 -1
  102. package/dist/cjs/list/bulk-export.native.js.map +1 -1
  103. package/dist/cjs/list/bulk-submit-cancel.native.js.map +1 -1
  104. package/dist/cjs/list/bulkActions.native.js.map +1 -1
  105. package/dist/cjs/list/filter-chips.native.js +1 -1
  106. package/dist/cjs/list/filter-chips.native.js.map +1 -1
  107. package/dist/cjs/list/filter-editor.native.js +1 -1
  108. package/dist/cjs/list/filter-editor.native.js.map +1 -1
  109. package/dist/cjs/list/filter-fields.native.js.map +1 -1
  110. package/dist/cjs/list/filter-saved.native.js +1 -1
  111. package/dist/cjs/list/filter-saved.native.js.map +1 -1
  112. package/dist/cjs/list/filter-sort.native.js +1 -1
  113. package/dist/cjs/list/filter-sort.native.js.map +1 -1
  114. package/dist/cjs/list/filter-standard.native.js.map +1 -1
  115. package/dist/cjs/list/filterConversion.native.js.map +1 -1
  116. package/dist/cjs/list/list-tools-sheet.native.js +1 -1
  117. package/dist/cjs/list/list-tools-sheet.native.js.map +1 -1
  118. package/dist/cjs/list/listColumns.native.js.map +1 -1
  119. package/dist/cjs/list/listFields.native.js.map +1 -1
  120. package/dist/cjs/list/listFormat.native.js.map +1 -1
  121. package/dist/cjs/list/listUrlState.native.js.map +1 -1
  122. package/dist/cjs/list/sidebar-section.native.js +1 -1
  123. package/dist/cjs/list/sidebar-section.native.js.map +1 -1
  124. package/dist/cjs/list/sidebar-stats.native.js.map +1 -1
  125. package/dist/cjs/list/statusColors.native.js.map +1 -1
  126. package/dist/cjs/navigation/navigator.native.js.map +1 -1
  127. package/dist/cjs/navigation/paths.native.js.map +1 -1
  128. package/dist/cjs/oneAdapter/index.native.js.map +1 -1
  129. package/dist/cjs/quickEntry/QuickEntryDialog.native.js +1 -1
  130. package/dist/cjs/quickEntry/QuickEntryDialog.native.js.map +1 -1
  131. package/dist/cjs/quickEntry/quickEntryPlan.native.js.map +1 -1
  132. package/dist/cjs/report/DoctypeReportView.cjs +3 -1
  133. package/dist/cjs/report/DoctypeReportView.native.js +5 -3
  134. package/dist/cjs/report/DoctypeReportView.native.js.map +1 -1
  135. package/dist/cjs/report/QueryReportScreen.native.js +1 -1
  136. package/dist/cjs/report/QueryReportScreen.native.js.map +1 -1
  137. package/dist/cjs/report/queryReportColumns.native.js.map +1 -1
  138. package/dist/cjs/report/queryReportFilterBar.native.js +1 -1
  139. package/dist/cjs/report/queryReportFilterBar.native.js.map +1 -1
  140. package/dist/cjs/report/queryReportUrlState.native.js.map +1 -1
  141. package/dist/cjs/report/report-grid.native.js +1 -1
  142. package/dist/cjs/report/report-grid.native.js.map +1 -1
  143. package/dist/cjs/report/report-toolbar.native.js +1 -1
  144. package/dist/cjs/report/report-toolbar.native.js.map +1 -1
  145. package/dist/cjs/report/reportShapes.native.js.map +1 -1
  146. package/dist/cjs/report/reportViewModel.native.js.map +1 -1
  147. package/dist/cjs/report/savedReports.native.js.map +1 -1
  148. package/dist/cjs/report/useQueryReport.native.js.map +1 -1
  149. package/dist/cjs/shared/deskLinks.native.js.map +1 -1
  150. package/dist/cjs/shared/listNavContext.native.js.map +1 -1
  151. package/dist/cjs/shared/types.native.js.map +1 -1
  152. package/dist/cjs/shared/useDocinfo.native.js.map +1 -1
  153. package/dist/cjs/shared/useDoctypeMeta.native.js.map +1 -1
  154. package/dist/cjs/shared/useFrappeApp.native.js.map +1 -1
  155. package/dist/cjs/shared/useRecentVisit.native.js.map +1 -1
  156. package/dist/cjs/shared/useSessionUserId.native.js.map +1 -1
  157. package/dist/cjs/shared/useSlugTarget.native.js.map +1 -1
  158. package/dist/cjs/shared/useUserRoles.native.js.map +1 -1
  159. package/dist/cjs/shell/BackofficeShell.native.js +1 -1
  160. package/dist/cjs/shell/BackofficeShell.native.js.map +1 -1
  161. package/dist/cjs/shell/HomeRedirect.native.js +1 -1
  162. package/dist/cjs/shell/HomeRedirect.native.js.map +1 -1
  163. package/dist/cjs/shell/NotFoundScreen.native.js +1 -1
  164. package/dist/cjs/shell/NotFoundScreen.native.js.map +1 -1
  165. package/dist/cjs/shell/SlugScreen.native.js +1 -1
  166. package/dist/cjs/shell/SlugScreen.native.js.map +1 -1
  167. package/dist/cjs/shell/WorkspaceSidebar.native.js +1 -1
  168. package/dist/cjs/shell/WorkspaceSidebar.native.js.map +1 -1
  169. package/dist/cjs/shell/useWorkspaces.native.js.map +1 -1
  170. package/dist/cjs/shell/workspaceIcons.native.js.map +1 -1
  171. package/dist/cjs/views/CalendarView.cjs +5 -0
  172. package/dist/cjs/views/CalendarView.native.js +6 -1
  173. package/dist/cjs/views/CalendarView.native.js.map +1 -1
  174. package/dist/cjs/views/DashboardView.cjs +5 -3
  175. package/dist/cjs/views/DashboardView.native.js +6 -4
  176. package/dist/cjs/views/DashboardView.native.js.map +1 -1
  177. package/dist/cjs/views/DoctypeViewScreen.native.js.map +1 -1
  178. package/dist/cjs/views/ImageView.cjs +5 -0
  179. package/dist/cjs/views/ImageView.native.js +6 -1
  180. package/dist/cjs/views/ImageView.native.js.map +1 -1
  181. package/dist/cjs/views/KanbanView.cjs +5 -2
  182. package/dist/cjs/views/KanbanView.native.js +6 -3
  183. package/dist/cjs/views/KanbanView.native.js.map +1 -1
  184. package/dist/cjs/views/ReportView.native.js +1 -1
  185. package/dist/cjs/views/ReportView.native.js.map +1 -1
  186. package/dist/cjs/views/TreeView.cjs +5 -0
  187. package/dist/cjs/views/TreeView.native.js +6 -1
  188. package/dist/cjs/views/TreeView.native.js.map +1 -1
  189. package/dist/cjs/views/ViewHeader.native.js +1 -1
  190. package/dist/cjs/views/ViewHeader.native.js.map +1 -1
  191. package/dist/cjs/views/ViewStates.native.js +1 -1
  192. package/dist/cjs/views/ViewStates.native.js.map +1 -1
  193. package/dist/cjs/views/ViewSwitcherMenu.native.js +1 -1
  194. package/dist/cjs/views/ViewSwitcherMenu.native.js.map +1 -1
  195. package/dist/cjs/views/calendar-field-selector.native.js +1 -1
  196. package/dist/cjs/views/calendar-field-selector.native.js.map +1 -1
  197. package/dist/cjs/views/connection.native.js.map +1 -1
  198. package/dist/cjs/views/dashboard-data.native.js.map +1 -1
  199. package/dist/cjs/views/deskViewConfigs.native.js.map +1 -1
  200. package/dist/cjs/views/kanban-board-controls.native.js +1 -1
  201. package/dist/cjs/views/kanban-board-controls.native.js.map +1 -1
  202. package/dist/cjs/views/kanban-field-picker.native.js +1 -1
  203. package/dist/cjs/views/kanban-field-picker.native.js.map +1 -1
  204. package/dist/cjs/views/kanbanBoardOps.native.js.map +1 -1
  205. package/dist/cjs/views/report-controls.native.js +1 -1
  206. package/dist/cjs/views/report-controls.native.js.map +1 -1
  207. package/dist/cjs/views/viewAvailability.native.js.map +1 -1
  208. package/dist/cjs/views/viewMeta.native.js.map +1 -1
  209. package/dist/cjs/workspace/WorkspaceChartBlock.native.js +1 -1
  210. package/dist/cjs/workspace/WorkspaceChartBlock.native.js.map +1 -1
  211. package/dist/cjs/workspace/WorkspaceGrid.native.js.map +1 -1
  212. package/dist/cjs/workspace/WorkspaceLinkCard.native.js +1 -1
  213. package/dist/cjs/workspace/WorkspaceLinkCard.native.js.map +1 -1
  214. package/dist/cjs/workspace/WorkspaceLinkDirectory.native.js +1 -1
  215. package/dist/cjs/workspace/WorkspaceLinkDirectory.native.js.map +1 -1
  216. package/dist/cjs/workspace/WorkspaceNumberCard.native.js +1 -1
  217. package/dist/cjs/workspace/WorkspaceNumberCard.native.js.map +1 -1
  218. package/dist/cjs/workspace/WorkspaceQuickList.native.js +1 -1
  219. package/dist/cjs/workspace/WorkspaceQuickList.native.js.map +1 -1
  220. package/dist/cjs/workspace/WorkspaceRecents.native.js +1 -1
  221. package/dist/cjs/workspace/WorkspaceRecents.native.js.map +1 -1
  222. package/dist/cjs/workspace/WorkspaceScreen.native.js +1 -1
  223. package/dist/cjs/workspace/WorkspaceScreen.native.js.map +1 -1
  224. package/dist/cjs/workspace/WorkspaceShortcut.native.js +1 -1
  225. package/dist/cjs/workspace/WorkspaceShortcut.native.js.map +1 -1
  226. package/dist/cjs/workspace/parseContent.native.js.map +1 -1
  227. package/dist/cjs/workspace/types.native.js.map +1 -1
  228. package/dist/cjs/workspace/useDashboardChart.native.js.map +1 -1
  229. package/dist/cjs/workspace/useWorkspaceDoc.native.js.map +1 -1
  230. package/dist/esm/chrome/BackofficeAwesomebar.native.js.map +1 -1
  231. package/dist/esm/chrome/CommandPalette.native.js.map +1 -1
  232. package/dist/esm/chrome/HelpMenu.native.js.map +1 -1
  233. package/dist/esm/chrome/NotificationsButton.native.js.map +1 -1
  234. package/dist/esm/chrome/UserMenu.native.js.map +1 -1
  235. package/dist/esm/chrome/awesomebar-data.native.js.map +1 -1
  236. package/dist/esm/chrome/command-palette-model.native.js.map +1 -1
  237. package/dist/esm/chrome/help-about-dialog.native.js.map +1 -1
  238. package/dist/esm/chrome/help-shortcuts-dialog.native.js.map +1 -1
  239. package/dist/esm/chrome/notifications-data.native.js.map +1 -1
  240. package/dist/esm/chrome/notifications-panel.native.js.map +1 -1
  241. package/dist/esm/chrome/notifications-utils.native.js.map +1 -1
  242. package/dist/esm/chrome/shortcuts.native.js.map +1 -1
  243. package/dist/esm/chrome/user-session.native.js.map +1 -1
  244. package/dist/esm/config/BackofficeProvider.mjs +5 -11
  245. package/dist/esm/config/BackofficeProvider.mjs.map +1 -1
  246. package/dist/esm/config/BackofficeProvider.native.js +10 -30
  247. package/dist/esm/config/BackofficeProvider.native.js.map +1 -1
  248. package/dist/esm/config/capabilities.native.js.map +1 -1
  249. package/dist/esm/config/events.native.js.map +1 -1
  250. package/dist/esm/config/slots.native.js.map +1 -1
  251. package/dist/esm/desk/Desk.mjs +162 -0
  252. package/dist/esm/desk/Desk.mjs.map +1 -0
  253. package/dist/esm/desk/Desk.native.js +186 -0
  254. package/dist/esm/desk/Desk.native.js.map +1 -0
  255. package/dist/esm/desk/DeskSurface.mjs +97 -0
  256. package/dist/esm/desk/DeskSurface.mjs.map +1 -0
  257. package/dist/esm/desk/DeskSurface.native.js +101 -0
  258. package/dist/esm/desk/DeskSurface.native.js.map +1 -0
  259. package/dist/esm/desk/resolveDeskPath.mjs +93 -0
  260. package/dist/esm/desk/resolveDeskPath.mjs.map +1 -0
  261. package/dist/esm/desk/resolveDeskPath.native.js +95 -0
  262. package/dist/esm/desk/resolveDeskPath.native.js.map +1 -0
  263. package/dist/esm/desk/scope.mjs +27 -0
  264. package/dist/esm/desk/scope.mjs.map +1 -0
  265. package/dist/esm/desk/scope.native.js +31 -0
  266. package/dist/esm/desk/scope.native.js.map +1 -0
  267. package/dist/esm/desk/target.mjs +147 -0
  268. package/dist/esm/desk/target.mjs.map +1 -0
  269. package/dist/esm/desk/target.native.js +148 -0
  270. package/dist/esm/desk/target.native.js.map +1 -0
  271. package/dist/esm/form/DocFormScreen.native.js.map +1 -1
  272. package/dist/esm/form/FormConnections.native.js.map +1 -1
  273. package/dist/esm/form/FormDialogs.native.js.map +1 -1
  274. package/dist/esm/form/FormErrorBoundary.native.js.map +1 -1
  275. package/dist/esm/form/FormHeaderCluster.native.js.map +1 -1
  276. package/dist/esm/form/FormSidebarPanel.native.js.map +1 -1
  277. package/dist/esm/form/FormTimeline.native.js.map +1 -1
  278. package/dist/esm/form/FormToolbar.native.js.map +1 -1
  279. package/dist/esm/form/connections-data.native.js.map +1 -1
  280. package/dist/esm/form/createPrefill.native.js.map +1 -1
  281. package/dist/esm/form/dependsOn.native.js.map +1 -1
  282. package/dist/esm/form/dirtyTracking.native.js.map +1 -1
  283. package/dist/esm/form/docinfo.native.js.map +1 -1
  284. package/dist/esm/form/fetchFrom.native.js.map +1 -1
  285. package/dist/esm/form/fieldPermissions.native.js.map +1 -1
  286. package/dist/esm/form/formActions.native.js.map +1 -1
  287. package/dist/esm/form/formLayout.native.js.map +1 -1
  288. package/dist/esm/form/platformHooks.native.js.map +1 -1
  289. package/dist/esm/form/sidebar-attachments.native.js.map +1 -1
  290. package/dist/esm/form/sidebar-dialogs.native.js.map +1 -1
  291. package/dist/esm/form/sidebar-people.native.js.map +1 -1
  292. package/dist/esm/form/sidebar-rpc.native.js.map +1 -1
  293. package/dist/esm/form/sidebar-utils.native.js.map +1 -1
  294. package/dist/esm/form/timeline-entries.native.js.map +1 -1
  295. package/dist/esm/form/timeline-utils.native.js.map +1 -1
  296. package/dist/esm/form/useFormEngine.native.js.map +1 -1
  297. package/dist/esm/i18n/en.native.js.map +1 -1
  298. package/dist/esm/i18n/index.native.js.map +1 -1
  299. package/dist/esm/index.mjs +6 -1
  300. package/dist/esm/index.mjs.map +1 -1
  301. package/dist/esm/index.native.js +6 -1
  302. package/dist/esm/index.native.js.map +1 -1
  303. package/dist/esm/list/AddTagsDialog.native.js.map +1 -1
  304. package/dist/esm/list/AssignToDialog.native.js.map +1 -1
  305. package/dist/esm/list/DoctypeListScreen.mjs +3 -1
  306. package/dist/esm/list/DoctypeListScreen.mjs.map +1 -1
  307. package/dist/esm/list/DoctypeListScreen.native.js +3 -1
  308. package/dist/esm/list/DoctypeListScreen.native.js.map +1 -1
  309. package/dist/esm/list/ListBulkActionsBar.native.js.map +1 -1
  310. package/dist/esm/list/ListFilterBar.native.js.map +1 -1
  311. package/dist/esm/list/ListSidebar.native.js.map +1 -1
  312. package/dist/esm/list/bulk-edit-dialog.native.js.map +1 -1
  313. package/dist/esm/list/bulk-export.native.js.map +1 -1
  314. package/dist/esm/list/bulk-submit-cancel.native.js.map +1 -1
  315. package/dist/esm/list/bulkActions.native.js.map +1 -1
  316. package/dist/esm/list/filter-chips.native.js.map +1 -1
  317. package/dist/esm/list/filter-editor.native.js.map +1 -1
  318. package/dist/esm/list/filter-fields.native.js.map +1 -1
  319. package/dist/esm/list/filter-saved.native.js.map +1 -1
  320. package/dist/esm/list/filter-sort.native.js.map +1 -1
  321. package/dist/esm/list/filter-standard.native.js.map +1 -1
  322. package/dist/esm/list/filterConversion.native.js.map +1 -1
  323. package/dist/esm/list/list-tools-sheet.native.js.map +1 -1
  324. package/dist/esm/list/listColumns.native.js.map +1 -1
  325. package/dist/esm/list/listFields.native.js.map +1 -1
  326. package/dist/esm/list/listFormat.native.js.map +1 -1
  327. package/dist/esm/list/listUrlState.native.js.map +1 -1
  328. package/dist/esm/list/sidebar-section.native.js.map +1 -1
  329. package/dist/esm/list/sidebar-stats.native.js.map +1 -1
  330. package/dist/esm/list/statusColors.native.js.map +1 -1
  331. package/dist/esm/navigation/navigator.native.js.map +1 -1
  332. package/dist/esm/navigation/paths.native.js.map +1 -1
  333. package/dist/esm/oneAdapter/index.native.js.map +1 -1
  334. package/dist/esm/quickEntry/QuickEntryDialog.native.js.map +1 -1
  335. package/dist/esm/quickEntry/quickEntryPlan.native.js.map +1 -1
  336. package/dist/esm/report/DoctypeReportView.mjs +3 -1
  337. package/dist/esm/report/DoctypeReportView.mjs.map +1 -1
  338. package/dist/esm/report/DoctypeReportView.native.js +4 -2
  339. package/dist/esm/report/DoctypeReportView.native.js.map +1 -1
  340. package/dist/esm/report/QueryReportScreen.native.js.map +1 -1
  341. package/dist/esm/report/queryReportColumns.native.js.map +1 -1
  342. package/dist/esm/report/queryReportFilterBar.native.js.map +1 -1
  343. package/dist/esm/report/queryReportUrlState.native.js.map +1 -1
  344. package/dist/esm/report/report-grid.native.js.map +1 -1
  345. package/dist/esm/report/report-toolbar.native.js.map +1 -1
  346. package/dist/esm/report/reportShapes.native.js.map +1 -1
  347. package/dist/esm/report/reportViewModel.native.js.map +1 -1
  348. package/dist/esm/report/savedReports.native.js.map +1 -1
  349. package/dist/esm/report/useQueryReport.native.js.map +1 -1
  350. package/dist/esm/shared/deskLinks.native.js.map +1 -1
  351. package/dist/esm/shared/listNavContext.native.js.map +1 -1
  352. package/dist/esm/shared/types.native.js.map +1 -1
  353. package/dist/esm/shared/useDocinfo.native.js.map +1 -1
  354. package/dist/esm/shared/useDoctypeMeta.native.js.map +1 -1
  355. package/dist/esm/shared/useFrappeApp.native.js.map +1 -1
  356. package/dist/esm/shared/useRecentVisit.native.js.map +1 -1
  357. package/dist/esm/shared/useSessionUserId.native.js.map +1 -1
  358. package/dist/esm/shared/useSlugTarget.native.js.map +1 -1
  359. package/dist/esm/shared/useUserRoles.native.js.map +1 -1
  360. package/dist/esm/shell/BackofficeShell.native.js.map +1 -1
  361. package/dist/esm/shell/HomeRedirect.native.js.map +1 -1
  362. package/dist/esm/shell/NotFoundScreen.native.js.map +1 -1
  363. package/dist/esm/shell/SlugScreen.native.js.map +1 -1
  364. package/dist/esm/shell/WorkspaceSidebar.native.js.map +1 -1
  365. package/dist/esm/shell/useWorkspaces.native.js.map +1 -1
  366. package/dist/esm/shell/workspaceIcons.native.js.map +1 -1
  367. package/dist/esm/views/CalendarView.mjs +5 -0
  368. package/dist/esm/views/CalendarView.mjs.map +1 -1
  369. package/dist/esm/views/CalendarView.native.js +5 -0
  370. package/dist/esm/views/CalendarView.native.js.map +1 -1
  371. package/dist/esm/views/DashboardView.mjs +5 -3
  372. package/dist/esm/views/DashboardView.mjs.map +1 -1
  373. package/dist/esm/views/DashboardView.native.js +5 -3
  374. package/dist/esm/views/DashboardView.native.js.map +1 -1
  375. package/dist/esm/views/DoctypeViewScreen.native.js.map +1 -1
  376. package/dist/esm/views/ImageView.mjs +5 -0
  377. package/dist/esm/views/ImageView.mjs.map +1 -1
  378. package/dist/esm/views/ImageView.native.js +5 -0
  379. package/dist/esm/views/ImageView.native.js.map +1 -1
  380. package/dist/esm/views/KanbanView.mjs +5 -2
  381. package/dist/esm/views/KanbanView.mjs.map +1 -1
  382. package/dist/esm/views/KanbanView.native.js +5 -2
  383. package/dist/esm/views/KanbanView.native.js.map +1 -1
  384. package/dist/esm/views/ReportView.native.js.map +1 -1
  385. package/dist/esm/views/TreeView.mjs +5 -0
  386. package/dist/esm/views/TreeView.mjs.map +1 -1
  387. package/dist/esm/views/TreeView.native.js +5 -0
  388. package/dist/esm/views/TreeView.native.js.map +1 -1
  389. package/dist/esm/views/ViewHeader.native.js.map +1 -1
  390. package/dist/esm/views/ViewStates.native.js.map +1 -1
  391. package/dist/esm/views/ViewSwitcherMenu.native.js.map +1 -1
  392. package/dist/esm/views/calendar-field-selector.native.js.map +1 -1
  393. package/dist/esm/views/connection.native.js.map +1 -1
  394. package/dist/esm/views/dashboard-data.native.js.map +1 -1
  395. package/dist/esm/views/deskViewConfigs.native.js.map +1 -1
  396. package/dist/esm/views/kanban-board-controls.native.js.map +1 -1
  397. package/dist/esm/views/kanban-field-picker.native.js.map +1 -1
  398. package/dist/esm/views/kanbanBoardOps.native.js.map +1 -1
  399. package/dist/esm/views/report-controls.native.js.map +1 -1
  400. package/dist/esm/views/viewAvailability.native.js.map +1 -1
  401. package/dist/esm/views/viewMeta.native.js.map +1 -1
  402. package/dist/esm/workspace/WorkspaceChartBlock.native.js.map +1 -1
  403. package/dist/esm/workspace/WorkspaceGrid.native.js.map +1 -1
  404. package/dist/esm/workspace/WorkspaceLinkCard.native.js.map +1 -1
  405. package/dist/esm/workspace/WorkspaceLinkDirectory.native.js.map +1 -1
  406. package/dist/esm/workspace/WorkspaceNumberCard.native.js.map +1 -1
  407. package/dist/esm/workspace/WorkspaceQuickList.native.js.map +1 -1
  408. package/dist/esm/workspace/WorkspaceRecents.native.js.map +1 -1
  409. package/dist/esm/workspace/WorkspaceScreen.native.js.map +1 -1
  410. package/dist/esm/workspace/WorkspaceShortcut.native.js.map +1 -1
  411. package/dist/esm/workspace/parseContent.native.js.map +1 -1
  412. package/dist/esm/workspace/types.native.js.map +1 -1
  413. package/dist/esm/workspace/useDashboardChart.native.js.map +1 -1
  414. package/dist/esm/workspace/useWorkspaceDoc.native.js.map +1 -1
  415. package/dist/jsx/config/BackofficeProvider.mjs +5 -11
  416. package/dist/jsx/config/BackofficeProvider.mjs.map +1 -1
  417. package/dist/jsx/config/BackofficeProvider.native.js +9 -29
  418. package/dist/jsx/config/BackofficeProvider.native.js.map +1 -1
  419. package/dist/jsx/desk/Desk.mjs +162 -0
  420. package/dist/jsx/desk/Desk.mjs.map +1 -0
  421. package/dist/jsx/desk/Desk.native.js +214 -0
  422. package/dist/jsx/desk/Desk.native.js.map +1 -0
  423. package/dist/jsx/desk/DeskSurface.mjs +97 -0
  424. package/dist/jsx/desk/DeskSurface.mjs.map +1 -0
  425. package/dist/jsx/desk/DeskSurface.native.js +130 -0
  426. package/dist/jsx/desk/DeskSurface.native.js.map +1 -0
  427. package/dist/jsx/desk/resolveDeskPath.mjs +93 -0
  428. package/dist/jsx/desk/resolveDeskPath.mjs.map +1 -0
  429. package/dist/jsx/desk/resolveDeskPath.native.js +123 -0
  430. package/dist/jsx/desk/resolveDeskPath.native.js.map +1 -0
  431. package/dist/jsx/desk/scope.mjs +27 -0
  432. package/dist/jsx/desk/scope.mjs.map +1 -0
  433. package/dist/jsx/desk/scope.native.js +61 -0
  434. package/dist/jsx/desk/scope.native.js.map +1 -0
  435. package/dist/jsx/desk/target.mjs +147 -0
  436. package/dist/jsx/desk/target.mjs.map +1 -0
  437. package/dist/jsx/desk/target.native.js +178 -0
  438. package/dist/jsx/desk/target.native.js.map +1 -0
  439. package/dist/jsx/index.js +6 -1
  440. package/dist/jsx/index.js.map +1 -1
  441. package/dist/jsx/index.mjs +6 -1
  442. package/dist/jsx/index.mjs.map +1 -1
  443. package/dist/jsx/index.native.js +13 -0
  444. package/dist/jsx/index.native.js.map +1 -1
  445. package/dist/jsx/list/DoctypeListScreen.mjs +3 -1
  446. package/dist/jsx/list/DoctypeListScreen.mjs.map +1 -1
  447. package/dist/jsx/list/DoctypeListScreen.native.js +3 -1
  448. package/dist/jsx/list/DoctypeListScreen.native.js.map +1 -1
  449. package/dist/jsx/report/DoctypeReportView.mjs +3 -1
  450. package/dist/jsx/report/DoctypeReportView.mjs.map +1 -1
  451. package/dist/jsx/report/DoctypeReportView.native.js +4 -2
  452. package/dist/jsx/report/DoctypeReportView.native.js.map +1 -1
  453. package/dist/jsx/views/CalendarView.mjs +5 -0
  454. package/dist/jsx/views/CalendarView.mjs.map +1 -1
  455. package/dist/jsx/views/CalendarView.native.js +5 -0
  456. package/dist/jsx/views/CalendarView.native.js.map +1 -1
  457. package/dist/jsx/views/DashboardView.mjs +5 -3
  458. package/dist/jsx/views/DashboardView.mjs.map +1 -1
  459. package/dist/jsx/views/DashboardView.native.js +5 -3
  460. package/dist/jsx/views/DashboardView.native.js.map +1 -1
  461. package/dist/jsx/views/ImageView.mjs +5 -0
  462. package/dist/jsx/views/ImageView.mjs.map +1 -1
  463. package/dist/jsx/views/ImageView.native.js +5 -0
  464. package/dist/jsx/views/ImageView.native.js.map +1 -1
  465. package/dist/jsx/views/KanbanView.mjs +5 -2
  466. package/dist/jsx/views/KanbanView.mjs.map +1 -1
  467. package/dist/jsx/views/KanbanView.native.js +5 -2
  468. package/dist/jsx/views/KanbanView.native.js.map +1 -1
  469. package/dist/jsx/views/TreeView.mjs +5 -0
  470. package/dist/jsx/views/TreeView.mjs.map +1 -1
  471. package/dist/jsx/views/TreeView.native.js +5 -0
  472. package/dist/jsx/views/TreeView.native.js.map +1 -1
  473. package/package.json +12 -12
  474. package/src/config/BackofficeProvider.tsx +11 -18
  475. package/src/desk/Desk.spec.tsx +287 -0
  476. package/src/desk/Desk.tsx +308 -0
  477. package/src/desk/DeskSurface.tsx +132 -0
  478. package/src/desk/doctrine.spec.ts +48 -0
  479. package/src/desk/resolveDeskPath.spec.ts +174 -0
  480. package/src/desk/resolveDeskPath.ts +111 -0
  481. package/src/desk/scope.tsx +52 -0
  482. package/src/desk/target.ts +169 -0
  483. package/src/index.ts +17 -0
  484. package/src/list/DoctypeListScreen.tsx +4 -1
  485. package/src/report/DoctypeReportView.tsx +6 -2
  486. package/src/views/CalendarView.tsx +3 -0
  487. package/src/views/DashboardView.tsx +5 -3
  488. package/src/views/ImageView.tsx +3 -0
  489. package/src/views/KanbanView.tsx +5 -1
  490. package/src/views/TreeView.tsx +3 -0
  491. package/types/config/BackofficeProvider.d.ts +6 -4
  492. package/types/config/BackofficeProvider.d.ts.map +1 -1
  493. package/types/desk/Desk.d.ts +91 -0
  494. package/types/desk/Desk.d.ts.map +1 -0
  495. package/types/desk/DeskSurface.d.ts +24 -0
  496. package/types/desk/DeskSurface.d.ts.map +1 -0
  497. package/types/desk/resolveDeskPath.d.ts +60 -0
  498. package/types/desk/resolveDeskPath.d.ts.map +1 -0
  499. package/types/desk/scope.d.ts +31 -0
  500. package/types/desk/scope.d.ts.map +1 -0
  501. package/types/desk/target.d.ts +57 -0
  502. package/types/desk/target.d.ts.map +1 -0
  503. package/types/index.d.ts +10 -0
  504. package/types/index.d.ts.map +1 -1
  505. package/types/list/DoctypeListScreen.d.ts.map +1 -1
  506. package/types/report/DoctypeReportView.d.ts.map +1 -1
  507. package/types/views/CalendarView.d.ts.map +1 -1
  508. package/types/views/DashboardView.d.ts.map +1 -1
  509. package/types/views/ImageView.d.ts.map +1 -1
  510. package/types/views/KanbanView.d.ts.map +1 -1
  511. package/types/views/TreeView.d.ts.map +1 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * DeskSurface — the target→surface switch plus the surface override
3
+ * registry (MPO-14 / gaps GL-1 assembly half + GL-6, spec 09 §3, §5.1).
4
+ *
5
+ * A pure dispatch: every branch renders an EXISTING wired component; no
6
+ * fetch, no filter construction, no visual values (DK-2/DK-3). Overrides
7
+ * ride props (per-Desk by construction, DK-7): per-doctype first, then
8
+ * per-kind, then the built-in.
9
+ */
10
+ import { Spinner, YStack } from "@multiplatform.one/components";
11
+ import { useMemo, type ComponentType } from "react";
12
+ import { setCreatePrefill } from "../form/createPrefill";
13
+ import { DocFormScreen } from "../form/DocFormScreen";
14
+ import { DoctypeListScreen } from "../list/DoctypeListScreen";
15
+ import type { BackofficeView } from "../navigation/paths";
16
+ import { QueryReportScreen } from "../report/QueryReportScreen";
17
+ import type { FrappeFilters } from "../shared/types";
18
+ import { HomeRedirect } from "../shell/HomeRedirect";
19
+ import { NotFoundScreen } from "../shell/NotFoundScreen";
20
+ import { DoctypeViewScreen } from "../views/DoctypeViewScreen";
21
+ import { WorkspaceScreen } from "../workspace/WorkspaceScreen";
22
+ import type { DeskTarget } from "./target";
23
+
24
+ export type DeskSurfaceKind = DeskTarget["kind"];
25
+
26
+ /** The whole contract an override receives — thin enough to wrap the built-in. */
27
+ export interface DeskSurfaceProps {
28
+ target: DeskTarget;
29
+ readOnly?: boolean;
30
+ }
31
+
32
+ /** A component per kind, or per doctype under that kind. */
33
+ export type DeskSurfaceOverride =
34
+ | ComponentType<DeskSurfaceProps>
35
+ | Record<string, ComponentType<DeskSurfaceProps>>;
36
+
37
+ export type DeskSurfaceOverrides = Partial<Record<DeskSurfaceKind, DeskSurfaceOverride>>;
38
+
39
+ function resolveOverride(
40
+ overrides: DeskSurfaceOverrides | undefined,
41
+ target: DeskTarget,
42
+ ): ComponentType<DeskSurfaceProps> | undefined {
43
+ const entry = overrides?.[target.kind];
44
+ if (!entry) return undefined;
45
+ if (typeof entry === "function") return entry;
46
+ const doctype = "doctype" in target ? target.doctype : undefined;
47
+ return doctype ? entry[doctype] : undefined;
48
+ }
49
+
50
+ /** Create mode, `?d=`/pin defaults routed through the ONE prefill stash. */
51
+ function NewDocSurface({
52
+ doctype,
53
+ defaults,
54
+ readOnly,
55
+ }: {
56
+ doctype: string;
57
+ defaults?: Record<string, unknown>;
58
+ readOnly?: boolean;
59
+ }) {
60
+ const defaultsKey = JSON.stringify(defaults ?? null);
61
+ // Stash in a memo (not an effect) so the values land before
62
+ // DocFormScreen's create-mode seeding runs — same contract as the old
63
+ // host route screen this replaces.
64
+ useMemo(() => {
65
+ if (defaults && Object.keys(defaults).length > 0) setCreatePrefill(doctype, defaults);
66
+ // oxlint-disable-next-line exhaustive-deps
67
+ }, [doctype, defaultsKey]);
68
+ // Keyed on defaults: same-doctype navigation with different `?d=` must
69
+ // remount to re-seed.
70
+ return <DocFormScreen key={defaultsKey} doctype={doctype} name="new" readOnly={readOnly} />;
71
+ }
72
+
73
+ export interface DeskSurfaceHostProps extends DeskSurfaceProps {
74
+ overrides?: DeskSurfaceOverrides;
75
+ /** Seed for the list surface's user-editable filter channel. */
76
+ initialFilters?: FrappeFilters;
77
+ /** View-switcher allowlist forwarded to the list surface. */
78
+ views?: readonly BackofficeView[];
79
+ }
80
+
81
+ export function DeskSurface({
82
+ target,
83
+ overrides,
84
+ readOnly,
85
+ initialFilters,
86
+ views,
87
+ }: DeskSurfaceHostProps) {
88
+ const Override = resolveOverride(overrides, target);
89
+ if (Override) return <Override target={target} readOnly={readOnly} />;
90
+
91
+ switch (target.kind) {
92
+ case "home":
93
+ return <HomeRedirect />;
94
+ case "workspace":
95
+ return <WorkspaceScreen workspace={target.workspace} />;
96
+ case "list":
97
+ return (
98
+ <DoctypeListScreen
99
+ doctype={target.doctype}
100
+ filtersParam={target.filtersParam}
101
+ sortParam={target.sortParam}
102
+ initialFilters={initialFilters}
103
+ views={views}
104
+ />
105
+ );
106
+ case "view":
107
+ return <DoctypeViewScreen doctype={target.doctype} view={target.view} />;
108
+ case "new":
109
+ return (
110
+ <NewDocSurface doctype={target.doctype} defaults={target.defaults} readOnly={readOnly} />
111
+ );
112
+ case "form":
113
+ // MPO-15: DocFormScreen is the strong form today. When the form-engine
114
+ // seam collapses (formLayout + useFormEngine hoisted into frappe-ui,
115
+ // gap GL-3), the exported FrappeForm becomes this branch's renderer —
116
+ // swap here, nowhere else.
117
+ return <DocFormScreen doctype={target.doctype} name={target.name} readOnly={readOnly} />;
118
+ case "report":
119
+ return <QueryReportScreen reportName={target.reportName} />;
120
+ case "not-found":
121
+ return <NotFoundScreen />;
122
+ }
123
+ }
124
+
125
+ /** The resolving state — same presentation as the slug route's spinner. */
126
+ export function DeskSurfaceLoading() {
127
+ return (
128
+ <YStack flex={1} alignItems="center" justifyContent="center">
129
+ <Spinner size="large" />
130
+ </YStack>
131
+ );
132
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The doctrine greps (spec 09 §9.2), shipped as spec tests — a rule nobody
3
+ * runs is a wish.
4
+ *
5
+ * DK-2: Desk contains no data wiring. Every byte it displays is fetched by
6
+ * a component it renders or an exported hook.
7
+ * DK-3: Desk contains no visual values — no color literal, no pixel literal.
8
+ */
9
+ import { readdirSync, readFileSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { describe, expect, it } from "vitest";
12
+
13
+ const DESK_DIR = join(__dirname);
14
+
15
+ function deskSources(extensions: readonly string[]): { file: string; source: string }[] {
16
+ return readdirSync(DESK_DIR)
17
+ .filter(
18
+ (file) =>
19
+ extensions.some((extension) => file.endsWith(extension)) &&
20
+ !file.includes(".spec.") &&
21
+ !file.includes(".stories."),
22
+ )
23
+ .map((file) => ({ file, source: readFileSync(join(DESK_DIR, file), "utf8") }));
24
+ }
25
+
26
+ /** Match lines, reporting file:line so a failure names its violation. */
27
+ function violations(sources: { file: string; source: string }[], pattern: RegExp): string[] {
28
+ const found: string[] = [];
29
+ for (const { file, source } of sources) {
30
+ source.split("\n").forEach((line, index) => {
31
+ if (pattern.test(line)) found.push(`${file}:${index + 1}: ${line.trim()}`);
32
+ });
33
+ }
34
+ return found;
35
+ }
36
+
37
+ describe("desk doctrine (spec 09 §9.2)", () => {
38
+ it("DK-2: no data wiring anywhere in src/desk", () => {
39
+ const pattern =
40
+ /HttpClient|useFrappeCollection|useLiveQuery|\bfetch\(|axios|\/api\/(resource|method)/;
41
+ expect(violations(deskSources([".ts", ".tsx"]), pattern)).toEqual([]);
42
+ });
43
+
44
+ it("DK-3: no color or pixel literals anywhere in src/desk", () => {
45
+ const pattern = /#[0-9a-fA-F]{3,8}\b|rgba?\(|\b(width|height|padding|margin|fontSize)=\{[0-9]/;
46
+ expect(violations(deskSources([".tsx"]), pattern)).toEqual([]);
47
+ });
48
+ });
@@ -0,0 +1,174 @@
1
+ /**
2
+ * DM-1 correctness proof (spec 09 §4.3): for every builder in
3
+ * `createBackofficePaths`, `resolveDeskPath(paths.x(...))` returns the
4
+ * address that built it — both halves are pure, so the round-trip is the
5
+ * whole contract.
6
+ */
7
+ import { describe, expect, it } from "vitest";
8
+ import { parseBackofficeHref } from "../navigation/navigator";
9
+ import { BACKOFFICE_VIEWS, createBackofficePaths } from "../navigation/paths";
10
+ import { resolveDeskPath, type DeskAddress } from "./resolveDeskPath";
11
+
12
+ const BASE_PATHS = ["/backoffice", "/admin", "/", "/nested/desk"] as const;
13
+
14
+ /** Split a built href the way the navigator does, then resolve it. */
15
+ function resolve(href: string, basePath: string): DeskAddress {
16
+ const { path, params } = parseBackofficeHref(href);
17
+ return resolveDeskPath(path, basePath, params);
18
+ }
19
+
20
+ describe.each(BASE_PATHS)("resolveDeskPath round-trips createBackofficePaths at %s", (basePath) => {
21
+ const paths = createBackofficePaths(basePath);
22
+
23
+ it("home() → home", () => {
24
+ expect(resolve(paths.home(), basePath)).toEqual({ kind: "home" });
25
+ });
26
+
27
+ it("workspace() → slug (ambiguity is data, resolved downstream)", () => {
28
+ expect(resolve(paths.workspace("Accounting"), basePath)).toEqual({
29
+ kind: "slug",
30
+ slug: "accounting",
31
+ filtersParam: undefined,
32
+ sortParam: undefined,
33
+ });
34
+ });
35
+
36
+ it("list() → slug", () => {
37
+ expect(resolve(paths.list("Sales Order"), basePath)).toMatchObject({
38
+ kind: "slug",
39
+ slug: "sales-order",
40
+ });
41
+ });
42
+
43
+ it.each(BACKOFFICE_VIEWS.filter((view) => view !== "list"))("view(%s) → slug-view", (view) => {
44
+ expect(resolve(paths.view("Sales Order", view), basePath)).toEqual({
45
+ kind: "slug-view",
46
+ slug: "sales-order",
47
+ view,
48
+ });
49
+ });
50
+
51
+ it("view('list') → the list surface, exactly like list()", () => {
52
+ expect(resolve(paths.view("Sales Order", "list"), basePath)).toMatchObject({
53
+ kind: "slug",
54
+ slug: "sales-order",
55
+ });
56
+ });
57
+
58
+ it("newDoc() → slug-new, without and with ?d= defaults", () => {
59
+ expect(resolve(paths.newDoc("Sales Order"), basePath)).toEqual({
60
+ kind: "slug-new",
61
+ slug: "sales-order",
62
+ defaults: undefined,
63
+ });
64
+ const defaults = { customer: "ACME & Sons", qty: 2 };
65
+ expect(resolve(paths.newDoc("Sales Order", defaults), basePath)).toEqual({
66
+ kind: "slug-new",
67
+ slug: "sales-order",
68
+ defaults,
69
+ });
70
+ });
71
+
72
+ it("form() → slug-name, decoding encoded document names", () => {
73
+ expect(resolve(paths.form("Sales Order", "SO-0001"), basePath)).toEqual({
74
+ kind: "slug-name",
75
+ slug: "sales-order",
76
+ name: "SO-0001",
77
+ });
78
+ expect(resolve(paths.form("File", "a b/c#1"), basePath)).toEqual({
79
+ kind: "slug-name",
80
+ slug: "file",
81
+ name: "a b/c#1",
82
+ });
83
+ });
84
+
85
+ it("a document literally named 'new' still resolves as create mode (desk parity)", () => {
86
+ expect(resolve(paths.form("Task", "new"), basePath)).toMatchObject({ kind: "slug-new" });
87
+ });
88
+
89
+ it("queryReport() → report, decoding encoded report names", () => {
90
+ expect(resolve(paths.queryReport("Accounts Receivable"), basePath)).toEqual({
91
+ kind: "report",
92
+ reportName: "Accounts Receivable",
93
+ filtersParam: undefined,
94
+ });
95
+ });
96
+ });
97
+
98
+ describe("resolveDeskPath search params", () => {
99
+ const paths = createBackofficePaths("/backoffice");
100
+
101
+ it("carries ?f=/?sort= on the list address", () => {
102
+ const address = resolveDeskPath("/backoffice/todo", "/backoffice", {
103
+ f: '[["status","=","Open"]]',
104
+ sort: "modified.desc",
105
+ });
106
+ expect(address).toEqual({
107
+ kind: "slug",
108
+ slug: "todo",
109
+ filtersParam: '[["status","=","Open"]]',
110
+ sortParam: "modified.desc",
111
+ });
112
+ });
113
+
114
+ it("carries ?board=/?field=/?f= on the view address", () => {
115
+ const address = resolveDeskPath(`${paths.view("ToDo", "kanban")}`, "/backoffice", {
116
+ board: "My Board",
117
+ field: "date",
118
+ });
119
+ expect(address).toEqual({
120
+ kind: "slug-view",
121
+ slug: "todo",
122
+ view: "kanban",
123
+ params: { board: "My Board", field: "date", filtersParam: undefined },
124
+ });
125
+ });
126
+
127
+ it("carries ?filters= on the report address", () => {
128
+ const address = resolveDeskPath(
129
+ "/backoffice/query-report/Accounts%20Receivable",
130
+ "/backoffice",
131
+ {
132
+ filters: '{"company":"ACME"}',
133
+ },
134
+ );
135
+ expect(address).toEqual({
136
+ kind: "report",
137
+ reportName: "Accounts Receivable",
138
+ filtersParam: '{"company":"ACME"}',
139
+ });
140
+ });
141
+ });
142
+
143
+ describe("resolveDeskPath rejections", () => {
144
+ it("paths outside basePath are not-found", () => {
145
+ expect(resolveDeskPath("/elsewhere/todo", "/backoffice")).toEqual({
146
+ kind: "not-found",
147
+ path: "/elsewhere/todo",
148
+ });
149
+ // Prefix must match on a segment boundary.
150
+ expect(resolveDeskPath("/backofficex/todo", "/backoffice")).toMatchObject({
151
+ kind: "not-found",
152
+ });
153
+ });
154
+
155
+ it("malformed shapes are not-found", () => {
156
+ expect(resolveDeskPath("/backoffice/todo/view/nope", "/backoffice")).toMatchObject({
157
+ kind: "not-found",
158
+ });
159
+ expect(resolveDeskPath("/backoffice/todo/view/kanban/extra", "/backoffice")).toMatchObject({
160
+ kind: "not-found",
161
+ });
162
+ expect(resolveDeskPath("/backoffice/query-report", "/backoffice")).toMatchObject({
163
+ kind: "not-found",
164
+ });
165
+ });
166
+
167
+ it("trailing slashes normalize", () => {
168
+ expect(resolveDeskPath("/backoffice/", "/backoffice")).toEqual({ kind: "home" });
169
+ expect(resolveDeskPath("/backoffice/todo/", "/backoffice")).toMatchObject({
170
+ kind: "slug",
171
+ slug: "todo",
172
+ });
173
+ });
174
+ });
@@ -0,0 +1,111 @@
1
+ /**
2
+ * resolveDeskPath — the pure path→surface resolver (MPO-14 / gap GL-1,
3
+ * spec 09 §DM-1, §4.3).
4
+ *
5
+ * One inverse for every builder in `createBackofficePaths`, so dispatch
6
+ * lives in the package once instead of being re-derived per host route
7
+ * file. Pure: no network, no React. The slug half of an address stays
8
+ * AMBIGUOUS here (workspace vs doctype is data, resolved by
9
+ * `useSlugTarget`); `useDeskTarget` composes the two.
10
+ */
11
+ import type { BackofficeParams } from "../navigation/navigator";
12
+ import {
13
+ BACKOFFICE_BASE,
14
+ isBackofficeView,
15
+ parseDocDefaults,
16
+ type BackofficeView,
17
+ } from "../navigation/paths";
18
+
19
+ /** View search params the view surface reads (board/field/f — spec §2.2). */
20
+ export interface DeskViewParams {
21
+ /** `?board=` kanban board selection. */
22
+ board?: string;
23
+ /** `?field=` calendar date field. */
24
+ field?: string;
25
+ /** `?f=` report base filters (raw urlencoded JSON). */
26
+ filtersParam?: string;
27
+ }
28
+
29
+ /**
30
+ * A resolved desk address: the shape of the URL, before slug disambiguation.
31
+ * `slug` kinds still need the runtime workspace/doctype index.
32
+ */
33
+ export type DeskAddress =
34
+ | { kind: "home" }
35
+ | { kind: "slug"; slug: string; filtersParam?: string; sortParam?: string }
36
+ | {
37
+ kind: "slug-view";
38
+ slug: string;
39
+ view: Exclude<BackofficeView, "list">;
40
+ params?: DeskViewParams;
41
+ }
42
+ | { kind: "slug-new"; slug: string; defaults?: Record<string, unknown> }
43
+ | { kind: "slug-name"; slug: string; name: string }
44
+ | { kind: "report"; reportName: string; filtersParam?: string }
45
+ | { kind: "not-found"; path: string };
46
+
47
+ function first(value: string | string[] | undefined): string | undefined {
48
+ return typeof value === "string" ? value : value?.[0];
49
+ }
50
+
51
+ function decode(segment: string): string {
52
+ try {
53
+ return decodeURIComponent(segment);
54
+ } catch {
55
+ return segment; // malformed escape — keep the raw segment
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Resolve `path` (no query string; query lives in `params`, One-router
61
+ * semantics) against the six route shapes `createBackofficePaths` writes.
62
+ * Paths outside `basePath` resolve to `not-found`.
63
+ */
64
+ export function resolveDeskPath(
65
+ path: string,
66
+ basePath: string = BACKOFFICE_BASE,
67
+ params: BackofficeParams = {},
68
+ ): DeskAddress {
69
+ const base = basePath.replace(/\/+$/, "") || "/";
70
+ const clean = path.replace(/\/+$/, "") || "/";
71
+ let rest: string;
72
+ if (base === "/") rest = clean;
73
+ else if (clean === base) rest = "/";
74
+ else if (clean.startsWith(`${base}/`)) rest = clean.slice(base.length);
75
+ else return { kind: "not-found", path };
76
+
77
+ const segments = rest.split("/").filter(Boolean).map(decode);
78
+ if (segments.length === 0) return { kind: "home" };
79
+
80
+ if (segments[0] === "query-report") {
81
+ if (segments.length === 2 && segments[1]) {
82
+ return { kind: "report", reportName: segments[1], filtersParam: first(params.filters) };
83
+ }
84
+ return { kind: "not-found", path };
85
+ }
86
+
87
+ const slug = segments[0];
88
+ if (segments.length === 1) {
89
+ return { kind: "slug", slug, filtersParam: first(params.f), sortParam: first(params.sort) };
90
+ }
91
+ if (segments.length === 2 && segments[1] === "new") {
92
+ return { kind: "slug-new", slug, defaults: parseDocDefaults(first(params.d)) };
93
+ }
94
+ if (segments.length === 3 && segments[1] === "view" && isBackofficeView(segments[2])) {
95
+ const view = segments[2];
96
+ // /view/list is the list surface (DoctypeViewScreen bounces it too).
97
+ if (view === "list") {
98
+ return { kind: "slug", slug, filtersParam: first(params.f), sortParam: first(params.sort) };
99
+ }
100
+ const board = first(params.board);
101
+ const field = first(params.field);
102
+ const filtersParam = first(params.f);
103
+ const viewParams: DeskViewParams | undefined =
104
+ board || field || filtersParam ? { board, field, filtersParam } : undefined;
105
+ return { kind: "slug-view", slug, view, ...(viewParams && { params: viewParams }) };
106
+ }
107
+ if (segments.length === 2) {
108
+ return { kind: "slug-name", slug, name: segments[1] };
109
+ }
110
+ return { kind: "not-found", path };
111
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Desk scope — the tenant seam (MPO-14 / gap GL-5, spec 09 §DM-4).
3
+ *
4
+ * `scope` filters are ALWAYS ANDed into every doctype-homed query, invisible
5
+ * to the filter chrome and not removable by the user. Before this context
6
+ * existed the seam reached exactly one surface (DoctypeListScreen's
7
+ * `fixedFilters`), so a scoped desk leaked rows the moment the user switched
8
+ * to kanban. Surfaces read the context themselves; hosts set it once via
9
+ * `<Desk scope={…} />` (or `DeskScopeProvider` directly).
10
+ *
11
+ * Scope applies to doctype-homed surfaces (list, kanban, calendar, tree,
12
+ * image, dashboard, report view). Query/Script reports run server-side SQL
13
+ * and the awesomebar searches across doctypes, so field-tuple scope cannot
14
+ * soundly AND into either; restrict those with `capabilities` instead.
15
+ */
16
+ import type { ReactNode } from "react";
17
+ import { createContext, useContext, useMemo } from "react";
18
+ import type { FrappeFilters } from "../shared/types";
19
+
20
+ const EMPTY_SCOPE: FrappeFilters = [];
21
+
22
+ const DeskScopeContext = createContext<FrappeFilters>(EMPTY_SCOPE);
23
+
24
+ export interface DeskScopeProviderProps {
25
+ /** Filter tuples ANDed into every doctype-homed query in the subtree. */
26
+ scope?: FrappeFilters;
27
+ children: ReactNode;
28
+ }
29
+
30
+ export function DeskScopeProvider({ scope, children }: DeskScopeProviderProps) {
31
+ // Value-keyed so unstable array literals from the host don't churn readers.
32
+ const scopeKey = JSON.stringify(scope ?? EMPTY_SCOPE);
33
+ const value = useMemo(() => (JSON.parse(scopeKey) as FrappeFilters) ?? EMPTY_SCOPE, [scopeKey]);
34
+ return <DeskScopeContext.Provider value={value}>{children}</DeskScopeContext.Provider>;
35
+ }
36
+
37
+ /** The ambient desk scope; `[]` outside any DeskScopeProvider. */
38
+ export function useDeskScope(): FrappeFilters {
39
+ return useContext(DeskScopeContext);
40
+ }
41
+
42
+ /**
43
+ * AND the ambient scope into `filters`. Returns `undefined` when there is
44
+ * nothing to apply, so callers can spread-conditionally into leaf props.
45
+ */
46
+ export function useScopedFilters(filters?: FrappeFilters): FrappeFilters | undefined {
47
+ const scope = useDeskScope();
48
+ return useMemo(() => {
49
+ if (scope.length === 0 && (!filters || filters.length === 0)) return undefined;
50
+ return [...scope, ...(filters ?? [])];
51
+ }, [scope, filters]);
52
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * DeskTarget — the resolved surface (spec 09 §2.2) — and useDeskTarget, the
3
+ * hook that composes the pure resolver with the runtime slug index.
4
+ *
5
+ * Precedence (spec §2.3): `path` beats the pins, the pins beat the navigator
6
+ * location, the navigator location beats home. A pin plus a live navigator
7
+ * is legal: the pin is the ENTRY, and once the location moves the navigator
8
+ * drives, still fenced by whatever scope the pin implied.
9
+ *
10
+ * Desk writes no fetch: the only read here is `useSlugTarget`, the exported
11
+ * once-per-session slug index (DK-2 holding at the one place it was most at
12
+ * risk).
13
+ */
14
+ import { useMemo, useRef } from "react";
15
+ import { useBackofficeConfig, useBackofficeLocation } from "../config/BackofficeProvider";
16
+ import { parseBackofficeHref } from "../navigation/navigator";
17
+ import { slugToDisplayName, type BackofficeView } from "../navigation/paths";
18
+ import { useSlugTarget } from "../shared/useSlugTarget";
19
+ import { resolveDeskPath, type DeskAddress, type DeskViewParams } from "./resolveDeskPath";
20
+
21
+ export type DeskTarget =
22
+ | { kind: "home" }
23
+ | { kind: "workspace"; workspace: string }
24
+ | { kind: "list"; doctype: string; filtersParam?: string; sortParam?: string }
25
+ | {
26
+ kind: "view";
27
+ doctype: string;
28
+ view: Exclude<BackofficeView, "list">;
29
+ params?: DeskViewParams;
30
+ }
31
+ | { kind: "new"; doctype: string; defaults?: Record<string, unknown> }
32
+ | { kind: "form"; doctype: string; name: string }
33
+ | { kind: "report"; reportName: string; filtersParam?: string }
34
+ | { kind: "not-found"; slug?: string };
35
+
36
+ /** The surface pins a host sets on `<Desk />` (spec §2, "what it shows"). */
37
+ export interface DeskPins {
38
+ doctype?: string;
39
+ name?: string;
40
+ view?: BackofficeView;
41
+ workspace?: string;
42
+ report?: string;
43
+ path?: string;
44
+ }
45
+
46
+ export function hasDeskPin(pins: DeskPins): boolean {
47
+ return Boolean(pins.doctype || pins.workspace || pins.report || pins.path);
48
+ }
49
+
50
+ /** Pins → target, directly: pins carry proper-cased names, no slug hop. */
51
+ function pinnedTarget(pins: DeskPins): DeskTarget | undefined {
52
+ if (pins.doctype) {
53
+ if (pins.name === "new") return { kind: "new", doctype: pins.doctype };
54
+ if (pins.name) return { kind: "form", doctype: pins.doctype, name: pins.name };
55
+ if (pins.view && pins.view !== "list") {
56
+ return { kind: "view", doctype: pins.doctype, view: pins.view };
57
+ }
58
+ return { kind: "list", doctype: pins.doctype };
59
+ }
60
+ if (pins.workspace) return { kind: "workspace", workspace: pins.workspace };
61
+ if (pins.report) return { kind: "report", reportName: pins.report };
62
+ return undefined;
63
+ }
64
+
65
+ /** Address + resolved slug → target. Ambiguous slugs stay `undefined` while
66
+ * the index loads (the caller renders a spinner, exactly like SlugScreen). */
67
+ function addressToTarget(
68
+ address: DeskAddress,
69
+ slugKind: "workspace" | "doctype" | "loading" | "not-found",
70
+ slugName: string | undefined,
71
+ ): DeskTarget | undefined {
72
+ switch (address.kind) {
73
+ case "home":
74
+ return { kind: "home" };
75
+ case "report":
76
+ return { kind: "report", reportName: address.reportName, filtersParam: address.filtersParam };
77
+ case "not-found":
78
+ return { kind: "not-found" };
79
+ default:
80
+ break;
81
+ }
82
+ if (slugKind === "loading") return undefined;
83
+ if (slugKind === "not-found" || !slugName) return { kind: "not-found", slug: address.slug };
84
+ if (slugKind === "workspace") {
85
+ // Only the bare slug route can be a workspace page; /new, /view/x and
86
+ // /[name] under a workspace slug are dead addresses.
87
+ return address.kind === "slug"
88
+ ? { kind: "workspace", workspace: slugName }
89
+ : { kind: "not-found", slug: address.slug };
90
+ }
91
+ switch (address.kind) {
92
+ case "slug":
93
+ return {
94
+ kind: "list",
95
+ doctype: slugName,
96
+ filtersParam: address.filtersParam,
97
+ sortParam: address.sortParam,
98
+ };
99
+ case "slug-view":
100
+ return { kind: "view", doctype: slugName, view: address.view, params: address.params };
101
+ case "slug-new":
102
+ return { kind: "new", doctype: slugName, defaults: address.defaults };
103
+ case "slug-name":
104
+ return { kind: "form", doctype: slugName, name: address.name };
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Pure, best-effort address→target for pre-navigation interception
110
+ * (`onNavigate`): the slug degrades to a title-cased doctype guess, the same
111
+ * degrade `useSlugTarget` applies when the index is unavailable.
112
+ */
113
+ export function guessDeskTarget(path: string, basePath: string): DeskTarget {
114
+ const { path: cleanPath, params } = parseBackofficeHref(path);
115
+ const address = resolveDeskPath(cleanPath, basePath, params);
116
+ const guess = "slug" in address ? slugToDisplayName(address.slug) : undefined;
117
+ return addressToTarget(address, guess ? "doctype" : "not-found", guess) ?? { kind: "not-found" };
118
+ }
119
+
120
+ /**
121
+ * The desk's current target. `undefined` while an ambiguous slug is still
122
+ * resolving against the once-per-session index. Must be called under
123
+ * BackofficeProvider (it reads the navigator location and the frappe
124
+ * connection from context).
125
+ */
126
+ export function useDeskTarget(pins: DeskPins): DeskTarget | undefined {
127
+ const { basePath } = useBackofficeConfig();
128
+ const location = useBackofficeLocation();
129
+
130
+ // The pins (and the `path` prop) are the ENTRY: they win until the
131
+ // location moves, then the navigator drives (spec §2.3). Location
132
+ // snapshots have stable identity until they change, so reference
133
+ // equality against the mount-time snapshot is the "has it moved" test.
134
+ const initialLocation = useRef(location);
135
+ const entryActive = location === initialLocation.current;
136
+
137
+ const address = useMemo<DeskAddress | undefined>(() => {
138
+ if (entryActive && pins.path) {
139
+ const prefix = basePath === "/" ? "" : basePath.replace(/\/+$/, "");
140
+ const { path, params } = parseBackofficeHref(`${prefix}${pins.path}`);
141
+ return resolveDeskPath(path, basePath, params);
142
+ }
143
+ if (entryActive && hasDeskPin(pins)) return undefined; // pinned target, no address
144
+ return resolveDeskPath(location.path, basePath, location.params);
145
+ }, [entryActive, pins, basePath, location]);
146
+
147
+ const pinned = entryActive && !pins.path ? pinnedTarget(pins) : undefined;
148
+
149
+ const slug = !pinned && address && "slug" in address ? address.slug : undefined;
150
+ const slugTarget = useSlugTarget(slug);
151
+
152
+ return useMemo(() => {
153
+ if (pinned) return pinned;
154
+ if (!address) return undefined;
155
+ const slugKind =
156
+ slugTarget.status === "loading"
157
+ ? "loading"
158
+ : slugTarget.status === "not-found"
159
+ ? "not-found"
160
+ : slugTarget.kind;
161
+ const slugName =
162
+ slugTarget.status === "resolved"
163
+ ? slugTarget.kind === "workspace"
164
+ ? slugTarget.workspace
165
+ : slugTarget.doctype
166
+ : undefined;
167
+ return addressToTarget(address, slugKind, slugName);
168
+ }, [pinned, address, slugTarget]);
169
+ }