@stackcraftmx/calcita 0.31.0 → 0.32.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 (281) hide show
  1. package/README.md +7 -0
  2. package/dist/DataTable/AuditTrailDialog.js +4 -1
  3. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  4. package/dist/DataTable/AuditTrailTable.js +4 -1
  5. package/dist/DataTable/AuditTrailTable.js.map +1 -1
  6. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -1
  7. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  8. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -1
  9. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  10. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +4 -1
  11. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  12. package/dist/DataTable/ColumnFilters/TextColumnFilter.js +3 -1
  13. package/dist/DataTable/ColumnFilters/TextColumnFilter.js.map +1 -1
  14. package/dist/DataTable/EmptyState.js +3 -1
  15. package/dist/DataTable/EmptyState.js.map +1 -1
  16. package/dist/DataTable/FilterChips.js +3 -1
  17. package/dist/DataTable/FilterChips.js.map +1 -1
  18. package/dist/DataTable/GoToPage.js +3 -1
  19. package/dist/DataTable/GoToPage.js.map +1 -1
  20. package/dist/DataTable/ServerTable.js +4 -1
  21. package/dist/DataTable/ServerTable.js.map +1 -1
  22. package/dist/DataTable/columns.js +3 -1
  23. package/dist/DataTable/columns.js.map +1 -1
  24. package/dist/access/Can.js +3 -1
  25. package/dist/access/Can.js.map +1 -1
  26. package/dist/access/PermissionMatrix.js +3 -1
  27. package/dist/access/PermissionMatrix.js.map +1 -1
  28. package/dist/access/RequireAccess.js +3 -1
  29. package/dist/access/RequireAccess.js.map +1 -1
  30. package/dist/account/AccountProvider.js +3 -1
  31. package/dist/account/AccountProvider.js.map +1 -1
  32. package/dist/account/AccountSecuritySection.js +3 -1
  33. package/dist/account/AccountSecuritySection.js.map +1 -1
  34. package/dist/account/DemoTotpCodeButton.js +3 -1
  35. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  36. package/dist/account/ForgotPasswordScreen.js +3 -1
  37. package/dist/account/ForgotPasswordScreen.js.map +1 -1
  38. package/dist/account/ProfileScreen.js +4 -1
  39. package/dist/account/ProfileScreen.js.map +1 -1
  40. package/dist/account/ResetPasswordScreen.js +4 -1
  41. package/dist/account/ResetPasswordScreen.js.map +1 -1
  42. package/dist/account/SignInScreen.js +3 -1
  43. package/dist/account/SignInScreen.js.map +1 -1
  44. package/dist/appShell/AccountMenu.js +3 -1
  45. package/dist/appShell/AccountMenu.js.map +1 -1
  46. package/dist/appShell/AppLayout.js +4 -1
  47. package/dist/appShell/AppLayout.js.map +1 -1
  48. package/dist/appShell/AppearanceSettings.js +4 -1
  49. package/dist/appShell/AppearanceSettings.js.map +1 -1
  50. package/dist/appShell/AuthLayout.js +3 -1
  51. package/dist/appShell/AuthLayout.js.map +1 -1
  52. package/dist/appShell/BarActions.js +3 -1
  53. package/dist/appShell/BarActions.js.map +1 -1
  54. package/dist/appShell/BarSearch.js +3 -1
  55. package/dist/appShell/BarSearch.js.map +1 -1
  56. package/dist/appShell/HeaderTools.js +4 -1
  57. package/dist/appShell/HeaderTools.js.map +1 -1
  58. package/dist/appShell/MenuLinks.js +3 -1
  59. package/dist/appShell/MenuLinks.js.map +1 -1
  60. package/dist/appShell/MobileTabBar.js +3 -1
  61. package/dist/appShell/MobileTabBar.js.map +1 -1
  62. package/dist/appShell/SettingsMenu.js +3 -1
  63. package/dist/appShell/SettingsMenu.js.map +1 -1
  64. package/dist/appShell/SideMenu.js +4 -1
  65. package/dist/appShell/SideMenu.js.map +1 -1
  66. package/dist/appShell/SideMenuEntry.js +3 -1
  67. package/dist/appShell/SideMenuEntry.js.map +1 -1
  68. package/dist/appShell/SubmenuActionsMenu.js +3 -1
  69. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  70. package/dist/appShell/TabBarEditor.js +3 -1
  71. package/dist/appShell/TabBarEditor.js.map +1 -1
  72. package/dist/appShell/TopMenu.js +3 -1
  73. package/dist/appShell/TopMenu.js.map +1 -1
  74. package/dist/appShell/Wordmark.js +3 -1
  75. package/dist/appShell/Wordmark.js.map +1 -1
  76. package/dist/appShell/pageTitle.js +3 -1
  77. package/dist/appShell/pageTitle.js.map +1 -1
  78. package/dist/auth/PasswordChecklist.js +3 -1
  79. package/dist/auth/PasswordChecklist.js.map +1 -1
  80. package/dist/calendar/EventCalendar.js +4 -1
  81. package/dist/calendar/EventCalendar.js.map +1 -1
  82. package/dist/calendar/EventDetails.js +3 -1
  83. package/dist/calendar/EventDetails.js.map +1 -1
  84. package/dist/datePickers/DateInput.js +4 -1
  85. package/dist/datePickers/DateInput.js.map +1 -1
  86. package/dist/downloads/DownloadManager.js +3 -1
  87. package/dist/downloads/DownloadManager.js.map +1 -1
  88. package/dist/feedback/ConfirmDialog.js +4 -1
  89. package/dist/feedback/ConfirmDialog.js.map +1 -1
  90. package/dist/feedback/ModalWaiting.js +3 -1
  91. package/dist/feedback/ModalWaiting.js.map +1 -1
  92. package/dist/feedback/NewBuildNotice.js +3 -1
  93. package/dist/feedback/NewBuildNotice.js.map +1 -1
  94. package/dist/filepond/FileDropzone.js +4 -1
  95. package/dist/filepond/FileDropzone.js.map +1 -1
  96. package/dist/formatting.js +8 -5
  97. package/dist/formatting.js.map +1 -1
  98. package/dist/forms/FormProblemAlert.js +3 -1
  99. package/dist/forms/FormProblemAlert.js.map +1 -1
  100. package/dist/forms/FormServerProblem.js +3 -1
  101. package/dist/forms/FormServerProblem.js.map +1 -1
  102. package/dist/forms/FormWizard.js +3 -1
  103. package/dist/forms/FormWizard.js.map +1 -1
  104. package/dist/forms/auth/ChangePasswordForm.js +3 -1
  105. package/dist/forms/auth/ChangePasswordForm.js.map +1 -1
  106. package/dist/forms/auth/ForgotPasswordForm.js +3 -1
  107. package/dist/forms/auth/ForgotPasswordForm.js.map +1 -1
  108. package/dist/forms/auth/SignInForm.js +3 -1
  109. package/dist/forms/auth/SignInForm.js.map +1 -1
  110. package/dist/forms/security/SecondStepForm.js +3 -1
  111. package/dist/forms/security/SecondStepForm.js.map +1 -1
  112. package/dist/forms/security/TwoStepVerificationCard.js +3 -1
  113. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  114. package/dist/hookForm/FormProblemAlert.js +3 -1
  115. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  116. package/dist/hookForm/FormWizard.js +3 -1
  117. package/dist/hookForm/FormWizard.js.map +1 -1
  118. package/dist/inbox/InboxLayout.js +4 -1
  119. package/dist/inbox/InboxLayout.js.map +1 -1
  120. package/dist/inbox/MessageList.js +4 -1
  121. package/dist/inbox/MessageList.js.map +1 -1
  122. package/dist/inbox/MessageView.js +3 -1
  123. package/dist/inbox/MessageView.js.map +1 -1
  124. package/dist/index.js +3 -1
  125. package/dist/inputs/CatalogInput.js +4 -1
  126. package/dist/inputs/CatalogInput.js.map +1 -1
  127. package/dist/inputs/ColorInput.js +4 -1
  128. package/dist/inputs/ColorInput.js.map +1 -1
  129. package/dist/inputs/FieldFrame.js +3 -1
  130. package/dist/inputs/FieldFrame.js.map +1 -1
  131. package/dist/inputs/FormSection.js +5 -2
  132. package/dist/inputs/FormSection.js.map +1 -1
  133. package/dist/inputs/NumberInput.js +4 -1
  134. package/dist/inputs/NumberInput.js.map +1 -1
  135. package/dist/inputs/SelectInput.js +4 -1
  136. package/dist/inputs/SelectInput.js.map +1 -1
  137. package/dist/inputs/TextInput.js +2 -0
  138. package/dist/inputs/TextInput.js.map +1 -1
  139. package/dist/inputs/WizardLayout.js +4 -1
  140. package/dist/inputs/WizardLayout.js.map +1 -1
  141. package/dist/kanban/KanbanBoard.js +4 -1
  142. package/dist/kanban/KanbanBoard.js.map +1 -1
  143. package/dist/maps/MapView.js +4 -1
  144. package/dist/maps/MapView.js.map +1 -1
  145. package/dist/pwa/InstallAppSetting.js +3 -1
  146. package/dist/pwa/InstallAppSetting.js.map +1 -1
  147. package/dist/pwa/InstallInstructionsDialog.js +3 -1
  148. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  149. package/dist/pwa/InstallPromptBanner.js +3 -1
  150. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  151. package/dist/security/ActivityLog.js +3 -1
  152. package/dist/security/ActivityLog.js.map +1 -1
  153. package/dist/security/RecoveryCodesDialog.js +3 -1
  154. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  155. package/dist/security/SessionsCard.js +3 -1
  156. package/dist/security/SessionsCard.js.map +1 -1
  157. package/dist/theme/createToolkitTheme.js +4 -1
  158. package/dist/theme/createToolkitTheme.js.map +1 -1
  159. package/dist/toolkit/ComponentTexts.js +3 -1
  160. package/dist/toolkit/ComponentTexts.js.map +1 -1
  161. package/dist/toolkit/ToolkitProvider.js +24 -3
  162. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  163. package/dist/toolkit/toolkitContext.js.map +1 -1
  164. package/dist/toolkit/toolkitSettings.js +9 -0
  165. package/dist/toolkit/toolkitSettings.js.map +1 -1
  166. package/dist/toolkit/unknownProps.js +33 -0
  167. package/dist/toolkit/unknownProps.js.map +1 -0
  168. package/dist/types/DataTable/AuditTrailTable.d.ts +1 -1
  169. package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +1 -1
  170. package/dist/types/DataTable/columns.d.ts +3 -1
  171. package/dist/types/access/Can.d.ts +1 -1
  172. package/dist/types/access/RequireAccess.d.ts +1 -1
  173. package/dist/types/account/AccountProvider.d.ts +1 -1
  174. package/dist/types/account/ForgotPasswordScreen.d.ts +1 -1
  175. package/dist/types/account/ResetPasswordScreen.d.ts +1 -1
  176. package/dist/types/appShell/MenuLinks.d.ts +1 -1
  177. package/dist/types/appShell/pageTitle.d.ts +1 -1
  178. package/dist/types/datePickers/DateInput.d.ts +1 -1
  179. package/dist/types/downloads/DownloadManager.d.ts +1 -1
  180. package/dist/types/formatting.d.ts +2 -1
  181. package/dist/types/forms/FormProblemAlert.d.ts +1 -1
  182. package/dist/types/forms/FormServerProblem.d.ts +1 -1
  183. package/dist/types/forms/FormWizard.d.ts +1 -1
  184. package/dist/types/forms/auth/ChangePasswordForm.d.ts +1 -1
  185. package/dist/types/forms/auth/ForgotPasswordForm.d.ts +1 -1
  186. package/dist/types/hookForm/FormProblemAlert.d.ts +1 -1
  187. package/dist/types/hookForm/FormWizard.d.ts +1 -1
  188. package/dist/types/index.d.ts +1 -1
  189. package/dist/types/inputs/CatalogInput.d.ts +1 -1
  190. package/dist/types/inputs/FieldFrame.d.ts +1 -1
  191. package/dist/types/inputs/NumberInput.d.ts +1 -1
  192. package/dist/types/inputs/TextInput.d.ts +2 -1
  193. package/dist/types/pwa/InstallAppSetting.d.ts +1 -1
  194. package/dist/types/theme/createToolkitTheme.d.ts +1 -1
  195. package/dist/types/toolkit/ComponentTexts.d.ts +1 -1
  196. package/dist/types/toolkit/ToolkitProvider.d.ts +4 -1
  197. package/dist/types/toolkit/toolkitContext.d.ts +2 -1
  198. package/dist/types/toolkit/toolkitSettings.d.ts +13 -2
  199. package/dist/types/toolkit/unknownProps.d.ts +23 -0
  200. package/dist/types/ui/actions/CopyButton.d.ts +1 -1
  201. package/dist/types/ui/actions/SecretField.d.ts +1 -1
  202. package/dist/types/ui/labels/DictionaryText.d.ts +1 -1
  203. package/dist/types/ui/layout/FullPageLoader.d.ts +1 -1
  204. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +9 -8
  205. package/dist/types/ui/metrics/chartParts.d.ts +3 -3
  206. package/dist/types/ui/metrics/heatmapScale.d.ts +23 -0
  207. package/dist/types/ui/navigation/DocumentTitle.d.ts +1 -1
  208. package/dist/ui/actions/ActionsMenu.js +3 -1
  209. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  210. package/dist/ui/actions/CopyButton.js +3 -1
  211. package/dist/ui/actions/CopyButton.js.map +1 -1
  212. package/dist/ui/actions/DownloadMenu.js +4 -1
  213. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  214. package/dist/ui/actions/SecretField.js +3 -1
  215. package/dist/ui/actions/SecretField.js.map +1 -1
  216. package/dist/ui/actions/SelectionActions.js +3 -1
  217. package/dist/ui/actions/SelectionActions.js.map +1 -1
  218. package/dist/ui/filters/DateRangeFilter.js +3 -1
  219. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  220. package/dist/ui/filters/PeriodRangeSelector.js +3 -1
  221. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  222. package/dist/ui/filters/QuickFilters.js +3 -1
  223. package/dist/ui/filters/QuickFilters.js.map +1 -1
  224. package/dist/ui/filters/SegmentedControl.js +3 -1
  225. package/dist/ui/filters/SegmentedControl.js.map +1 -1
  226. package/dist/ui/labels/DictionaryText.js +3 -1
  227. package/dist/ui/labels/DictionaryText.js.map +1 -1
  228. package/dist/ui/labels/StatusChip.js +3 -1
  229. package/dist/ui/labels/StatusChip.js.map +1 -1
  230. package/dist/ui/layout/CollapsibleSection.js +3 -1
  231. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  232. package/dist/ui/layout/ContentDialog.js +3 -1
  233. package/dist/ui/layout/ContentDialog.js.map +1 -1
  234. package/dist/ui/layout/DefinitionList.js +3 -1
  235. package/dist/ui/layout/DefinitionList.js.map +1 -1
  236. package/dist/ui/layout/DetailHeader.js +3 -1
  237. package/dist/ui/layout/DetailHeader.js.map +1 -1
  238. package/dist/ui/layout/ErrorPage.js +4 -1
  239. package/dist/ui/layout/ErrorPage.js.map +1 -1
  240. package/dist/ui/layout/FullPageLoader.js +3 -1
  241. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  242. package/dist/ui/layout/PageHeader.js +3 -1
  243. package/dist/ui/layout/PageHeader.js.map +1 -1
  244. package/dist/ui/layout/PageHeading.js +3 -1
  245. package/dist/ui/layout/PageHeading.js.map +1 -1
  246. package/dist/ui/layout/ProfileHeader.js +3 -1
  247. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  248. package/dist/ui/layout/SectionCard.js +3 -1
  249. package/dist/ui/layout/SectionCard.js.map +1 -1
  250. package/dist/ui/metrics/BarList.js +3 -1
  251. package/dist/ui/metrics/BarList.js.map +1 -1
  252. package/dist/ui/metrics/CalendarHeatmap.js +13 -4
  253. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  254. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  255. package/dist/ui/metrics/ColumnChart.js +4 -1
  256. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  257. package/dist/ui/metrics/LineChart.js +4 -1
  258. package/dist/ui/metrics/LineChart.js.map +1 -1
  259. package/dist/ui/metrics/MetricCard.js +4 -1
  260. package/dist/ui/metrics/MetricCard.js.map +1 -1
  261. package/dist/ui/metrics/TableToggle.js +3 -1
  262. package/dist/ui/metrics/TableToggle.js.map +1 -1
  263. package/dist/ui/metrics/chartParts.js +7 -3
  264. package/dist/ui/metrics/chartParts.js.map +1 -1
  265. package/dist/ui/metrics/heatmapScale.js +15 -1
  266. package/dist/ui/metrics/heatmapScale.js.map +1 -1
  267. package/dist/ui/navigation/ColorSchemeToggle.js +3 -1
  268. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  269. package/dist/ui/navigation/DocumentTitle.js +3 -1
  270. package/dist/ui/navigation/DocumentTitle.js.map +1 -1
  271. package/dist/ui/navigation/FontSizeToggle.js +3 -1
  272. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  273. package/dist/ui/navigation/LanguageToggle.js +3 -1
  274. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  275. package/dist/ui/navigation/PageBreadcrumbs.js +3 -1
  276. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  277. package/dist/ui/timeline/GroupedTimeline.js +3 -1
  278. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  279. package/dist/upload/FileDropzone.js +4 -1
  280. package/dist/upload/FileDropzone.js.map +1 -1
  281. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ServerTable.js","sources":["../../src/DataTable/ServerTable.jsx"],"sourcesContent":["// La tabla: pagina, filtra y ordena EN EL SERVIDOR (contrato {filters, sortOrders, page, pageSize} → {rows, total, facets}).\n//\n// Cada cambio de filtro, orden o página es una consulta nueva contra el conjunto COMPLETO y el total que se muestra\n// es el real. Traer todo y filtrar en el navegador mentiría en cuanto el conjunto no quepa en una página.\n//\n// Contrato de fetchPage:\n// fetchPage({filters, sortOrders, page, pageSize}, signal) → Promise<{rows, total, facets?, capped?}>\n// - rows: cada fila con su id del SERVIDOR (getRowId). Fabricarlo en el front colisiona y el DataGrid conserva\n// filas de la consulta anterior;\n// - facets: {campo: [{value, total}]} contadas SIN el filtro de ese campo (lo hace el servidor), para que la\n// selección múltiple siga siendo posible;\n// - capped: el total es \"al menos esto\".\n//\n// Elegir renglones (selectionActions): una casilla por renglón y las acciones de los elegidos (rowSelection.js dice cómo\n// se conservan entre páginas y qué es «todos los que coinciden»; SelectionActions, dónde se ven sus acciones).\n//\n// Piezas: useTableState (URL con nuqs y prefijo) · tableMachine (XState: carga, error y respuestas rezagadas) ·\n// columns.jsx (encabezados con orden y filtro) · FilterChips · QuickFilters · GoToPage · EmptyState.\n//\n// Con @mui/x-data-grid 8 (compatible con MUI 7).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaServerTable con defaultProps y\n// styleOverrides de sus partes: toolbar, summary, customHeader, count, countRow, selectionNotice, error, card, grid,\n// pagination.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useMachine} from '@xstate/react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\nimport SearchIcon from '@mui/icons-material/Search';\nimport {DataGrid, GRID_CHECKBOX_SELECTION_COL_DEF, GRID_CHECKBOX_SELECTION_FIELD, GridPagination} from '@mui/x-data-grid';\nimport {enUS as dataGridEnglish, esES as dataGridSpanish} from '@mui/x-data-grid/locales';\n\nimport EmptyState from '@/DataTable/EmptyState.jsx';\nimport FilterChips from '@/DataTable/FilterChips.jsx';\nimport GoToPage from '@/DataTable/GoToPage.jsx';\nimport {TableFilterContext} from '@/DataTable/filterContext.js';\nimport {\n EMPTY_ROW_SELECTION, canSelectAllMatching, checkedIdsOf, rowSelectionOf, selectionAfterCheck,\n} from '@/DataTable/rowSelection.js';\nimport {buildTableActors, tableMachine} from '@/DataTable/tableMachine.js';\nimport {useDebouncedFilter} from '@/DataTable/useDebouncedFilter.js';\nimport {FILTER_KINDS, isFilterActive, useTableState} from '@/DataTable/useTableState.js';\nimport BarSearch from '@/appShell/BarSearch.jsx';\nimport {PHONE_MEDIA_QUERY} from '@/appShell/shellSizes.js';\nimport SelectionActions, {SELECTION_PHONE_LAYOUT, selectionFloatsOnPhone} from '@/ui/actions/SelectionActions.jsx';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {materialBackgroundOf} from '@/theme/glassSurface.js';\nimport QuickFilters from '@/ui/filters/QuickFilters.jsx';\nimport Tag from '@/ui/labels/Tag.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaServerTable)\nconst THEME_NAME = 'CalcitaServerTable';\nconst TableToolbar = piecePart(THEME_NAME, 'Toolbar', Stack);\nconst TableSummary = piecePart(THEME_NAME, 'Summary', Box);\nconst TableCustomHeader = piecePart(THEME_NAME, 'CustomHeader', Box);\nconst TableCount = piecePart(THEME_NAME, 'Count', Stack);\nconst TableCountRow = piecePart(THEME_NAME, 'CountRow', Stack);\nconst TableSelectionNotice = piecePart(THEME_NAME, 'SelectionNotice', Alert);\nconst TableError = piecePart(THEME_NAME, 'Error', Alert);\nconst TableCard = piecePart(THEME_NAME, 'Card', Paper);\nconst TableGrid = piecePart(THEME_NAME, 'Grid', DataGrid);\nconst TablePagination = piecePart(THEME_NAME, 'Pagination', Stack);\n\n// OJO: los textos del DataGrid van como PROP (localeText) y no solo en el tema: el grid resuelve sus defaults en\n// inglés y le ganan a los defaultProps del tema\nconst DATA_GRID_TEXT_BY_LANGUAGE = {\n es: dataGridSpanish.components.MuiDataGrid.defaultProps.localeText,\n en: dataGridEnglish.components.MuiDataGrid.defaultProps.localeText,\n};\n\n/**\n * Nonce de la CSP de la página, si la aplicación usa CSP y lo pone en <meta property=\"csp-nonce\">.\n *\n * IMPORTANTE: el DataGrid 8 inserta un <style> con sus variables CSS (bordes, fondos, espaciado). Sin el nonce la CSP lo\n * bloquea (\"style-src-elem\") y la tabla se pinta sin sus variables. OJO: el navegador esconde el valor del atributo\n * (getAttribute regresa \"\"); se lee con la propiedad .nonce, igual que el caché de emotion con nonce.\n *\n * @returns {string|undefined}\n */\nfunction readCspNonce() {\n // pintando en el servidor (Next.js) no hay documento: ahí el nonce lo pone quien arma el HTML\n if (typeof document === 'undefined') {\n return undefined;\n }\n\n return document.querySelector('meta[property=\"csp-nonce\"]')?.nonce || undefined;\n}\n\n// Densidad compacta en todas las tablas: el espaciado por omisión desperdicia renglones. Son los altos que pinta el DataGrid 8 con density=\"compact\": la base de 52 px del renglón y de 56 px del\n// encabezado por el factor 0.7, redondeados hacia abajo. El pie (paginación) no cambia con la densidad.\n// OJO: si se cambia la densidad, estos números se vuelven a medir en Chrome; con ellos se calcula el alto del contenedor\n// y un número viejo deja hueco blanco abajo o una barra de desplazamiento sin necesidad\nconst ROW_HEIGHT_PIXELS = 36;\nconst COLUMN_HEADER_HEIGHT_PIXELS = 39;\nconst FOOTER_HEIGHT_PIXELS = 52;\n// líneas del borde del encabezado y del pie\nconst GRID_BORDER_PIXELS = 2;\n// holgura de alto de la tabla: debajo del último renglón queda este hueco, así que va lo más chico que aguanta.\n// OJO: con el alto exacto, el redondeo de subpíxeles hace que el DataGrid crea que hay scroll vertical, reserve el ancho de\n// la barra y aparezca un scroll lateral de 5 px. Lo vigila e2e/tests/upload-control.spec.js (la tabla no se desliza de lado)\nconst HEIGHT_SLACK_PIXELS = 2;\nconst DATA_GRID_DENSITY = 'compact';\nconst STRIPED_ROW_CLASS = 'server-table-row--striped';\n// dónde van los elegidos en el teléfono: la regla vive en SelectionActions; la tabla la vuelve a exportar por comodidad\nexport {SELECTION_PHONE_LAYOUT};\n\n\n// a qué altura van la celda y el encabezado fijos: los mismos que usa el DataGrid de paga para sus columnas fijas. El\n// encabezado va arriba de la raya que separa columnas (30); con menos, la raya de las otras columnas lo cruzaba al deslizar\nconst FIXED_CELL_Z_INDEX = 30;\nconst FIXED_HEADER_Z_INDEX = 40;\n// ancho de la columna de casillas para elegir renglones (la del DataGrid)\nconst CHECKBOX_COLUMN_WIDTH_PIXELS = GRID_CHECKBOX_SELECTION_COL_DEF.width;\n\n/**\n * Estilos que dejan pegada a la izquierda una columna al deslizar la tabla de lado (en el teléfono y en una ventana angosta),\n * igual que fixedSelectColumn de mui-datatables. Fijar columnas en MUI X es de DataGridPro (de paga); por dentro Pro usa\n * position sticky en la celda, y eso mismo se hace aquí, también con su banda del encabezado cuando la banda es solo suya\n * (p. ej. una banda PERIODO de una sola columna).\n *\n * OJO, trampas pagadas:\n * - el DataGrid gratuito solo dibuja las columnas que se ven (virtualización) y al deslizar mucho a la derecha quitaba del\n * DOM a la columna fija, que desaparecía. Un margen de columnas extra (columnBufferPx) no alcanzó: con columna fija la\n * tabla va con disableVirtualization y dibuja todo, que en nuestras tablas son menos de quince columnas y una página;\n * - la celda fija necesita fondo SÓLIDO o se ve lo que pasa por debajo. Toma el color de su renglón (inherit), pero hay\n * renglones con color transparente (una banda de color, la cebra, el resaltado del mouse): ahí se asomaban las\n * cifras de las otras columnas. Por eso el fondo va en dos capas: abajo el papel, sólido (backgroundImage, que se pinta\n * encima del color propio de la celda), y encima el color del renglón en un ::before detrás del texto (zIndex -1 dentro\n * de la celda). Se ve igual que el renglón y no transparenta.\n * El renglón lleva el fondo del papel con :where(), que no suma especificidad: así los renglones que la página pinta de otro\n * color le siguen ganando. Los colores salen de la paleta del tema (de sus variables CSS si el tema las usa) para que\n * cambien con el modo oscuro.\n *\n * Con el contenido de material del tema de vidrio (createToolkitTheme({glass: {surfaces: true}})) la tabla no lleva fondo\n * propio: los renglones van transparentes y la celda pegada lleva el mismo material esmerilado, que tapa lo que pasa por\n * debajo sin verse como una columna blanca (así se veía con el papel sólido).\n *\n * Con renglones que se eligen, la casilla también se queda pegada, antes que la columna fija: si no, al deslizar la fija\n * tapaba la casilla.\n *\n * @param {object} theme tema de MUI\n * @param {string} field campo de la columna que se queda fija\n * @param {{withCheckboxColumn?: boolean}} [options]\n * @returns {object} estilos para el sx del DataGrid\n */\nfunction fixedColumnSxOf(theme, field, {withCheckboxColumn = false} = {}) {\n // un tema con variables CSS (cssVariables) las trae en theme.vars; el tema por omisión de MUI, solo en theme.palette\n const {palette} = theme.vars ?? theme;\n const paper = palette.background.paper;\n const divider = `1px solid ${palette.divider}`;\n // la banda del encabezado que lleva solo a esta columna: el DataGrid la marca con sus campos entre |- y -|\n const ownBandHeader = `.MuiDataGrid-columnHeader[data-fields=\"|-${field}-|\"]`;\n const isMaterialContent = Boolean(theme.toolkit?.glass?.surfaces);\n // abajo la capa (el papel o el material) y encima el color del renglón (el ::before)\n const stickyBackground = {backgroundColor: 'inherit', ...(isMaterialContent ? materialBackgroundOf(theme, {thick: true}) : {backgroundImage: `linear-gradient(${paper}, ${paper})`})};\n const headerBackground = isMaterialContent ? materialBackgroundOf(theme, {thick: true}) : {backgroundColor: paper};\n const rowColorLayer = {content: '\"\"', position: 'absolute', inset: 0, zIndex: -1, backgroundColor: 'inherit'};\n const fixedLeft = withCheckboxColumn ? CHECKBOX_COLUMN_WIDTH_PIXELS : 0;\n const checkboxCell = `.MuiDataGrid-cell[data-field=\"${GRID_CHECKBOX_SELECTION_FIELD}\"]`;\n const checkboxHeader = `.MuiDataGrid-columnHeader[data-field=\"${GRID_CHECKBOX_SELECTION_FIELD}\"]`;\n\n return {\n '& :where(.MuiDataGrid-row)': {backgroundColor: isMaterialContent ? 'transparent' : paper},\n [`& .MuiDataGrid-cell[data-field=\"${field}\"]`]: {\n position: 'sticky', left: fixedLeft, zIndex: FIXED_CELL_Z_INDEX, borderRight: divider,\n ...stickyBackground,\n '&::before': rowColorLayer,\n },\n [`& :where(.MuiDataGrid-columnHeader[data-field=\"${field}\"], ${ownBandHeader})`]: headerBackground,\n [`& .MuiDataGrid-columnHeader[data-field=\"${field}\"], & ${ownBandHeader}`]: {\n position: 'sticky', left: fixedLeft, zIndex: FIXED_HEADER_Z_INDEX, borderRight: divider,\n },\n ...(withCheckboxColumn && {\n [`& ${checkboxCell}`]: {position: 'sticky', left: 0, zIndex: FIXED_CELL_Z_INDEX, ...stickyBackground, '&::before': rowColorLayer},\n [`& :where(${checkboxHeader})`]: headerBackground,\n [`& ${checkboxHeader}`]: {position: 'sticky', left: 0, zIndex: FIXED_HEADER_Z_INDEX},\n }),\n };\n}\nconst COMPACT_DENSITY_FACTOR = 0.7;\n\n/** Una tira de accesos rápidos sobre un campo de la tabla, alimentada por su faceta. */\nfunction QuickFilterRow({quickFilter, facets, total, filters, isMultiple, setFilter, setFilters}) {\n const {t} = useToolkitTranslation('table');\n const facetOptions = facets[quickFilter.facetKey ?? quickFilter.field] ?? [];\n const orderedOptions = quickFilter.order\n ? quickFilter.order.map((optionValue) => facetOptions.find((option) => option.value === optionValue) ?? {value: optionValue, total: 0})\n : facetOptions;\n\n // en un filtro múltiple el chip activo es la opción cuando es la ÚNICA elegida: con varias puestas desde la columna\n // ningún chip miente estando encendido\n const currentValue = filters[quickFilter.field];\n // si otro control del mismo \"qué\" está puesto (un rango de fechas), ningún chip se enciende\n const isOverridden = quickFilter.isOverridden?.(filters) ?? false;\n let selectedValue = currentValue ?? '';\n if (isOverridden) {\n selectedValue = '__overridden__';\n } else if (isMultiple) {\n selectedValue = Array.isArray(currentValue) && currentValue.length === 1 ? currentValue[0] : '';\n }\n\n // el conteo de \"Todas\" es la suma de la faceta (el resultado SIN este filtro), no el de la página actual; cuando las\n // opciones se traslapan la suma mentiría: el total lo da el servidor en allCountKey o, si no lo da, no se pinta\n // conteo (hideAllCount) antes que pintar uno falso\n let allCount = facetOptions.reduce((sum, option) => sum + (option.total ?? 0), 0) || total;\n if (quickFilter.allCountKey && typeof facets[quickFilter.allCountKey] === 'number') {\n allCount = facets[quickFilter.allCountKey];\n } else if (quickFilter.hideAllCount) {\n allCount = undefined;\n }\n\n const handleChange = (nextValue) => {\n const pickedValue = isMultiple ? (nextValue ? [nextValue] : []) : nextValue;\n // elegir un chip limpia los controles que compiten con él\n if (quickFilter.clears) {\n setFilters({[quickFilter.field]: pickedValue, ...quickFilter.clears});\n } else {\n setFilter(quickFilter.field, pickedValue);\n }\n };\n\n return (\n <QuickFilters\n caption={quickFilter.caption}\n ariaLabel={quickFilter.caption}\n value={selectedValue}\n onChange={handleChange}\n extra={quickFilter.renderExtra?.({filters, setFilters})}\n options={[\n {value: '', label: quickFilter.allLabel ?? t('quickFilters.all'), count: allCount},\n ...orderedOptions.map((option) => ({\n value: option.value,\n label: quickFilter.renderLabel ? quickFilter.renderLabel(option.value) : option.value,\n count: option.total,\n })),\n ]}\n />\n );\n}\n\n/** @typedef {import('@/DataTable/rowSelection.js').RowSelection} RowSelection */\n\n/**\n * @param {object} props\n * @param {(params: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}, signal: AbortSignal) => Promise<{rows: any[], total: number, facets?: Record<string, Array<{value: any, total: number}> | number>, capped?: boolean}>} props.fetchPage\n * page cuenta desde 0; toServerTableParams lo convierte a la query del API\n * @param {string} props.queryKey cambia cuando cambia el CONJUNTO (no los filtros): dispara recarga\n * @param {boolean} [props.enabled] false mientras la sección está oculta: una tabla que nadie ve no consulta\n * @param {Array<object>} props.columns textColumn / facetColumn / detailColumn o columnas del DataGrid\n * @param {Record<string, string>} [props.filterKinds]\n * @param {Record<string, unknown>} [props.filterDefaults]\n * @param {Array<object>} [props.chipConfig] buildChipConfig\n * @param {Array<object>} [props.quickFilters] {field, facetKey, caption, allLabel, renderLabel, order, clears,\n * isOverridden, renderExtra, allCountKey, hideAllCount}\n * @param {string|null} [props.searchField] filtro de texto que se saca a la barra; null quita la caja\n * @param {string} [props.searchPlaceholder]\n * @param {boolean} [props.searchInBar] la caja de búsqueda va arriba, en la barra de la app (BarActions): en escritorio,\n * como el buscador de una ventana de macOS; en el teléfono con cápsulas flota arriba con las demás; sin cápsulas se\n * queda aquí. Por omisión no\n * @param {boolean} [props.collapseSearchInBar] en la barra, sin usar se encoge a la lupa y se estira al picarla; por\n * omisión sí (false: siempre abierta)\n * @param {string} [props.emptyLabel]\n * @param {(total: number) => string} [props.countLabel] \"12 pedidos\"; por defecto \"12 registros\"\n * @param {number[]} [props.pageSizeOptions]\n * @param {number} [props.defaultPageSize]\n * @param {(row: any) => string|number} [props.getRowId]\n * @param {string} [props.prefix] estado en la URL con este prefijo (nuqs); sin él, en memoria\n * @param {unknown} [props.refreshToken] cambia para volver a consultar la misma página (después de una acción)\n * @param {(summary: {total: number, capped: boolean}) => import('react').ReactNode} [props.footer]\n * @param {import('react').ReactNode} [props.toolbarExtra] a la derecha del conteo (p. ej. el selector de año)\n * @param {(summary: {countText: string, total: number, capped: boolean}) => import('react').ReactNode} [props.header] reemplaza\n * el renglón del conteo: la página pinta título, conteo y controles en uno solo. countText ya viene traducido y con\n * el tope\n * @param {import('react').ReactNode} [props.beforeQuickFilters] arriba de los accesos rápidos (p. ej. las pestañas de producto)\n * @param {Array<object>} [props.columnGroupingModel] bandas que agrupan columnas bajo un nombre, arriba de sus\n * encabezados (columnGroupingModel del DataGrid). Con ellas el encabezado mide un renglón más\n * @param {(params: any) => string} [props.getRowClassName]\n * @param {(row: any) => boolean} [props.isRowVisible] cuáles renglones de la página se pintan; los demás se esconden\n * SIN volver a consultar (p. ej. plegar un grupo de renglones). Sin ella se pintan todos. OJO: va con useCallback;\n * una función nueva en cada pintada haría filtrar la página cada vez\n * @param {boolean} [props.striped] renglones alternos (cebra) con el color de hover del tema; al pasar el cursor se usa\n * el de «seleccionado» para que el renglón bajo el cursor se siga distinguiendo\n * @param {(params: any) => number|'auto'|null} [props.getRowHeight]\n * @param {boolean} [props.hideFooterWhenAllRowsFit] esconde el pie (el paginador) mientras todo lo que hay cabe en la\n * página; si un día no cabe, el pie vuelve solo. Para tablas que casi nunca pasan de una página\n * @param {boolean} [props.showGoToPage] «Ir a página N» junto al paginador; por omisión escondido (con las flechas basta en\n * casi todas las tablas). Para listas de muchas páginas que se recorren por número\n * @param {object} [props.gridSx] estilos extra del DataGrid (clases de renglón)\n * @param {number} [props.maxGridHeight] alto máximo del contenedor; sin él la tabla crece con sus renglones (default)\n * @param {string} [props.ariaLabel] nombre de la tabla para lectores de pantalla\n * @param {string} [props.fixedColumn] campo de la columna que se queda pegada a la izquierda al deslizar de lado (como\n * fixedSelectColumn de mui-datatables)\n * @param {Array<{key: string, label: string, icon?: import('react').ReactNode, color?: 'inherit'|'primary'|'secondary'|'error'|'info'|'success'|'warning', isDisabled?: (selection: RowSelection) => boolean, onClick: (selection: RowSelection, helpers: {clearSelection: () => void, refresh: () => void}) => unknown}>} [props.selectionActions]\n * con ellas cada renglón lleva su casilla y, al elegir, sale la barra de los elegidos con estas acciones. label ya\n * traducido; onClick recibe la selección (con isAllMatching mande `filters`, no `ids`) y cómo quitar la selección y volver\n * a consultar después de actuar\n * @param {(row: any) => boolean} [props.isRowSelectable] cuáles renglones se pueden elegir (un pedido entregado no se cancela)\n * @param {boolean} [props.allowSelectAllMatching] la casilla de arriba elige todos los que coinciden (la acción recibe los\n * filtros) y el aviso deja quedarse solo con la página; por omisión sí. false: la casilla elige la página y nunca se\n * ofrece «todos»\n * @param {(selection: RowSelection) => void} [props.onSelectionChange] cada que cambia la selección; también enciende las\n * casillas sin barra de acciones (la pantalla pinta las suyas)\n * @param {'top'|'split'} [props.selectionPhoneLayout] SELECTION_PHONE_LAYOUT: en el teléfono con vidrio o minimalista, todo\n * arriba (por omisión) o el conteo arriba y las acciones abajo. Sin vidrio, en el renglón como en escritorio\n * @param {(request: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}) => void} [props.onQueryChange]\n * cada que cambia lo que pide la tabla (un filtro, el orden, la página), antes de consultar: para la lógica de negocio que\n * depende de lo filtrado («si eligió Cancelados, enseñe el motivo»)\n * @param {(result: {rows: any[], total: number, facets: object, capped: boolean}) => void} [props.onLoaded] cada que llega una\n * página del servidor\n * @param {(error: unknown) => void} [props.onLoadError] cuando la consulta falla (la tabla ya enseña su aviso con «Reintentar»)\n * @param {object} [props.gridProps] lo demás del DataGrid de MUI, sobre todo sus eventos (onRowClick, onRowDoubleClick,\n * onCellKeyDown…). OJO: lo que la tabla controla (paginar, ordenar y filtrar en el servidor, el alto, la selección) no se\n * reemplaza desde aquí: para eso están sus props\n * @param {object} [props.texts] los textos de la tabla que cambian, con la forma de `table` en los textos del paquete\n * (src/locales/es.js), ya en el idioma de la pantalla: {selection: {clear: 'Deseleccionar'}, empty: {filtered: '…'}}.\n * También les llegan a sus filtros de columna, sus chips y su barra de elegidos\n */\nexport default function ServerTable(props) {\n // lo que el proyecto puso en su tema (components.CalcitaServerTable.defaultProps) y encima lo que llega aquí\n const {\n fetchPage,\n queryKey,\n enabled = true,\n columns,\n filterKinds = {},\n filterDefaults = {},\n chipConfig = [],\n quickFilters = [],\n searchField = 'contains',\n searchPlaceholder,\n searchInBar = false,\n collapseSearchInBar = true,\n emptyLabel,\n countLabel,\n pageSizeOptions = [10, 25, 50, 100],\n defaultPageSize = 25,\n getRowId,\n prefix,\n refreshToken,\n footer,\n toolbarExtra,\n header,\n beforeQuickFilters,\n columnGroupingModel,\n getRowClassName,\n isRowVisible,\n hideFooterWhenAllRowsFit = false,\n showGoToPage = false,\n striped = false,\n getRowHeight,\n gridSx,\n maxGridHeight = null,\n ariaLabel,\n fixedColumn,\n selectionActions = [],\n isRowSelectable,\n allowSelectAllMatching = true,\n onSelectionChange,\n selectionPhoneLayout = SELECTION_PHONE_LAYOUT.top,\n onQueryChange,\n onLoaded,\n onLoadError,\n gridProps,\n texts,\n} = usePieceProps(props, THEME_NAME);\n const {t, language} = useToolkitTranslation('table', texts);\n const {formatNumber} = useFormatters();\n const theme = useTheme();\n const tableState = useTableState({prefix, filterDefaults, filterKinds, defaultPageSize});\n const {filters, sortOrders, page, pageSize} = tableState;\n\n // la caja de búsqueda rebota: se escribe sin latencia y al servidor va una consulta cuando se deja de teclear\n const [searchDraft, setSearchDraft] = useDebouncedFilter(\n searchField ? filters[searchField] : '',\n (value) => searchField && tableState.setFilter(searchField, value),\n );\n\n // NOTA: fetchPage suele ser una función nueva en cada render; la máquina siempre llama a la más reciente\n const latestFetchPage = useRef(fetchPage);\n latestFetchPage.current = fetchPage;\n const latestEvents = useRef({onQueryChange, onLoaded, onLoadError});\n latestEvents.current = {onQueryChange, onLoaded, onLoadError};\n const [tableSnapshot, sendToTable] = useMachine(\n tableMachine.provide({actors: buildTableActors((params, signal) => latestFetchPage.current(params, signal))}),\n );\n const {rows, total, facets, capped, error} = tableSnapshot.context;\n // lo que se pinta: la página completa o, si la pantalla esconde renglones (un grupo plegado), solo los que deja ver.\n // Con memoria: un arreglo nuevo en cada pintada haría que el DataGrid volviera a procesar todos sus renglones\n const visibleRows = useMemo(() => (isRowVisible ? rows.filter(isRowVisible) : rows), [rows, isRowVisible]);\n const isLoading = tableSnapshot.matches('loading') || tableSnapshot.matches('idle');\n\n const requestParams = {filters, sortOrders, page, pageSize};\n const requestFingerprint = JSON.stringify({queryKey, enabled, refreshToken, ...requestParams});\n\n // IMPORTANTE: UN solo efecto dispara la consulta. Varios useEffect pidiendo lo mismo es como nacen las consultas\n // duplicadas\n useEffect(() => {\n if (!queryKey || !enabled) {\n return;\n }\n latestEvents.current.onQueryChange?.(requestParams);\n sendToTable({type: 'FETCH', params: requestParams});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [requestFingerprint]);\n\n // los eventos de la carga salen hacia afuera (la lógica de negocio que depende de lo que llegó). Con referencia a la\n // función más reciente: la pantalla suele pasar funciones nuevas en cada pintada\n const isReady = tableSnapshot.matches('ready');\n useEffect(() => {\n if (isReady) {\n latestEvents.current.onLoaded?.({rows, total, facets, capped});\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isReady, rows]);\n useEffect(() => {\n if (error) {\n latestEvents.current.onLoadError?.(error);\n }\n }, [error]);\n\n const toggleSort = (column) => {\n const currentSort = sortOrders.find((sortOrder) => sortOrder.column === column);\n if (!currentSort) {\n tableState.setSort([{column, direction: 'desc'}]);\n } else if (currentSort.direction === 'desc') {\n tableState.setSort([{column, direction: 'asc'}]);\n } else {\n // tercer clic: regresa al orden por defecto del servidor\n tableState.setSort([]);\n }\n };\n\n // ─── Renglones elegidos (rowSelection.js) ───\n // con acciones (o quien escuche los cambios) cada renglón lleva su casilla\n const isSelectable = selectionActions.length > 0 || Boolean(onSelectionChange);\n const [rowSelection, setRowSelection] = useState(EMPTY_ROW_SELECTION);\n const idOf = useCallback((row) => (getRowId ? getRowId(row) : row.id), [getRowId]);\n const pageRowsById = useMemo(() => new Map(visibleRows.map((row) => [idOf(row), row])), [visibleRows, idOf]);\n const selectablePageIds = useMemo(\n () => visibleRows.filter((row) => !isRowSelectable || isRowSelectable(row)).map(idOf),\n [visibleRows, isRowSelectable, idOf],\n );\n const checkedIds = useMemo(() => checkedIdsOf(rowSelection, selectablePageIds), [rowSelection, selectablePageIds]);\n const selection = rowSelectionOf(rowSelection, {total, capped, filters});\n\n const updateSelection = (nextSelection) => {\n setRowSelection(nextSelection);\n onSelectionChange?.(rowSelectionOf(nextSelection, {total, capped, filters}));\n };\n const clearSelection = () => updateSelection(EMPTY_ROW_SELECTION);\n\n // otro filtro u otro conjunto son otros renglones: la selección se borra para no actuar sobre lo que ya no se ve. Cambiar\n // de página o de orden la conserva\n const selectionResetKey = JSON.stringify({queryKey, filters});\n const lastSelectionResetKey = useRef(selectionResetKey);\n useEffect(() => {\n if (lastSelectionResetKey.current === selectionResetKey) {\n return;\n }\n lastSelectionResetKey.current = selectionResetKey;\n if (rowSelection !== EMPTY_ROW_SELECTION) {\n clearSelection();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectionResetKey]);\n\n // el DataGrid avisa qué quedó marcado; con disableRowSelectionExcludeModel siempre es la lista de los marcados\n const handleGridSelectionChange = (model) => {\n // la casilla de arriba elige todos los que coinciden (si se permite); el aviso deja quedarse con la página\n const nextSelection = selectionAfterCheck(rowSelection, model.ids, pageRowsById, selectablePageIds, {\n allMatchingOnWholePage: allowSelectAllMatching, total, capped,\n });\n if (nextSelection !== rowSelection) {\n updateSelection(nextSelection);\n }\n };\n\n const hasSelection = isSelectable && selection.count > 0;\n // en el teléfono con barra de pestañas abajo (vidrio, o minimalista con cápsulas) las acciones de los elegidos flotan\n // (SelectionActions decide dónde) y el conteo de la tabla se queda; sin esa barra, ocupan el lugar del conteo\n const floatsSelectionOnPhone = selectionFloatsOnPhone(theme);\n const selectionCountText = selection.isCapped\n ? t('selection.allMatchingCapped')\n : t('selection.count', {count: selection.count, total: formatNumber(selection.count)});\n // cada acción recibe la selección y cómo dejar la tabla al terminar; isDisabled se resuelve con la selección de ahora\n const selectionHelpers = {clearSelection, refresh: () => sendToTable({type: 'FETCH', params: requestParams})};\n const selectionActionItems = selectionActions.map(({key, label, icon, color, isDisabled, onClick}) => ({\n key, label, icon, color, disabled: isDisabled?.(selection) ?? false, onClick: () => onClick(selection, selectionHelpers),\n }));\n const offersAllMatching = isSelectable && allowSelectAllMatching && canSelectAllMatching(rowSelection, selectablePageIds, {total, capped});\n\n // el texto de la caja de búsqueda no cuenta como filtro oculto: se está viendo en su propia caja\n const hasActiveFilters = Object.entries(filters)\n .some(([field, value]) => field !== searchField && isFilterActive(filterKinds[field], value));\n\n // un acceso rápido está \"puesto\" cuando se aleja de su default; los que además tienen chip ya se cuentan ahí\n const quickActiveCount = quickFilters.filter((quickFilter) => !chipConfig.some((chipDeclaration) => chipDeclaration.key === quickFilter.field)\n && JSON.stringify(filters[quickFilter.field] ?? '') !== JSON.stringify(filterDefaults[quickFilter.field] ?? '')).length;\n\n const tableFilterValue = useMemo(() => ({\n filters,\n setFilter: tableState.setFilter,\n clearFilter: tableState.clearFilter,\n sortOrders,\n toggleSort,\n clearSort: () => tableState.setSort([]),\n facets,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [filters, sortOrders, facets]);\n\n // alto según lo que hay: una tabla de 3 organizaciones no deja 500 px en blanco. Sin renglones reservamos lugar para el\n // esqueleto de carga (hasta 8) o para el aviso de tabla vacía (3); con renglones, ni un pixel de hueco abajo\n let placeholderRowCount = 0;\n if (visibleRows.length === 0) {\n placeholderRowCount = isLoading ? Math.min(pageSize, 8) : 3;\n }\n // OJO: el alto se suma renglón por renglón con el alto que pide la pantalla (getRowHeight; p. ej. un renglón de\n // resumen más alto que los demás). Con un solo alto para todos, la tabla quedaba con hueco blanco o\n // con barra de desplazamiento sin necesidad\n let rowsHeight = placeholderRowCount * ROW_HEIGHT_PIXELS;\n for (const row of visibleRows) {\n const requestedRowHeight = getRowHeight?.({id: getRowId ? getRowId(row) : row.id, model: row, densityFactor: COMPACT_DENSITY_FACTOR});\n rowsHeight += typeof requestedRowHeight === 'number' ? requestedRowHeight : ROW_HEIGHT_PIXELS;\n }\n // la tabla crece con los renglones de la página y NO tiene scroll vertical propio (un solo scroll, el\n // de la página). La paginación del servidor ya acota cuántos renglones hay; maxGridHeight queda solo para quien\n // de verdad necesite un tope (un diálogo con altura fija)\n // con bandas el encabezado son dos renglones del mismo alto: el de las bandas y el de las columnas\n const headerHeight = columnGroupingModel ? 2 * COLUMN_HEADER_HEIGHT_PIXELS : COLUMN_HEADER_HEIGHT_PIXELS;\n // sin paginador que usar no hay pie: todo lo que hay ya está a la vista en la primera página\n const isFooterHidden = hideFooterWhenAllRowsFit && page === 0 && total <= pageSize;\n // el pie mide su alto más las líneas de borde; sin pie no hay ni lo uno ni lo otro\n const footerHeight = isFooterHidden ? 0 : FOOTER_HEIGHT_PIXELS + GRID_BORDER_PIXELS;\n const contentHeight = headerHeight + rowsHeight + footerHeight + HEIGHT_SLACK_PIXELS;\n const gridHeight = maxGridHeight ? Math.min(contentHeight, maxGridHeight) : contentHeight;\n\n const gridText = DATA_GRID_TEXT_BY_LANGUAGE[language] ?? DATA_GRID_TEXT_BY_LANGUAGE.es;\n const formattedTotal = formatNumber(total);\n const countText = countLabel ? countLabel(total) : t('count.records', {count: total, total: formattedTotal});\n\n const searchText = searchPlaceholder ?? t('search.placeholder');\n\n return (\n <ComponentTexts namespace=\"table\" texts={texts}>\n <TableFilterContext value={tableFilterValue}>\n <TableToolbar direction={{xs: 'column', md: 'row'}} spacing={2} ownSx={{mb: 1.5, alignItems: {md: 'center'}}}>\n {/* la búsqueda: aquí o arriba en la barra de la app (BarSearch: se encoge a la lupa sin usar) */}\n {searchField && (\n <BarSearch value={searchDraft} onChange={setSearchDraft} placeholder={searchText} inBar={searchInBar} collapsible={collapseSearchInBar} />\n )}\n {/* con elegidos, sus acciones ocupan el lugar del conteo (en el teléfono con barra de pestañas, flotan). Sus\n textos son los de la tabla: así el `texts` de ServerTable también los cambia */}\n {hasSelection && (\n <SelectionActions countText={selectionCountText} actions={selectionActionItems} onClear={clearSelection}\n phoneLayout={selectionPhoneLayout}\n texts={{selection: {clear: t('selection.clear'), actionsLabel: t('selection.actionsLabel'), summaryLabel: t('selection.summaryLabel')}}} />\n )}\n <TableSummary ownSx={{\n flexGrow: 1, minWidth: 0, display: 'flex',\n ...(hasSelection && {display: 'none', ...(floatsSelectionOnPhone && {[PHONE_MEDIA_QUERY]: {display: 'flex'}})}),\n }}>\n {header ? (\n <TableCustomHeader ownSx={{flexGrow: 1, minWidth: 0}}>\n {header({countText: capped ? t('count.capped', {total: formattedTotal}) : countText, total, capped})}\n </TableCustomHeader>\n ) : (\n // NOTA: el extra va pegado al conteo y no empujado a la orilla (ml: 'auto'): en escritorio quedaba a todo\n // el ancho de distancia y no se leía como parte de la misma tabla (caso del selector de año)\n <TableCount direction=\"row\" spacing={2} useFlexGap ownSx={{flexGrow: 1, alignItems: 'center', flexWrap: 'wrap'}}>\n <TableCountRow direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <Typography variant=\"body2\" color=\"text.secondary\" role=\"status\" aria-live=\"polite\">\n {capped ? t('count.capped', {total: formattedTotal}) : countText}\n </Typography>\n {capped && <Tag label={t('count.cappedTag')} color=\"warning\" tooltip={t('count.cappedTooltip')} />}\n </TableCountRow>\n {toolbarExtra}\n </TableCount>\n )}\n </TableSummary>\n </TableToolbar>\n\n {beforeQuickFilters}\n\n {quickFilters.map((quickFilter) => (\n <QuickFilterRow key={quickFilter.field} quickFilter={quickFilter} facets={facets} total={total} filters={filters}\n isMultiple={filterKinds[quickFilter.field] === FILTER_KINDS.multiSelect}\n setFilter={tableState.setFilter} setFilters={tableState.setFilters} />\n ))}\n\n <FilterChips chipConfig={chipConfig} filters={filters} quickActiveCount={quickActiveCount}\n onSetFilter={tableState.setFilter} onClearAll={tableState.clearAll} />\n\n {/* todos los que coinciden (lo elige la casilla de arriba): se puede volver a solo esta página; la página llena a\n mano: se ofrece elegir todos */}\n {(offersAllMatching || (isSelectable && rowSelection.isAllMatching)) && (\n <TableSelectionNotice severity=\"info\" icon={false} ownSx={{mb: 1, alignItems: 'center'}}\n action={rowSelection.isAllMatching ? (\n <Button color=\"inherit\" size=\"small\"\n onClick={() => updateSelection({\n rowsById: new Map(selectablePageIds.map((id) => [id, pageRowsById.get(id)])), isAllMatching: false,\n })}>\n {t('selection.onlyThisPage')}\n </Button>\n ) : (\n <Button color=\"inherit\" size=\"small\" onClick={() => updateSelection({rowsById: new Map(), isAllMatching: true})}>\n {capped ? t('selection.selectAllMatchingCapped') : t('selection.selectAllMatching', {total: formattedTotal})}\n </Button>\n )}>\n {rowSelection.isAllMatching\n ? (capped ? t('selection.allMatchingCapped') : t('selection.allMatching', {total: formattedTotal}))\n : t('selection.pageSelected', {count: selectablePageIds.length})}\n </TableSelectionNotice>\n )}\n\n {error && (\n <TableError severity=\"error\" role=\"alert\" ownSx={{mb: 1}}\n action={(\n <Button color=\"inherit\" size=\"small\" onClick={() => sendToTable({type: 'FETCH', params: requestParams})}>\n {t('common:actions.retry')}\n </Button>\n )}>\n {error.message ?? t('error.generic')}\n </TableError>\n )}\n\n {/* minWidth 0: dentro de un flex o grid el DataGrid no empuja la página; en el teléfono la tabla se desliza\n de lado DENTRO de su tarjeta y la página no */}\n <TableCard variant=\"outlined\" ownSx={{width: '100%', minWidth: 0, overflow: 'hidden'}}>\n <TableGrid\n // primero lo de la pantalla (sus eventos); lo de abajo es lo que la tabla controla y le gana\n {...gridProps}\n rows={visibleRows}\n columns={columns}\n columnGroupingModel={columnGroupingModel}\n getRowId={getRowId}\n getRowClassName={(params) => [\n getRowClassName?.(params),\n striped && params.indexRelativeToCurrentPage % 2 === 1 ? STRIPED_ROW_CLASS : '',\n ].filter(Boolean).join(' ')}\n getRowHeight={getRowHeight}\n aria-label={ariaLabel}\n nonce={readCspNonce()}\n loading={isLoading}\n // IMPORTANTE: paginación y orden del servidor; el DataGrid no reordena ni recorta nada solo\n paginationMode=\"server\"\n sortingMode=\"server\"\n filterMode=\"server\"\n rowCount={total}\n paginationModel={{page, pageSize}}\n onPaginationModelChange={(paginationModel) => {\n if (paginationModel.pageSize !== pageSize) {\n tableState.setPageSize(paginationModel.pageSize);\n } else {\n tableState.setPage(paginationModel.page);\n }\n }}\n pageSizeOptions={pageSizeOptions}\n hideFooter={isFooterHidden}\n disableColumnMenu\n disableRowSelectionOnClick\n // elegir renglones: solo con la casilla (el clic en el renglón no elige). Los elegidos de otras páginas\n // se conservan (keepNonExistentRowsSelected). OJO: sin disableRowSelectionExcludeModel la casilla de\n // arriba marca «todos los de todas las páginas» en lugar de los de esta página\n checkboxSelection={isSelectable}\n rowSelectionModel={isSelectable ? {type: 'include', ids: checkedIds} : undefined}\n onRowSelectionModelChange={isSelectable ? handleGridSelectionChange : undefined}\n isRowSelectable={isSelectable && isRowSelectable ? (params) => isRowSelectable(params.row) : undefined}\n keepNonExistentRowsSelected={isSelectable}\n disableRowSelectionExcludeModel\n // el conteo de los elegidos lo dice la barra de arriba; el del pie del DataGrid sobraría\n hideFooterSelectedRowCount\n // con columna fija se dibuja todo: si no, la fija desaparecería al deslizar a la derecha (fixedColumnSxOf)\n disableVirtualization={Boolean(fixedColumn)}\n density={DATA_GRID_DENSITY}\n localeText={{...gridText, noRowsLabel: emptyLabel ?? t('empty.default')}}\n slotProps={{\n // con filas ya pintadas, barra delgada arriba sin tapar lo que se lee; con la tabla vacía, esqueleto\n loadingOverlay: {variant: 'linear-progress', noRowsVariant: 'skeleton'},\n }}\n slots={{\n // \"ir a la página N\" (solo si se pide) pegado a la paginación: ahí lo busca quien ya está leyendo\n // \"51-75 de 1,234\". Sin él, la paginación de siempre del DataGrid\n ...(showGoToPage && {\n pagination: () => (\n <TablePagination direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <GoToPage page={page} pageCount={Math.ceil(total / pageSize) || 1} onChange={tableState.setPage} />\n <GridPagination />\n </TablePagination>\n ),\n }),\n noResultsOverlay: () => <EmptyState filtered label={emptyLabel} onClearFilters={tableState.clearAll} />,\n noRowsOverlay: () => <EmptyState filtered={hasActiveFilters} label={emptyLabel} onClearFilters={tableState.clearAll} />,\n }}\n ownSx={[{\n // IMPORTANTE: el alto va en la raíz del DataGrid y no en la caja de afuera: las variables\n // --DataGrid-hasScrollX y --DataGrid-scrollbarSize solo existen en la raíz. Cuando las columnas no\n // caben (historial a 390 px) la barra horizontal ocupa su alto dentro de la tabla y, sin sumarlo, los\n // renglones se desplazaban 13 px por dentro. Con barras superpuestas (teléfono, trackpad) mide 0\n height: `calc(${gridHeight}px + var(--DataGrid-hasScrollX, 0) * var(--DataGrid-scrollbarSize, 0px))`,\n border: 0,\n // todo centrado verticalmente: el texto suelto se pegaba arriba y los chips quedaban a media altura\n '& .MuiDataGrid-cell': {display: 'flex', alignItems: 'center'},\n '& .MuiDataGrid-columnHeader': {alignItems: 'center'},\n // cebra: el color del hover del tema\n [`& .${STRIPED_ROW_CLASS}`]: {bgcolor: 'action.hover'},\n [`& .${STRIPED_ROW_CLASS}:hover`]: {bgcolor: 'action.selected'},\n ...gridSx,\n }, (gridTheme) => (fixedColumn ? fixedColumnSxOf(gridTheme, fixedColumn, {withCheckboxColumn: isSelectable}) : {})]}\n />\n </TableCard>\n\n {footer?.({total, capped})}\n </TableFilterContext>\n </ComponentTexts>\n );\n}\n"],"names":["dataGridSpanish","dataGridEnglish"],"mappings":"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"}
1
+ {"version":3,"file":"ServerTable.js","sources":["../../src/DataTable/ServerTable.jsx"],"sourcesContent":["// La tabla: pagina, filtra y ordena EN EL SERVIDOR (contrato {filters, sortOrders, page, pageSize} → {rows, total, facets}).\n//\n// Cada cambio de filtro, orden o página es una consulta nueva contra el conjunto COMPLETO y el total que se muestra\n// es el real. Traer todo y filtrar en el navegador mentiría en cuanto el conjunto no quepa en una página.\n//\n// Contrato de fetchPage:\n// fetchPage({filters, sortOrders, page, pageSize}, signal) → Promise<{rows, total, facets?, capped?}>\n// - rows: cada fila con su id del SERVIDOR (getRowId). Fabricarlo en el front colisiona y el DataGrid conserva\n// filas de la consulta anterior;\n// - facets: {campo: [{value, total}]} contadas SIN el filtro de ese campo (lo hace el servidor), para que la\n// selección múltiple siga siendo posible;\n// - capped: el total es \"al menos esto\".\n//\n// Elegir renglones (selectionActions): una casilla por renglón y las acciones de los elegidos (rowSelection.js dice cómo\n// se conservan entre páginas y qué es «todos los que coinciden»; SelectionActions, dónde se ven sus acciones).\n//\n// Piezas: useTableState (URL con nuqs y prefijo) · tableMachine (XState: carga, error y respuestas rezagadas) ·\n// columns.jsx (encabezados con orden y filtro) · FilterChips · QuickFilters · GoToPage · EmptyState.\n//\n// Con @mui/x-data-grid 8 (compatible con MUI 7).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaServerTable con defaultProps y\n// styleOverrides de sus partes: toolbar, summary, customHeader, count, countRow, selectionNotice, error, card, grid,\n// pagination.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport {useMachine} from '@xstate/react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\nimport SearchIcon from '@mui/icons-material/Search';\nimport {DataGrid, GRID_CHECKBOX_SELECTION_COL_DEF, GRID_CHECKBOX_SELECTION_FIELD, GridPagination} from '@mui/x-data-grid';\nimport {enUS as dataGridEnglish, esES as dataGridSpanish} from '@mui/x-data-grid/locales';\n\nimport EmptyState from '@/DataTable/EmptyState.jsx';\nimport FilterChips from '@/DataTable/FilterChips.jsx';\nimport GoToPage from '@/DataTable/GoToPage.jsx';\nimport {TableFilterContext} from '@/DataTable/filterContext.js';\nimport {\n EMPTY_ROW_SELECTION, canSelectAllMatching, checkedIdsOf, rowSelectionOf, selectionAfterCheck,\n} from '@/DataTable/rowSelection.js';\nimport {buildTableActors, tableMachine} from '@/DataTable/tableMachine.js';\nimport {useDebouncedFilter} from '@/DataTable/useDebouncedFilter.js';\nimport {FILTER_KINDS, isFilterActive, useTableState} from '@/DataTable/useTableState.js';\nimport BarSearch from '@/appShell/BarSearch.jsx';\nimport {PHONE_MEDIA_QUERY} from '@/appShell/shellSizes.js';\nimport SelectionActions, {SELECTION_PHONE_LAYOUT, selectionFloatsOnPhone} from '@/ui/actions/SelectionActions.jsx';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {materialBackgroundOf} from '@/theme/glassSurface.js';\nimport QuickFilters from '@/ui/filters/QuickFilters.jsx';\nimport Tag from '@/ui/labels/Tag.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaServerTable)\nconst THEME_NAME = 'CalcitaServerTable';\nconst TableToolbar = piecePart(THEME_NAME, 'Toolbar', Stack);\nconst TableSummary = piecePart(THEME_NAME, 'Summary', Box);\nconst TableCustomHeader = piecePart(THEME_NAME, 'CustomHeader', Box);\nconst TableCount = piecePart(THEME_NAME, 'Count', Stack);\nconst TableCountRow = piecePart(THEME_NAME, 'CountRow', Stack);\nconst TableSelectionNotice = piecePart(THEME_NAME, 'SelectionNotice', Alert);\nconst TableError = piecePart(THEME_NAME, 'Error', Alert);\nconst TableCard = piecePart(THEME_NAME, 'Card', Paper);\nconst TableGrid = piecePart(THEME_NAME, 'Grid', DataGrid);\nconst TablePagination = piecePart(THEME_NAME, 'Pagination', Stack);\n\n// OJO: los textos del DataGrid van como PROP (localeText) y no solo en el tema: el grid resuelve sus defaults en\n// inglés y le ganan a los defaultProps del tema\nconst DATA_GRID_TEXT_BY_LANGUAGE = {\n es: dataGridSpanish.components.MuiDataGrid.defaultProps.localeText,\n en: dataGridEnglish.components.MuiDataGrid.defaultProps.localeText,\n};\n\n/**\n * Nonce de la CSP de la página, si la aplicación usa CSP y lo pone en <meta property=\"csp-nonce\">.\n *\n * IMPORTANTE: el DataGrid 8 inserta un <style> con sus variables CSS (bordes, fondos, espaciado). Sin el nonce la CSP lo\n * bloquea (\"style-src-elem\") y la tabla se pinta sin sus variables. OJO: el navegador esconde el valor del atributo\n * (getAttribute regresa \"\"); se lee con la propiedad .nonce, igual que el caché de emotion con nonce.\n *\n * @returns {string|undefined}\n */\nfunction readCspNonce() {\n // pintando en el servidor (Next.js) no hay documento: ahí el nonce lo pone quien arma el HTML\n if (typeof document === 'undefined') {\n return undefined;\n }\n\n return document.querySelector('meta[property=\"csp-nonce\"]')?.nonce || undefined;\n}\n\n// Densidad compacta en todas las tablas: el espaciado por omisión desperdicia renglones. Son los altos que pinta el DataGrid 8 con density=\"compact\": la base de 52 px del renglón y de 56 px del\n// encabezado por el factor 0.7, redondeados hacia abajo. El pie (paginación) no cambia con la densidad.\n// OJO: si se cambia la densidad, estos números se vuelven a medir en Chrome; con ellos se calcula el alto del contenedor\n// y un número viejo deja hueco blanco abajo o una barra de desplazamiento sin necesidad\nconst ROW_HEIGHT_PIXELS = 36;\nconst COLUMN_HEADER_HEIGHT_PIXELS = 39;\nconst FOOTER_HEIGHT_PIXELS = 52;\n// líneas del borde del encabezado y del pie\nconst GRID_BORDER_PIXELS = 2;\n// holgura de alto de la tabla: debajo del último renglón queda este hueco, así que va lo más chico que aguanta.\n// OJO: con el alto exacto, el redondeo de subpíxeles hace que el DataGrid crea que hay scroll vertical, reserve el ancho de\n// la barra y aparezca un scroll lateral de 5 px. Lo vigila e2e/tests/upload-control.spec.js (la tabla no se desliza de lado)\nconst HEIGHT_SLACK_PIXELS = 2;\nconst DATA_GRID_DENSITY = 'compact';\nconst STRIPED_ROW_CLASS = 'server-table-row--striped';\n// dónde van los elegidos en el teléfono: la regla vive en SelectionActions; la tabla la vuelve a exportar por comodidad\nexport {SELECTION_PHONE_LAYOUT};\n\n\n// a qué altura van la celda y el encabezado fijos: los mismos que usa el DataGrid de paga para sus columnas fijas. El\n// encabezado va arriba de la raya que separa columnas (30); con menos, la raya de las otras columnas lo cruzaba al deslizar\nconst FIXED_CELL_Z_INDEX = 30;\nconst FIXED_HEADER_Z_INDEX = 40;\n// ancho de la columna de casillas para elegir renglones (la del DataGrid)\nconst CHECKBOX_COLUMN_WIDTH_PIXELS = GRID_CHECKBOX_SELECTION_COL_DEF.width;\n\n/**\n * Estilos que dejan pegada a la izquierda una columna al deslizar la tabla de lado (en el teléfono y en una ventana angosta),\n * igual que fixedSelectColumn de mui-datatables. Fijar columnas en MUI X es de DataGridPro (de paga); por dentro Pro usa\n * position sticky en la celda, y eso mismo se hace aquí, también con su banda del encabezado cuando la banda es solo suya\n * (p. ej. una banda PERIODO de una sola columna).\n *\n * OJO, trampas pagadas:\n * - el DataGrid gratuito solo dibuja las columnas que se ven (virtualización) y al deslizar mucho a la derecha quitaba del\n * DOM a la columna fija, que desaparecía. Un margen de columnas extra (columnBufferPx) no alcanzó: con columna fija la\n * tabla va con disableVirtualization y dibuja todo, que en nuestras tablas son menos de quince columnas y una página;\n * - la celda fija necesita fondo SÓLIDO o se ve lo que pasa por debajo. Toma el color de su renglón (inherit), pero hay\n * renglones con color transparente (una banda de color, la cebra, el resaltado del mouse): ahí se asomaban las\n * cifras de las otras columnas. Por eso el fondo va en dos capas: abajo el papel, sólido (backgroundImage, que se pinta\n * encima del color propio de la celda), y encima el color del renglón en un ::before detrás del texto (zIndex -1 dentro\n * de la celda). Se ve igual que el renglón y no transparenta.\n * El renglón lleva el fondo del papel con :where(), que no suma especificidad: así los renglones que la página pinta de otro\n * color le siguen ganando. Los colores salen de la paleta del tema (de sus variables CSS si el tema las usa) para que\n * cambien con el modo oscuro.\n *\n * Con el contenido de material del tema de vidrio (createToolkitTheme({glass: {surfaces: true}})) la tabla no lleva fondo\n * propio: los renglones van transparentes y la celda pegada lleva el mismo material esmerilado, que tapa lo que pasa por\n * debajo sin verse como una columna blanca (así se veía con el papel sólido).\n *\n * Con renglones que se eligen, la casilla también se queda pegada, antes que la columna fija: si no, al deslizar la fija\n * tapaba la casilla.\n *\n * @param {object} theme tema de MUI\n * @param {string} field campo de la columna que se queda fija\n * @param {{withCheckboxColumn?: boolean}} [options]\n * @returns {object} estilos para el sx del DataGrid\n */\nfunction fixedColumnSxOf(theme, field, {withCheckboxColumn = false} = {}) {\n // un tema con variables CSS (cssVariables) las trae en theme.vars; el tema por omisión de MUI, solo en theme.palette\n const {palette} = theme.vars ?? theme;\n const paper = palette.background.paper;\n const divider = `1px solid ${palette.divider}`;\n // la banda del encabezado que lleva solo a esta columna: el DataGrid la marca con sus campos entre |- y -|\n const ownBandHeader = `.MuiDataGrid-columnHeader[data-fields=\"|-${field}-|\"]`;\n const isMaterialContent = Boolean(theme.toolkit?.glass?.surfaces);\n // abajo la capa (el papel o el material) y encima el color del renglón (el ::before)\n const stickyBackground = {backgroundColor: 'inherit', ...(isMaterialContent ? materialBackgroundOf(theme, {thick: true}) : {backgroundImage: `linear-gradient(${paper}, ${paper})`})};\n const headerBackground = isMaterialContent ? materialBackgroundOf(theme, {thick: true}) : {backgroundColor: paper};\n const rowColorLayer = {content: '\"\"', position: 'absolute', inset: 0, zIndex: -1, backgroundColor: 'inherit'};\n const fixedLeft = withCheckboxColumn ? CHECKBOX_COLUMN_WIDTH_PIXELS : 0;\n const checkboxCell = `.MuiDataGrid-cell[data-field=\"${GRID_CHECKBOX_SELECTION_FIELD}\"]`;\n const checkboxHeader = `.MuiDataGrid-columnHeader[data-field=\"${GRID_CHECKBOX_SELECTION_FIELD}\"]`;\n\n return {\n '& :where(.MuiDataGrid-row)': {backgroundColor: isMaterialContent ? 'transparent' : paper},\n [`& .MuiDataGrid-cell[data-field=\"${field}\"]`]: {\n position: 'sticky', left: fixedLeft, zIndex: FIXED_CELL_Z_INDEX, borderRight: divider,\n ...stickyBackground,\n '&::before': rowColorLayer,\n },\n [`& :where(.MuiDataGrid-columnHeader[data-field=\"${field}\"], ${ownBandHeader})`]: headerBackground,\n [`& .MuiDataGrid-columnHeader[data-field=\"${field}\"], & ${ownBandHeader}`]: {\n position: 'sticky', left: fixedLeft, zIndex: FIXED_HEADER_Z_INDEX, borderRight: divider,\n },\n ...(withCheckboxColumn && {\n [`& ${checkboxCell}`]: {position: 'sticky', left: 0, zIndex: FIXED_CELL_Z_INDEX, ...stickyBackground, '&::before': rowColorLayer},\n [`& :where(${checkboxHeader})`]: headerBackground,\n [`& ${checkboxHeader}`]: {position: 'sticky', left: 0, zIndex: FIXED_HEADER_Z_INDEX},\n }),\n };\n}\nconst COMPACT_DENSITY_FACTOR = 0.7;\n\n/** Una tira de accesos rápidos sobre un campo de la tabla, alimentada por su faceta. */\nfunction QuickFilterRow({quickFilter, facets, total, filters, isMultiple, setFilter, setFilters}) {\n const {t} = useToolkitTranslation('table');\n const facetOptions = facets[quickFilter.facetKey ?? quickFilter.field] ?? [];\n const orderedOptions = quickFilter.order\n ? quickFilter.order.map((optionValue) => facetOptions.find((option) => option.value === optionValue) ?? {value: optionValue, total: 0})\n : facetOptions;\n\n // en un filtro múltiple el chip activo es la opción cuando es la ÚNICA elegida: con varias puestas desde la columna\n // ningún chip miente estando encendido\n const currentValue = filters[quickFilter.field];\n // si otro control del mismo \"qué\" está puesto (un rango de fechas), ningún chip se enciende\n const isOverridden = quickFilter.isOverridden?.(filters) ?? false;\n let selectedValue = currentValue ?? '';\n if (isOverridden) {\n selectedValue = '__overridden__';\n } else if (isMultiple) {\n selectedValue = Array.isArray(currentValue) && currentValue.length === 1 ? currentValue[0] : '';\n }\n\n // el conteo de \"Todas\" es la suma de la faceta (el resultado SIN este filtro), no el de la página actual; cuando las\n // opciones se traslapan la suma mentiría: el total lo da el servidor en allCountKey o, si no lo da, no se pinta\n // conteo (hideAllCount) antes que pintar uno falso\n let allCount = facetOptions.reduce((sum, option) => sum + (option.total ?? 0), 0) || total;\n if (quickFilter.allCountKey && typeof facets[quickFilter.allCountKey] === 'number') {\n allCount = facets[quickFilter.allCountKey];\n } else if (quickFilter.hideAllCount) {\n allCount = undefined;\n }\n\n const handleChange = (nextValue) => {\n const pickedValue = isMultiple ? (nextValue ? [nextValue] : []) : nextValue;\n // elegir un chip limpia los controles que compiten con él\n if (quickFilter.clears) {\n setFilters({[quickFilter.field]: pickedValue, ...quickFilter.clears});\n } else {\n setFilter(quickFilter.field, pickedValue);\n }\n };\n\n return (\n <QuickFilters\n caption={quickFilter.caption}\n ariaLabel={quickFilter.caption}\n value={selectedValue}\n onChange={handleChange}\n extra={quickFilter.renderExtra?.({filters, setFilters})}\n options={[\n {value: '', label: quickFilter.allLabel ?? t('quickFilters.all'), count: allCount},\n ...orderedOptions.map((option) => ({\n value: option.value,\n label: quickFilter.renderLabel ? quickFilter.renderLabel(option.value) : option.value,\n count: option.total,\n })),\n ]}\n />\n );\n}\n\n/** @typedef {import('@/DataTable/rowSelection.js').RowSelection} RowSelection */\n\n/**\n * @param {object} props\n * @param {(params: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}, signal: AbortSignal) => Promise<{rows: any[], total: number, facets?: Record<string, Array<{value: any, total: number}> | number>, capped?: boolean}>} props.fetchPage\n * page cuenta desde 0; toServerTableParams lo convierte a la query del API\n * @param {string} props.queryKey cambia cuando cambia el CONJUNTO (no los filtros): dispara recarga\n * @param {boolean} [props.enabled] false mientras la sección está oculta: una tabla que nadie ve no consulta\n * @param {Array<object>} props.columns textColumn / facetColumn / detailColumn o columnas del DataGrid\n * @param {Record<string, string>} [props.filterKinds]\n * @param {Record<string, unknown>} [props.filterDefaults]\n * @param {Array<object>} [props.chipConfig] buildChipConfig\n * @param {Array<object>} [props.quickFilters] {field, facetKey, caption, allLabel, renderLabel, order, clears,\n * isOverridden, renderExtra, allCountKey, hideAllCount}\n * @param {string|null} [props.searchField] filtro de texto que se saca a la barra; null quita la caja\n * @param {string} [props.searchPlaceholder]\n * @param {boolean} [props.searchInBar] la caja de búsqueda va arriba, en la barra de la app (BarActions): en escritorio,\n * como el buscador de una ventana de macOS; en el teléfono con cápsulas flota arriba con las demás; sin cápsulas se\n * queda aquí. Por omisión no\n * @param {boolean} [props.collapseSearchInBar] en la barra, sin usar se encoge a la lupa y se estira al picarla; por\n * omisión sí (false: siempre abierta)\n * @param {string} [props.emptyLabel]\n * @param {(total: number) => string} [props.countLabel] \"12 pedidos\"; por defecto \"12 registros\"\n * @param {number[]} [props.pageSizeOptions]\n * @param {number} [props.defaultPageSize]\n * @param {(row: any) => string|number} [props.getRowId]\n * @param {string} [props.prefix] estado en la URL con este prefijo (nuqs); sin él, en memoria\n * @param {unknown} [props.refreshToken] cambia para volver a consultar la misma página (después de una acción)\n * @param {(summary: {total: number, capped: boolean}) => import('react').ReactNode} [props.footer]\n * @param {import('react').ReactNode} [props.toolbarExtra] a la derecha del conteo (p. ej. el selector de año)\n * @param {(summary: {countText: string, total: number, capped: boolean}) => import('react').ReactNode} [props.header] reemplaza\n * el renglón del conteo: la página pinta título, conteo y controles en uno solo. countText ya viene traducido y con\n * el tope\n * @param {import('react').ReactNode} [props.beforeQuickFilters] arriba de los accesos rápidos (p. ej. las pestañas de producto)\n * @param {Array<object>} [props.columnGroupingModel] bandas que agrupan columnas bajo un nombre, arriba de sus\n * encabezados (columnGroupingModel del DataGrid). Con ellas el encabezado mide un renglón más\n * @param {(params: any) => string} [props.getRowClassName]\n * @param {(row: any) => boolean} [props.isRowVisible] cuáles renglones de la página se pintan; los demás se esconden\n * SIN volver a consultar (p. ej. plegar un grupo de renglones). Sin ella se pintan todos. OJO: va con useCallback;\n * una función nueva en cada pintada haría filtrar la página cada vez\n * @param {boolean} [props.striped] renglones alternos (cebra) con el color de hover del tema; al pasar el cursor se usa\n * el de «seleccionado» para que el renglón bajo el cursor se siga distinguiendo\n * @param {(params: any) => number|'auto'|null} [props.getRowHeight]\n * @param {boolean} [props.hideFooterWhenAllRowsFit] esconde el pie (el paginador) mientras todo lo que hay cabe en la\n * página; si un día no cabe, el pie vuelve solo. Para tablas que casi nunca pasan de una página\n * @param {boolean} [props.showGoToPage] «Ir a página N» junto al paginador; por omisión escondido (con las flechas basta en\n * casi todas las tablas). Para listas de muchas páginas que se recorren por número\n * @param {object} [props.gridSx] estilos extra del DataGrid (clases de renglón)\n * @param {number} [props.maxGridHeight] alto máximo del contenedor; sin él la tabla crece con sus renglones (default)\n * @param {string} [props.ariaLabel] nombre de la tabla para lectores de pantalla\n * @param {string} [props.fixedColumn] campo de la columna que se queda pegada a la izquierda al deslizar de lado (como\n * fixedSelectColumn de mui-datatables)\n * @param {Array<{key: string, label: string, icon?: import('react').ReactNode, color?: 'inherit'|'primary'|'secondary'|'error'|'info'|'success'|'warning', isDisabled?: (selection: RowSelection) => boolean, onClick: (selection: RowSelection, helpers: {clearSelection: () => void, refresh: () => void}) => unknown}>} [props.selectionActions]\n * con ellas cada renglón lleva su casilla y, al elegir, sale la barra de los elegidos con estas acciones. label ya\n * traducido; onClick recibe la selección (con isAllMatching mande `filters`, no `ids`) y cómo quitar la selección y volver\n * a consultar después de actuar\n * @param {(row: any) => boolean} [props.isRowSelectable] cuáles renglones se pueden elegir (un pedido entregado no se cancela)\n * @param {boolean} [props.allowSelectAllMatching] la casilla de arriba elige todos los que coinciden (la acción recibe los\n * filtros) y el aviso deja quedarse solo con la página; por omisión sí. false: la casilla elige la página y nunca se\n * ofrece «todos»\n * @param {(selection: RowSelection) => void} [props.onSelectionChange] cada que cambia la selección; también enciende las\n * casillas sin barra de acciones (la pantalla pinta las suyas)\n * @param {'top'|'split'} [props.selectionPhoneLayout] SELECTION_PHONE_LAYOUT: en el teléfono con vidrio o minimalista, todo\n * arriba (por omisión) o el conteo arriba y las acciones abajo. Sin vidrio, en el renglón como en escritorio\n * @param {(request: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}) => void} [props.onQueryChange]\n * cada que cambia lo que pide la tabla (un filtro, el orden, la página), antes de consultar: para la lógica de negocio que\n * depende de lo filtrado («si eligió Cancelados, enseñe el motivo»)\n * @param {(result: {rows: any[], total: number, facets: object, capped: boolean}) => void} [props.onLoaded] cada que llega una\n * página del servidor\n * @param {(error: unknown) => void} [props.onLoadError] cuando la consulta falla (la tabla ya enseña su aviso con «Reintentar»)\n * @param {object} [props.gridProps] lo demás del DataGrid de MUI, sobre todo sus eventos (onRowClick, onRowDoubleClick,\n * onCellKeyDown…). OJO: lo que la tabla controla (paginar, ordenar y filtrar en el servidor, el alto, la selección) no se\n * reemplaza desde aquí: para eso están sus props\n * @param {object} [props.texts] los textos de la tabla que cambian, con la forma de `table` en los textos del paquete\n * (src/locales/es.js), ya en el idioma de la pantalla: {selection: {clear: 'Deseleccionar'}, empty: {filtered: '…'}}.\n * También les llegan a sus filtros de columna, sus chips y su barra de elegidos\n */\nexport default function ServerTable(props) {\n // lo que el proyecto puso en su tema (components.CalcitaServerTable.defaultProps) y encima lo que llega aquí\n const {\n fetchPage,\n queryKey,\n enabled = true,\n columns,\n filterKinds = {},\n filterDefaults = {},\n chipConfig = [],\n quickFilters = [],\n searchField = 'contains',\n searchPlaceholder,\n searchInBar = false,\n collapseSearchInBar = true,\n emptyLabel,\n countLabel,\n pageSizeOptions = [10, 25, 50, 100],\n defaultPageSize = 25,\n getRowId,\n prefix,\n refreshToken,\n footer,\n toolbarExtra,\n header,\n beforeQuickFilters,\n columnGroupingModel,\n getRowClassName,\n isRowVisible,\n hideFooterWhenAllRowsFit = false,\n showGoToPage = false,\n striped = false,\n getRowHeight,\n gridSx,\n maxGridHeight = null,\n ariaLabel,\n fixedColumn,\n selectionActions = [],\n isRowSelectable,\n allowSelectAllMatching = true,\n onSelectionChange,\n selectionPhoneLayout = SELECTION_PHONE_LAYOUT.top,\n onQueryChange,\n onLoaded,\n onLoadError,\n gridProps,\n texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t, language} = useToolkitTranslation('table', texts);\n const {formatNumber} = useFormatters();\n const theme = useTheme();\n const tableState = useTableState({prefix, filterDefaults, filterKinds, defaultPageSize});\n const {filters, sortOrders, page, pageSize} = tableState;\n\n // la caja de búsqueda rebota: se escribe sin latencia y al servidor va una consulta cuando se deja de teclear\n const [searchDraft, setSearchDraft] = useDebouncedFilter(\n searchField ? filters[searchField] : '',\n (value) => searchField && tableState.setFilter(searchField, value),\n );\n\n // NOTA: fetchPage suele ser una función nueva en cada render; la máquina siempre llama a la más reciente\n const latestFetchPage = useRef(fetchPage);\n latestFetchPage.current = fetchPage;\n const latestEvents = useRef({onQueryChange, onLoaded, onLoadError});\n latestEvents.current = {onQueryChange, onLoaded, onLoadError};\n const [tableSnapshot, sendToTable] = useMachine(\n tableMachine.provide({actors: buildTableActors((params, signal) => latestFetchPage.current(params, signal))}),\n );\n const {rows, total, facets, capped, error} = tableSnapshot.context;\n // lo que se pinta: la página completa o, si la pantalla esconde renglones (un grupo plegado), solo los que deja ver.\n // Con memoria: un arreglo nuevo en cada pintada haría que el DataGrid volviera a procesar todos sus renglones\n const visibleRows = useMemo(() => (isRowVisible ? rows.filter(isRowVisible) : rows), [rows, isRowVisible]);\n const isLoading = tableSnapshot.matches('loading') || tableSnapshot.matches('idle');\n\n const requestParams = {filters, sortOrders, page, pageSize};\n const requestFingerprint = JSON.stringify({queryKey, enabled, refreshToken, ...requestParams});\n\n // IMPORTANTE: UN solo efecto dispara la consulta. Varios useEffect pidiendo lo mismo es como nacen las consultas\n // duplicadas\n useEffect(() => {\n if (!queryKey || !enabled) {\n return;\n }\n latestEvents.current.onQueryChange?.(requestParams);\n sendToTable({type: 'FETCH', params: requestParams});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [requestFingerprint]);\n\n // los eventos de la carga salen hacia afuera (la lógica de negocio que depende de lo que llegó). Con referencia a la\n // función más reciente: la pantalla suele pasar funciones nuevas en cada pintada\n const isReady = tableSnapshot.matches('ready');\n useEffect(() => {\n if (isReady) {\n latestEvents.current.onLoaded?.({rows, total, facets, capped});\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isReady, rows]);\n useEffect(() => {\n if (error) {\n latestEvents.current.onLoadError?.(error);\n }\n }, [error]);\n\n const toggleSort = (column) => {\n const currentSort = sortOrders.find((sortOrder) => sortOrder.column === column);\n if (!currentSort) {\n tableState.setSort([{column, direction: 'desc'}]);\n } else if (currentSort.direction === 'desc') {\n tableState.setSort([{column, direction: 'asc'}]);\n } else {\n // tercer clic: regresa al orden por defecto del servidor\n tableState.setSort([]);\n }\n };\n\n // ─── Renglones elegidos (rowSelection.js) ───\n // con acciones (o quien escuche los cambios) cada renglón lleva su casilla\n const isSelectable = selectionActions.length > 0 || Boolean(onSelectionChange);\n const [rowSelection, setRowSelection] = useState(EMPTY_ROW_SELECTION);\n const idOf = useCallback((row) => (getRowId ? getRowId(row) : row.id), [getRowId]);\n const pageRowsById = useMemo(() => new Map(visibleRows.map((row) => [idOf(row), row])), [visibleRows, idOf]);\n const selectablePageIds = useMemo(\n () => visibleRows.filter((row) => !isRowSelectable || isRowSelectable(row)).map(idOf),\n [visibleRows, isRowSelectable, idOf],\n );\n const checkedIds = useMemo(() => checkedIdsOf(rowSelection, selectablePageIds), [rowSelection, selectablePageIds]);\n const selection = rowSelectionOf(rowSelection, {total, capped, filters});\n\n const updateSelection = (nextSelection) => {\n setRowSelection(nextSelection);\n onSelectionChange?.(rowSelectionOf(nextSelection, {total, capped, filters}));\n };\n const clearSelection = () => updateSelection(EMPTY_ROW_SELECTION);\n\n // otro filtro u otro conjunto son otros renglones: la selección se borra para no actuar sobre lo que ya no se ve. Cambiar\n // de página o de orden la conserva\n const selectionResetKey = JSON.stringify({queryKey, filters});\n const lastSelectionResetKey = useRef(selectionResetKey);\n useEffect(() => {\n if (lastSelectionResetKey.current === selectionResetKey) {\n return;\n }\n lastSelectionResetKey.current = selectionResetKey;\n if (rowSelection !== EMPTY_ROW_SELECTION) {\n clearSelection();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectionResetKey]);\n\n // el DataGrid avisa qué quedó marcado; con disableRowSelectionExcludeModel siempre es la lista de los marcados\n const handleGridSelectionChange = (model) => {\n // la casilla de arriba elige todos los que coinciden (si se permite); el aviso deja quedarse con la página\n const nextSelection = selectionAfterCheck(rowSelection, model.ids, pageRowsById, selectablePageIds, {\n allMatchingOnWholePage: allowSelectAllMatching, total, capped,\n });\n if (nextSelection !== rowSelection) {\n updateSelection(nextSelection);\n }\n };\n\n const hasSelection = isSelectable && selection.count > 0;\n // en el teléfono con barra de pestañas abajo (vidrio, o minimalista con cápsulas) las acciones de los elegidos flotan\n // (SelectionActions decide dónde) y el conteo de la tabla se queda; sin esa barra, ocupan el lugar del conteo\n const floatsSelectionOnPhone = selectionFloatsOnPhone(theme);\n const selectionCountText = selection.isCapped\n ? t('selection.allMatchingCapped')\n : t('selection.count', {count: selection.count, total: formatNumber(selection.count)});\n // cada acción recibe la selección y cómo dejar la tabla al terminar; isDisabled se resuelve con la selección de ahora\n const selectionHelpers = {clearSelection, refresh: () => sendToTable({type: 'FETCH', params: requestParams})};\n const selectionActionItems = selectionActions.map(({key, label, icon, color, isDisabled, onClick}) => ({\n key, label, icon, color, disabled: isDisabled?.(selection) ?? false, onClick: () => onClick(selection, selectionHelpers),\n }));\n const offersAllMatching = isSelectable && allowSelectAllMatching && canSelectAllMatching(rowSelection, selectablePageIds, {total, capped});\n\n // el texto de la caja de búsqueda no cuenta como filtro oculto: se está viendo en su propia caja\n const hasActiveFilters = Object.entries(filters)\n .some(([field, value]) => field !== searchField && isFilterActive(filterKinds[field], value));\n\n // un acceso rápido está \"puesto\" cuando se aleja de su default; los que además tienen chip ya se cuentan ahí\n const quickActiveCount = quickFilters.filter((quickFilter) => !chipConfig.some((chipDeclaration) => chipDeclaration.key === quickFilter.field)\n && JSON.stringify(filters[quickFilter.field] ?? '') !== JSON.stringify(filterDefaults[quickFilter.field] ?? '')).length;\n\n const tableFilterValue = useMemo(() => ({\n filters,\n setFilter: tableState.setFilter,\n clearFilter: tableState.clearFilter,\n sortOrders,\n toggleSort,\n clearSort: () => tableState.setSort([]),\n facets,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [filters, sortOrders, facets]);\n\n // alto según lo que hay: una tabla de 3 organizaciones no deja 500 px en blanco. Sin renglones reservamos lugar para el\n // esqueleto de carga (hasta 8) o para el aviso de tabla vacía (3); con renglones, ni un pixel de hueco abajo\n let placeholderRowCount = 0;\n if (visibleRows.length === 0) {\n placeholderRowCount = isLoading ? Math.min(pageSize, 8) : 3;\n }\n // OJO: el alto se suma renglón por renglón con el alto que pide la pantalla (getRowHeight; p. ej. un renglón de\n // resumen más alto que los demás). Con un solo alto para todos, la tabla quedaba con hueco blanco o\n // con barra de desplazamiento sin necesidad\n let rowsHeight = placeholderRowCount * ROW_HEIGHT_PIXELS;\n for (const row of visibleRows) {\n const requestedRowHeight = getRowHeight?.({id: getRowId ? getRowId(row) : row.id, model: row, densityFactor: COMPACT_DENSITY_FACTOR});\n rowsHeight += typeof requestedRowHeight === 'number' ? requestedRowHeight : ROW_HEIGHT_PIXELS;\n }\n // la tabla crece con los renglones de la página y NO tiene scroll vertical propio (un solo scroll, el\n // de la página). La paginación del servidor ya acota cuántos renglones hay; maxGridHeight queda solo para quien\n // de verdad necesite un tope (un diálogo con altura fija)\n // con bandas el encabezado son dos renglones del mismo alto: el de las bandas y el de las columnas\n const headerHeight = columnGroupingModel ? 2 * COLUMN_HEADER_HEIGHT_PIXELS : COLUMN_HEADER_HEIGHT_PIXELS;\n // sin paginador que usar no hay pie: todo lo que hay ya está a la vista en la primera página\n const isFooterHidden = hideFooterWhenAllRowsFit && page === 0 && total <= pageSize;\n // el pie mide su alto más las líneas de borde; sin pie no hay ni lo uno ni lo otro\n const footerHeight = isFooterHidden ? 0 : FOOTER_HEIGHT_PIXELS + GRID_BORDER_PIXELS;\n const contentHeight = headerHeight + rowsHeight + footerHeight + HEIGHT_SLACK_PIXELS;\n const gridHeight = maxGridHeight ? Math.min(contentHeight, maxGridHeight) : contentHeight;\n\n const gridText = DATA_GRID_TEXT_BY_LANGUAGE[language] ?? DATA_GRID_TEXT_BY_LANGUAGE.es;\n const formattedTotal = formatNumber(total);\n const countText = countLabel ? countLabel(total) : t('count.records', {count: total, total: formattedTotal});\n\n const searchText = searchPlaceholder ?? t('search.placeholder');\n\n return (\n <ComponentTexts namespace=\"table\" texts={texts}>\n <TableFilterContext value={tableFilterValue}>\n <TableToolbar direction={{xs: 'column', md: 'row'}} spacing={2} ownSx={{mb: 1.5, alignItems: {md: 'center'}}}>\n {/* la búsqueda: aquí o arriba en la barra de la app (BarSearch: se encoge a la lupa sin usar) */}\n {searchField && (\n <BarSearch value={searchDraft} onChange={setSearchDraft} placeholder={searchText} inBar={searchInBar} collapsible={collapseSearchInBar} />\n )}\n {/* con elegidos, sus acciones ocupan el lugar del conteo (en el teléfono con barra de pestañas, flotan). Sus\n textos son los de la tabla: así el `texts` de ServerTable también los cambia */}\n {hasSelection && (\n <SelectionActions countText={selectionCountText} actions={selectionActionItems} onClear={clearSelection}\n phoneLayout={selectionPhoneLayout}\n texts={{selection: {clear: t('selection.clear'), actionsLabel: t('selection.actionsLabel'), summaryLabel: t('selection.summaryLabel')}}} />\n )}\n <TableSummary ownSx={{\n flexGrow: 1, minWidth: 0, display: 'flex',\n ...(hasSelection && {display: 'none', ...(floatsSelectionOnPhone && {[PHONE_MEDIA_QUERY]: {display: 'flex'}})}),\n }}>\n {header ? (\n <TableCustomHeader ownSx={{flexGrow: 1, minWidth: 0}}>\n {header({countText: capped ? t('count.capped', {total: formattedTotal}) : countText, total, capped})}\n </TableCustomHeader>\n ) : (\n // NOTA: el extra va pegado al conteo y no empujado a la orilla (ml: 'auto'): en escritorio quedaba a todo\n // el ancho de distancia y no se leía como parte de la misma tabla (caso del selector de año)\n <TableCount direction=\"row\" spacing={2} useFlexGap ownSx={{flexGrow: 1, alignItems: 'center', flexWrap: 'wrap'}}>\n <TableCountRow direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <Typography variant=\"body2\" color=\"text.secondary\" role=\"status\" aria-live=\"polite\">\n {capped ? t('count.capped', {total: formattedTotal}) : countText}\n </Typography>\n {capped && <Tag label={t('count.cappedTag')} color=\"warning\" tooltip={t('count.cappedTooltip')} />}\n </TableCountRow>\n {toolbarExtra}\n </TableCount>\n )}\n </TableSummary>\n </TableToolbar>\n\n {beforeQuickFilters}\n\n {quickFilters.map((quickFilter) => (\n <QuickFilterRow key={quickFilter.field} quickFilter={quickFilter} facets={facets} total={total} filters={filters}\n isMultiple={filterKinds[quickFilter.field] === FILTER_KINDS.multiSelect}\n setFilter={tableState.setFilter} setFilters={tableState.setFilters} />\n ))}\n\n <FilterChips chipConfig={chipConfig} filters={filters} quickActiveCount={quickActiveCount}\n onSetFilter={tableState.setFilter} onClearAll={tableState.clearAll} />\n\n {/* todos los que coinciden (lo elige la casilla de arriba): se puede volver a solo esta página; la página llena a\n mano: se ofrece elegir todos */}\n {(offersAllMatching || (isSelectable && rowSelection.isAllMatching)) && (\n <TableSelectionNotice severity=\"info\" icon={false} ownSx={{mb: 1, alignItems: 'center'}}\n action={rowSelection.isAllMatching ? (\n <Button color=\"inherit\" size=\"small\"\n onClick={() => updateSelection({\n rowsById: new Map(selectablePageIds.map((id) => [id, pageRowsById.get(id)])), isAllMatching: false,\n })}>\n {t('selection.onlyThisPage')}\n </Button>\n ) : (\n <Button color=\"inherit\" size=\"small\" onClick={() => updateSelection({rowsById: new Map(), isAllMatching: true})}>\n {capped ? t('selection.selectAllMatchingCapped') : t('selection.selectAllMatching', {total: formattedTotal})}\n </Button>\n )}>\n {rowSelection.isAllMatching\n ? (capped ? t('selection.allMatchingCapped') : t('selection.allMatching', {total: formattedTotal}))\n : t('selection.pageSelected', {count: selectablePageIds.length})}\n </TableSelectionNotice>\n )}\n\n {error && (\n <TableError severity=\"error\" role=\"alert\" ownSx={{mb: 1}}\n action={(\n <Button color=\"inherit\" size=\"small\" onClick={() => sendToTable({type: 'FETCH', params: requestParams})}>\n {t('common:actions.retry')}\n </Button>\n )}>\n {error.message ?? t('error.generic')}\n </TableError>\n )}\n\n {/* minWidth 0: dentro de un flex o grid el DataGrid no empuja la página; en el teléfono la tabla se desliza\n de lado DENTRO de su tarjeta y la página no */}\n <TableCard variant=\"outlined\" ownSx={{width: '100%', minWidth: 0, overflow: 'hidden'}}>\n <TableGrid\n // primero lo de la pantalla (sus eventos); lo de abajo es lo que la tabla controla y le gana\n {...gridProps}\n rows={visibleRows}\n columns={columns}\n columnGroupingModel={columnGroupingModel}\n getRowId={getRowId}\n getRowClassName={(params) => [\n getRowClassName?.(params),\n striped && params.indexRelativeToCurrentPage % 2 === 1 ? STRIPED_ROW_CLASS : '',\n ].filter(Boolean).join(' ')}\n getRowHeight={getRowHeight}\n aria-label={ariaLabel}\n nonce={readCspNonce()}\n loading={isLoading}\n // IMPORTANTE: paginación y orden del servidor; el DataGrid no reordena ni recorta nada solo\n paginationMode=\"server\"\n sortingMode=\"server\"\n filterMode=\"server\"\n rowCount={total}\n paginationModel={{page, pageSize}}\n onPaginationModelChange={(paginationModel) => {\n if (paginationModel.pageSize !== pageSize) {\n tableState.setPageSize(paginationModel.pageSize);\n } else {\n tableState.setPage(paginationModel.page);\n }\n }}\n pageSizeOptions={pageSizeOptions}\n hideFooter={isFooterHidden}\n disableColumnMenu\n disableRowSelectionOnClick\n // elegir renglones: solo con la casilla (el clic en el renglón no elige). Los elegidos de otras páginas\n // se conservan (keepNonExistentRowsSelected). OJO: sin disableRowSelectionExcludeModel la casilla de\n // arriba marca «todos los de todas las páginas» en lugar de los de esta página\n checkboxSelection={isSelectable}\n rowSelectionModel={isSelectable ? {type: 'include', ids: checkedIds} : undefined}\n onRowSelectionModelChange={isSelectable ? handleGridSelectionChange : undefined}\n isRowSelectable={isSelectable && isRowSelectable ? (params) => isRowSelectable(params.row) : undefined}\n keepNonExistentRowsSelected={isSelectable}\n disableRowSelectionExcludeModel\n // el conteo de los elegidos lo dice la barra de arriba; el del pie del DataGrid sobraría\n hideFooterSelectedRowCount\n // con columna fija se dibuja todo: si no, la fija desaparecería al deslizar a la derecha (fixedColumnSxOf)\n disableVirtualization={Boolean(fixedColumn)}\n density={DATA_GRID_DENSITY}\n localeText={{...gridText, noRowsLabel: emptyLabel ?? t('empty.default')}}\n slotProps={{\n // con filas ya pintadas, barra delgada arriba sin tapar lo que se lee; con la tabla vacía, esqueleto\n loadingOverlay: {variant: 'linear-progress', noRowsVariant: 'skeleton'},\n }}\n slots={{\n // \"ir a la página N\" (solo si se pide) pegado a la paginación: ahí lo busca quien ya está leyendo\n // \"51-75 de 1,234\". Sin él, la paginación de siempre del DataGrid\n ...(showGoToPage && {\n pagination: () => (\n <TablePagination direction=\"row\" spacing={1} ownSx={{alignItems: 'center'}}>\n <GoToPage page={page} pageCount={Math.ceil(total / pageSize) || 1} onChange={tableState.setPage} />\n <GridPagination />\n </TablePagination>\n ),\n }),\n noResultsOverlay: () => <EmptyState filtered label={emptyLabel} onClearFilters={tableState.clearAll} />,\n noRowsOverlay: () => <EmptyState filtered={hasActiveFilters} label={emptyLabel} onClearFilters={tableState.clearAll} />,\n }}\n ownSx={[{\n // IMPORTANTE: el alto va en la raíz del DataGrid y no en la caja de afuera: las variables\n // --DataGrid-hasScrollX y --DataGrid-scrollbarSize solo existen en la raíz. Cuando las columnas no\n // caben (historial a 390 px) la barra horizontal ocupa su alto dentro de la tabla y, sin sumarlo, los\n // renglones se desplazaban 13 px por dentro. Con barras superpuestas (teléfono, trackpad) mide 0\n height: `calc(${gridHeight}px + var(--DataGrid-hasScrollX, 0) * var(--DataGrid-scrollbarSize, 0px))`,\n border: 0,\n // todo centrado verticalmente: el texto suelto se pegaba arriba y los chips quedaban a media altura\n '& .MuiDataGrid-cell': {display: 'flex', alignItems: 'center'},\n '& .MuiDataGrid-columnHeader': {alignItems: 'center'},\n // cebra: el color del hover del tema\n [`& .${STRIPED_ROW_CLASS}`]: {bgcolor: 'action.hover'},\n [`& .${STRIPED_ROW_CLASS}:hover`]: {bgcolor: 'action.selected'},\n ...gridSx,\n }, (gridTheme) => (fixedColumn ? fixedColumnSxOf(gridTheme, fixedColumn, {withCheckboxColumn: isSelectable}) : {})]}\n />\n </TableCard>\n\n {footer?.({total, capped})}\n </TableFilterContext>\n </ComponentTexts>\n );\n}\n"],"names":["dataGridSpanish","dataGridEnglish"],"mappings":"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"}
@@ -10,6 +10,7 @@ import SortableFilterHeader from "./ColumnFilters/SortableFilterHeader.js";
10
10
  import TextColumnFilter from "./ColumnFilters/TextColumnFilter.js";
11
11
  import { useTableFilter } from "./filterContext.js";
12
12
  import { FILTER_KINDS, isFilterActive } from "./useTableState.js";
13
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
13
14
  function activeCountOf(kind, value) {
14
15
  if (!isFilterActive(kind, value)) {
15
16
  return 0;
@@ -95,7 +96,8 @@ function DetailCell({ row, onOpen, ariaLabelOf }) {
95
96
  const ariaLabel = ariaLabelOf?.(row) ?? t("detail.ariaLabel");
96
97
  return /* @__PURE__ */ jsx(Tooltip, { title: t("detail.tooltip"), children: /* @__PURE__ */ jsx(IconButton, { size: "small", "aria-label": ariaLabel, onClick: () => onOpen(row), children: /* @__PURE__ */ jsx(VisibilityOutlinedIcon, { fontSize: "small" }) }) });
97
98
  }
98
- function detailColumn({ onOpen, ariaLabelOf }) {
99
+ function detailColumn({ onOpen, ariaLabelOf, ...unknownOptions }) {
100
+ warnUnknownProps("detailColumn", unknownOptions);
99
101
  return {
100
102
  field: "__detail",
101
103
  headerName: "",
@@ -1 +1 @@
1
- {"version":3,"file":"columns.js","sources":["../../src/DataTable/columns.jsx"],"sourcesContent":["// Armadores de columna para ServerTable: la definición del DataGrid + su encabezado con orden y filtro.\n//\n// El filtro vive en el ENCABEZADO de su columna porque ahí está el dato. Aquí solo se COMPONE: el encabezado, el\n// globo y cada tipo de filtro viven en ColumnFilters/, uno por archivo.\n//\n// OJO: sortable y filterable del DataGrid van en false siempre. El orden y el filtro los pide la tabla al SERVIDOR;\n// los nativos del DataGrid ordenarían y filtrarían solo la página que ya llegó.\n//\n// Armadores genéricos: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {MultiSelectColumnFilter, SortableFilterHeader, TextColumnFilter} from '@/DataTable/ColumnFilters';\nimport {useTableFilter} from '@/DataTable/filterContext.js';\nimport {FILTER_KINDS, isFilterActive} from '@/DataTable/useTableState.js';\n\n/** Cuántos valores tiene puestos esta columna (lo que muestra el badge). */\nfunction activeCountOf(kind, value) {\n if (!isFilterActive(kind, value)) {\n return 0;\n }\n return kind === FILTER_KINDS.multiSelect ? value.length : 1;\n}\n\n/** Lo que todo encabezado necesita del contexto de la tabla. */\nfunction useColumnHeader(field, kind) {\n const {filters, setFilter, clearFilter, sortOrders, toggleSort, clearSort, facets} = useTableFilter();\n\n return {\n value: filters[field],\n setValue: (value) => setFilter(field, value),\n onClear: () => clearFilter(field),\n sortEntry: sortOrders.find((sortOrder) => sortOrder.column === field),\n onSort: () => toggleSort(field),\n onClearSort: clearSort,\n activeCount: activeCountOf(kind, filters[field]),\n facets,\n };\n}\n\nfunction TextHeader({field, label, sort, filter}) {\n const header = useColumnHeader(field, FILTER_KINDS.text);\n\n return (\n <SortableFilterHeader label={label} sortable={sort} filterable={filter} sortEntry={header.sortEntry}\n onSort={header.onSort} onClearSort={header.onClearSort} activeCount={header.activeCount}\n onClear={header.onClear}>\n <TextColumnFilter value={header.value ?? ''} onChange={header.setValue} />\n </SortableFilterHeader>\n );\n}\n\nfunction FacetHeader({field, label, facetKey, renderOption, sort}) {\n const header = useColumnHeader(field, FILTER_KINDS.multiSelect);\n\n return (\n <SortableFilterHeader label={label} sortable={sort} sortEntry={header.sortEntry} onSort={header.onSort}\n onClearSort={header.onClearSort} activeCount={header.activeCount} onClear={header.onClear}>\n <MultiSelectColumnFilter value={header.value ?? []} onChange={header.setValue}\n options={header.facets[facetKey] ?? []} renderOption={renderOption} />\n </SortableFilterHeader>\n );\n}\n\n/**\n * Las props de columna del DataGrid que más se usan, con su tipo, y cualquier otra suya (Record). OJO: tipo propio y no\n * GridColDef del DataGrid: apuntar a sus tipos hace que un proyecto estricto (skipLibCheck: false) revise los internos del\n * DataGrid, que no compilan con TypeScript 7.\n *\n * @typedef {{width?: number, minWidth?: number, maxWidth?: number, flex?: number, align?: 'left'|'center'|'right', headerAlign?: 'left'|'center'|'right', valueFormatter?: (value: any, row: any) => string, valueGetter?: (value: any, row: any) => any, renderCell?: (params: any) => import('react').ReactNode} & Record<string, any>} GridColumnProps\n */\n\n/**\n * Columna de texto con orden y filtro \"contiene\" en el servidor.\n *\n * @param {{field: string, label: string, sort?: boolean, filter?: boolean} & GridColumnProps} columnDeclaration\n * label ya traducido; lo demás son props de columna del DataGrid (width, flex, valueFormatter, renderCell…)\n */\nexport function textColumn({field, label, sort = true, filter = true, ...gridColumnProps}) {\n return {\n field,\n headerName: label,\n sortable: false,\n filterable: false,\n ...gridColumnProps,\n renderHeader: () => <TextHeader field={field} label={label} sort={sort} filter={filter} />,\n };\n}\n\n/**\n * Columna con filtro de opciones alimentado por las FACETAS del servidor.\n *\n * @param {{field: string, label: string, facetKey?: string, renderOption?: (value: string) => import('react').ReactNode, sort?: boolean} & GridColumnProps} columnDeclaration\n */\nexport function facetColumn({field, label, facetKey, renderOption, sort = true, ...gridColumnProps}) {\n return {\n field,\n headerName: label,\n sortable: false,\n filterable: false,\n ...gridColumnProps,\n renderHeader: () => (\n <FacetHeader field={field} label={label} facetKey={facetKey ?? field} renderOption={renderOption} sort={sort} />\n ),\n };\n}\n\nfunction DetailCell({row, onOpen, ariaLabelOf}) {\n const {t} = useToolkitTranslation('table');\n const ariaLabel = ariaLabelOf?.(row) ?? t('detail.ariaLabel');\n\n return (\n <Tooltip title={t('detail.tooltip')}>\n <IconButton size=\"small\" aria-label={ariaLabel} onClick={() => onOpen(row)}>\n <VisibilityOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n );\n}\n\n/**\n * Columna de acción al final de la fila: un icono que abre el detalle (la ruta propia del renglón). Un icono y no la\n * fila entera a propósito: la fila como botón se dispara al seleccionar texto y no se ve que se puede abrir.\n *\n * @param {{onOpen: (row: any) => void, ariaLabelOf?: (row: any) => string}} declaration ariaLabelOf ya traducido\n */\nexport function detailColumn({onOpen, ariaLabelOf}) {\n return {\n field: '__detail',\n headerName: '',\n sortable: false,\n filterable: false,\n disableColumnMenu: true,\n width: 64,\n align: 'center',\n renderCell: ({row}) => <DetailCell row={row} onOpen={onOpen} ariaLabelOf={ariaLabelOf} />,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"columns.js","sources":["../../src/DataTable/columns.jsx"],"sourcesContent":["// Armadores de columna para ServerTable: la definición del DataGrid + su encabezado con orden y filtro.\n//\n// El filtro vive en el ENCABEZADO de su columna porque ahí está el dato. Aquí solo se COMPONE: el encabezado, el\n// globo y cada tipo de filtro viven en ColumnFilters/, uno por archivo.\n//\n// OJO: sortable y filterable del DataGrid van en false siempre. El orden y el filtro los pide la tabla al SERVIDOR;\n// los nativos del DataGrid ordenarían y filtrarían solo la página que ya llegó.\n//\n// Armadores genéricos: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';\n\nimport {MultiSelectColumnFilter, SortableFilterHeader, TextColumnFilter} from '@/DataTable/ColumnFilters';\nimport {useTableFilter} from '@/DataTable/filterContext.js';\nimport {FILTER_KINDS, isFilterActive} from '@/DataTable/useTableState.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/** Cuántos valores tiene puestos esta columna (lo que muestra el badge). */\nfunction activeCountOf(kind, value) {\n if (!isFilterActive(kind, value)) {\n return 0;\n }\n return kind === FILTER_KINDS.multiSelect ? value.length : 1;\n}\n\n/** Lo que todo encabezado necesita del contexto de la tabla. */\nfunction useColumnHeader(field, kind) {\n const {filters, setFilter, clearFilter, sortOrders, toggleSort, clearSort, facets} = useTableFilter();\n\n return {\n value: filters[field],\n setValue: (value) => setFilter(field, value),\n onClear: () => clearFilter(field),\n sortEntry: sortOrders.find((sortOrder) => sortOrder.column === field),\n onSort: () => toggleSort(field),\n onClearSort: clearSort,\n activeCount: activeCountOf(kind, filters[field]),\n facets,\n };\n}\n\nfunction TextHeader({field, label, sort, filter}) {\n const header = useColumnHeader(field, FILTER_KINDS.text);\n\n return (\n <SortableFilterHeader label={label} sortable={sort} filterable={filter} sortEntry={header.sortEntry}\n onSort={header.onSort} onClearSort={header.onClearSort} activeCount={header.activeCount}\n onClear={header.onClear}>\n <TextColumnFilter value={header.value ?? ''} onChange={header.setValue} />\n </SortableFilterHeader>\n );\n}\n\nfunction FacetHeader({field, label, facetKey, renderOption, sort}) {\n const header = useColumnHeader(field, FILTER_KINDS.multiSelect);\n\n return (\n <SortableFilterHeader label={label} sortable={sort} sortEntry={header.sortEntry} onSort={header.onSort}\n onClearSort={header.onClearSort} activeCount={header.activeCount} onClear={header.onClear}>\n <MultiSelectColumnFilter value={header.value ?? []} onChange={header.setValue}\n options={header.facets[facetKey] ?? []} renderOption={renderOption} />\n </SortableFilterHeader>\n );\n}\n\n/**\n * Las props de columna del DataGrid que más se usan, con su tipo, y cualquier otra suya (Record). OJO: tipo propio y no\n * GridColDef del DataGrid: apuntar a sus tipos hace que un proyecto estricto (skipLibCheck: false) revise los internos del\n * DataGrid, que no compilan con TypeScript 7.\n *\n * @typedef {{width?: number, minWidth?: number, maxWidth?: number, flex?: number, align?: 'left'|'center'|'right', headerAlign?: 'left'|'center'|'right', valueFormatter?: (value: any, row: any) => string, valueGetter?: (value: any, row: any) => any, renderCell?: (params: any) => import('react').ReactNode} & Record<string, any>} GridColumnProps\n */\n\n/**\n * Columna de texto con orden y filtro \"contiene\" en el servidor.\n *\n * @param {{field: string, label: string, sort?: boolean, filter?: boolean} & GridColumnProps} columnDeclaration\n * label ya traducido; lo demás son props de columna del DataGrid (width, flex, valueFormatter, renderCell…)\n */\nexport function textColumn({field, label, sort = true, filter = true, ...gridColumnProps}) {\n return {\n field,\n headerName: label,\n sortable: false,\n filterable: false,\n ...gridColumnProps,\n renderHeader: () => <TextHeader field={field} label={label} sort={sort} filter={filter} />,\n };\n}\n\n/**\n * Columna con filtro de opciones alimentado por las FACETAS del servidor.\n *\n * @param {{field: string, label: string, facetKey?: string, renderOption?: (value: string) => import('react').ReactNode, sort?: boolean} & GridColumnProps} columnDeclaration\n */\nexport function facetColumn({field, label, facetKey, renderOption, sort = true, ...gridColumnProps}) {\n return {\n field,\n headerName: label,\n sortable: false,\n filterable: false,\n ...gridColumnProps,\n renderHeader: () => (\n <FacetHeader field={field} label={label} facetKey={facetKey ?? field} renderOption={renderOption} sort={sort} />\n ),\n };\n}\n\nfunction DetailCell({row, onOpen, ariaLabelOf}) {\n const {t} = useToolkitTranslation('table');\n const ariaLabel = ariaLabelOf?.(row) ?? t('detail.ariaLabel');\n\n return (\n <Tooltip title={t('detail.tooltip')}>\n <IconButton size=\"small\" aria-label={ariaLabel} onClick={() => onOpen(row)}>\n <VisibilityOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n );\n}\n\n/**\n * Columna de acción al final de la fila: un icono que abre el detalle (la ruta propia del renglón). Un icono y no la\n * fila entera a propósito: la fila como botón se dispara al seleccionar texto y no se ve que se puede abrir.\n *\n * El globo del icono se cambia con los textos de la tabla (ServerTable texts={{detail: {tooltip: '…'}}}), no aquí.\n *\n * @param {{onOpen: (row: any) => void, ariaLabelOf?: (row: any) => string}} declaration ariaLabelOf ya traducido\n */\nexport function detailColumn({onOpen, ariaLabelOf, ...unknownOptions}) {\n // un nombre que no existe (label, tooltip) se perdía sin decir nada: se avisa mientras se programa\n warnUnknownProps('detailColumn', unknownOptions);\n return {\n field: '__detail',\n headerName: '',\n sortable: false,\n filterable: false,\n disableColumnMenu: true,\n width: 64,\n align: 'center',\n renderCell: ({row}) => <DetailCell row={row} onOpen={onOpen} ariaLabelOf={ariaLabelOf} />,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
  import { useCan } from "./useCan.js";
3
- function Can({ access, children, fallback = null }) {
3
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
4
+ function Can({ access, children, fallback = null, ...unknownProps }) {
5
+ warnUnknownProps("Can", unknownProps);
4
6
  return useCan(access) ? children : fallback;
5
7
  }
6
8
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"Can.js","sources":["../../src/access/Can.jsx"],"sourcesContent":["// Pinta lo de adentro solo si la sesión puede (la misma regla del menú y las rutas):\n//\n// <Can access={{ability: 'orders.cancel'}}><Button>Cancelar pedido</Button></Can>\n//\n// Lo que no se puede, no se ve (fallback, si se quiere enseñar otra cosa). El backend vuelve a revisar cada petición.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCan} from '@/access/useCan.js';\n\n/**\n * @param {object} props\n * @param {object} props.access la regla (accessRules.js)\n * @param {import('react').ReactNode} props.children\n * @param {import('react').ReactNode} [props.fallback] lo que se pinta si no puede; por omisión nada\n */\nexport default function Can({access, children, fallback = null}) {\n return useCan(access) ? children : fallback;\n}\n"],"names":[],"mappings":";;AAeA,SAAwB,IAAI,EAAC,QAAQ,UAAU,WAAW,QAAO;AAC7D,SAAO,OAAO,MAAM,IAAI,WAAW;AACvC;"}
1
+ {"version":3,"file":"Can.js","sources":["../../src/access/Can.jsx"],"sourcesContent":["// Pinta lo de adentro solo si la sesión puede (la misma regla del menú y las rutas):\n//\n// <Can access={{ability: 'orders.cancel'}}><Button>Cancelar pedido</Button></Can>\n//\n// Lo que no se puede, no se ve (fallback, si se quiere enseñar otra cosa). El backend vuelve a revisar cada petición.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCan} from '@/access/useCan.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {object} props.access la regla (accessRules.js)\n * @param {import('react').ReactNode} props.children\n * @param {import('react').ReactNode} [props.fallback] lo que se pinta si no puede; por omisión nada\n */\nexport default function Can({access, children, fallback = null, ...unknownProps}) {\n warnUnknownProps('Can', unknownProps);\n return useCan(access) ? children : fallback;\n}\n"],"names":[],"mappings":";;;AAgBA,SAAwB,IAAI,EAAC,QAAQ,UAAU,WAAW,MAAM,GAAG,gBAAe;AAC9E,mBAAiB,OAAO,YAAY;AACpC,SAAO,OAAO,MAAM,IAAI,WAAW;AACvC;"}
@@ -12,6 +12,7 @@ import Typography from "@mui/material/Typography";
12
12
  import { groupStateOf, withPermissionGroup, withPermission } from "./permissionGroups.js";
13
13
  import ComponentTexts from "../toolkit/ComponentTexts.js";
14
14
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
15
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
15
16
  const THEME_NAME = "CalcitaPermissionMatrix";
16
17
  const PermissionsPermission = piecePart(THEME_NAME, "Permission", FormControlLabel);
17
18
  const PermissionsCheckbox = piecePart(THEME_NAME, "Checkbox", Checkbox);
@@ -83,7 +84,8 @@ function PermissionGroup({ group, value, onChange, isReadOnly }) {
83
84
  ] });
84
85
  }
85
86
  function PermissionMatrix(props) {
86
- const { groups, value, onChange, readOnly = false, texts } = usePieceProps(props, THEME_NAME);
87
+ const { groups, value, onChange, readOnly = false, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
88
+ warnUnknownProps(THEME_NAME, unknownProps);
87
89
  const isReadOnly = readOnly || !onChange;
88
90
  return /* @__PURE__ */ jsx(ComponentTexts, { namespace: "access", texts, children: /* @__PURE__ */ jsx(Stack, { spacing: 1.5, children: groups.map((group) => /* @__PURE__ */ jsx(PermissionGroup, { group, value, onChange, isReadOnly }, group.key)) }) });
89
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionMatrix.js","sources":["../../src/access/PermissionMatrix.jsx"],"sourcesContent":["// Los permisos de un perfil, agrupados (un grupo por módulo), para la pantalla de «Perfiles y permisos»: cada grupo con\n// su casilla de «todos» (a medias si tiene algunos) y cuántos tiene, y cada permiso con su nombre y, si hace falta, qué\n// deja hacer en palabras normales.\n//\n// <PermissionMatrix groups={PERMISSION_GROUPS} value={profile.abilities} onChange={setAbilities} />\n//\n// Los permisos son los mismos textos que piden los menu.js y las rutas (access: {ability: 'orders.view'}), así que lo que\n// se palomea aquí es lo que el menú enseña o esconde. La lista de grupos la arma el proyecto (RBAC propio); guardar es\n// cosa de la pantalla.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaPermissionMatrix con defaultProps y\n// styleOverrides de sus partes: permission, checkbox, group, groupHeader, groupTitle, grid.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: todo llega ya traducido.\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport Chip from '@mui/material/Chip';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {groupStateOf, withPermission, withPermissionGroup} from '@/access/permissionGroups.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaPermissionMatrix)\nconst THEME_NAME = 'CalcitaPermissionMatrix';\nconst PermissionsPermission = piecePart(THEME_NAME, 'Permission', FormControlLabel);\nconst PermissionsCheckbox = piecePart(THEME_NAME, 'Checkbox', Checkbox);\nconst PermissionsGroup = piecePart(THEME_NAME, 'Group', Paper);\nconst PermissionsGroupHeader = piecePart(THEME_NAME, 'GroupHeader', Stack);\nconst PermissionsGroupTitle = piecePart(THEME_NAME, 'GroupTitle', Typography);\nconst PermissionsGrid = piecePart(THEME_NAME, 'Grid', Box);\n\n/**\n * Un permiso: su casilla, su nombre y qué deja hacer.\n *\n * @param {{permission: {key: string, label: string, description?: string}, isGranted: boolean, readOnly: boolean, onToggle: (isGranted: boolean) => void}} props\n */\nfunction PermissionOption({permission, isGranted, readOnly, onToggle}) {\n return (\n <PermissionsPermission\n ownSx={{alignItems: 'flex-start', m: 0, gap: 0.5}}\n control={<PermissionsCheckbox size=\"small\" checked={isGranted} disabled={readOnly} onChange={(event) => onToggle(event.target.checked)}\n slotProps={{input: {'data-permission': permission.key}}} ownSx={{mt: -0.5}} />}\n label={(\n <Box>\n <Typography variant=\"body2\">{permission.label}</Typography>\n {permission.description && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\">{permission.description}</Typography>}\n </Box>\n )}\n />\n );\n}\n\n/**\n * Un grupo: su encabezado con «todos» y cuántos tiene, y sus permisos.\n *\n * OJO: es un grupo con role=\"group\" y no un <fieldset>: el navegador pinta el <legend> encima del borde y dejaba una franja\n * blanca arriba del encabezado.\n *\n * @param {{group: object, value: string[], onChange: Function, isReadOnly: boolean}} props\n */\nfunction PermissionGroup({group, value, onChange, isReadOnly}) {\n const {t} = useToolkitTranslation('access');\n const titleId = useId();\n const state = groupStateOf(group, value);\n return (\n <PermissionsGroup variant=\"outlined\" role=\"group\" aria-labelledby={titleId} data-group={group.key} ownSx={{overflow: 'hidden'}}>\n <PermissionsGroupHeader direction=\"row\" spacing={1} ownSx={{alignItems: 'center', px: 1.5, py: 0.75, borderBottom: 1, borderColor: 'divider', bgcolor: 'action.hover'}}>\n <Checkbox size=\"small\" checked={state.isAll} indeterminate={state.isSome} disabled={isReadOnly || state.total === 0}\n onChange={(event) => onChange(withPermissionGroup(value, group, event.target.checked))}\n slotProps={{input: {'aria-label': t('permissions.allOf', {group: group.label})}}} />\n <PermissionsGroupTitle id={titleId} variant=\"subtitle2\" component=\"h3\" ownSx={{flexGrow: 1}}>{group.label}</PermissionsGroupTitle>\n <Chip size=\"small\" label={t('permissions.countOf', {count: state.grantedCount, total: state.total})}\n color={state.grantedCount > 0 ? 'primary' : 'default'} variant={state.isAll ? 'filled' : 'outlined'} />\n </PermissionsGroupHeader>\n <PermissionsGrid ownSx={{display: 'grid', gridTemplateColumns: {xs: '1fr', md: 'repeat(2, minmax(0, 1fr))'}, gap: 1.5, p: 2}}>\n {group.permissions.map((permission) => (\n <PermissionOption key={permission.key} permission={permission} isGranted={value.includes(permission.key)} readOnly={isReadOnly}\n onToggle={(isGranted) => onChange(withPermission(value, permission.key, isGranted))} />\n ))}\n </PermissionsGrid>\n </PermissionsGroup>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{key: string, label: string, permissions: Array<{key: string, label: string, description?: string}>}>} props.groups\n * @param {string[]} props.value los permisos del perfil\n * @param {(value: string[]) => void} [props.onChange] sin ella, o con readOnly, solo se ven\n * @param {boolean} [props.readOnly] un perfil que no se puede cambiar (el de administración)\n * @param {object} [props.texts] los textos que cambian, con la forma de `access` en los textos del paquete\n */\nexport default function PermissionMatrix(props) {\n // lo que el proyecto puso en su tema (components.CalcitaPermissionMatrix.defaultProps) y encima lo que llega aquí\n const {groups, value, onChange, readOnly = false, texts} = usePieceProps(props, THEME_NAME);\n const isReadOnly = readOnly || !onChange;\n return (\n <ComponentTexts namespace=\"access\" texts={texts}>\n <Stack spacing={1.5}>\n {groups.map((group) => <PermissionGroup key={group.key} group={group} value={value} onChange={onChange} isReadOnly={isReadOnly} />)}\n </Stack>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PermissionMatrix.js","sources":["../../src/access/PermissionMatrix.jsx"],"sourcesContent":["// Los permisos de un perfil, agrupados (un grupo por módulo), para la pantalla de «Perfiles y permisos»: cada grupo con\n// su casilla de «todos» (a medias si tiene algunos) y cuántos tiene, y cada permiso con su nombre y, si hace falta, qué\n// deja hacer en palabras normales.\n//\n// <PermissionMatrix groups={PERMISSION_GROUPS} value={profile.abilities} onChange={setAbilities} />\n//\n// Los permisos son los mismos textos que piden los menu.js y las rutas (access: {ability: 'orders.view'}), así que lo que\n// se palomea aquí es lo que el menú enseña o esconde. La lista de grupos la arma el proyecto (RBAC propio); guardar es\n// cosa de la pantalla.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaPermissionMatrix con defaultProps y\n// styleOverrides de sus partes: permission, checkbox, group, groupHeader, groupTitle, grid.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: todo llega ya traducido.\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Checkbox from '@mui/material/Checkbox';\nimport Chip from '@mui/material/Chip';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {groupStateOf, withPermission, withPermissionGroup} from '@/access/permissionGroups.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaPermissionMatrix)\nconst THEME_NAME = 'CalcitaPermissionMatrix';\nconst PermissionsPermission = piecePart(THEME_NAME, 'Permission', FormControlLabel);\nconst PermissionsCheckbox = piecePart(THEME_NAME, 'Checkbox', Checkbox);\nconst PermissionsGroup = piecePart(THEME_NAME, 'Group', Paper);\nconst PermissionsGroupHeader = piecePart(THEME_NAME, 'GroupHeader', Stack);\nconst PermissionsGroupTitle = piecePart(THEME_NAME, 'GroupTitle', Typography);\nconst PermissionsGrid = piecePart(THEME_NAME, 'Grid', Box);\n\n/**\n * Un permiso: su casilla, su nombre y qué deja hacer.\n *\n * @param {{permission: {key: string, label: string, description?: string}, isGranted: boolean, readOnly: boolean, onToggle: (isGranted: boolean) => void}} props\n */\nfunction PermissionOption({permission, isGranted, readOnly, onToggle}) {\n return (\n <PermissionsPermission\n ownSx={{alignItems: 'flex-start', m: 0, gap: 0.5}}\n control={<PermissionsCheckbox size=\"small\" checked={isGranted} disabled={readOnly} onChange={(event) => onToggle(event.target.checked)}\n slotProps={{input: {'data-permission': permission.key}}} ownSx={{mt: -0.5}} />}\n label={(\n <Box>\n <Typography variant=\"body2\">{permission.label}</Typography>\n {permission.description && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\">{permission.description}</Typography>}\n </Box>\n )}\n />\n );\n}\n\n/**\n * Un grupo: su encabezado con «todos» y cuántos tiene, y sus permisos.\n *\n * OJO: es un grupo con role=\"group\" y no un <fieldset>: el navegador pinta el <legend> encima del borde y dejaba una franja\n * blanca arriba del encabezado.\n *\n * @param {{group: object, value: string[], onChange: Function, isReadOnly: boolean}} props\n */\nfunction PermissionGroup({group, value, onChange, isReadOnly}) {\n const {t} = useToolkitTranslation('access');\n const titleId = useId();\n const state = groupStateOf(group, value);\n return (\n <PermissionsGroup variant=\"outlined\" role=\"group\" aria-labelledby={titleId} data-group={group.key} ownSx={{overflow: 'hidden'}}>\n <PermissionsGroupHeader direction=\"row\" spacing={1} ownSx={{alignItems: 'center', px: 1.5, py: 0.75, borderBottom: 1, borderColor: 'divider', bgcolor: 'action.hover'}}>\n <Checkbox size=\"small\" checked={state.isAll} indeterminate={state.isSome} disabled={isReadOnly || state.total === 0}\n onChange={(event) => onChange(withPermissionGroup(value, group, event.target.checked))}\n slotProps={{input: {'aria-label': t('permissions.allOf', {group: group.label})}}} />\n <PermissionsGroupTitle id={titleId} variant=\"subtitle2\" component=\"h3\" ownSx={{flexGrow: 1}}>{group.label}</PermissionsGroupTitle>\n <Chip size=\"small\" label={t('permissions.countOf', {count: state.grantedCount, total: state.total})}\n color={state.grantedCount > 0 ? 'primary' : 'default'} variant={state.isAll ? 'filled' : 'outlined'} />\n </PermissionsGroupHeader>\n <PermissionsGrid ownSx={{display: 'grid', gridTemplateColumns: {xs: '1fr', md: 'repeat(2, minmax(0, 1fr))'}, gap: 1.5, p: 2}}>\n {group.permissions.map((permission) => (\n <PermissionOption key={permission.key} permission={permission} isGranted={value.includes(permission.key)} readOnly={isReadOnly}\n onToggle={(isGranted) => onChange(withPermission(value, permission.key, isGranted))} />\n ))}\n </PermissionsGrid>\n </PermissionsGroup>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{key: string, label: string, permissions: Array<{key: string, label: string, description?: string}>}>} props.groups\n * @param {string[]} props.value los permisos del perfil\n * @param {(value: string[]) => void} [props.onChange] sin ella, o con readOnly, solo se ven\n * @param {boolean} [props.readOnly] un perfil que no se puede cambiar (el de administración)\n * @param {object} [props.texts] los textos que cambian, con la forma de `access` en los textos del paquete\n */\nexport default function PermissionMatrix(props) {\n // lo que el proyecto puso en su tema (components.CalcitaPermissionMatrix.defaultProps) y encima lo que llega aquí\n const {groups, value, onChange, readOnly = false, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const isReadOnly = readOnly || !onChange;\n return (\n <ComponentTexts namespace=\"access\" texts={texts}>\n <Stack spacing={1.5}>\n {groups.map((group) => <PermissionGroup key={group.key} group={group} value={value} onChange={onChange} isReadOnly={isReadOnly} />)}\n </Stack>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -2,7 +2,9 @@
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useCan } from "./useCan.js";
4
4
  import ErrorPage, { ERROR_PAGE_KIND } from "../ui/layout/ErrorPage.js";
5
- function RequireAccess({ access, children, fallback }) {
5
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
6
+ function RequireAccess({ access, children, fallback, ...unknownProps }) {
7
+ warnUnknownProps("RequireAccess", unknownProps);
6
8
  if (useCan(access)) {
7
9
  return children;
8
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RequireAccess.js","sources":["../../src/access/RequireAccess.jsx"],"sourcesContent":["// Una pantalla (o un grupo de pantallas) que solo se ve con permiso, con la misma regla de su menu.js: quien no puede ve\n// la página de «sin permiso» (403) en lugar de una pantalla vacía que truena al pedir sus datos.\n//\n// <RequireAccess access={{ability: 'users.admin'}}><UsersPage /></RequireAccess>\n//\n// Con react-router, withAccess (@stackcraftmx/calcita/react-router) envuelve un grupo de rutas con esto.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCan} from '@/access/useCan.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\n\n/**\n * @param {object} props\n * @param {object} [props.access] la regla (accessRules.js); sin ella se ve\n * @param {import('react').ReactNode} props.children\n * @param {import('react').ReactNode} [props.fallback] lo que se ve sin permiso; por omisión la página de 403\n */\nexport default function RequireAccess({access, children, fallback}) {\n if (useCan(access)) {\n return children;\n }\n return fallback ?? <ErrorPage kind={ERROR_PAGE_KIND.forbidden} />;\n}\n"],"names":[],"mappings":";;;;AAiBA,SAAwB,cAAc,EAAC,QAAQ,UAAU,YAAW;AAChE,MAAI,OAAO,MAAM,GAAG;AAChB,WAAO;AAAA,EACX;AACA,SAAO,YAAY,oBAAC,WAAA,EAAU,MAAM,gBAAgB,WAAW;AACnE;"}
1
+ {"version":3,"file":"RequireAccess.js","sources":["../../src/access/RequireAccess.jsx"],"sourcesContent":["// Una pantalla (o un grupo de pantallas) que solo se ve con permiso, con la misma regla de su menu.js: quien no puede ve\n// la página de «sin permiso» (403) en lugar de una pantalla vacía que truena al pedir sus datos.\n//\n// <RequireAccess access={{ability: 'users.admin'}}><UsersPage /></RequireAccess>\n//\n// Con react-router, withAccess (@stackcraftmx/calcita/react-router) envuelve un grupo de rutas con esto.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCan} from '@/access/useCan.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {object} [props.access] la regla (accessRules.js); sin ella se ve\n * @param {import('react').ReactNode} props.children\n * @param {import('react').ReactNode} [props.fallback] lo que se ve sin permiso; por omisión la página de 403\n */\nexport default function RequireAccess({access, children, fallback, ...unknownProps}) {\n warnUnknownProps('RequireAccess', unknownProps);\n if (useCan(access)) {\n return children;\n }\n return fallback ?? <ErrorPage kind={ERROR_PAGE_KIND.forbidden} />;\n}\n"],"names":[],"mappings":";;;;;AAkBA,SAAwB,cAAc,EAAC,QAAQ,UAAU,UAAU,GAAG,gBAAe;AACjF,mBAAiB,iBAAiB,YAAY;AAC9C,MAAI,OAAO,MAAM,GAAG;AAChB,WAAO;AAAA,EACX;AACA,SAAO,YAAY,oBAAC,WAAA,EAAU,MAAM,gBAAgB,WAAW;AACnE;"}
@@ -5,9 +5,11 @@ import { missingConnectorFunctionsOf } from "./accountConnector.js";
5
5
  import { createAccessChecker } from "../access/accessRules.js";
6
6
  import ErrorPage, { ERROR_PAGE_KIND } from "../ui/layout/ErrorPage.js";
7
7
  import FullPageLoader from "../ui/layout/FullPageLoader.js";
8
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
8
9
  const AccountContext = createContext(null);
9
10
  const NOT_LOADED = void 0;
10
- function AccountProvider({ connector, refreshKey, initialSession = NOT_LOADED, children }) {
11
+ function AccountProvider({ connector, refreshKey, initialSession = NOT_LOADED, children, ...unknownProps }) {
12
+ warnUnknownProps("AccountProvider", unknownProps);
11
13
  const missingFunctions = missingConnectorFunctionsOf(connector);
12
14
  if (missingFunctions.length > 0) {
13
15
  throw new Error(`Al conector de la cuenta le faltan estas funciones: ${missingFunctions.join(", ")}`);
@@ -1 +1 @@
1
- {"version":3,"file":"AccountProvider.js","sources":["../../src/account/AccountProvider.jsx"],"sourcesContent":["// La cuenta al alcance de toda la app: carga la sesión al abrir (connector.loadSession) y la reparte. Las pantallas de la\n// cuenta y la barra la leen con useAccount; el menú, las rutas y los botones preguntan sus permisos con la regla que sale de\n// aquí (createAccessChecker), que se le pasa a ToolkitProvider:\n//\n// <AccountProvider connector={accountConnector}>\n// {(canAccess) => <ToolkitProvider canAccess={canAccess} …>…</ToolkitProvider>}\n// </AccountProvider>\n//\n// Mientras llega la primera respuesta se ve la pantalla de carga (sin ella, el menú se pintaría vacío un instante); si el\n// servidor no contesta, la página de error con «Intentar de nuevo», no la de entrar (no es que no haya sesión).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';\n\nimport {missingConnectorFunctionsOf} from '@/account/accountConnector.js';\nimport {createAccessChecker} from '@/access/accessRules.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\nimport FullPageLoader from '@/ui/layout/FullPageLoader.jsx';\n\nconst AccountContext = createContext(null);\n// lo que se sabe antes de la primera respuesta: ni dentro ni fuera\nconst NOT_LOADED = undefined;\n\n/**\n * @param {object} props\n * @param {import('@/account/accountConnector.js').AccountConnector} props.connector las llamadas al backend\n * @param {unknown} [props.refreshKey] al cambiar, la sesión se vuelve a leer (p. ej. el idioma, si el backend manda los\n * nombres de los perfiles traducidos)\n * @param {import('@/account/accountConnector.js').AccountSession|null} [props.initialSession] la sesión que ya se conoce\n * (p. ej. la que leyó el servidor al pintar): se usa sin esperar la primera respuesta\n * @param {(canAccess: (access: object|null|undefined) => boolean) => import('react').ReactNode} props.children recibe la\n * regla de permisos de la sesión\n */\nexport default function AccountProvider({connector, refreshKey, initialSession = NOT_LOADED, children}) {\n // guard clause: un conector incompleto es un error de quien lo escribió; se avisa al arrancar y no al picar un botón\n const missingFunctions = missingConnectorFunctionsOf(connector);\n if (missingFunctions.length > 0) {\n throw new Error(`Al conector de la cuenta le faltan estas funciones: ${missingFunctions.join(', ')}`);\n }\n\n const [session, setSession] = useState(initialSession);\n const [loadError, setLoadError] = useState(null);\n\n const refreshSession = useCallback(async () => {\n try {\n setSession(await connector.loadSession());\n setLoadError(null);\n } catch (error) {\n setLoadError(error);\n }\n }, [connector]);\n\n const signOut = useCallback(async () => {\n await connector.signOut();\n setSession(null);\n }, [connector]);\n\n // con la sesión ya conocida no se pide al abrir; sí cuando cambia refreshKey\n const skipsFirstLoad = useRef(initialSession !== NOT_LOADED);\n useEffect(() => {\n if (skipsFirstLoad.current) {\n skipsFirstLoad.current = false;\n return;\n }\n refreshSession();\n }, [refreshSession, refreshKey]);\n\n const canAccess = useMemo(() => createAccessChecker({abilities: session?.abilities ?? [], roles: session?.roles ?? []}), [session]);\n const value = useMemo(() => ({connector, session: session ?? null, refreshSession, signOut}), [connector, session, refreshSession, signOut]);\n\n if (loadError && session === NOT_LOADED) {\n return <ErrorPage kind={ERROR_PAGE_KIND.serverError} text={loadError.message} onRetry={refreshSession} />;\n }\n if (session === NOT_LOADED) {\n return <FullPageLoader />;\n }\n return <AccountContext.Provider value={value}>{children(canAccess)}</AccountContext.Provider>;\n}\n\n/**\n * La cuenta: {session, refreshSession, signOut, connector}. session es null si nadie está dentro.\n *\n * @returns {{session: import('@/account/accountConnector.js').AccountSession|null, refreshSession: () => Promise<void>, signOut: () => Promise<void>, connector: import('@/account/accountConnector.js').AccountConnector}}\n */\nexport function useAccount() {\n const account = useContext(AccountContext);\n if (!account) {\n throw new Error('useAccount necesita estar dentro de <AccountProvider>');\n }\n return account;\n}\n"],"names":[],"mappings":";;;;;;;AAmBA,MAAM,iBAAiB,cAAc,IAAI;AAEzC,MAAM,aAAa;AAYnB,SAAwB,gBAAgB,EAAC,WAAW,YAAY,iBAAiB,YAAY,YAAW;AAEpG,QAAM,mBAAmB,4BAA4B,SAAS;AAC9D,MAAI,iBAAiB,SAAS,GAAG;AAC7B,UAAM,IAAI,MAAM,uDAAuD,iBAAiB,KAAK,IAAI,CAAC,EAAE;AAAA,EACxG;AAEA,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,cAAc;AACrD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAE/C,QAAM,iBAAiB,YAAY,YAAY;AAC3C,QAAI;AACA,iBAAW,MAAM,UAAU,aAAa;AACxC,mBAAa,IAAI;AAAA,IACrB,SAAS,OAAO;AACZ,mBAAa,KAAK;AAAA,IACtB;AAAA,EACJ,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,UAAU,YAAY,YAAY;AACpC,UAAM,UAAU,QAAA;AAChB,eAAW,IAAI;AAAA,EACnB,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,iBAAiB,OAAO,mBAAmB,UAAU;AAC3D,YAAU,MAAM;AACZ,QAAI,eAAe,SAAS;AACxB,qBAAe,UAAU;AACzB;AAAA,IACJ;AACA,mBAAA;AAAA,EACJ,GAAG,CAAC,gBAAgB,UAAU,CAAC;AAE/B,QAAM,YAAY,QAAQ,MAAM,oBAAoB,EAAC,WAAW,SAAS,aAAa,CAAA,GAAI,OAAO,SAAS,SAAS,CAAA,EAAC,CAAE,GAAG,CAAC,OAAO,CAAC;AAClI,QAAM,QAAQ,QAAQ,OAAO,EAAC,WAAW,SAAS,WAAW,MAAM,gBAAgB,QAAA,IAAW,CAAC,WAAW,SAAS,gBAAgB,OAAO,CAAC;AAE3I,MAAI,aAAa,YAAY,YAAY;AACrC,WAAO,oBAAC,aAAU,MAAM,gBAAgB,aAAa,MAAM,UAAU,SAAS,SAAS,eAAA,CAAgB;AAAA,EAC3G;AACA,MAAI,YAAY,YAAY;AACxB,+BAAQ,gBAAA,EAAe;AAAA,EAC3B;AACA,6BAAQ,eAAe,UAAf,EAAwB,OAAe,UAAA,SAAS,SAAS,GAAE;AACvE;AAOO,SAAS,aAAa;AACzB,QAAM,UAAU,WAAW,cAAc;AACzC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,uDAAuD;AAAA,EAC3E;AACA,SAAO;AACX;"}
1
+ {"version":3,"file":"AccountProvider.js","sources":["../../src/account/AccountProvider.jsx"],"sourcesContent":["// La cuenta al alcance de toda la app: carga la sesión al abrir (connector.loadSession) y la reparte. Las pantallas de la\n// cuenta y la barra la leen con useAccount; el menú, las rutas y los botones preguntan sus permisos con la regla que sale de\n// aquí (createAccessChecker), que se le pasa a ToolkitProvider:\n//\n// <AccountProvider connector={accountConnector}>\n// {(canAccess) => <ToolkitProvider canAccess={canAccess} …>…</ToolkitProvider>}\n// </AccountProvider>\n//\n// Mientras llega la primera respuesta se ve la pantalla de carga (sin ella, el menú se pintaría vacío un instante); si el\n// servidor no contesta, la página de error con «Intentar de nuevo», no la de entrar (no es que no haya sesión).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';\n\nimport {missingConnectorFunctionsOf} from '@/account/accountConnector.js';\nimport {createAccessChecker} from '@/access/accessRules.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\nimport FullPageLoader from '@/ui/layout/FullPageLoader.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\nconst AccountContext = createContext(null);\n// lo que se sabe antes de la primera respuesta: ni dentro ni fuera\nconst NOT_LOADED = undefined;\n\n/**\n * @param {object} props\n * @param {import('@/account/accountConnector.js').AccountConnector} props.connector las llamadas al backend\n * @param {unknown} [props.refreshKey] al cambiar, la sesión se vuelve a leer (p. ej. el idioma, si el backend manda los\n * nombres de los perfiles traducidos)\n * @param {import('@/account/accountConnector.js').AccountSession|null} [props.initialSession] la sesión que ya se conoce\n * (p. ej. la que leyó el servidor al pintar): se usa sin esperar la primera respuesta\n * @param {(canAccess: (access: object|null|undefined) => boolean) => import('react').ReactNode} props.children recibe la\n * regla de permisos de la sesión\n */\nexport default function AccountProvider({connector, refreshKey, initialSession = NOT_LOADED, children, ...unknownProps}) {\n warnUnknownProps('AccountProvider', unknownProps);\n // guard clause: un conector incompleto es un error de quien lo escribió; se avisa al arrancar y no al picar un botón\n const missingFunctions = missingConnectorFunctionsOf(connector);\n if (missingFunctions.length > 0) {\n throw new Error(`Al conector de la cuenta le faltan estas funciones: ${missingFunctions.join(', ')}`);\n }\n\n const [session, setSession] = useState(initialSession);\n const [loadError, setLoadError] = useState(null);\n\n const refreshSession = useCallback(async () => {\n try {\n setSession(await connector.loadSession());\n setLoadError(null);\n } catch (error) {\n setLoadError(error);\n }\n }, [connector]);\n\n const signOut = useCallback(async () => {\n await connector.signOut();\n setSession(null);\n }, [connector]);\n\n // con la sesión ya conocida no se pide al abrir; sí cuando cambia refreshKey\n const skipsFirstLoad = useRef(initialSession !== NOT_LOADED);\n useEffect(() => {\n if (skipsFirstLoad.current) {\n skipsFirstLoad.current = false;\n return;\n }\n refreshSession();\n }, [refreshSession, refreshKey]);\n\n const canAccess = useMemo(() => createAccessChecker({abilities: session?.abilities ?? [], roles: session?.roles ?? []}), [session]);\n const value = useMemo(() => ({connector, session: session ?? null, refreshSession, signOut}), [connector, session, refreshSession, signOut]);\n\n if (loadError && session === NOT_LOADED) {\n return <ErrorPage kind={ERROR_PAGE_KIND.serverError} text={loadError.message} onRetry={refreshSession} />;\n }\n if (session === NOT_LOADED) {\n return <FullPageLoader />;\n }\n return <AccountContext.Provider value={value}>{children(canAccess)}</AccountContext.Provider>;\n}\n\n/**\n * La cuenta: {session, refreshSession, signOut, connector}. session es null si nadie está dentro.\n *\n * @returns {{session: import('@/account/accountConnector.js').AccountSession|null, refreshSession: () => Promise<void>, signOut: () => Promise<void>, connector: import('@/account/accountConnector.js').AccountConnector}}\n */\nexport function useAccount() {\n const account = useContext(AccountContext);\n if (!account) {\n throw new Error('useAccount necesita estar dentro de <AccountProvider>');\n }\n return account;\n}\n"],"names":[],"mappings":";;;;;;;;AAoBA,MAAM,iBAAiB,cAAc,IAAI;AAEzC,MAAM,aAAa;AAYnB,SAAwB,gBAAgB,EAAC,WAAW,YAAY,iBAAiB,YAAY,UAAU,GAAG,gBAAe;AACrH,mBAAiB,mBAAmB,YAAY;AAEhD,QAAM,mBAAmB,4BAA4B,SAAS;AAC9D,MAAI,iBAAiB,SAAS,GAAG;AAC7B,UAAM,IAAI,MAAM,uDAAuD,iBAAiB,KAAK,IAAI,CAAC,EAAE;AAAA,EACxG;AAEA,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,cAAc;AACrD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAE/C,QAAM,iBAAiB,YAAY,YAAY;AAC3C,QAAI;AACA,iBAAW,MAAM,UAAU,aAAa;AACxC,mBAAa,IAAI;AAAA,IACrB,SAAS,OAAO;AACZ,mBAAa,KAAK;AAAA,IACtB;AAAA,EACJ,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,UAAU,YAAY,YAAY;AACpC,UAAM,UAAU,QAAA;AAChB,eAAW,IAAI;AAAA,EACnB,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,iBAAiB,OAAO,mBAAmB,UAAU;AAC3D,YAAU,MAAM;AACZ,QAAI,eAAe,SAAS;AACxB,qBAAe,UAAU;AACzB;AAAA,IACJ;AACA,mBAAA;AAAA,EACJ,GAAG,CAAC,gBAAgB,UAAU,CAAC;AAE/B,QAAM,YAAY,QAAQ,MAAM,oBAAoB,EAAC,WAAW,SAAS,aAAa,CAAA,GAAI,OAAO,SAAS,SAAS,CAAA,EAAC,CAAE,GAAG,CAAC,OAAO,CAAC;AAClI,QAAM,QAAQ,QAAQ,OAAO,EAAC,WAAW,SAAS,WAAW,MAAM,gBAAgB,QAAA,IAAW,CAAC,WAAW,SAAS,gBAAgB,OAAO,CAAC;AAE3I,MAAI,aAAa,YAAY,YAAY;AACrC,WAAO,oBAAC,aAAU,MAAM,gBAAgB,aAAa,MAAM,UAAU,SAAS,SAAS,eAAA,CAAgB;AAAA,EAC3G;AACA,MAAI,YAAY,YAAY;AACxB,+BAAQ,gBAAA,EAAe;AAAA,EAC3B;AACA,6BAAQ,eAAe,UAAf,EAAwB,OAAe,UAAA,SAAS,SAAS,GAAE;AACvE;AAOO,SAAS,aAAa;AACzB,QAAM,UAAU,WAAW,cAAc;AACzC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,uDAAuD;AAAA,EAC3E;AACA,SAAO;AACX;"}
@@ -15,13 +15,15 @@ import SessionsCard from "../security/SessionsCard.js";
15
15
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
16
16
  import SectionCard from "../ui/layout/SectionCard.js";
17
17
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
18
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
18
19
  const THEME_NAME = "CalcitaAccountSecurity";
19
20
  const SecurityTitle = piecePart(THEME_NAME, "Title", Typography);
20
21
  const SecurityForm = piecePart(THEME_NAME, "Form", Stack);
21
22
  const FORM_MAX_WIDTH = 520;
22
23
  const LOADING_HEIGHT_PIXELS = 220;
23
24
  function AccountSecuritySection(props) {
24
- const { showPasswordChange = true, texts } = usePieceProps(props, THEME_NAME);
25
+ const { showPasswordChange = true, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
26
+ warnUnknownProps(THEME_NAME, unknownProps);
25
27
  const { t } = useToolkitTranslation("account", texts);
26
28
  const { connector, session } = useAccount();
27
29
  const [security, setSecurity] = useState(null);
@@ -1 +1 @@
1
- {"version":3,"file":"AccountSecuritySection.js","sources":["../../src/account/AccountSecuritySection.jsx"],"sourcesContent":["// La seguridad de la cuenta, completa: cambiar la contraseña (ChangePasswordForm), la verificación en dos pasos\n// (TwoStepVerificationCard: llaves de acceso, app autenticadora y códigos de recuperación), las sesiones abiertas\n// (SessionsCard) y la bitácora (ActivityLog). Todo lo del servidor sale del conector de la cuenta.\n//\n// Las llaves de acceso se crean aquí con el navegador (createPasskey) y la respuesta va al servidor (savePasskey). La\n// bitácora se vuelve a pedir después de cada cambio: así se ve aparecer lo que se acaba de hacer.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountSecurity con defaultProps y\n// styleOverrides de sus partes: title, form.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCallback, useEffect, useMemo, useState} from 'react';\nimport Alert from '@mui/material/Alert';\nimport Skeleton from '@mui/material/Skeleton';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport ChangePasswordForm from '@/forms/auth/ChangePasswordForm.jsx';\nimport TwoStepVerificationCard from '@/forms/security/TwoStepVerificationCard.jsx';\nimport ActivityLog from '@/security/ActivityLog.jsx';\nimport {createPasskey, passkeysSupported} from '@/security/passkeys.js';\nimport SessionsCard from '@/security/SessionsCard.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountSecurity)\nconst THEME_NAME = 'CalcitaAccountSecurity';\nconst SecurityTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst SecurityForm = piecePart(THEME_NAME, 'Form', Stack);\n\n// lo ancho del formulario de la contraseña: un renglón cómodo\nconst FORM_MAX_WIDTH = 520;\nconst LOADING_HEIGHT_PIXELS = 220;\n\n/**\n * @param {object} props\n * @param {boolean} [props.showPasswordChange] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete\n */\nexport default function AccountSecuritySection(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountSecurity.defaultProps) y encima lo que llega aquí\n const {showPasswordChange = true, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session} = useAccount();\n const [security, setSecurity] = useState(null);\n const [sessions, setSessions] = useState(null);\n const [events, setEvents] = useState(null);\n const [loadError, setLoadError] = useState(null);\n const isDemo = typeof connector.demoTotpCode === 'function';\n\n const refreshActivity = useCallback(() => connector.listActivity().then(setEvents).catch((error) => setLoadError(error.message)), [connector]);\n const refreshSessions = useCallback(() => connector.listSessions().then(setSessions).catch((error) => setLoadError(error.message)), [connector]);\n\n useEffect(() => {\n connector.loadSecurity().then(setSecurity).catch((error) => setLoadError(error.message));\n refreshSessions();\n refreshActivity();\n }, [connector, refreshActivity, refreshSessions]);\n\n // lo que hace la tarjeta de dos pasos en cada caso, con el conector\n const actions = useMemo(() => ({\n addPasskey: async (name) => connector.savePasskey({name, credential: await createPasskey(await connector.passkeyRegistrationOptions())}),\n removePasskey: (passkey, password) => connector.removePasskey({passkeyId: passkey.id, password}),\n startTotp: async () => ({\n ...await connector.startTotp(),\n // en la demostración, el atajo del código abajo del campo\n extra: isDemo ? <DemoTotpCodeButton loadCode={connector.demoTotpCode} /> : undefined,\n }),\n confirmTotp: (code) => connector.confirmTotp(code),\n disableTotp: (password) => connector.disableTotp(password),\n regenerateRecoveryCodes: (password) => connector.regenerateRecoveryCodes(password),\n }), [connector, isDemo]);\n\n const changeSecurity = (nextSecurity) => {\n setSecurity(nextSecurity);\n refreshActivity();\n };\n\n return (\n <Stack spacing={3}>\n {loadError && <Alert severity=\"error\">{loadError}</Alert>}\n {showPasswordChange && (\n <SectionCard title={t('profile.password.title')}>\n <SecurityTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.password.text')}</SecurityTitle>\n <SecurityForm ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <ChangePasswordForm onSubmit={async (values) => {\n await connector.changePassword(values);\n refreshActivity();\n }} />\n </SecurityForm>\n </SectionCard>\n )}\n {security\n ? <TwoStepVerificationCard security={security} onSecurityChange={changeSecurity} actions={actions}\n canUsePasskeys={passkeysSupported()} account={session?.user.email}\n // en la demostración la llave es de verdad pero el servidor se olvida al recargar:\n // se avisa antes de crearla para que nadie se quede con una llave huérfana\n passkeyNotice={isDemo ? t('demo.passkeyNote') : undefined} />\n : <Skeleton variant=\"rounded\" height={LOADING_HEIGHT_PIXELS} />}\n {isDemo && <Alert severity=\"info\">{t('demo.securityNote')}</Alert>}\n <SessionsCard sessions={sessions} onCloseOthers={connector.closeOtherSessions} onClosed={() => {\n refreshSessions();\n refreshActivity();\n }} />\n <ActivityLog events={events} />\n </Stack>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA6BA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,SAAS,UAAU;AAC/D,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AAGxD,MAAM,iBAAiB;AACvB,MAAM,wBAAwB;AAO9B,SAAwB,uBAAuB,OAAO;AAElD,QAAM,EAAC,qBAAqB,MAAM,UAAS,cAAc,OAAO,UAAU;AAC1E,QAAM,EAAC,EAAA,IAAK,sBAAsB,WAAW,KAAK;AAClD,QAAM,EAAC,WAAW,QAAA,IAAW,WAAA;AAC7B,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI;AAC7C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI;AAC7C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,IAAI;AACzC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,SAAS,OAAO,UAAU,iBAAiB;AAEjD,QAAM,kBAAkB,YAAY,MAAM,UAAU,aAAA,EAAe,KAAK,SAAS,EAAE,MAAM,CAAC,UAAU,aAAa,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AAC7I,QAAM,kBAAkB,YAAY,MAAM,UAAU,aAAA,EAAe,KAAK,WAAW,EAAE,MAAM,CAAC,UAAU,aAAa,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AAE/I,YAAU,MAAM;AACZ,cAAU,aAAA,EAAe,KAAK,WAAW,EAAE,MAAM,CAAC,UAAU,aAAa,MAAM,OAAO,CAAC;AACvF,oBAAA;AACA,oBAAA;AAAA,EACJ,GAAG,CAAC,WAAW,iBAAiB,eAAe,CAAC;AAGhD,QAAM,UAAU,QAAQ,OAAO;AAAA,IAC3B,YAAY,OAAO,SAAS,UAAU,YAAY,EAAC,MAAM,YAAY,MAAM,cAAc,MAAM,UAAU,2BAAA,CAA4B,GAAE;AAAA,IACvI,eAAe,CAAC,SAAS,aAAa,UAAU,cAAc,EAAC,WAAW,QAAQ,IAAI,UAAS;AAAA,IAC/F,WAAW,aAAa;AAAA,MACpB,GAAG,MAAM,UAAU,UAAA;AAAA;AAAA,MAEnB,OAAO,SAAS,oBAAC,sBAAmB,UAAU,UAAU,cAAc,IAAK;AAAA,IAAA;AAAA,IAE/E,aAAa,CAAC,SAAS,UAAU,YAAY,IAAI;AAAA,IACjD,aAAa,CAAC,aAAa,UAAU,YAAY,QAAQ;AAAA,IACzD,yBAAyB,CAAC,aAAa,UAAU,wBAAwB,QAAQ;AAAA,EAAA,IACjF,CAAC,WAAW,MAAM,CAAC;AAEvB,QAAM,iBAAiB,CAAC,iBAAiB;AACrC,gBAAY,YAAY;AACxB,oBAAA;AAAA,EACJ;AAEA,SACI,qBAAC,OAAA,EAAM,SAAS,GACX,UAAA;AAAA,IAAA,aAAa,oBAAC,OAAA,EAAM,UAAS,SAAS,UAAA,WAAU;AAAA,IAChD,sBACG,qBAAC,aAAA,EAAY,OAAO,EAAE,wBAAwB,GAC1C,UAAA;AAAA,MAAA,oBAAC,eAAA,EAAc,SAAQ,SAAQ,OAAM,kBAAiB,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,EAAE,uBAAuB,EAAA,CAAE;AAAA,MAClG,oBAAC,cAAA,EAAa,OAAO,EAAC,UAAU,eAAA,GAC5B,UAAA,oBAAC,oBAAA,EAAmB,UAAU,OAAO,WAAW;AAC5C,cAAM,UAAU,eAAe,MAAM;AACrC,wBAAA;AAAA,MACJ,GAAG,EAAA,CACP;AAAA,IAAA,GACJ;AAAA,IAEH,WACK;AAAA,MAAC;AAAA,MAAA;AAAA,QAAwB;AAAA,QAAoB,kBAAkB;AAAA,QAAgB;AAAA,QACtD,gBAAgB,kBAAA;AAAA,QAAqB,SAAS,SAAS,KAAK;AAAA,QAG5D,eAAe,SAAS,EAAE,kBAAkB,IAAI;AAAA,MAAA;AAAA,IAAA,IACzE,oBAAC,UAAA,EAAS,SAAQ,WAAU,QAAQ,uBAAuB;AAAA,IAChE,UAAU,oBAAC,OAAA,EAAM,UAAS,QAAQ,UAAA,EAAE,mBAAmB,GAAE;AAAA,wBACzD,cAAA,EAAa,UAAoB,eAAe,UAAU,oBAAoB,UAAU,MAAM;AAC3F,sBAAA;AACA,sBAAA;AAAA,IACJ,GAAG;AAAA,IACH,oBAAC,eAAY,OAAA,CAAgB;AAAA,EAAA,GACjC;AAER;"}
1
+ {"version":3,"file":"AccountSecuritySection.js","sources":["../../src/account/AccountSecuritySection.jsx"],"sourcesContent":["// La seguridad de la cuenta, completa: cambiar la contraseña (ChangePasswordForm), la verificación en dos pasos\n// (TwoStepVerificationCard: llaves de acceso, app autenticadora y códigos de recuperación), las sesiones abiertas\n// (SessionsCard) y la bitácora (ActivityLog). Todo lo del servidor sale del conector de la cuenta.\n//\n// Las llaves de acceso se crean aquí con el navegador (createPasskey) y la respuesta va al servidor (savePasskey). La\n// bitácora se vuelve a pedir después de cada cambio: así se ve aparecer lo que se acaba de hacer.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountSecurity con defaultProps y\n// styleOverrides de sus partes: title, form.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCallback, useEffect, useMemo, useState} from 'react';\nimport Alert from '@mui/material/Alert';\nimport Skeleton from '@mui/material/Skeleton';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport ChangePasswordForm from '@/forms/auth/ChangePasswordForm.jsx';\nimport TwoStepVerificationCard from '@/forms/security/TwoStepVerificationCard.jsx';\nimport ActivityLog from '@/security/ActivityLog.jsx';\nimport {createPasskey, passkeysSupported} from '@/security/passkeys.js';\nimport SessionsCard from '@/security/SessionsCard.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountSecurity)\nconst THEME_NAME = 'CalcitaAccountSecurity';\nconst SecurityTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst SecurityForm = piecePart(THEME_NAME, 'Form', Stack);\n\n// lo ancho del formulario de la contraseña: un renglón cómodo\nconst FORM_MAX_WIDTH = 520;\nconst LOADING_HEIGHT_PIXELS = 220;\n\n/**\n * @param {object} props\n * @param {boolean} [props.showPasswordChange] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete\n */\nexport default function AccountSecuritySection(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountSecurity.defaultProps) y encima lo que llega aquí\n const {showPasswordChange = true, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session} = useAccount();\n const [security, setSecurity] = useState(null);\n const [sessions, setSessions] = useState(null);\n const [events, setEvents] = useState(null);\n const [loadError, setLoadError] = useState(null);\n const isDemo = typeof connector.demoTotpCode === 'function';\n\n const refreshActivity = useCallback(() => connector.listActivity().then(setEvents).catch((error) => setLoadError(error.message)), [connector]);\n const refreshSessions = useCallback(() => connector.listSessions().then(setSessions).catch((error) => setLoadError(error.message)), [connector]);\n\n useEffect(() => {\n connector.loadSecurity().then(setSecurity).catch((error) => setLoadError(error.message));\n refreshSessions();\n refreshActivity();\n }, [connector, refreshActivity, refreshSessions]);\n\n // lo que hace la tarjeta de dos pasos en cada caso, con el conector\n const actions = useMemo(() => ({\n addPasskey: async (name) => connector.savePasskey({name, credential: await createPasskey(await connector.passkeyRegistrationOptions())}),\n removePasskey: (passkey, password) => connector.removePasskey({passkeyId: passkey.id, password}),\n startTotp: async () => ({\n ...await connector.startTotp(),\n // en la demostración, el atajo del código abajo del campo\n extra: isDemo ? <DemoTotpCodeButton loadCode={connector.demoTotpCode} /> : undefined,\n }),\n confirmTotp: (code) => connector.confirmTotp(code),\n disableTotp: (password) => connector.disableTotp(password),\n regenerateRecoveryCodes: (password) => connector.regenerateRecoveryCodes(password),\n }), [connector, isDemo]);\n\n const changeSecurity = (nextSecurity) => {\n setSecurity(nextSecurity);\n refreshActivity();\n };\n\n return (\n <Stack spacing={3}>\n {loadError && <Alert severity=\"error\">{loadError}</Alert>}\n {showPasswordChange && (\n <SectionCard title={t('profile.password.title')}>\n <SecurityTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.password.text')}</SecurityTitle>\n <SecurityForm ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <ChangePasswordForm onSubmit={async (values) => {\n await connector.changePassword(values);\n refreshActivity();\n }} />\n </SecurityForm>\n </SectionCard>\n )}\n {security\n ? <TwoStepVerificationCard security={security} onSecurityChange={changeSecurity} actions={actions}\n canUsePasskeys={passkeysSupported()} account={session?.user.email}\n // en la demostración la llave es de verdad pero el servidor se olvida al recargar:\n // se avisa antes de crearla para que nadie se quede con una llave huérfana\n passkeyNotice={isDemo ? t('demo.passkeyNote') : undefined} />\n : <Skeleton variant=\"rounded\" height={LOADING_HEIGHT_PIXELS} />}\n {isDemo && <Alert severity=\"info\">{t('demo.securityNote')}</Alert>}\n <SessionsCard sessions={sessions} onCloseOthers={connector.closeOtherSessions} onClosed={() => {\n refreshSessions();\n refreshActivity();\n }} />\n <ActivityLog events={events} />\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}