@stackcraftmx/calcita 0.0.0-stage → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/README.md +611 -2
- package/cli/askQuestions.js +63 -0
- package/cli/calcita.js +150 -0
- package/cli/makeComponent.js +50 -0
- package/cli/makeForm.js +68 -0
- package/cli/makeModule.js +78 -0
- package/cli/makePage.js +62 -0
- package/cli/names.js +64 -0
- package/cli/newProject.js +103 -0
- package/cli/packageVersions.js +38 -0
- package/cli/projectAnswers.js +145 -0
- package/cli/projectConfig.js +38 -0
- package/cli/projectFiles.js +126 -0
- package/cli/screenLabels.js +41 -0
- package/cli/templateFiles.js +186 -0
- package/cli/templates/component/core/__ComponentName__.jsx.tpl +23 -0
- package/cli/templates/component/module/__ComponentName__.jsx.tpl +21 -0
- package/cli/templates/form/formik/__FormName__.jsx.tpl +50 -0
- package/cli/templates/form/hookForm/__FormName__.jsx.tpl +53 -0
- package/cli/templates/form/shared/__formName__Schema.js.tpl +20 -0
- package/cli/templates/form/shared/__formName__Texts.js.tpl +6 -0
- package/cli/templates/module/__Name__Page.jsx.tpl +75 -0
- package/cli/templates/module/__name__Api.js.tpl +39 -0
- package/cli/templates/module/__name__Texts.js.tpl +27 -0
- package/cli/templates/module/menu.js.tpl +21 -0
- package/cli/templates/module/routes.js.tpl +7 -0
- package/cli/templates/moduleServer/__name__Server.js.tpl +68 -0
- package/cli/templates/page/__PageName__Page.jsx.tpl +22 -0
- package/cli/templates/page/__pageName__PageTexts.js.tpl +23 -0
- package/cli/templates/project/README.md.tpl +55 -0
- package/cli/templates/project/dot-gitignore.tpl +11 -0
- package/cli/templates/project/index.html.tpl +20 -0
- package/cli/templates/project/jsconfig.json.tpl +16 -0
- package/cli/templates/project/pnpm-workspace.yaml.tpl +5 -0
- package/cli/templates/project/public/favicon.svg +1 -0
- package/cli/templates/project/public/icons/apple-touch-icon.png +0 -0
- package/cli/templates/project/public/icons/icon-192.png +0 -0
- package/cli/templates/project/public/icons/icon-512-maskable.png +0 -0
- package/cli/templates/project/public/icons/icon-512.png +0 -0
- package/cli/templates/project/public/manifest.webmanifest.tpl +17 -0
- package/cli/templates/project/src/app/AppProviders.jsx.tpl +102 -0
- package/cli/templates/project/src/app/AppShell.jsx.tpl +87 -0
- package/cli/templates/project/src/app/appRouter.jsx.tpl +49 -0
- package/cli/templates/project/src/app/appSettings.js.tpl +13 -0
- package/cli/templates/project/src/app/appTexts.js.tpl +15 -0
- package/cli/templates/project/src/app/combineTexts.js.tpl +31 -0
- package/cli/templates/project/src/app/i18n.js.tpl +19 -0
- package/cli/templates/project/src/app/shellTexts.js.tpl +16 -0
- package/cli/templates/project/src/core/AppLogo.jsx.tpl +12 -0
- package/cli/templates/project/src/core/accountConnector.js.tpl +36 -0
- package/cli/templates/project/src/core/apiClient.js.tpl +15 -0
- package/cli/templates/project/src/core/appPaths.js.tpl +11 -0
- package/cli/templates/project/src/core/index.js.tpl +8 -0
- package/cli/templates/project/src/fakeServer/networkDelay.js.tpl +40 -0
- package/cli/templates/project/src/fakeServer/serverText.js.tpl +20 -0
- package/cli/templates/project/src/main.jsx.tpl +24 -0
- package/cli/templates/project/src/modules/auth/ForgotPasswordPage.jsx.tpl +14 -0
- package/cli/templates/project/src/modules/auth/ResetPasswordPage.jsx.tpl +15 -0
- package/cli/templates/project/src/modules/auth/SignInPage.jsx.tpl +29 -0
- package/cli/templates/project/src/modules/auth/authTexts.js.tpl +6 -0
- package/cli/templates/project/src/modules/auth/routes.js.tpl +11 -0
- package/cli/templates/project/src/modules/home/HomePage.jsx.tpl +38 -0
- package/cli/templates/project/src/modules/home/homeTexts.js.tpl +29 -0
- package/cli/templates/project/src/modules/home/menu.js.tpl +17 -0
- package/cli/templates/project/src/modules/home/routes.js.tpl +4 -0
- package/cli/templates/project/src/modules/profile/ProfilePage.jsx.tpl +13 -0
- package/cli/templates/project/src/modules/profile/routes.js.tpl +6 -0
- package/cli/templates/project/vite.config.js.tpl +27 -0
- package/dist/DataTable/AuditTrailDialog.js +40 -0
- package/dist/DataTable/AuditTrailDialog.js.map +1 -0
- package/dist/DataTable/AuditTrailTable.js +87 -0
- package/dist/DataTable/AuditTrailTable.js.map +1 -0
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +71 -0
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -0
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +50 -0
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -0
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +54 -0
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -0
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js +24 -0
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js.map +1 -0
- package/dist/DataTable/EmptyState.js +22 -0
- package/dist/DataTable/EmptyState.js.map +1 -0
- package/dist/DataTable/FilterChips.js +39 -0
- package/dist/DataTable/FilterChips.js.map +1 -0
- package/dist/DataTable/GoToPage.js +62 -0
- package/dist/DataTable/GoToPage.js.map +1 -0
- package/dist/DataTable/ServerTable.js +407 -0
- package/dist/DataTable/ServerTable.js.map +1 -0
- package/dist/DataTable/buildChipConfig.js +27 -0
- package/dist/DataTable/buildChipConfig.js.map +1 -0
- package/dist/DataTable/columns.js +122 -0
- package/dist/DataTable/columns.js.map +1 -0
- package/dist/DataTable/filterContext.js +15 -0
- package/dist/DataTable/filterContext.js.map +1 -0
- package/dist/DataTable/serverTableParams.js +19 -0
- package/dist/DataTable/serverTableParams.js.map +1 -0
- package/dist/DataTable/tableMachine.js +87 -0
- package/dist/DataTable/tableMachine.js.map +1 -0
- package/dist/DataTable/useDebouncedFilter.js +29 -0
- package/dist/DataTable/useDebouncedFilter.js.map +1 -0
- package/dist/DataTable/useTableState.js +132 -0
- package/dist/DataTable/useTableState.js.map +1 -0
- package/dist/access/Can.js +9 -0
- package/dist/access/Can.js.map +1 -0
- package/dist/access/PermissionMatrix.js +83 -0
- package/dist/access/PermissionMatrix.js.map +1 -0
- package/dist/access/RequireAccess.js +14 -0
- package/dist/access/RequireAccess.js.map +1 -0
- package/dist/access/accessRules.js +49 -0
- package/dist/access/accessRules.js.map +1 -0
- package/dist/access/permissionGroups.js +43 -0
- package/dist/access/permissionGroups.js.map +1 -0
- package/dist/access/useCan.js +12 -0
- package/dist/access/useCan.js.map +1 -0
- package/dist/account/AccountProvider.js +58 -0
- package/dist/account/AccountProvider.js.map +1 -0
- package/dist/account/AccountSecuritySection.js +81 -0
- package/dist/account/AccountSecuritySection.js.map +1 -0
- package/dist/account/DemoTotpCodeButton.js +26 -0
- package/dist/account/DemoTotpCodeButton.js.map +1 -0
- package/dist/account/ForgotPasswordScreen.js +26 -0
- package/dist/account/ForgotPasswordScreen.js.map +1 -0
- package/dist/account/ProfileScreen.js +108 -0
- package/dist/account/ProfileScreen.js.map +1 -0
- package/dist/account/ResetPasswordScreen.js +57 -0
- package/dist/account/ResetPasswordScreen.js.map +1 -0
- package/dist/account/SignInScreen.js +101 -0
- package/dist/account/SignInScreen.js.map +1 -0
- package/dist/account/accountConnector.js +31 -0
- package/dist/account/accountConnector.js.map +1 -0
- package/dist/account/demo/createDemoAccountConnector.js +368 -0
- package/dist/account/demo/createDemoAccountConnector.js.map +1 -0
- package/dist/account/demo/totp.js +61 -0
- package/dist/account/demo/totp.js.map +1 -0
- package/dist/account/restAccountConnector.js +117 -0
- package/dist/account/restAccountConnector.js.map +1 -0
- package/dist/account-demo.js +12 -0
- package/dist/account-demo.js.map +1 -0
- package/dist/account.js +25 -0
- package/dist/account.js.map +1 -0
- package/dist/adapters/i18next.js +7 -0
- package/dist/adapters/i18next.js.map +1 -0
- package/dist/adapters/nextNavigation.js +36 -0
- package/dist/adapters/nextNavigation.js.map +1 -0
- package/dist/adapters/reactRouter.js +7 -0
- package/dist/adapters/reactRouter.js.map +1 -0
- package/dist/adapters/reactRouterRoutes.js +48 -0
- package/dist/adapters/reactRouterRoutes.js.map +1 -0
- package/dist/api/ApiError.js +58 -0
- package/dist/api/ApiError.js.map +1 -0
- package/dist/api/createApiClient.js +226 -0
- package/dist/api/createApiClient.js.map +1 -0
- package/dist/api/staleChunks.js +47 -0
- package/dist/api/staleChunks.js.map +1 -0
- package/dist/appShell/AccountMenu.js +86 -0
- package/dist/appShell/AccountMenu.js.map +1 -0
- package/dist/appShell/AppLayout.js +493 -0
- package/dist/appShell/AppLayout.js.map +1 -0
- package/dist/appShell/AppearanceSettings.js +93 -0
- package/dist/appShell/AppearanceSettings.js.map +1 -0
- package/dist/appShell/AuthLayout.js +44 -0
- package/dist/appShell/AuthLayout.js.map +1 -0
- package/dist/appShell/BarActionButton.js +31 -0
- package/dist/appShell/BarActionButton.js.map +1 -0
- package/dist/appShell/BarActions.js +94 -0
- package/dist/appShell/BarActions.js.map +1 -0
- package/dist/appShell/BarCapsule.js +35 -0
- package/dist/appShell/BarCapsule.js.map +1 -0
- package/dist/appShell/HeaderTools.js +53 -0
- package/dist/appShell/HeaderTools.js.map +1 -0
- package/dist/appShell/MobileTabBar.js +346 -0
- package/dist/appShell/MobileTabBar.js.map +1 -0
- package/dist/appShell/SettingsMenu.js +41 -0
- package/dist/appShell/SettingsMenu.js.map +1 -0
- package/dist/appShell/SideMenu.js +217 -0
- package/dist/appShell/SideMenu.js.map +1 -0
- package/dist/appShell/SideMenuEntry.js +140 -0
- package/dist/appShell/SideMenuEntry.js.map +1 -0
- package/dist/appShell/SubmenuActionsMenu.js +71 -0
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -0
- package/dist/appShell/TabBarEditor.js +55 -0
- package/dist/appShell/TabBarEditor.js.map +1 -0
- package/dist/appShell/TopMenu.js +80 -0
- package/dist/appShell/TopMenu.js.map +1 -0
- package/dist/appShell/appMenuContext.js +11 -0
- package/dist/appShell/appMenuContext.js.map +1 -0
- package/dist/appShell/barActionsSlot.js +26 -0
- package/dist/appShell/barActionsSlot.js.map +1 -0
- package/dist/appShell/barMenuPlacement.js +33 -0
- package/dist/appShell/barMenuPlacement.js.map +1 -0
- package/dist/appShell/menuItemText.js +33 -0
- package/dist/appShell/menuItemText.js.map +1 -0
- package/dist/appShell/pageTitle.js +45 -0
- package/dist/appShell/pageTitle.js.map +1 -0
- package/dist/appShell/shellSizes.js +38 -0
- package/dist/appShell/shellSizes.js.map +1 -0
- package/dist/appShell/tabBarRule.js +12 -0
- package/dist/appShell/tabBarRule.js.map +1 -0
- package/dist/appShell/tabBarScroll.js +23 -0
- package/dist/appShell/tabBarScroll.js.map +1 -0
- package/dist/appShell/useDrawerCollapsed.js +29 -0
- package/dist/appShell/useDrawerCollapsed.js.map +1 -0
- package/dist/appShell/useFittingActionCount.js +45 -0
- package/dist/appShell/useFittingActionCount.js.map +1 -0
- package/dist/appShell/usePinnedMobileTabs.js +32 -0
- package/dist/appShell/usePinnedMobileTabs.js.map +1 -0
- package/dist/appShell/useTabBarMinimized.js +33 -0
- package/dist/appShell/useTabBarMinimized.js.map +1 -0
- package/dist/auth/PasswordChecklist.js +44 -0
- package/dist/auth/PasswordChecklist.js.map +1 -0
- package/dist/auth/passwordRules.js +43 -0
- package/dist/auth/passwordRules.js.map +1 -0
- package/dist/calendar/EventCalendar.js +138 -0
- package/dist/calendar/EventCalendar.js.map +1 -0
- package/dist/calendar.js +6 -0
- package/dist/calendar.js.map +1 -0
- package/dist/charts.js +7 -0
- package/dist/charts.js.map +1 -0
- package/dist/date-pickers.js +8 -0
- package/dist/date-pickers.js.map +1 -0
- package/dist/datePickers/DateInput.js +75 -0
- package/dist/datePickers/DateInput.js.map +1 -0
- package/dist/datePickers/FormDateField.js +12 -0
- package/dist/datePickers/FormDateField.js.map +1 -0
- package/dist/dates.js +25 -0
- package/dist/dates.js.map +1 -0
- package/dist/dictionaries/dictionaries.js +48 -0
- package/dist/dictionaries/dictionaries.js.map +1 -0
- package/dist/downloads/DownloadManager.js +201 -0
- package/dist/downloads/DownloadManager.js.map +1 -0
- package/dist/downloads/downloadQueue.js +54 -0
- package/dist/downloads/downloadQueue.js.map +1 -0
- package/dist/downloads/downloadsMachine.js +77 -0
- package/dist/downloads/downloadsMachine.js.map +1 -0
- package/dist/excel/reportWorkbook.js +299 -0
- package/dist/excel/reportWorkbook.js.map +1 -0
- package/dist/excel.js +13 -0
- package/dist/excel.js.map +1 -0
- package/dist/feedback/ConfirmDialog.js +72 -0
- package/dist/feedback/ConfirmDialog.js.map +1 -0
- package/dist/feedback/ModalWaiting.js +23 -0
- package/dist/feedback/ModalWaiting.js.map +1 -0
- package/dist/feedback/NewBuildNotice.js +79 -0
- package/dist/feedback/NewBuildNotice.js.map +1 -0
- package/dist/feedback/StaleBuildBoundary.js +36 -0
- package/dist/feedback/StaleBuildBoundary.js.map +1 -0
- package/dist/feedback/Toaster.js +20 -0
- package/dist/feedback/Toaster.js.map +1 -0
- package/dist/feedback/confirmActionMachine.js +67 -0
- package/dist/feedback/confirmActionMachine.js.map +1 -0
- package/dist/feedback/toast.js +88 -0
- package/dist/feedback/toast.js.map +1 -0
- package/dist/feedback/useConfirmAction.js +40 -0
- package/dist/feedback/useConfirmAction.js.map +1 -0
- package/dist/filepond/FileDropzone.js +254 -0
- package/dist/filepond/FileDropzone.js.map +1 -0
- package/dist/filepond/pondServer.js +48 -0
- package/dist/filepond/pondServer.js.map +1 -0
- package/dist/filepond.js +10 -0
- package/dist/filepond.js.map +1 -0
- package/dist/files.js +43 -0
- package/dist/files.js.map +1 -0
- package/dist/formatting.js +177 -0
- package/dist/formatting.js.map +1 -0
- package/dist/forms/FormCatalogField.js +12 -0
- package/dist/forms/FormCatalogField.js.map +1 -0
- package/dist/forms/FormColorField.js +12 -0
- package/dist/forms/FormColorField.js.map +1 -0
- package/dist/forms/FormNumberField.js +12 -0
- package/dist/forms/FormNumberField.js.map +1 -0
- package/dist/forms/FormProblemAlert.js +15 -0
- package/dist/forms/FormProblemAlert.js.map +1 -0
- package/dist/forms/FormSelectField.js +12 -0
- package/dist/forms/FormSelectField.js.map +1 -0
- package/dist/forms/FormServerProblem.js +23 -0
- package/dist/forms/FormServerProblem.js.map +1 -0
- package/dist/forms/FormTextField.js +12 -0
- package/dist/forms/FormTextField.js.map +1 -0
- package/dist/forms/FormWizard.js +90 -0
- package/dist/forms/FormWizard.js.map +1 -0
- package/dist/forms/SubmitButton.js +14 -0
- package/dist/forms/SubmitButton.js.map +1 -0
- package/dist/forms/applyServerProblem.js +15 -0
- package/dist/forms/applyServerProblem.js.map +1 -0
- package/dist/forms/auth/ChangePasswordForm.js +46 -0
- package/dist/forms/auth/ChangePasswordForm.js.map +1 -0
- package/dist/forms/auth/ForgotPasswordForm.js +50 -0
- package/dist/forms/auth/ForgotPasswordForm.js.map +1 -0
- package/dist/forms/auth/SignInForm.js +48 -0
- package/dist/forms/auth/SignInForm.js.map +1 -0
- package/dist/forms/security/SecondStepForm.js +122 -0
- package/dist/forms/security/SecondStepForm.js.map +1 -0
- package/dist/forms/security/TwoStepVerificationCard.js +336 -0
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -0
- package/dist/forms/security/securityRules.js +28 -0
- package/dist/forms/security/securityRules.js.map +1 -0
- package/dist/forms/serverProblemFields.js +25 -0
- package/dist/forms/serverProblemFields.js.map +1 -0
- package/dist/forms/useFormikField.js +16 -0
- package/dist/forms/useFormikField.js.map +1 -0
- package/dist/forms/validation.js +55 -0
- package/dist/forms/validation.js.map +1 -0
- package/dist/forms/validationMessages.js +16 -0
- package/dist/forms/validationMessages.js.map +1 -0
- package/dist/forms.js +57 -0
- package/dist/forms.js.map +1 -0
- package/dist/hookForm/FormCatalogField.js +12 -0
- package/dist/hookForm/FormCatalogField.js.map +1 -0
- package/dist/hookForm/FormColorField.js +12 -0
- package/dist/hookForm/FormColorField.js.map +1 -0
- package/dist/hookForm/FormNumberField.js +12 -0
- package/dist/hookForm/FormNumberField.js.map +1 -0
- package/dist/hookForm/FormProblemAlert.js +17 -0
- package/dist/hookForm/FormProblemAlert.js.map +1 -0
- package/dist/hookForm/FormSelectField.js +12 -0
- package/dist/hookForm/FormSelectField.js.map +1 -0
- package/dist/hookForm/FormTextField.js +12 -0
- package/dist/hookForm/FormTextField.js.map +1 -0
- package/dist/hookForm/SubmitButton.js +15 -0
- package/dist/hookForm/SubmitButton.js.map +1 -0
- package/dist/hookForm/applyServerProblem.js +21 -0
- package/dist/hookForm/applyServerProblem.js.map +1 -0
- package/dist/hookForm/useHookFormField.js +19 -0
- package/dist/hookForm/useHookFormField.js.map +1 -0
- package/dist/i18next.js +5 -0
- package/dist/i18next.js.map +1 -0
- package/dist/identifiers.js +8 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/inbox/InboxLayout.js +68 -0
- package/dist/inbox/InboxLayout.js.map +1 -0
- package/dist/inbox/MessageList.js +64 -0
- package/dist/inbox/MessageList.js.map +1 -0
- package/dist/inbox/MessageView.js +53 -0
- package/dist/inbox/MessageView.js.map +1 -0
- package/dist/inbox/inboxDates.js +8 -0
- package/dist/inbox/inboxDates.js.map +1 -0
- package/dist/index.js +383 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/CatalogInput.js +62 -0
- package/dist/inputs/CatalogInput.js.map +1 -0
- package/dist/inputs/ColorInput.js +108 -0
- package/dist/inputs/ColorInput.js.map +1 -0
- package/dist/inputs/FieldFrame.js +20 -0
- package/dist/inputs/FieldFrame.js.map +1 -0
- package/dist/inputs/FormSection.js +105 -0
- package/dist/inputs/FormSection.js.map +1 -0
- package/dist/inputs/NumberInput.js +69 -0
- package/dist/inputs/NumberInput.js.map +1 -0
- package/dist/inputs/SelectInput.js +66 -0
- package/dist/inputs/SelectInput.js.map +1 -0
- package/dist/inputs/TextInput.js +97 -0
- package/dist/inputs/TextInput.js.map +1 -0
- package/dist/inputs/colorContrast.js +46 -0
- package/dist/inputs/colorContrast.js.map +1 -0
- package/dist/inputs/formLayoutContext.js +9 -0
- package/dist/inputs/formLayoutContext.js.map +1 -0
- package/dist/inputs/numberText.js +48 -0
- package/dist/inputs/numberText.js.map +1 -0
- package/dist/kanban/KanbanBoard.js +113 -0
- package/dist/kanban/KanbanBoard.js.map +1 -0
- package/dist/kanban/kanbanMoves.js +29 -0
- package/dist/kanban/kanbanMoves.js.map +1 -0
- package/dist/kanban.js +9 -0
- package/dist/kanban.js.map +1 -0
- package/dist/laravel/csrfRetry.js +18 -0
- package/dist/laravel/csrfRetry.js.map +1 -0
- package/dist/laravel.js +6 -0
- package/dist/laravel.js.map +1 -0
- package/dist/lastListUrl.js +35 -0
- package/dist/lastListUrl.js.map +1 -0
- package/dist/locales/en.js +714 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.js +714 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/maps/MapView.js +96 -0
- package/dist/maps/MapView.js.map +1 -0
- package/dist/maps/mapMarkers.js +19 -0
- package/dist/maps/mapMarkers.js.map +1 -0
- package/dist/maps.js +10 -0
- package/dist/maps.js.map +1 -0
- package/dist/money/money.js +380 -0
- package/dist/money/money.js.map +1 -0
- package/dist/money.js +6 -0
- package/dist/money.js.map +1 -0
- package/dist/navigation/appMenu.js +93 -0
- package/dist/navigation/appMenu.js.map +1 -0
- package/dist/navigation/useMenuBadges.js +45 -0
- package/dist/navigation/useMenuBadges.js.map +1 -0
- package/dist/navigation.js +30 -0
- package/dist/navigation.js.map +1 -0
- package/dist/navigationTrail.js +82 -0
- package/dist/navigationTrail.js.map +1 -0
- package/dist/next.js +5 -0
- package/dist/next.js.map +1 -0
- package/dist/observability/buildWatch.js +19 -0
- package/dist/observability/buildWatch.js.map +1 -0
- package/dist/observability/logger.js +43 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/publishedBuild.js +39 -0
- package/dist/observability/publishedBuild.js.map +1 -0
- package/dist/observability/usePublishedBuildWatch.js +76 -0
- package/dist/observability/usePublishedBuildWatch.js.map +1 -0
- package/dist/passkeys.js +7 -0
- package/dist/passkeys.js.map +1 -0
- package/dist/periodRanges.js +33 -0
- package/dist/periodRanges.js.map +1 -0
- package/dist/problems.js +51 -0
- package/dist/problems.js.map +1 -0
- package/dist/pwa/InstallAppSetting.js +33 -0
- package/dist/pwa/InstallAppSetting.js.map +1 -0
- package/dist/pwa/InstallInstructionsDialog.js +35 -0
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -0
- package/dist/pwa/InstallPromptBanner.js +64 -0
- package/dist/pwa/InstallPromptBanner.js.map +1 -0
- package/dist/pwa/installInstructions.js +60 -0
- package/dist/pwa/installInstructions.js.map +1 -0
- package/dist/pwa/useInstallPrompt.js +70 -0
- package/dist/pwa/useInstallPrompt.js.map +1 -0
- package/dist/react-hook-form.js +30 -0
- package/dist/react-hook-form.js.map +1 -0
- package/dist/react-router.js +10 -0
- package/dist/react-router.js.map +1 -0
- package/dist/security/ActivityLog.js +79 -0
- package/dist/security/ActivityLog.js.map +1 -0
- package/dist/security/RecoveryCodesDialog.js +84 -0
- package/dist/security/RecoveryCodesDialog.js.map +1 -0
- package/dist/security/SessionsCard.js +81 -0
- package/dist/security/SessionsCard.js.map +1 -0
- package/dist/security/passkeys.js +39 -0
- package/dist/security/passkeys.js.map +1 -0
- package/dist/table.js +35 -0
- package/dist/table.js.map +1 -0
- package/dist/theme/androidDevice.js +16 -0
- package/dist/theme/androidDevice.js.map +1 -0
- package/dist/theme/appleTracking.js +34 -0
- package/dist/theme/appleTracking.js.map +1 -0
- package/dist/theme/components/MuiAppBar.js +27 -0
- package/dist/theme/components/MuiAppBar.js.map +1 -0
- package/dist/theme/components/MuiBackdrop.js +13 -0
- package/dist/theme/components/MuiBackdrop.js.map +1 -0
- package/dist/theme/components/MuiButton.js +25 -0
- package/dist/theme/components/MuiButton.js.map +1 -0
- package/dist/theme/components/MuiButtonBase.js +16 -0
- package/dist/theme/components/MuiButtonBase.js.map +1 -0
- package/dist/theme/components/MuiChip.js +30 -0
- package/dist/theme/components/MuiChip.js.map +1 -0
- package/dist/theme/components/MuiDataGrid.js +30 -0
- package/dist/theme/components/MuiDataGrid.js.map +1 -0
- package/dist/theme/components/MuiDrawer.js +18 -0
- package/dist/theme/components/MuiDrawer.js.map +1 -0
- package/dist/theme/components/MuiMenuItem.js +17 -0
- package/dist/theme/components/MuiMenuItem.js.map +1 -0
- package/dist/theme/components/MuiTypography.js +22 -0
- package/dist/theme/components/MuiTypography.js.map +1 -0
- package/dist/theme/components/glassComponents.js +885 -0
- package/dist/theme/components/glassComponents.js.map +1 -0
- package/dist/theme/components/minimalComponents.js +146 -0
- package/dist/theme/components/minimalComponents.js.map +1 -0
- package/dist/theme/components/paletteOf.js +7 -0
- package/dist/theme/components/paletteOf.js.map +1 -0
- package/dist/theme/createToolkitTheme.js +100 -0
- package/dist/theme/createToolkitTheme.js.map +1 -0
- package/dist/theme/glassSurface.js +328 -0
- package/dist/theme/glassSurface.js.map +1 -0
- package/dist/theme/glassToasterStyles.js +50 -0
- package/dist/theme/glassToasterStyles.js.map +1 -0
- package/dist/theme/mergeComponents.js +42 -0
- package/dist/theme/mergeComponents.js.map +1 -0
- package/dist/theme/stackcraftPalette.js +59 -0
- package/dist/theme/stackcraftPalette.js.map +1 -0
- package/dist/theme/toolkitComponents.js +26 -0
- package/dist/theme/toolkitComponents.js.map +1 -0
- package/dist/timeline.js +8 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toolkit/ToolkitProvider.js +49 -0
- package/dist/toolkit/ToolkitProvider.js.map +1 -0
- package/dist/toolkit/browserNavigation.js +34 -0
- package/dist/toolkit/browserNavigation.js.map +1 -0
- package/dist/toolkit/toolkitContext.js +19 -0
- package/dist/toolkit/toolkitContext.js.map +1 -0
- package/dist/toolkit/toolkitSettings.js +87 -0
- package/dist/toolkit/toolkitSettings.js.map +1 -0
- package/dist/toolkit/useToolkitTranslation.js +18 -0
- package/dist/toolkit/useToolkitTranslation.js.map +1 -0
- package/dist/types/DataTable/AuditTrailDialog.d.ts +32 -0
- package/dist/types/DataTable/AuditTrailTable.d.ts +28 -0
- package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +8 -0
- package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +16 -0
- package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +26 -0
- package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +8 -0
- package/dist/types/DataTable/ColumnFilters/index.d.ts +4 -0
- package/dist/types/DataTable/EmptyState.d.ts +8 -0
- package/dist/types/DataTable/FilterChips.d.ts +15 -0
- package/dist/types/DataTable/GoToPage.d.ts +8 -0
- package/dist/types/DataTable/ServerTable.d.ts +110 -0
- package/dist/types/DataTable/buildChipConfig.d.ts +22 -0
- package/dist/types/DataTable/columns.d.ts +93 -0
- package/dist/types/DataTable/filterContext.d.ts +13 -0
- package/dist/types/DataTable/index.d.ts +13 -0
- package/dist/types/DataTable/serverTableParams.d.ts +16 -0
- package/dist/types/DataTable/tableMachine.d.ts +41 -0
- package/dist/types/DataTable/useDebouncedFilter.d.ts +8 -0
- package/dist/types/DataTable/useTableState.d.ts +93 -0
- package/dist/types/access/Can.d.ts +11 -0
- package/dist/types/access/PermissionMatrix.d.ts +21 -0
- package/dist/types/access/RequireAccess.d.ts +11 -0
- package/dist/types/access/accessRules.d.ts +24 -0
- package/dist/types/access/permissionGroups.d.ts +56 -0
- package/dist/types/access/useCan.d.ts +11 -0
- package/dist/types/account/AccountProvider.d.ts +27 -0
- package/dist/types/account/AccountSecuritySection.d.ts +7 -0
- package/dist/types/account/DemoTotpCodeButton.d.ts +6 -0
- package/dist/types/account/ForgotPasswordScreen.d.ts +15 -0
- package/dist/types/account/ProfileScreen.d.ts +13 -0
- package/dist/types/account/ResetPasswordScreen.d.ts +19 -0
- package/dist/types/account/SignInScreen.d.ts +25 -0
- package/dist/types/account/accountConnector.d.ts +263 -0
- package/dist/types/account/demo/createDemoAccountConnector.d.ts +30 -0
- package/dist/types/account/demo/totp.d.ts +45 -0
- package/dist/types/account/restAccountConnector.d.ts +49 -0
- package/dist/types/account-demo.d.ts +2 -0
- package/dist/types/account.d.ts +16 -0
- package/dist/types/adapters/i18next.d.ts +11 -0
- package/dist/types/adapters/nextNavigation.d.ts +33 -0
- package/dist/types/adapters/reactRouter.d.ts +6 -0
- package/dist/types/adapters/reactRouterRoutes.d.ts +30 -0
- package/dist/types/api/ApiError.d.ts +42 -0
- package/dist/types/api/createApiClient.d.ts +146 -0
- package/dist/types/api/staleChunks.d.ts +15 -0
- package/dist/types/appShell/AccountMenu.d.ts +28 -0
- package/dist/types/appShell/AppLayout.d.ts +66 -0
- package/dist/types/appShell/AppearanceSettings.d.ts +34 -0
- package/dist/types/appShell/AuthLayout.d.ts +21 -0
- package/dist/types/appShell/BarActionButton.d.ts +15 -0
- package/dist/types/appShell/BarActions.d.ts +18 -0
- package/dist/types/appShell/BarCapsule.d.ts +12 -0
- package/dist/types/appShell/HeaderTools.d.ts +27 -0
- package/dist/types/appShell/MobileTabBar.d.ts +17 -0
- package/dist/types/appShell/SettingsMenu.d.ts +13 -0
- package/dist/types/appShell/SideMenu.d.ts +31 -0
- package/dist/types/appShell/SideMenuEntry.d.ts +17 -0
- package/dist/types/appShell/SubmenuActionsMenu.d.ts +24 -0
- package/dist/types/appShell/TabBarEditor.d.ts +13 -0
- package/dist/types/appShell/TopMenu.d.ts +7 -0
- package/dist/types/appShell/appMenuContext.d.ts +9 -0
- package/dist/types/appShell/barActionsSlot.d.ts +35 -0
- package/dist/types/appShell/barMenuPlacement.d.ts +9 -0
- package/dist/types/appShell/menuItemText.d.ts +55 -0
- package/dist/types/appShell/pageTitle.d.ts +26 -0
- package/dist/types/appShell/shellSizes.d.ts +45 -0
- package/dist/types/appShell/tabBarRule.d.ts +5 -0
- package/dist/types/appShell/tabBarScroll.d.ts +26 -0
- package/dist/types/appShell/useDrawerCollapsed.d.ts +8 -0
- package/dist/types/appShell/useFittingActionCount.d.ts +7 -0
- package/dist/types/appShell/usePinnedMobileTabs.d.ts +7 -0
- package/dist/types/appShell/useTabBarMinimized.d.ts +8 -0
- package/dist/types/auth/PasswordChecklist.d.ts +11 -0
- package/dist/types/auth/passwordRules.d.ts +34 -0
- package/dist/types/calendar/EventCalendar.d.ts +46 -0
- package/dist/types/calendar.d.ts +1 -0
- package/dist/types/charts.d.ts +2 -0
- package/dist/types/date-pickers.d.ts +2 -0
- package/dist/types/datePickers/DateInput.d.ts +39 -0
- package/dist/types/datePickers/FormDateField.d.ts +7 -0
- package/dist/types/dates.d.ts +18 -0
- package/dist/types/dictionaries/dictionaries.d.ts +54 -0
- package/dist/types/downloads/DownloadManager.d.ts +1 -0
- package/dist/types/downloads/downloadQueue.d.ts +45 -0
- package/dist/types/downloads/downloadsMachine.d.ts +10 -0
- package/dist/types/downloads/index.d.ts +3 -0
- package/dist/types/excel/reportWorkbook.d.ts +157 -0
- package/dist/types/excel.d.ts +1 -0
- package/dist/types/feedback/ConfirmDialog.d.ts +29 -0
- package/dist/types/feedback/ModalWaiting.d.ts +8 -0
- package/dist/types/feedback/NewBuildNotice.d.ts +18 -0
- package/dist/types/feedback/StaleBuildBoundary.d.ts +21 -0
- package/dist/types/feedback/Toaster.d.ts +1 -0
- package/dist/types/feedback/confirmActionMachine.d.ts +19 -0
- package/dist/types/feedback/index.d.ts +8 -0
- package/dist/types/feedback/toast.d.ts +100 -0
- package/dist/types/feedback/useConfirmAction.d.ts +33 -0
- package/dist/types/filepond/FileDropzone.d.ts +59 -0
- package/dist/types/filepond/pondServer.d.ts +17 -0
- package/dist/types/filepond.d.ts +3 -0
- package/dist/types/files.d.ts +29 -0
- package/dist/types/formatting.d.ts +106 -0
- package/dist/types/forms/FormCatalogField.d.ts +6 -0
- package/dist/types/forms/FormColorField.d.ts +6 -0
- package/dist/types/forms/FormNumberField.d.ts +6 -0
- package/dist/types/forms/FormProblemAlert.d.ts +6 -0
- package/dist/types/forms/FormSelectField.d.ts +6 -0
- package/dist/types/forms/FormServerProblem.d.ts +8 -0
- package/dist/types/forms/FormTextField.d.ts +6 -0
- package/dist/types/forms/FormWizard.d.ts +20 -0
- package/dist/types/forms/SubmitButton.d.ts +9 -0
- package/dist/types/forms/applyServerProblem.d.ts +9 -0
- package/dist/types/forms/auth/ChangePasswordForm.d.ts +15 -0
- package/dist/types/forms/auth/ForgotPasswordForm.d.ts +12 -0
- package/dist/types/forms/auth/SignInForm.d.ts +18 -0
- package/dist/types/forms/index.d.ts +19 -0
- package/dist/types/forms/security/SecondStepForm.d.ts +28 -0
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +81 -0
- package/dist/types/forms/security/securityRules.d.ts +24 -0
- package/dist/types/forms/serverProblemFields.d.ts +19 -0
- package/dist/types/forms/useFormikField.d.ts +11 -0
- package/dist/types/forms/validation.d.ts +251 -0
- package/dist/types/forms/validationMessages.d.ts +12 -0
- package/dist/types/forms.d.ts +2 -0
- package/dist/types/hookForm/FormCatalogField.d.ts +8 -0
- package/dist/types/hookForm/FormColorField.d.ts +8 -0
- package/dist/types/hookForm/FormNumberField.d.ts +8 -0
- package/dist/types/hookForm/FormProblemAlert.d.ts +7 -0
- package/dist/types/hookForm/FormSelectField.d.ts +8 -0
- package/dist/types/hookForm/FormTextField.d.ts +8 -0
- package/dist/types/hookForm/SubmitButton.d.ts +21 -0
- package/dist/types/hookForm/applyServerProblem.d.ts +10 -0
- package/dist/types/hookForm/useHookFormField.d.ts +13 -0
- package/dist/types/i18next.d.ts +1 -0
- package/dist/types/identifiers.d.ts +2 -0
- package/dist/types/inbox/InboxLayout.d.ts +26 -0
- package/dist/types/inbox/MessageList.d.ts +27 -0
- package/dist/types/inbox/MessageView.d.ts +23 -0
- package/dist/types/inbox/inboxDates.d.ts +6 -0
- package/dist/types/index.d.ts +84 -0
- package/dist/types/inputs/CatalogInput.d.ts +41 -0
- package/dist/types/inputs/ColorInput.d.ts +28 -0
- package/dist/types/inputs/FieldFrame.d.ts +14 -0
- package/dist/types/inputs/FormSection.d.ts +29 -0
- package/dist/types/inputs/NumberInput.d.ts +36 -0
- package/dist/types/inputs/SelectInput.d.ts +34 -0
- package/dist/types/inputs/TextInput.d.ts +60 -0
- package/dist/types/inputs/colorContrast.d.ts +18 -0
- package/dist/types/inputs/formLayoutContext.d.ts +3 -0
- package/dist/types/inputs/numberText.d.ts +25 -0
- package/dist/types/kanban/KanbanBoard.d.ts +33 -0
- package/dist/types/kanban/kanbanMoves.d.ts +38 -0
- package/dist/types/kanban.d.ts +2 -0
- package/dist/types/laravel/csrfRetry.d.ts +21 -0
- package/dist/types/laravel.d.ts +1 -0
- package/dist/types/lastListUrl.d.ts +20 -0
- package/dist/types/locales/en.d.ts +711 -0
- package/dist/types/locales/es.d.ts +711 -0
- package/dist/types/maps/MapView.d.ts +32 -0
- package/dist/types/maps/mapMarkers.d.ts +23 -0
- package/dist/types/maps.d.ts +2 -0
- package/dist/types/money/money.d.ts +203 -0
- package/dist/types/money.d.ts +1 -0
- package/dist/types/navigation/appMenu.d.ts +92 -0
- package/dist/types/navigation/useMenuBadges.d.ts +16 -0
- package/dist/types/navigation.d.ts +22 -0
- package/dist/types/navigationTrail.d.ts +49 -0
- package/dist/types/next.d.ts +1 -0
- package/dist/types/observability/buildWatch.d.ts +28 -0
- package/dist/types/observability/logger.d.ts +19 -0
- package/dist/types/observability/publishedBuild.d.ts +35 -0
- package/dist/types/observability/usePublishedBuildWatch.d.ts +16 -0
- package/dist/types/passkeys.d.ts +1 -0
- package/dist/types/periodRanges.d.ts +32 -0
- package/dist/types/problems.d.ts +31 -0
- package/dist/types/pwa/InstallAppSetting.d.ts +1 -0
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +18 -0
- package/dist/types/pwa/InstallPromptBanner.d.ts +7 -0
- package/dist/types/pwa/installInstructions.d.ts +52 -0
- package/dist/types/pwa/useInstallPrompt.d.ts +12 -0
- package/dist/types/react-hook-form.d.ts +11 -0
- package/dist/types/react-router.d.ts +2 -0
- package/dist/types/security/ActivityLog.d.ts +31 -0
- package/dist/types/security/RecoveryCodesDialog.d.ts +11 -0
- package/dist/types/security/SessionsCard.d.ts +22 -0
- package/dist/types/security/passkeys.d.ts +18 -0
- package/dist/types/table.d.ts +1 -0
- package/dist/types/theme/androidDevice.d.ts +11 -0
- package/dist/types/theme/appleTracking.d.ts +17 -0
- package/dist/types/theme/components/MuiAppBar.d.ts +13 -0
- package/dist/types/theme/components/MuiBackdrop.d.ts +11 -0
- package/dist/types/theme/components/MuiButton.d.ts +27 -0
- package/dist/types/theme/components/MuiButtonBase.d.ts +14 -0
- package/dist/types/theme/components/MuiChip.d.ts +29 -0
- package/dist/types/theme/components/MuiDataGrid.d.ts +45 -0
- package/dist/types/theme/components/MuiDrawer.d.ts +13 -0
- package/dist/types/theme/components/MuiMenuItem.d.ts +17 -0
- package/dist/types/theme/components/MuiTypography.d.ts +20 -0
- package/dist/types/theme/components/glassComponents.d.ts +8 -0
- package/dist/types/theme/components/minimalComponents.d.ts +22 -0
- package/dist/types/theme/components/paletteOf.d.ts +5 -0
- package/dist/types/theme/createToolkitTheme.d.ts +48 -0
- package/dist/types/theme/glassSurface.d.ts +247 -0
- package/dist/types/theme/glassToasterStyles.d.ts +7 -0
- package/dist/types/theme/mergeComponents.d.ts +15 -0
- package/dist/types/theme/stackcraftPalette.d.ts +142 -0
- package/dist/types/theme/toolkitComponents.d.ts +4 -0
- package/dist/types/timeline.d.ts +2 -0
- package/dist/types/toolkit/ToolkitProvider.d.ts +31 -0
- package/dist/types/toolkit/browserNavigation.d.ts +32 -0
- package/dist/types/toolkit/toolkitContext.d.ts +28 -0
- package/dist/types/toolkit/toolkitSettings.d.ts +68 -0
- package/dist/types/toolkit/useToolkitTranslation.d.ts +10 -0
- package/dist/types/ui/actions/CopyButton.d.ts +13 -0
- package/dist/types/ui/actions/DownloadMenu.d.ts +50 -0
- package/dist/types/ui/actions/SecretField.d.ts +13 -0
- package/dist/types/ui/filters/DateRangeFilter.d.ts +16 -0
- package/dist/types/ui/filters/PeriodRangeSelector.d.ts +28 -0
- package/dist/types/ui/filters/QuickFilters.d.ts +21 -0
- package/dist/types/ui/filters/SegmentedControl.d.ts +44 -0
- package/dist/types/ui/index.d.ts +33 -0
- package/dist/types/ui/labels/DictionaryText.d.ts +7 -0
- package/dist/types/ui/labels/StatusChip.d.ts +21 -0
- package/dist/types/ui/labels/Tag.d.ts +19 -0
- package/dist/types/ui/layout/CollapsibleSection.d.ts +15 -0
- package/dist/types/ui/layout/ContentDialog.d.ts +13 -0
- package/dist/types/ui/layout/DefinitionList.d.ts +15 -0
- package/dist/types/ui/layout/DetailHeader.d.ts +15 -0
- package/dist/types/ui/layout/ErrorPage.d.ts +22 -0
- package/dist/types/ui/layout/FullPageLoader.d.ts +1 -0
- package/dist/types/ui/layout/GlassLensFilter.d.ts +1 -0
- package/dist/types/ui/layout/GlassPanel.d.ts +11 -0
- package/dist/types/ui/layout/PageHeader.d.ts +15 -0
- package/dist/types/ui/layout/PageHeading.d.ts +18 -0
- package/dist/types/ui/layout/ProfileHeader.d.ts +17 -0
- package/dist/types/ui/layout/ScrollableRow.d.ts +33 -0
- package/dist/types/ui/layout/SectionCard.d.ts +11 -0
- package/dist/types/ui/layout/appBarHeight.d.ts +13 -0
- package/dist/types/ui/metrics/BarList.d.ts +19 -0
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +28 -0
- package/dist/types/ui/metrics/ChartTooltip.d.ts +5 -0
- package/dist/types/ui/metrics/ColumnChart.d.ts +35 -0
- package/dist/types/ui/metrics/MetricCard.d.ts +31 -0
- package/dist/types/ui/metrics/TableToggle.d.ts +7 -0
- package/dist/types/ui/metrics/barListLabels.d.ts +17 -0
- package/dist/types/ui/metrics/heatmapScale.d.ts +45 -0
- package/dist/types/ui/navigation/BackButton.d.ts +11 -0
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +7 -0
- package/dist/types/ui/navigation/DocumentTitle.d.ts +6 -0
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -0
- package/dist/types/ui/navigation/LanguageToggle.d.ts +8 -0
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +9 -0
- package/dist/types/ui/navigation/colorMode.d.ts +18 -0
- package/dist/types/ui/navigation/fontSizeLevels.d.ts +25 -0
- package/dist/types/ui/navigation/useFontSize.d.ts +10 -0
- package/dist/types/ui/timeline/GroupedTimeline.d.ts +38 -0
- package/dist/types/ui/timeline/timelineDot.d.ts +19 -0
- package/dist/types/upload/FileDropzone.d.ts +34 -0
- package/dist/types/upload/fileRules.d.ts +51 -0
- package/dist/types/upload/uploadMachine.d.ts +23 -0
- package/dist/types/upload/uploadWithProgress.d.ts +16 -0
- package/dist/ui/actions/CopyButton.js +28 -0
- package/dist/ui/actions/CopyButton.js.map +1 -0
- package/dist/ui/actions/DownloadMenu.js +163 -0
- package/dist/ui/actions/DownloadMenu.js.map +1 -0
- package/dist/ui/actions/SecretField.js +57 -0
- package/dist/ui/actions/SecretField.js.map +1 -0
- package/dist/ui/filters/DateRangeFilter.js +86 -0
- package/dist/ui/filters/DateRangeFilter.js.map +1 -0
- package/dist/ui/filters/PeriodRangeSelector.js +56 -0
- package/dist/ui/filters/PeriodRangeSelector.js.map +1 -0
- package/dist/ui/filters/QuickFilters.js +91 -0
- package/dist/ui/filters/QuickFilters.js.map +1 -0
- package/dist/ui/filters/SegmentedControl.js +80 -0
- package/dist/ui/filters/SegmentedControl.js.map +1 -0
- package/dist/ui/labels/DictionaryText.js +11 -0
- package/dist/ui/labels/DictionaryText.js.map +1 -0
- package/dist/ui/labels/StatusChip.js +52 -0
- package/dist/ui/labels/StatusChip.js.map +1 -0
- package/dist/ui/labels/Tag.js +26 -0
- package/dist/ui/labels/Tag.js.map +1 -0
- package/dist/ui/layout/CollapsibleSection.js +48 -0
- package/dist/ui/layout/CollapsibleSection.js.map +1 -0
- package/dist/ui/layout/ContentDialog.js +97 -0
- package/dist/ui/layout/ContentDialog.js.map +1 -0
- package/dist/ui/layout/DefinitionList.js +30 -0
- package/dist/ui/layout/DefinitionList.js.map +1 -0
- package/dist/ui/layout/DetailHeader.js +27 -0
- package/dist/ui/layout/DetailHeader.js.map +1 -0
- package/dist/ui/layout/ErrorPage.js +40 -0
- package/dist/ui/layout/ErrorPage.js.map +1 -0
- package/dist/ui/layout/FullPageLoader.js +13 -0
- package/dist/ui/layout/FullPageLoader.js.map +1 -0
- package/dist/ui/layout/GlassLensFilter.js +53 -0
- package/dist/ui/layout/GlassLensFilter.js.map +1 -0
- package/dist/ui/layout/GlassPanel.js +18 -0
- package/dist/ui/layout/GlassPanel.js.map +1 -0
- package/dist/ui/layout/PageHeader.js +23 -0
- package/dist/ui/layout/PageHeader.js.map +1 -0
- package/dist/ui/layout/PageHeading.js +51 -0
- package/dist/ui/layout/PageHeading.js.map +1 -0
- package/dist/ui/layout/ProfileHeader.js +64 -0
- package/dist/ui/layout/ProfileHeader.js.map +1 -0
- package/dist/ui/layout/ScrollableRow.js +156 -0
- package/dist/ui/layout/ScrollableRow.js.map +1 -0
- package/dist/ui/layout/SectionCard.js +18 -0
- package/dist/ui/layout/SectionCard.js.map +1 -0
- package/dist/ui/layout/appBarHeight.js +42 -0
- package/dist/ui/layout/appBarHeight.js.map +1 -0
- package/dist/ui/metrics/BarList.js +89 -0
- package/dist/ui/metrics/BarList.js.map +1 -0
- package/dist/ui/metrics/CalendarHeatmap.js +131 -0
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -0
- package/dist/ui/metrics/ChartTooltip.js +16 -0
- package/dist/ui/metrics/ChartTooltip.js.map +1 -0
- package/dist/ui/metrics/ColumnChart.js +110 -0
- package/dist/ui/metrics/ColumnChart.js.map +1 -0
- package/dist/ui/metrics/MetricCard.js +64 -0
- package/dist/ui/metrics/MetricCard.js.map +1 -0
- package/dist/ui/metrics/TableToggle.js +13 -0
- package/dist/ui/metrics/TableToggle.js.map +1 -0
- package/dist/ui/metrics/barListLabels.js +9 -0
- package/dist/ui/metrics/barListLabels.js.map +1 -0
- package/dist/ui/metrics/heatmapScale.js +67 -0
- package/dist/ui/metrics/heatmapScale.js.map +1 -0
- package/dist/ui/navigation/BackButton.js +28 -0
- package/dist/ui/navigation/BackButton.js.map +1 -0
- package/dist/ui/navigation/ColorSchemeToggle.js +37 -0
- package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -0
- package/dist/ui/navigation/DocumentTitle.js +11 -0
- package/dist/ui/navigation/DocumentTitle.js.map +1 -0
- package/dist/ui/navigation/FontSizeToggle.js +40 -0
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -0
- package/dist/ui/navigation/LanguageToggle.js +27 -0
- package/dist/ui/navigation/LanguageToggle.js.map +1 -0
- package/dist/ui/navigation/PageBreadcrumbs.js +51 -0
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -0
- package/dist/ui/navigation/colorMode.js +13 -0
- package/dist/ui/navigation/colorMode.js.map +1 -0
- package/dist/ui/navigation/fontSizeLevels.js +24 -0
- package/dist/ui/navigation/fontSizeLevels.js.map +1 -0
- package/dist/ui/navigation/useFontSize.js +44 -0
- package/dist/ui/navigation/useFontSize.js.map +1 -0
- package/dist/ui/timeline/GroupedTimeline.js +104 -0
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -0
- package/dist/ui/timeline/timelineDot.js +20 -0
- package/dist/ui/timeline/timelineDot.js.map +1 -0
- package/dist/upload/FileDropzone.js +143 -0
- package/dist/upload/FileDropzone.js.map +1 -0
- package/dist/upload/fileRules.js +62 -0
- package/dist/upload/fileRules.js.map +1 -0
- package/dist/upload/uploadMachine.js +73 -0
- package/dist/upload/uploadMachine.js.map +1 -0
- package/dist/upload/uploadWithProgress.js +45 -0
- package/dist/upload/uploadWithProgress.js.map +1 -0
- package/package.json +303 -5
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
4
|
+
import IconButton from "@mui/material/IconButton";
|
|
5
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
6
|
+
import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
|
|
7
|
+
import "react";
|
|
8
|
+
import "@mui/material/Badge";
|
|
9
|
+
import "@mui/material/Box";
|
|
10
|
+
import "@mui/material/Button";
|
|
11
|
+
import "@mui/material/Popover";
|
|
12
|
+
import "@mui/material/Stack";
|
|
13
|
+
import "@mui/icons-material/FilterAlt";
|
|
14
|
+
import "@mui/icons-material/FilterAltOutlined";
|
|
15
|
+
import MultiSelectColumnFilter from "./ColumnFilters/MultiSelectColumnFilter.js";
|
|
16
|
+
import SortableFilterHeader from "./ColumnFilters/SortableFilterHeader.js";
|
|
17
|
+
import TextColumnFilter from "./ColumnFilters/TextColumnFilter.js";
|
|
18
|
+
import { useTableFilter } from "./filterContext.js";
|
|
19
|
+
import { FILTER_KINDS, isFilterActive } from "./useTableState.js";
|
|
20
|
+
function activeCountOf(kind, value) {
|
|
21
|
+
if (!isFilterActive(kind, value)) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
return kind === FILTER_KINDS.multiSelect ? value.length : 1;
|
|
25
|
+
}
|
|
26
|
+
function useColumnHeader(field, kind) {
|
|
27
|
+
const { filters, setFilter, clearFilter, sortOrders, toggleSort, clearSort, facets } = useTableFilter();
|
|
28
|
+
return {
|
|
29
|
+
value: filters[field],
|
|
30
|
+
setValue: (value) => setFilter(field, value),
|
|
31
|
+
onClear: () => clearFilter(field),
|
|
32
|
+
sortEntry: sortOrders.find((sortOrder) => sortOrder.column === field),
|
|
33
|
+
onSort: () => toggleSort(field),
|
|
34
|
+
onClearSort: clearSort,
|
|
35
|
+
activeCount: activeCountOf(kind, filters[field]),
|
|
36
|
+
facets
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function TextHeader({ field, label, sort, filter }) {
|
|
40
|
+
const header = useColumnHeader(field, FILTER_KINDS.text);
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
SortableFilterHeader,
|
|
43
|
+
{
|
|
44
|
+
label,
|
|
45
|
+
sortable: sort,
|
|
46
|
+
filterable: filter,
|
|
47
|
+
sortEntry: header.sortEntry,
|
|
48
|
+
onSort: header.onSort,
|
|
49
|
+
onClearSort: header.onClearSort,
|
|
50
|
+
activeCount: header.activeCount,
|
|
51
|
+
onClear: header.onClear,
|
|
52
|
+
children: /* @__PURE__ */ jsx(TextColumnFilter, { value: header.value ?? "", onChange: header.setValue })
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function FacetHeader({ field, label, facetKey, renderOption, sort }) {
|
|
57
|
+
const header = useColumnHeader(field, FILTER_KINDS.multiSelect);
|
|
58
|
+
return /* @__PURE__ */ jsx(
|
|
59
|
+
SortableFilterHeader,
|
|
60
|
+
{
|
|
61
|
+
label,
|
|
62
|
+
sortable: sort,
|
|
63
|
+
sortEntry: header.sortEntry,
|
|
64
|
+
onSort: header.onSort,
|
|
65
|
+
onClearSort: header.onClearSort,
|
|
66
|
+
activeCount: header.activeCount,
|
|
67
|
+
onClear: header.onClear,
|
|
68
|
+
children: /* @__PURE__ */ jsx(
|
|
69
|
+
MultiSelectColumnFilter,
|
|
70
|
+
{
|
|
71
|
+
value: header.value ?? [],
|
|
72
|
+
onChange: header.setValue,
|
|
73
|
+
options: header.facets[facetKey] ?? [],
|
|
74
|
+
renderOption
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function textColumn({ field, label, sort = true, filter = true, ...gridColumnProps }) {
|
|
81
|
+
return {
|
|
82
|
+
field,
|
|
83
|
+
headerName: label,
|
|
84
|
+
sortable: false,
|
|
85
|
+
filterable: false,
|
|
86
|
+
...gridColumnProps,
|
|
87
|
+
renderHeader: () => /* @__PURE__ */ jsx(TextHeader, { field, label, sort, filter })
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function facetColumn({ field, label, facetKey, renderOption, sort = true, ...gridColumnProps }) {
|
|
91
|
+
return {
|
|
92
|
+
field,
|
|
93
|
+
headerName: label,
|
|
94
|
+
sortable: false,
|
|
95
|
+
filterable: false,
|
|
96
|
+
...gridColumnProps,
|
|
97
|
+
renderHeader: () => /* @__PURE__ */ jsx(FacetHeader, { field, label, facetKey: facetKey ?? field, renderOption, sort })
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function DetailCell({ row, onOpen, ariaLabelOf }) {
|
|
101
|
+
const { t } = useToolkitTranslation("table");
|
|
102
|
+
const ariaLabel = ariaLabelOf?.(row) ?? t("detail.ariaLabel");
|
|
103
|
+
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" }) }) });
|
|
104
|
+
}
|
|
105
|
+
function detailColumn({ onOpen, ariaLabelOf }) {
|
|
106
|
+
return {
|
|
107
|
+
field: "__detail",
|
|
108
|
+
headerName: "",
|
|
109
|
+
sortable: false,
|
|
110
|
+
filterable: false,
|
|
111
|
+
disableColumnMenu: true,
|
|
112
|
+
width: 64,
|
|
113
|
+
align: "center",
|
|
114
|
+
renderCell: ({ row }) => /* @__PURE__ */ jsx(DetailCell, { row, onOpen, ariaLabelOf })
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
detailColumn,
|
|
119
|
+
facetColumn,
|
|
120
|
+
textColumn
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=columns.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;AAmBA,SAAS,cAAc,MAAM,OAAO;AAChC,MAAI,CAAC,eAAe,MAAM,KAAK,GAAG;AAC9B,WAAO;AAAA,EACX;AACA,SAAO,SAAS,aAAa,cAAc,MAAM,SAAS;AAC9D;AAGA,SAAS,gBAAgB,OAAO,MAAM;AAClC,QAAM,EAAC,SAAS,WAAW,aAAa,YAAY,YAAY,WAAW,OAAA,IAAU,eAAA;AAErF,SAAO;AAAA,IACH,OAAO,QAAQ,KAAK;AAAA,IACpB,UAAU,CAAC,UAAU,UAAU,OAAO,KAAK;AAAA,IAC3C,SAAS,MAAM,YAAY,KAAK;AAAA,IAChC,WAAW,WAAW,KAAK,CAAC,cAAc,UAAU,WAAW,KAAK;AAAA,IACpE,QAAQ,MAAM,WAAW,KAAK;AAAA,IAC9B,aAAa;AAAA,IACb,aAAa,cAAc,MAAM,QAAQ,KAAK,CAAC;AAAA,IAC/C;AAAA,EAAA;AAER;AAEA,SAAS,WAAW,EAAC,OAAO,OAAO,MAAM,UAAS;AAC9C,QAAM,SAAS,gBAAgB,OAAO,aAAa,IAAI;AAEvD,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAqB;AAAA,MAAc,UAAU;AAAA,MAAM,YAAY;AAAA,MAAQ,WAAW,OAAO;AAAA,MACpE,QAAQ,OAAO;AAAA,MAAQ,aAAa,OAAO;AAAA,MAAa,aAAa,OAAO;AAAA,MAC5E,SAAS,OAAO;AAAA,MAClC,UAAA,oBAAC,oBAAiB,OAAO,OAAO,SAAS,IAAI,UAAU,OAAO,SAAA,CAAU;AAAA,IAAA;AAAA,EAAA;AAGpF;AAEA,SAAS,YAAY,EAAC,OAAO,OAAO,UAAU,cAAc,QAAO;AAC/D,QAAM,SAAS,gBAAgB,OAAO,aAAa,WAAW;AAE9D,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAqB;AAAA,MAAc,UAAU;AAAA,MAAM,WAAW,OAAO;AAAA,MAAW,QAAQ,OAAO;AAAA,MAC1E,aAAa,OAAO;AAAA,MAAa,aAAa,OAAO;AAAA,MAAa,SAAS,OAAO;AAAA,MACpG,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UAAwB,OAAO,OAAO,SAAS,CAAA;AAAA,UAAI,UAAU,OAAO;AAAA,UAC5C,SAAS,OAAO,OAAO,QAAQ,KAAK,CAAA;AAAA,UAAI;AAAA,QAAA;AAAA,MAAA;AAAA,IAA4B;AAAA,EAAA;AAGzG;AAgBO,SAAS,WAAW,EAAC,OAAO,OAAO,OAAO,MAAM,SAAS,MAAM,GAAG,mBAAkB;AACvF,SAAO;AAAA,IACH;AAAA,IACA,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,GAAG;AAAA,IACH,cAAc,MAAM,oBAAC,cAAW,OAAc,OAAc,MAAY,OAAA,CAAgB;AAAA,EAAA;AAEhG;AAOO,SAAS,YAAY,EAAC,OAAO,OAAO,UAAU,cAAc,OAAO,MAAM,GAAG,mBAAkB;AACjG,SAAO;AAAA,IACH;AAAA,IACA,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,GAAG;AAAA,IACH,cAAc,MACV,oBAAC,aAAA,EAAY,OAAc,OAAc,UAAU,YAAY,OAAO,cAA4B,KAAA,CAAY;AAAA,EAAA;AAG1H;AAEA,SAAS,WAAW,EAAC,KAAK,QAAQ,eAAc;AAC5C,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,YAAY,cAAc,GAAG,KAAK,EAAE,kBAAkB;AAE5D,SACI,oBAAC,WAAQ,OAAO,EAAE,gBAAgB,GAC9B,UAAA,oBAAC,YAAA,EAAW,MAAK,SAAQ,cAAY,WAAW,SAAS,MAAM,OAAO,GAAG,GACrE,8BAAC,wBAAA,EAAuB,UAAS,SAAQ,EAAA,CAC7C,EAAA,CACJ;AAER;AAQO,SAAS,aAAa,EAAC,QAAQ,eAAc;AAChD,SAAO;AAAA,IACH,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,YAAY,CAAC,EAAC,UAAS,oBAAC,YAAA,EAAW,KAAU,QAAgB,YAAA,CAA0B;AAAA,EAAA;AAE/F;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
const TableFilterContext = createContext(null);
|
|
4
|
+
function useTableFilter() {
|
|
5
|
+
const tableFilterValue = useContext(TableFilterContext);
|
|
6
|
+
if (!tableFilterValue) {
|
|
7
|
+
throw new Error("Un encabezado de columna se montó fuera de <ServerTable>.");
|
|
8
|
+
}
|
|
9
|
+
return tableFilterValue;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
TableFilterContext,
|
|
13
|
+
useTableFilter
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=filterContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterContext.js","sources":["../../src/DataTable/filterContext.js"],"sourcesContent":["// Contexto que comparten los encabezados de columna con la tabla.\n//\n// Existe para que renderHeader de cada columna no reciba media docena de props: el encabezado pide lo que necesita\n// (el filtro de SU campo, el orden y las facetas del servidor) y la tabla no se entera.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createContext, useContext} from 'react';\n\nexport const TableFilterContext = createContext(null);\n\n/**\n * @returns {{filters: object, setFilter: Function, clearFilter: Function, sortOrders: Array, toggleSort: Function, clearSort: Function, facets: object}}\n */\nexport function useTableFilter() {\n const tableFilterValue = useContext(TableFilterContext);\n if (!tableFilterValue) {\n // mejor tronar aquí que pintar un encabezado muerto que no filtra y nadie entiende por qué\n throw new Error('Un encabezado de columna se montó fuera de <ServerTable>.');\n }\n return tableFilterValue;\n}\n"],"names":[],"mappings":";;AAQY,MAAC,qBAAqB,cAAc,IAAI;AAK7C,SAAS,iBAAiB;AAC7B,QAAM,mBAAmB,WAAW,kBAAkB;AACtD,MAAI,CAAC,kBAAkB;AAEnB,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC/E;AACA,SAAO;AACX;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function toServerTableParams({ filters = {}, sortOrders = [], page, pageSize }, { parameterNames = {} } = {}) {
|
|
2
|
+
const params = { page: page + 1, page_size: pageSize };
|
|
3
|
+
if (sortOrders.length > 0) {
|
|
4
|
+
params.sort = sortOrders[0].column;
|
|
5
|
+
params.direction = sortOrders[0].direction;
|
|
6
|
+
}
|
|
7
|
+
for (const [field, value] of Object.entries(filters)) {
|
|
8
|
+
const isEmpty = value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0;
|
|
9
|
+
if (isEmpty) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
params[parameterNames[field] ?? field] = value;
|
|
13
|
+
}
|
|
14
|
+
return params;
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
toServerTableParams
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=serverTableParams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverTableParams.js","sources":["../../src/DataTable/serverTableParams.js"],"sourcesContent":["// Traductor del estado de ServerTable a la query del backend (contrato ServerTable del API).\n//\n// {filters, sortOrders, page, pageSize} → {page, page_size, sort, direction, <filtro>: valor}\n//\n// Lo que se decide aquí y no en cada pantalla:\n// - page: la tabla cuenta desde 0 (DataGrid) y el API desde 1;\n// - un filtro vacío ('' o []) NO viaja: el backend lo leería como \"filtrar por vacío\";\n// - un filtro múltiple viaja como arreglo; axios lo serializa como status[]=a&status[]=b, que es lo que valida Laravel.\n//\n// Pura: sin imports; se prueba con node --test (serverTableParams.test.js).\n\n/**\n * @param {{filters?: object, sortOrders?: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}} tableRequest\n * @param {{parameterNames?: Record<string, string>}} [options] campo de la tabla → nombre del parámetro en el API\n * @returns {Record<string, unknown>} params para getInfo\n */\nexport function toServerTableParams({filters = {}, sortOrders = [], page, pageSize}, {parameterNames = {}} = {}) {\n const params = {page: page + 1, page_size: pageSize};\n\n if (sortOrders.length > 0) {\n params.sort = sortOrders[0].column;\n params.direction = sortOrders[0].direction;\n }\n\n for (const [field, value] of Object.entries(filters)) {\n const isEmpty = value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0);\n // guard clause: un filtro sin valor no se manda\n if (isEmpty) {\n continue;\n }\n params[parameterNames[field] ?? field] = value;\n }\n\n return params;\n}\n"],"names":[],"mappings":"AAgBO,SAAS,oBAAoB,EAAC,UAAU,CAAA,GAAI,aAAa,CAAA,GAAI,MAAM,SAAQ,GAAG,EAAC,iBAAiB,CAAA,EAAE,IAAI,CAAA,GAAI;AAC7G,QAAM,SAAS,EAAC,MAAM,OAAO,GAAG,WAAW,SAAQ;AAEnD,MAAI,WAAW,SAAS,GAAG;AACvB,WAAO,OAAO,WAAW,CAAC,EAAE;AAC5B,WAAO,YAAY,WAAW,CAAC,EAAE;AAAA,EACrC;AAEA,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAM,UAAU,UAAU,QAAQ,UAAU,UAAa,UAAU,MAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAEnH,QAAI,SAAS;AACT;AAAA,IACJ;AACA,WAAO,eAAe,KAAK,KAAK,KAAK,IAAI;AAAA,EAC7C;AAEA,SAAO;AACX;"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { assign, setup, fromPromise } from "xstate";
|
|
2
|
+
function isCancellation(error) {
|
|
3
|
+
return error?.name === "AbortError" || error?.name === "CanceledError" || error?.code === "ERR_CANCELED";
|
|
4
|
+
}
|
|
5
|
+
const startNewRequest = assign({
|
|
6
|
+
error: null,
|
|
7
|
+
requestId: ({ context }) => context.requestId + 1
|
|
8
|
+
});
|
|
9
|
+
const tableMachine = setup({
|
|
10
|
+
actors: {
|
|
11
|
+
// lo reemplaza buildTableActors; si alguien olvida proveerlo, que truene con un mensaje claro
|
|
12
|
+
fetchPage: fromPromise(async () => {
|
|
13
|
+
throw new Error("tableMachine: falta proveer fetchPage con buildTableActors().");
|
|
14
|
+
})
|
|
15
|
+
},
|
|
16
|
+
guards: {
|
|
17
|
+
isStaleResponse: ({ context, event }) => event.output.requestId !== context.requestId,
|
|
18
|
+
isCancellation: ({ event }) => isCancellation(event.error)
|
|
19
|
+
}
|
|
20
|
+
}).createMachine({
|
|
21
|
+
id: "table",
|
|
22
|
+
initial: "idle",
|
|
23
|
+
context: {
|
|
24
|
+
rows: [],
|
|
25
|
+
total: 0,
|
|
26
|
+
facets: {},
|
|
27
|
+
capped: false,
|
|
28
|
+
// el error tal cual (normalmente un ApiError con el mensaje ya traducido)
|
|
29
|
+
error: null,
|
|
30
|
+
// se incrementa en cada FETCH: identifica cuál es la consulta vigente
|
|
31
|
+
requestId: 0
|
|
32
|
+
},
|
|
33
|
+
states: {
|
|
34
|
+
// nadie ha pedido nada todavía
|
|
35
|
+
idle: {
|
|
36
|
+
on: { FETCH: { target: "loading", actions: startNewRequest } }
|
|
37
|
+
},
|
|
38
|
+
loading: {
|
|
39
|
+
invoke: {
|
|
40
|
+
src: "fetchPage",
|
|
41
|
+
// las acciones de la transición corren ANTES de entrar al estado: aquí el requestId ya es el nuevo
|
|
42
|
+
input: ({ context, event }) => ({ ...event.params, requestId: context.requestId }),
|
|
43
|
+
onDone: [
|
|
44
|
+
// respuesta de una consulta que ya no es la vigente: se tira en silencio (es una carrera)
|
|
45
|
+
{ guard: "isStaleResponse" },
|
|
46
|
+
{
|
|
47
|
+
target: "ready",
|
|
48
|
+
actions: assign({
|
|
49
|
+
rows: ({ event }) => event.output.rows ?? [],
|
|
50
|
+
total: ({ event }) => event.output.total ?? 0,
|
|
51
|
+
capped: ({ event }) => event.output.capped ?? false,
|
|
52
|
+
// si la respuesta no trae facetas (páginas 2 en adelante) se conservan las que había
|
|
53
|
+
facets: ({ context, event }) => Object.keys(event.output.facets ?? {}).length ? event.output.facets : context.facets,
|
|
54
|
+
error: null
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
onError: [
|
|
59
|
+
{ guard: "isCancellation" },
|
|
60
|
+
{ target: "error", actions: assign({ error: ({ event }) => event.error }) }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
on: { FETCH: { target: "loading", reenter: true, actions: startNewRequest } }
|
|
64
|
+
},
|
|
65
|
+
ready: {
|
|
66
|
+
on: { FETCH: { target: "loading", actions: startNewRequest } }
|
|
67
|
+
},
|
|
68
|
+
error: {
|
|
69
|
+
on: { FETCH: { target: "loading", actions: startNewRequest } }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
function buildTableActors(fetchPage) {
|
|
74
|
+
return {
|
|
75
|
+
fetchPage: fromPromise(async ({ input, signal }) => {
|
|
76
|
+
const { requestId, ...params } = input;
|
|
77
|
+
const tablePage = await fetchPage(params, signal);
|
|
78
|
+
return { ...tablePage, requestId };
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
buildTableActors,
|
|
84
|
+
isCancellation,
|
|
85
|
+
tableMachine
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=tableMachine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tableMachine.js","sources":["../../src/DataTable/tableMachine.js"],"sourcesContent":["// Máquina de la tabla de servidor: el ciclo de vida de la petición, y nada más.\n//\n// Reparto de responsabilidades, a propósito:\n// la URL (nuqs) es la fuente de verdad de filtros, orden y página;\n// esta máquina es la fuente de verdad de \"¿está cargando?, ¿qué trajo?\".\n// Tener los filtros en los dos lados es lo que produce pantallas donde la tabla dice una cosa y la URL otra.\n//\n// idle ──FETCH──▶ loading ──onDone──▶ ready\n// │ ▲ │\n// │ └──── FETCH ─────┤ (reenter: aborta la petición anterior)\n// └──onError──▶ error ┘\n//\n// IMPORTANTE: abortar es una PETICIÓN al navegador, no una garantía; una respuesta que ya venía en camino puede\n// resolverse igual. Por eso cada consulta lleva un requestId y se descarta todo lo que no sea la última: sin eso se\n// ven filas de dos filtros distintos mezcladas.\n//\n// Pura: solo importa xstate. La petición la pone quien la usa con buildTableActors(fetchPage). Prueba en\n// tableMachine.test.js (node --test).\nimport {assign, fromPromise, setup} from 'xstate';\n\n/**\n * ¿El error es una cancelación (axios o fetch)? Cancelar una consulta que ya no interesa no es un error que mostrar.\n *\n * @param {unknown} error\n * @returns {boolean}\n */\nexport function isCancellation(error) {\n return error?.name === 'AbortError' || error?.name === 'CanceledError' || error?.code === 'ERR_CANCELED';\n}\n\nconst startNewRequest = assign({\n error: null,\n requestId: ({context}) => context.requestId + 1,\n});\n\nexport const tableMachine = setup({\n actors: {\n // lo reemplaza buildTableActors; si alguien olvida proveerlo, que truene con un mensaje claro\n fetchPage: fromPromise(async () => {\n throw new Error('tableMachine: falta proveer fetchPage con buildTableActors().');\n }),\n },\n guards: {\n isStaleResponse: ({context, event}) => event.output.requestId !== context.requestId,\n isCancellation: ({event}) => isCancellation(event.error),\n },\n}).createMachine({\n id: 'table',\n initial: 'idle',\n context: {\n rows: [],\n total: 0,\n facets: {},\n capped: false,\n // el error tal cual (normalmente un ApiError con el mensaje ya traducido)\n error: null,\n // se incrementa en cada FETCH: identifica cuál es la consulta vigente\n requestId: 0,\n },\n states: {\n // nadie ha pedido nada todavía\n idle: {\n on: {FETCH: {target: 'loading', actions: startNewRequest}},\n },\n loading: {\n invoke: {\n src: 'fetchPage',\n // las acciones de la transición corren ANTES de entrar al estado: aquí el requestId ya es el nuevo\n input: ({context, event}) => ({...event.params, requestId: context.requestId}),\n onDone: [\n // respuesta de una consulta que ya no es la vigente: se tira en silencio (es una carrera)\n {guard: 'isStaleResponse'},\n {\n target: 'ready',\n actions: assign({\n rows: ({event}) => event.output.rows ?? [],\n total: ({event}) => event.output.total ?? 0,\n capped: ({event}) => event.output.capped ?? false,\n // si la respuesta no trae facetas (páginas 2 en adelante) se conservan las que había\n facets: ({context, event}) => (Object.keys(event.output.facets ?? {}).length\n ? event.output.facets\n : context.facets),\n error: null,\n }),\n },\n ],\n onError: [\n {guard: 'isCancellation'},\n {target: 'error', actions: assign({error: ({event}) => event.error})},\n ],\n },\n on: {FETCH: {target: 'loading', reenter: true, actions: startNewRequest}},\n },\n ready: {\n on: {FETCH: {target: 'loading', actions: startNewRequest}},\n },\n error: {\n on: {FETCH: {target: 'loading', actions: startNewRequest}},\n },\n },\n});\n\n/**\n * El actor fetchPage a partir de la función de la pantalla.\n *\n * @param {(params: {filters: object, sortOrders: Array, page: number, pageSize: number}, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object, capped?: boolean}>} fetchPage\n */\nexport function buildTableActors(fetchPage) {\n return {\n fetchPage: fromPromise(async ({input, signal}) => {\n const {requestId, ...params} = input;\n const tablePage = await fetchPage(params, signal);\n // el id viaja de vuelta con la respuesta: así se sabe si sigue siendo la consulta vigente\n return {...tablePage, requestId};\n }),\n };\n}\n"],"names":[],"mappings":";AA0BO,SAAS,eAAe,OAAO;AAClC,SAAO,OAAO,SAAS,gBAAgB,OAAO,SAAS,mBAAmB,OAAO,SAAS;AAC9F;AAEA,MAAM,kBAAkB,OAAO;AAAA,EAC3B,OAAO;AAAA,EACP,WAAW,CAAC,EAAC,QAAO,MAAM,QAAQ,YAAY;AAClD,CAAC;AAEW,MAAC,eAAe,MAAM;AAAA,EAC9B,QAAQ;AAAA;AAAA,IAEJ,WAAW,YAAY,YAAY;AAC/B,YAAM,IAAI,MAAM,+DAA+D;AAAA,IACnF,CAAC;AAAA,EACT;AAAA,EACI,QAAQ;AAAA,IACJ,iBAAiB,CAAC,EAAC,SAAS,MAAK,MAAM,MAAM,OAAO,cAAc,QAAQ;AAAA,IAC1E,gBAAgB,CAAC,EAAC,MAAK,MAAM,eAAe,MAAM,KAAK;AAAA,EAC/D;AACA,CAAC,EAAE,cAAc;AAAA,EACb,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS;AAAA,IACL,MAAM,CAAA;AAAA,IACN,OAAO;AAAA,IACP,QAAQ,CAAA;AAAA,IACR,QAAQ;AAAA;AAAA,IAER,OAAO;AAAA;AAAA,IAEP,WAAW;AAAA,EACnB;AAAA,EACI,QAAQ;AAAA;AAAA,IAEJ,MAAM;AAAA,MACF,IAAI,EAAC,OAAO,EAAC,QAAQ,WAAW,SAAS,gBAAe,EAAC;AAAA,IACrE;AAAA,IACQ,SAAS;AAAA,MACL,QAAQ;AAAA,QACJ,KAAK;AAAA;AAAA,QAEL,OAAO,CAAC,EAAC,SAAS,MAAK,OAAO,EAAC,GAAG,MAAM,QAAQ,WAAW,QAAQ,UAAS;AAAA,QAC5E,QAAQ;AAAA;AAAA,UAEJ,EAAC,OAAO,kBAAiB;AAAA,UACzB;AAAA,YACI,QAAQ;AAAA,YACR,SAAS,OAAO;AAAA,cACZ,MAAM,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,QAAQ,CAAA;AAAA,cACxC,OAAO,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,SAAS;AAAA,cAC1C,QAAQ,CAAC,EAAC,MAAK,MAAM,MAAM,OAAO,UAAU;AAAA;AAAA,cAE5C,QAAQ,CAAC,EAAC,SAAS,MAAK,MAAO,OAAO,KAAK,MAAM,OAAO,UAAU,CAAA,CAAE,EAAE,SAChE,MAAM,OAAO,SACb,QAAQ;AAAA,cACd,OAAO;AAAA,YACnC,CAAyB;AAAA,UACzB;AAAA,QACA;AAAA,QACgB,SAAS;AAAA,UACL,EAAC,OAAO,iBAAgB;AAAA,UACxB,EAAC,QAAQ,SAAS,SAAS,OAAO,EAAC,OAAO,CAAC,EAAC,MAAK,MAAM,MAAM,MAAK,CAAC,EAAC;AAAA,QACxF;AAAA,MACA;AAAA,MACY,IAAI,EAAC,OAAO,EAAC,QAAQ,WAAW,SAAS,MAAM,SAAS,gBAAe,EAAC;AAAA,IACpF;AAAA,IACQ,OAAO;AAAA,MACH,IAAI,EAAC,OAAO,EAAC,QAAQ,WAAW,SAAS,gBAAe,EAAC;AAAA,IACrE;AAAA,IACQ,OAAO;AAAA,MACH,IAAI,EAAC,OAAO,EAAC,QAAQ,WAAW,SAAS,gBAAe,EAAC;AAAA,IACrE;AAAA,EACA;AACA,CAAC;AAOM,SAAS,iBAAiB,WAAW;AACxC,SAAO;AAAA,IACH,WAAW,YAAY,OAAO,EAAC,OAAO,OAAM,MAAM;AAC9C,YAAM,EAAC,WAAW,GAAG,OAAM,IAAI;AAC/B,YAAM,YAAY,MAAM,UAAU,QAAQ,MAAM;AAEhD,aAAO,EAAC,GAAG,WAAW,UAAS;AAAA,IACnC,CAAC;AAAA,EACT;AACA;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useRef, useEffect } from "react";
|
|
3
|
+
const DEFAULT_DEBOUNCE_MILLISECONDS = 350;
|
|
4
|
+
function useDebouncedFilter(value, commit, delayMilliseconds = DEFAULT_DEBOUNCE_MILLISECONDS) {
|
|
5
|
+
const [draft, setDraft] = useState(value ?? "");
|
|
6
|
+
const committedValue = useRef(value ?? "");
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (value !== committedValue.current) {
|
|
9
|
+
committedValue.current = value ?? "";
|
|
10
|
+
setDraft(value ?? "");
|
|
11
|
+
}
|
|
12
|
+
}, [value]);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (draft === committedValue.current) {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
const timer = setTimeout(() => {
|
|
18
|
+
committedValue.current = draft;
|
|
19
|
+
commit(draft);
|
|
20
|
+
}, delayMilliseconds);
|
|
21
|
+
return () => clearTimeout(timer);
|
|
22
|
+
}, [draft, delayMilliseconds]);
|
|
23
|
+
return [draft, setDraft];
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
DEFAULT_DEBOUNCE_MILLISECONDS,
|
|
27
|
+
useDebouncedFilter
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=useDebouncedFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDebouncedFilter.js","sources":["../../src/DataTable/useDebouncedFilter.js"],"sourcesContent":["// Rebote para las cajas de texto que filtran en el servidor.\n//\n// Sin esto, cada tecla dispara una consulta: escribir \"VIDA\" son cuatro consultas de las que tres nacen muertas, y\n// con respuestas de medio segundo las carreras entre ellas se ven. El valor que se TECLEA es inmediato (la caja nunca\n// se siente lenta); el que viaja al servidor espera a que la persona deje de escribir.\n//\n// Hook genérico, no renderiza: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\n\nexport const DEFAULT_DEBOUNCE_MILLISECONDS = 350;\n\n/**\n * @param {string|undefined} value valor confirmado (el de la URL)\n * @param {(value: string) => void} commit se llama con el valor ya rebotado\n * @param {number} [delayMilliseconds]\n * @returns {[string, (value: string) => void]} borrador que pinta la caja y su setter\n */\nexport function useDebouncedFilter(value, commit, delayMilliseconds = DEFAULT_DEBOUNCE_MILLISECONDS) {\n const [draft, setDraft] = useState(value ?? '');\n const committedValue = useRef(value ?? '');\n\n // cambios que vienen de FUERA (la URL, \"Limpiar todo\") se reflejan en la caja sin dispararla de vuelta\n useEffect(() => {\n if (value !== committedValue.current) {\n committedValue.current = value ?? '';\n setDraft(value ?? '');\n }\n }, [value]);\n\n useEffect(() => {\n // guard clause: nada nuevo que mandar\n if (draft === committedValue.current) {\n return undefined;\n }\n const timer = setTimeout(() => {\n committedValue.current = draft;\n commit(draft);\n }, delayMilliseconds);\n return () => clearTimeout(timer);\n // OJO: commit fuera de las dependencias a propósito; suele ser una función nueva en cada render\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [draft, delayMilliseconds]);\n\n return [draft, setDraft];\n}\n"],"names":[],"mappings":";;AASY,MAAC,gCAAgC;AAQtC,SAAS,mBAAmB,OAAO,QAAQ,oBAAoB,+BAA+B;AACjG,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,SAAS,EAAE;AAC9C,QAAM,iBAAiB,OAAO,SAAS,EAAE;AAGzC,YAAU,MAAM;AACZ,QAAI,UAAU,eAAe,SAAS;AAClC,qBAAe,UAAU,SAAS;AAClC,eAAS,SAAS,EAAE;AAAA,IACxB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AAEZ,QAAI,UAAU,eAAe,SAAS;AAClC,aAAO;AAAA,IACX;AACA,UAAM,QAAQ,WAAW,MAAM;AAC3B,qBAAe,UAAU;AACzB,aAAO,KAAK;AAAA,IAChB,GAAG,iBAAiB;AACpB,WAAO,MAAM,aAAa,KAAK;AAAA,EAGnC,GAAG,CAAC,OAAO,iBAAiB,CAAC;AAE7B,SAAO,CAAC,OAAO,QAAQ;AAC3B;"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { parseAsString, parseAsInteger, useQueryStates, parseAsArrayOf } from "nuqs";
|
|
4
|
+
const FILTER_KINDS = Object.freeze({
|
|
5
|
+
text: "text",
|
|
6
|
+
multiSelect: "multiSelect"
|
|
7
|
+
});
|
|
8
|
+
const SORT_SEPARATOR = ":";
|
|
9
|
+
const DEFAULT_PAGE_SIZE = 25;
|
|
10
|
+
function isFilterActive(kind, value) {
|
|
11
|
+
if (value === null || value === void 0) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (kind === FILTER_KINDS.multiSelect) {
|
|
15
|
+
return value.length > 0;
|
|
16
|
+
}
|
|
17
|
+
return value !== "";
|
|
18
|
+
}
|
|
19
|
+
function parserFor(kind, defaultValue) {
|
|
20
|
+
if (kind === FILTER_KINDS.multiSelect) {
|
|
21
|
+
return parseAsArrayOf(parseAsString).withDefault(defaultValue);
|
|
22
|
+
}
|
|
23
|
+
return parseAsString.withDefault(defaultValue);
|
|
24
|
+
}
|
|
25
|
+
function parseSortValue(sortValue) {
|
|
26
|
+
if (!sortValue) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const [column, direction] = sortValue.split(SORT_SEPARATOR);
|
|
30
|
+
return column ? [{ column, direction: direction === "asc" ? "asc" : "desc" }] : [];
|
|
31
|
+
}
|
|
32
|
+
function serializeSortOrders(sortOrders) {
|
|
33
|
+
return sortOrders.length ? `${sortOrders[0].column}${SORT_SEPARATOR}${sortOrders[0].direction}` : "";
|
|
34
|
+
}
|
|
35
|
+
function filtersForDatasetSwitch(filterDefaults, values) {
|
|
36
|
+
return { ...filterDefaults, ...values };
|
|
37
|
+
}
|
|
38
|
+
function useUrlTableState(prefix, filterDefaults, filterKinds, defaultPageSize) {
|
|
39
|
+
const parsers = useMemo(() => Object.fromEntries([
|
|
40
|
+
...Object.entries(filterDefaults).map(([field, defaultValue]) => [field, parserFor(filterKinds[field], defaultValue)]),
|
|
41
|
+
["sort", parseAsString.withDefault("")],
|
|
42
|
+
["page", parseAsInteger.withDefault(0)],
|
|
43
|
+
["pageSize", parseAsInteger.withDefault(defaultPageSize)]
|
|
44
|
+
]), [filterDefaults, filterKinds, defaultPageSize]);
|
|
45
|
+
const [urlState, setUrlState] = useQueryStates(parsers, {
|
|
46
|
+
urlKeys: Object.fromEntries(Object.keys(parsers).map((key) => [key, `${prefix}_${key}`])),
|
|
47
|
+
// replace: filtrar no llena el historial de entradas intermedias; el Atrás del detalle regresa a la lista
|
|
48
|
+
history: "replace",
|
|
49
|
+
// lo que vale su default no se escribe en la URL
|
|
50
|
+
clearOnDefault: true
|
|
51
|
+
});
|
|
52
|
+
const filters = useMemo(
|
|
53
|
+
() => Object.fromEntries(Object.keys(filterDefaults).map((field) => [field, urlState[field]])),
|
|
54
|
+
[urlState, filterDefaults]
|
|
55
|
+
);
|
|
56
|
+
const sortOrders = useMemo(() => parseSortValue(urlState.sort), [urlState.sort]);
|
|
57
|
+
return {
|
|
58
|
+
filters,
|
|
59
|
+
sortOrders,
|
|
60
|
+
page: urlState.page,
|
|
61
|
+
pageSize: urlState.pageSize,
|
|
62
|
+
// IMPORTANTE: filtrar SIEMPRE regresa a la página 0; quedarse en la 3 de un resultado que ahora tiene una
|
|
63
|
+
// sola página deja la tabla vacía y parece que el filtro no encontró nada
|
|
64
|
+
setFilter: (field, value) => setUrlState({ [field]: value, page: 0 }),
|
|
65
|
+
// varios en UNA escritura: en dos, la tabla consultaría una vez con la mitad del cambio
|
|
66
|
+
setFilters: (values) => setUrlState({ ...values, page: 0 }),
|
|
67
|
+
clearFilter: (field) => setUrlState({ [field]: filterDefaults[field], page: 0 }),
|
|
68
|
+
clearAll: () => setUrlState({ ...filterDefaults, page: 0 }),
|
|
69
|
+
setSort: (orders) => setUrlState({ sort: serializeSortOrders(orders), page: 0 }),
|
|
70
|
+
// cambio de conjunto (otro producto): filtros, orden y página a su default en UNA escritura; el tamaño de
|
|
71
|
+
// página se respeta porque es preferencia de quien mira, no del conjunto
|
|
72
|
+
switchDataset: (values) => setUrlState({ ...filtersForDatasetSwitch(filterDefaults, values), sort: "", page: 0 }),
|
|
73
|
+
setPage: (page) => setUrlState({ page }),
|
|
74
|
+
setPageSize: (pageSize) => setUrlState({ pageSize, page: 0 })
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function useLocalTableState(filterDefaults, defaultPageSize) {
|
|
78
|
+
const [filters, setFilters] = useState(filterDefaults);
|
|
79
|
+
const [sortOrders, setSortOrders] = useState([]);
|
|
80
|
+
const [page, setPage] = useState(0);
|
|
81
|
+
const [pageSize, setPageSize] = useState(defaultPageSize);
|
|
82
|
+
return {
|
|
83
|
+
filters,
|
|
84
|
+
sortOrders,
|
|
85
|
+
page,
|
|
86
|
+
pageSize,
|
|
87
|
+
setFilter: (field, value) => {
|
|
88
|
+
setFilters((currentFilters) => ({ ...currentFilters, [field]: value }));
|
|
89
|
+
setPage(0);
|
|
90
|
+
},
|
|
91
|
+
setFilters: (values) => {
|
|
92
|
+
setFilters((currentFilters) => ({ ...currentFilters, ...values }));
|
|
93
|
+
setPage(0);
|
|
94
|
+
},
|
|
95
|
+
clearFilter: (field) => {
|
|
96
|
+
setFilters((currentFilters) => ({ ...currentFilters, [field]: filterDefaults[field] }));
|
|
97
|
+
setPage(0);
|
|
98
|
+
},
|
|
99
|
+
clearAll: () => {
|
|
100
|
+
setFilters(filterDefaults);
|
|
101
|
+
setPage(0);
|
|
102
|
+
},
|
|
103
|
+
setSort: (orders) => {
|
|
104
|
+
setSortOrders(orders);
|
|
105
|
+
setPage(0);
|
|
106
|
+
},
|
|
107
|
+
switchDataset: (values) => {
|
|
108
|
+
setFilters(filtersForDatasetSwitch(filterDefaults, values));
|
|
109
|
+
setSortOrders([]);
|
|
110
|
+
setPage(0);
|
|
111
|
+
},
|
|
112
|
+
setPage,
|
|
113
|
+
setPageSize: (nextPageSize) => {
|
|
114
|
+
setPageSize(nextPageSize);
|
|
115
|
+
setPage(0);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function useTableState({ prefix, filterDefaults = {}, filterKinds = {}, defaultPageSize = DEFAULT_PAGE_SIZE }) {
|
|
120
|
+
const urlTableState = useUrlTableState(prefix ?? "table", filterDefaults, filterKinds, defaultPageSize);
|
|
121
|
+
const localTableState = useLocalTableState(filterDefaults, defaultPageSize);
|
|
122
|
+
return prefix ? urlTableState : localTableState;
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
FILTER_KINDS,
|
|
126
|
+
filtersForDatasetSwitch,
|
|
127
|
+
isFilterActive,
|
|
128
|
+
parseSortValue,
|
|
129
|
+
serializeSortOrders,
|
|
130
|
+
useTableState
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=useTableState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableState.js","sources":["../../src/DataTable/useTableState.js"],"sourcesContent":["// Filtros, orden y página de una tabla. Con prefijo, la URL es la fuente de verdad (nuqs).\n//\n// Dos modos con la misma forma de salida, para que la tabla no sepa cuál está usando:\n// con `prefix` el estado vive en la URL: la pantalla se comparte por enlace, sobrevive a recargar y el botón\n// Atrás del detalle regresa a la lista tal como estaba;\n// sin `prefix` estado local, para tablas embebidas (un diálogo) donde reflejar filtros en la URL solo ensucia.\n//\n// El prefijo permite dos tablas en la misma pantalla sin pisarse (loads_year contra users_year). Las llaves que se\n// ven en la barra de direcciones son <prefijo>_<campo>.\n//\n// Hooks y funciones puras, no renderizan: function (regla de la casa).\nimport {useMemo, useState} from 'react';\nimport {parseAsArrayOf, parseAsInteger, parseAsString, useQueryStates} from 'nuqs';\n\nexport const FILTER_KINDS = Object.freeze({\n text: 'text',\n multiSelect: 'multiSelect',\n});\n\n// el orden viaja como columna:dirección, legible en la barra de direcciones\nconst SORT_SEPARATOR = ':';\n\nconst DEFAULT_PAGE_SIZE = 25;\n\n/**\n * ¿El filtro está puesto? Un texto vacío o una lista vacía no cuentan.\n *\n * @param {string|undefined} kind uno de FILTER_KINDS\n * @param {unknown} value valor del filtro\n * @returns {boolean}\n */\nexport function isFilterActive(kind, value) {\n if (value === null || value === undefined) {\n return false;\n }\n if (kind === FILTER_KINDS.multiSelect) {\n return value.length > 0;\n }\n return value !== '';\n}\n\n/**\n * Parser de nuqs según el tipo de filtro.\n *\n * @param {string|undefined} kind uno de FILTER_KINDS\n * @param {unknown} defaultValue valor cuando la URL no trae el parámetro\n */\nfunction parserFor(kind, defaultValue) {\n if (kind === FILTER_KINDS.multiSelect) {\n return parseAsArrayOf(parseAsString).withDefault(defaultValue);\n }\n return parseAsString.withDefault(defaultValue);\n}\n\n/**\n * \"year:desc\" → [{column: 'year', direction: 'desc'}].\n *\n * @param {string} sortValue valor de la URL\n * @returns {Array<{column: string, direction: 'asc'|'desc'}>}\n */\nexport function parseSortValue(sortValue) {\n if (!sortValue) {\n return [];\n }\n const [column, direction] = sortValue.split(SORT_SEPARATOR);\n return column ? [{column, direction: direction === 'asc' ? 'asc' : 'desc'}] : [];\n}\n\n/**\n * [{column: 'year', direction: 'desc'}] → \"year:desc\" ('' sin orden).\n *\n * @param {Array<{column: string, direction: 'asc'|'desc'}>} sortOrders\n * @returns {string}\n */\nexport function serializeSortOrders(sortOrders) {\n return sortOrders.length ? `${sortOrders[0].column}${SORT_SEPARATOR}${sortOrders[0].direction}` : '';\n}\n\n/**\n * Filtros con los que arranca una tabla cuando cambia el CONJUNTO que muestra (otro producto, otra pestaña).\n *\n * Por qué existe: los filtros, el orden y la página pertenecen al conjunto que se estaba viendo. Si al cambiar de\n * producto se conservan, la tabla nueva sale filtrada por un estado o un formato que la persona eligió para el otro\n * producto y parece que \"no hay datos\". Todo vuelve a su default salvo lo que el cambio fija (p. ej. el producto).\n *\n * @param {Record<string, unknown>} filterDefaults campo → valor sin filtro\n * @param {Record<string, unknown>} values lo que fija el cambio de conjunto ({product: 'SHOES'})\n * @returns {Record<string, unknown>} todos los filtros en su default más los valores fijados\n */\nexport function filtersForDatasetSwitch(filterDefaults, values) {\n return {...filterDefaults, ...values};\n}\n\nfunction useUrlTableState(prefix, filterDefaults, filterKinds, defaultPageSize) {\n const parsers = useMemo(() => Object.fromEntries([\n ...Object.entries(filterDefaults).map(([field, defaultValue]) => [field, parserFor(filterKinds[field], defaultValue)]),\n ['sort', parseAsString.withDefault('')],\n ['page', parseAsInteger.withDefault(0)],\n ['pageSize', parseAsInteger.withDefault(defaultPageSize)],\n ]), [filterDefaults, filterKinds, defaultPageSize]);\n\n const [urlState, setUrlState] = useQueryStates(parsers, {\n urlKeys: Object.fromEntries(Object.keys(parsers).map((key) => [key, `${prefix}_${key}`])),\n // replace: filtrar no llena el historial de entradas intermedias; el Atrás del detalle regresa a la lista\n history: 'replace',\n // lo que vale su default no se escribe en la URL\n clearOnDefault: true,\n });\n\n const filters = useMemo(\n () => Object.fromEntries(Object.keys(filterDefaults).map((field) => [field, urlState[field]])),\n [urlState, filterDefaults],\n );\n\n const sortOrders = useMemo(() => parseSortValue(urlState.sort), [urlState.sort]);\n\n return {\n filters,\n sortOrders,\n page: urlState.page,\n pageSize: urlState.pageSize,\n // IMPORTANTE: filtrar SIEMPRE regresa a la página 0; quedarse en la 3 de un resultado que ahora tiene una\n // sola página deja la tabla vacía y parece que el filtro no encontró nada\n setFilter: (field, value) => setUrlState({[field]: value, page: 0}),\n // varios en UNA escritura: en dos, la tabla consultaría una vez con la mitad del cambio\n setFilters: (values) => setUrlState({...values, page: 0}),\n clearFilter: (field) => setUrlState({[field]: filterDefaults[field], page: 0}),\n clearAll: () => setUrlState({...filterDefaults, page: 0}),\n setSort: (orders) => setUrlState({sort: serializeSortOrders(orders), page: 0}),\n // cambio de conjunto (otro producto): filtros, orden y página a su default en UNA escritura; el tamaño de\n // página se respeta porque es preferencia de quien mira, no del conjunto\n switchDataset: (values) => setUrlState({...filtersForDatasetSwitch(filterDefaults, values), sort: '', page: 0}),\n setPage: (page) => setUrlState({page}),\n setPageSize: (pageSize) => setUrlState({pageSize, page: 0}),\n };\n}\n\nfunction useLocalTableState(filterDefaults, defaultPageSize) {\n const [filters, setFilters] = useState(filterDefaults);\n const [sortOrders, setSortOrders] = useState([]);\n const [page, setPage] = useState(0);\n const [pageSize, setPageSize] = useState(defaultPageSize);\n\n return {\n filters,\n sortOrders,\n page,\n pageSize,\n setFilter: (field, value) => {\n setFilters((currentFilters) => ({...currentFilters, [field]: value}));\n setPage(0);\n },\n setFilters: (values) => {\n setFilters((currentFilters) => ({...currentFilters, ...values}));\n setPage(0);\n },\n clearFilter: (field) => {\n setFilters((currentFilters) => ({...currentFilters, [field]: filterDefaults[field]}));\n setPage(0);\n },\n clearAll: () => {\n setFilters(filterDefaults);\n setPage(0);\n },\n setSort: (orders) => {\n setSortOrders(orders);\n setPage(0);\n },\n switchDataset: (values) => {\n setFilters(filtersForDatasetSwitch(filterDefaults, values));\n setSortOrders([]);\n setPage(0);\n },\n setPage,\n setPageSize: (nextPageSize) => {\n setPageSize(nextPageSize);\n setPage(0);\n },\n };\n}\n\n/**\n * Estado de una tabla de servidor.\n *\n * OJO: filterDefaults y filterKinds se pasan como constantes de módulo (fuera del componente). Un objeto nuevo en\n * cada render arma parsers nuevos en cada render.\n *\n * @param {object} options\n * @param {string} [options.prefix] con prefijo, en la URL; sin él, en memoria\n * @param {Record<string, unknown>} [options.filterDefaults] campo → valor sin filtro ('' o [])\n * @param {Record<string, string>} [options.filterKinds] campo → FILTER_KINDS\n * @param {number} [options.defaultPageSize]\n */\nexport function useTableState({prefix, filterDefaults = {}, filterKinds = {}, defaultPageSize = DEFAULT_PAGE_SIZE}) {\n // los dos hooks se llaman SIEMPRE (regla de los hooks); el que no aplica no se usa\n const urlTableState = useUrlTableState(prefix ?? 'table', filterDefaults, filterKinds, defaultPageSize);\n const localTableState = useLocalTableState(filterDefaults, defaultPageSize);\n return prefix ? urlTableState : localTableState;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +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;"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
5
|
+
import Box from "@mui/material/Box";
|
|
6
|
+
import Checkbox from "@mui/material/Checkbox";
|
|
7
|
+
import Chip from "@mui/material/Chip";
|
|
8
|
+
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
9
|
+
import Paper from "@mui/material/Paper";
|
|
10
|
+
import Stack from "@mui/material/Stack";
|
|
11
|
+
import Typography from "@mui/material/Typography";
|
|
12
|
+
import { groupStateOf, withPermissionGroup, withPermission } from "./permissionGroups.js";
|
|
13
|
+
function PermissionOption({ permission, isGranted, readOnly, onToggle }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(
|
|
15
|
+
FormControlLabel,
|
|
16
|
+
{
|
|
17
|
+
sx: { alignItems: "flex-start", m: 0, gap: 0.5 },
|
|
18
|
+
control: /* @__PURE__ */ jsx(
|
|
19
|
+
Checkbox,
|
|
20
|
+
{
|
|
21
|
+
size: "small",
|
|
22
|
+
checked: isGranted,
|
|
23
|
+
disabled: readOnly,
|
|
24
|
+
onChange: (event) => onToggle(event.target.checked),
|
|
25
|
+
slotProps: { input: { "data-permission": permission.key } },
|
|
26
|
+
sx: { mt: -0.5 }
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
label: /* @__PURE__ */ jsxs(Box, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", children: permission.label }),
|
|
31
|
+
permission.description && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", component: "p", children: permission.description })
|
|
32
|
+
] })
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function PermissionGroup({ group, value, onChange, isReadOnly }) {
|
|
37
|
+
const { t } = useToolkitTranslation("access");
|
|
38
|
+
const titleId = useId();
|
|
39
|
+
const state = groupStateOf(group, value);
|
|
40
|
+
return /* @__PURE__ */ jsxs(Paper, { variant: "outlined", role: "group", "aria-labelledby": titleId, "data-group": group.key, sx: { overflow: "hidden" }, children: [
|
|
41
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center", px: 1.5, py: 0.75, borderBottom: 1, borderColor: "divider", bgcolor: "action.hover" }, children: [
|
|
42
|
+
/* @__PURE__ */ jsx(
|
|
43
|
+
Checkbox,
|
|
44
|
+
{
|
|
45
|
+
size: "small",
|
|
46
|
+
checked: state.isAll,
|
|
47
|
+
indeterminate: state.isSome,
|
|
48
|
+
disabled: isReadOnly || state.total === 0,
|
|
49
|
+
onChange: (event) => onChange(withPermissionGroup(value, group, event.target.checked)),
|
|
50
|
+
slotProps: { input: { "aria-label": t("permissions.allOf", { group: group.label }) } }
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ jsx(Typography, { id: titleId, variant: "subtitle2", component: "h3", sx: { flexGrow: 1 }, children: group.label }),
|
|
54
|
+
/* @__PURE__ */ jsx(
|
|
55
|
+
Chip,
|
|
56
|
+
{
|
|
57
|
+
size: "small",
|
|
58
|
+
label: t("permissions.countOf", { count: state.grantedCount, total: state.total }),
|
|
59
|
+
color: state.grantedCount > 0 ? "primary" : "default",
|
|
60
|
+
variant: state.isAll ? "filled" : "outlined"
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
] }),
|
|
64
|
+
/* @__PURE__ */ jsx(Box, { sx: { display: "grid", gridTemplateColumns: { xs: "1fr", md: "repeat(2, minmax(0, 1fr))" }, gap: 1.5, p: 2 }, children: group.permissions.map((permission) => /* @__PURE__ */ jsx(
|
|
65
|
+
PermissionOption,
|
|
66
|
+
{
|
|
67
|
+
permission,
|
|
68
|
+
isGranted: value.includes(permission.key),
|
|
69
|
+
readOnly: isReadOnly,
|
|
70
|
+
onToggle: (isGranted) => onChange(withPermission(value, permission.key, isGranted))
|
|
71
|
+
},
|
|
72
|
+
permission.key
|
|
73
|
+
)) })
|
|
74
|
+
] });
|
|
75
|
+
}
|
|
76
|
+
function PermissionMatrix({ groups, value, onChange, readOnly = false }) {
|
|
77
|
+
const isReadOnly = readOnly || !onChange;
|
|
78
|
+
return /* @__PURE__ */ jsx(Stack, { spacing: 1.5, children: groups.map((group) => /* @__PURE__ */ jsx(PermissionGroup, { group, value, onChange, isReadOnly }, group.key)) });
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
PermissionMatrix as default
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=PermissionMatrix.js.map
|
|
@@ -0,0 +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// 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';\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 <FormControlLabel\n sx={{alignItems: 'flex-start', m: 0, gap: 0.5}}\n control={<Checkbox size=\"small\" checked={isGranted} disabled={readOnly} onChange={(event) => onToggle(event.target.checked)}\n slotProps={{input: {'data-permission': permission.key}}} sx={{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 <Paper variant=\"outlined\" role=\"group\" aria-labelledby={titleId} data-group={group.key} sx={{overflow: 'hidden'}}>\n <Stack direction=\"row\" spacing={1} sx={{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 <Typography id={titleId} variant=\"subtitle2\" component=\"h3\" sx={{flexGrow: 1}}>{group.label}</Typography>\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 </Stack>\n <Box sx={{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 </Box>\n </Paper>\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 */\nexport default function PermissionMatrix({groups, value, onChange, readOnly = false}) {\n const isReadOnly = readOnly || !onChange;\n return (\n <Stack spacing={1.5}>\n {groups.map((group) => <PermissionGroup key={group.key} group={group} value={value} onChange={onChange} isReadOnly={isReadOnly} />)}\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCan } from "./useCan.js";
|
|
4
|
+
import ErrorPage, { ERROR_PAGE_KIND } from "../ui/layout/ErrorPage.js";
|
|
5
|
+
function RequireAccess({ access, children, fallback }) {
|
|
6
|
+
if (useCan(access)) {
|
|
7
|
+
return children;
|
|
8
|
+
}
|
|
9
|
+
return fallback ?? /* @__PURE__ */ jsx(ErrorPage, { kind: ERROR_PAGE_KIND.forbidden });
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
RequireAccess as default
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=RequireAccess.js.map
|
|
@@ -0,0 +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;"}
|