@stackcraftmx/calcita 0.0.0-stage → 0.25.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 +700 -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 +128 -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 +83 -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 +107 -0
- package/cli/templates/project/src/app/AppShell.jsx.tpl +87 -0
- package/cli/templates/project/src/app/appRouter.jsx.tpl +51 -0
- package/cli/templates/project/src/app/appSettings.js.tpl +27 -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 +14 -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 +9 -0
- package/cli/templates/project/src/core/publicPaths.js.tpl +24 -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 +53 -0
- package/dist/DataTable/AuditTrailDialog.js +40 -0
- package/dist/DataTable/AuditTrailDialog.js.map +1 -0
- package/dist/DataTable/AuditTrailTable.js +89 -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 +51 -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 +63 -0
- package/dist/DataTable/GoToPage.js.map +1 -0
- package/dist/DataTable/ServerTable.js +477 -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/rowSelection.js +61 -0
- package/dist/DataTable/rowSelection.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 +84 -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 +27 -0
- package/dist/account/ForgotPasswordScreen.js.map +1 -0
- package/dist/account/ProfileScreen.js +134 -0
- package/dist/account/ProfileScreen.js.map +1 -0
- package/dist/account/ResetPasswordScreen.js +58 -0
- package/dist/account/ResetPasswordScreen.js.map +1 -0
- package/dist/account/SignInScreen.js +102 -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 +118 -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 +49 -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 +256 -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 +513 -0
- package/dist/appShell/AppLayout.js.map +1 -0
- package/dist/appShell/AppearanceSettings.js +116 -0
- package/dist/appShell/AppearanceSettings.js.map +1 -0
- package/dist/appShell/AuthLayout.js +46 -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 +105 -0
- package/dist/appShell/BarActions.js.map +1 -0
- package/dist/appShell/BarCapsule.js +50 -0
- package/dist/appShell/BarCapsule.js.map +1 -0
- package/dist/appShell/BarSearch.js +92 -0
- package/dist/appShell/BarSearch.js.map +1 -0
- package/dist/appShell/HeaderTools.js +53 -0
- package/dist/appShell/HeaderTools.js.map +1 -0
- package/dist/appShell/MobileTabBar.js +348 -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 +40 -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 +149 -0
- package/dist/calendar/EventCalendar.js.map +1 -0
- package/dist/calendar/EventDetails.js +74 -0
- package/dist/calendar/EventDetails.js.map +1 -0
- package/dist/calendar/calendarEvents.js +31 -0
- package/dist/calendar/calendarEvents.js.map +1 -0
- package/dist/calendar.js +13 -0
- package/dist/calendar.js.map +1 -0
- package/dist/charts.js +16 -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 +76 -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 +195 -0
- package/dist/downloads/DownloadManager.js.map +1 -0
- package/dist/downloads/downloadQueue.js +56 -0
- package/dist/downloads/downloadQueue.js.map +1 -0
- package/dist/downloads/downloadsMachine.js +80 -0
- package/dist/downloads/downloadsMachine.js.map +1 -0
- package/dist/downloads/fileTypes.js +22 -0
- package/dist/downloads/fileTypes.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 +73 -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 +256 -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 +205 -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 +63 -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 +47 -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 +338 -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/FormWizard.js +59 -0
- package/dist/hookForm/FormWizard.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 +104 -0
- package/dist/inbox/InboxLayout.js.map +1 -0
- package/dist/inbox/MessageList.js +114 -0
- package/dist/inbox/MessageList.js.map +1 -0
- package/dist/inbox/MessageView.js +104 -0
- package/dist/inbox/MessageView.js.map +1 -0
- package/dist/inbox/inboxDates.js +9 -0
- package/dist/inbox/inboxDates.js.map +1 -0
- package/dist/index.js +407 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/CatalogInput.js +66 -0
- package/dist/inputs/CatalogInput.js.map +1 -0
- package/dist/inputs/ColorInput.js +109 -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 +70 -0
- package/dist/inputs/NumberInput.js.map +1 -0
- package/dist/inputs/SelectInput.js +84 -0
- package/dist/inputs/SelectInput.js.map +1 -0
- package/dist/inputs/TextInput.js +101 -0
- package/dist/inputs/TextInput.js.map +1 -0
- package/dist/inputs/WizardLayout.js +54 -0
- package/dist/inputs/WizardLayout.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 +338 -0
- package/dist/kanban/KanbanBoard.js.map +1 -0
- package/dist/kanban/kanbanCards.js +19 -0
- package/dist/kanban/kanbanCards.js.map +1 -0
- package/dist/kanban/kanbanMoves.js +29 -0
- package/dist/kanban/kanbanMoves.js.map +1 -0
- package/dist/kanban.js +15 -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 +787 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.js +787 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/maps/MapView.js +116 -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 +77 -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 +34 -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 +70 -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 +71 -0
- package/dist/pwa/useInstallPrompt.js.map +1 -0
- package/dist/react-hook-form.js +32 -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 +80 -0
- package/dist/security/ActivityLog.js.map +1 -0
- package/dist/security/RecoveryCodesDialog.js +85 -0
- package/dist/security/RecoveryCodesDialog.js.map +1 -0
- package/dist/security/SessionsCard.js +83 -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 +37 -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/MuiDialog.js +13 -0
- package/dist/theme/components/MuiDialog.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 +28 -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/ComponentTexts.js +13 -0
- package/dist/toolkit/ComponentTexts.js.map +1 -0
- package/dist/toolkit/ToolkitProvider.js +57 -0
- package/dist/toolkit/ToolkitProvider.js.map +1 -0
- package/dist/toolkit/browserNavigation.js +33 -0
- package/dist/toolkit/browserNavigation.js.map +1 -0
- package/dist/toolkit/componentTextsContext.js +15 -0
- package/dist/toolkit/componentTextsContext.js.map +1 -0
- package/dist/toolkit/hashNavigation.js +40 -0
- package/dist/toolkit/hashNavigation.js.map +1 -0
- package/dist/toolkit/navigationPaths.js +49 -0
- package/dist/toolkit/navigationPaths.js.map +1 -0
- package/dist/toolkit/toolkitContext.js +19 -0
- package/dist/toolkit/toolkitContext.js.map +1 -0
- package/dist/toolkit/toolkitSettings.js +107 -0
- package/dist/toolkit/toolkitSettings.js.map +1 -0
- package/dist/toolkit/useFormatters.js +12 -0
- package/dist/toolkit/useFormatters.js.map +1 -0
- package/dist/toolkit/useToolkitTranslation.js +22 -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 +30 -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 +13 -0
- package/dist/types/DataTable/FilterChips.d.ts +17 -0
- package/dist/types/DataTable/GoToPage.d.ts +13 -0
- package/dist/types/DataTable/SelectionBar.d.ts +32 -0
- package/dist/types/DataTable/ServerTable.d.ts +171 -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/rowSelection.d.ts +113 -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 +23 -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 +9 -0
- package/dist/types/account/DemoTotpCodeButton.d.ts +6 -0
- package/dist/types/account/ForgotPasswordScreen.d.ts +17 -0
- package/dist/types/account/ProfileScreen.d.ts +43 -0
- package/dist/types/account/ResetPasswordScreen.d.ts +21 -0
- package/dist/types/account/SignInScreen.d.ts +27 -0
- package/dist/types/account/accountConnector.d.ts +268 -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 +42 -0
- package/dist/types/api/ApiError.d.ts +42 -0
- package/dist/types/api/createApiClient.d.ts +174 -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 +76 -0
- package/dist/types/appShell/AppearanceSettings.d.ts +41 -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 +23 -0
- package/dist/types/appShell/BarCapsule.d.ts +20 -0
- package/dist/types/appShell/BarSearch.d.ts +24 -0
- package/dist/types/appShell/HeaderTools.d.ts +27 -0
- package/dist/types/appShell/MobileTabBar.d.ts +20 -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 +46 -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 +13 -0
- package/dist/types/auth/passwordRules.d.ts +34 -0
- package/dist/types/calendar/EventCalendar.d.ts +63 -0
- package/dist/types/calendar/EventDetails.d.ts +36 -0
- package/dist/types/calendar/calendarEvents.d.ts +27 -0
- package/dist/types/calendar.d.ts +3 -0
- package/dist/types/charts.d.ts +6 -0
- package/dist/types/date-pickers.d.ts +2 -0
- package/dist/types/datePickers/DateInput.d.ts +41 -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 +7 -0
- package/dist/types/downloads/downloadQueue.d.ts +50 -0
- package/dist/types/downloads/downloadsMachine.d.ts +10 -0
- package/dist/types/downloads/fileTypes.d.ts +39 -0
- package/dist/types/downloads/index.d.ts +4 -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 +31 -0
- package/dist/types/feedback/ModalWaiting.d.ts +13 -0
- package/dist/types/feedback/NewBuildNotice.d.ts +20 -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 +61 -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 +61 -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 +22 -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 +17 -0
- package/dist/types/forms/auth/ForgotPasswordForm.d.ts +14 -0
- package/dist/types/forms/auth/SignInForm.d.ts +20 -0
- package/dist/types/forms/index.d.ts +19 -0
- package/dist/types/forms/security/SecondStepForm.d.ts +30 -0
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +83 -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/FormWizard.d.ts +22 -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 +38 -0
- package/dist/types/inbox/MessageList.d.ts +52 -0
- package/dist/types/inbox/MessageView.d.ts +55 -0
- package/dist/types/inbox/inboxDates.d.ts +11 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/inputs/CatalogInput.d.ts +45 -0
- package/dist/types/inputs/ColorInput.d.ts +30 -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 +38 -0
- package/dist/types/inputs/SelectInput.d.ts +38 -0
- package/dist/types/inputs/TextInput.d.ts +62 -0
- package/dist/types/inputs/WizardLayout.d.ts +34 -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 +88 -0
- package/dist/types/kanban/kanbanCards.d.ts +22 -0
- package/dist/types/kanban/kanbanMoves.d.ts +38 -0
- package/dist/types/kanban.d.ts +3 -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 +788 -0
- package/dist/types/locales/es.d.ts +788 -0
- package/dist/types/maps/MapView.d.ts +41 -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 +18 -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 +7 -0
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +20 -0
- package/dist/types/pwa/InstallPromptBanner.d.ts +16 -0
- package/dist/types/pwa/installInstructions.d.ts +52 -0
- package/dist/types/pwa/useInstallPrompt.d.ts +13 -0
- package/dist/types/react-hook-form.d.ts +12 -0
- package/dist/types/react-router.d.ts +2 -0
- package/dist/types/security/ActivityLog.d.ts +33 -0
- package/dist/types/security/RecoveryCodesDialog.d.ts +16 -0
- package/dist/types/security/SessionsCard.d.ts +24 -0
- package/dist/types/security/passkeys.d.ts +18 -0
- package/dist/types/table.d.ts +3 -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/MuiDialog.d.ts +9 -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/ComponentTexts.d.ts +11 -0
- package/dist/types/toolkit/ToolkitProvider.d.ts +47 -0
- package/dist/types/toolkit/browserNavigation.d.ts +27 -0
- package/dist/types/toolkit/componentTextsContext.d.ts +20 -0
- package/dist/types/toolkit/hashNavigation.d.ts +12 -0
- package/dist/types/toolkit/navigationPaths.d.ts +43 -0
- package/dist/types/toolkit/toolkitContext.d.ts +28 -0
- package/dist/types/toolkit/toolkitSettings.d.ts +113 -0
- package/dist/types/toolkit/useFormatters.d.ts +6 -0
- package/dist/types/toolkit/useToolkitTranslation.d.ts +11 -0
- package/dist/types/ui/actions/ActionsMenu.d.ts +20 -0
- package/dist/types/ui/actions/CopyButton.d.ts +15 -0
- package/dist/types/ui/actions/DownloadMenu.d.ts +55 -0
- package/dist/types/ui/actions/SecretField.d.ts +17 -0
- package/dist/types/ui/actions/SelectionActions.d.ts +39 -0
- package/dist/types/ui/filters/DateRangeFilter.d.ts +18 -0
- package/dist/types/ui/filters/PeriodRangeSelector.d.ts +28 -0
- package/dist/types/ui/filters/QuickFilters.d.ts +23 -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/labels/tagOf.d.ts +13 -0
- package/dist/types/ui/layout/CollapsibleSection.d.ts +18 -0
- package/dist/types/ui/layout/ContentDialog.d.ts +15 -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 +35 -0
- package/dist/types/ui/layout/FullPageLoader.d.ts +7 -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 +20 -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 +25 -0
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +34 -0
- package/dist/types/ui/metrics/ChartTooltip.d.ts +11 -0
- package/dist/types/ui/metrics/ColumnChart.d.ts +47 -0
- package/dist/types/ui/metrics/LineChart.d.ts +41 -0
- package/dist/types/ui/metrics/MetricCard.d.ts +39 -0
- package/dist/types/ui/metrics/TableToggle.d.ts +14 -0
- package/dist/types/ui/metrics/barListLabels.d.ts +17 -0
- package/dist/types/ui/metrics/chartParts.d.ts +112 -0
- package/dist/types/ui/metrics/heatmapScale.d.ts +45 -0
- package/dist/types/ui/navigation/BackButton.d.ts +13 -0
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +13 -0
- package/dist/types/ui/navigation/DocumentTitle.d.ts +6 -0
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +11 -0
- package/dist/types/ui/navigation/LanguageToggle.d.ts +13 -0
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +12 -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 +41 -0
- package/dist/types/ui/timeline/timelineDot.d.ts +19 -0
- package/dist/types/upload/FileDropzone.d.ts +36 -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/ActionsMenu.js +51 -0
- package/dist/ui/actions/ActionsMenu.js.map +1 -0
- package/dist/ui/actions/CopyButton.js +28 -0
- package/dist/ui/actions/CopyButton.js.map +1 -0
- package/dist/ui/actions/DownloadMenu.js +162 -0
- package/dist/ui/actions/DownloadMenu.js.map +1 -0
- package/dist/ui/actions/SecretField.js +61 -0
- package/dist/ui/actions/SecretField.js.map +1 -0
- package/dist/ui/actions/SelectionActions.js +142 -0
- package/dist/ui/actions/SelectionActions.js.map +1 -0
- package/dist/ui/filters/DateRangeFilter.js +87 -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/labels/tagOf.js +7 -0
- package/dist/ui/labels/tagOf.js.map +1 -0
- package/dist/ui/layout/CollapsibleSection.js +52 -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 +54 -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 +94 -0
- package/dist/ui/metrics/BarList.js.map +1 -0
- package/dist/ui/metrics/CalendarHeatmap.js +136 -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 +106 -0
- package/dist/ui/metrics/ColumnChart.js.map +1 -0
- package/dist/ui/metrics/LineChart.js +117 -0
- package/dist/ui/metrics/LineChart.js.map +1 -0
- package/dist/ui/metrics/MetricCard.js +97 -0
- package/dist/ui/metrics/MetricCard.js.map +1 -0
- package/dist/ui/metrics/TableToggle.js +15 -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/chartParts.js +93 -0
- package/dist/ui/metrics/chartParts.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 +40 -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 +41 -0
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -0
- package/dist/ui/navigation/LanguageToggle.js +48 -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 +106 -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 +145 -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 +311 -5
|
@@ -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,84 @@
|
|
|
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
|
+
import ComponentTexts from "../toolkit/ComponentTexts.js";
|
|
14
|
+
function PermissionOption({ permission, isGranted, readOnly, onToggle }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
FormControlLabel,
|
|
17
|
+
{
|
|
18
|
+
sx: { alignItems: "flex-start", m: 0, gap: 0.5 },
|
|
19
|
+
control: /* @__PURE__ */ jsx(
|
|
20
|
+
Checkbox,
|
|
21
|
+
{
|
|
22
|
+
size: "small",
|
|
23
|
+
checked: isGranted,
|
|
24
|
+
disabled: readOnly,
|
|
25
|
+
onChange: (event) => onToggle(event.target.checked),
|
|
26
|
+
slotProps: { input: { "data-permission": permission.key } },
|
|
27
|
+
sx: { mt: -0.5 }
|
|
28
|
+
}
|
|
29
|
+
),
|
|
30
|
+
label: /* @__PURE__ */ jsxs(Box, { children: [
|
|
31
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", children: permission.label }),
|
|
32
|
+
permission.description && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", component: "p", children: permission.description })
|
|
33
|
+
] })
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function PermissionGroup({ group, value, onChange, isReadOnly }) {
|
|
38
|
+
const { t } = useToolkitTranslation("access");
|
|
39
|
+
const titleId = useId();
|
|
40
|
+
const state = groupStateOf(group, value);
|
|
41
|
+
return /* @__PURE__ */ jsxs(Paper, { variant: "outlined", role: "group", "aria-labelledby": titleId, "data-group": group.key, sx: { overflow: "hidden" }, children: [
|
|
42
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center", px: 1.5, py: 0.75, borderBottom: 1, borderColor: "divider", bgcolor: "action.hover" }, children: [
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
Checkbox,
|
|
45
|
+
{
|
|
46
|
+
size: "small",
|
|
47
|
+
checked: state.isAll,
|
|
48
|
+
indeterminate: state.isSome,
|
|
49
|
+
disabled: isReadOnly || state.total === 0,
|
|
50
|
+
onChange: (event) => onChange(withPermissionGroup(value, group, event.target.checked)),
|
|
51
|
+
slotProps: { input: { "aria-label": t("permissions.allOf", { group: group.label }) } }
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
/* @__PURE__ */ jsx(Typography, { id: titleId, variant: "subtitle2", component: "h3", sx: { flexGrow: 1 }, children: group.label }),
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
Chip,
|
|
57
|
+
{
|
|
58
|
+
size: "small",
|
|
59
|
+
label: t("permissions.countOf", { count: state.grantedCount, total: state.total }),
|
|
60
|
+
color: state.grantedCount > 0 ? "primary" : "default",
|
|
61
|
+
variant: state.isAll ? "filled" : "outlined"
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] }),
|
|
65
|
+
/* @__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(
|
|
66
|
+
PermissionOption,
|
|
67
|
+
{
|
|
68
|
+
permission,
|
|
69
|
+
isGranted: value.includes(permission.key),
|
|
70
|
+
readOnly: isReadOnly,
|
|
71
|
+
onToggle: (isGranted) => onChange(withPermission(value, permission.key, isGranted))
|
|
72
|
+
},
|
|
73
|
+
permission.key
|
|
74
|
+
)) })
|
|
75
|
+
] });
|
|
76
|
+
}
|
|
77
|
+
function PermissionMatrix({ groups, value, onChange, readOnly = false, texts }) {
|
|
78
|
+
const isReadOnly = readOnly || !onChange;
|
|
79
|
+
return /* @__PURE__ */ jsx(ComponentTexts, { namespace: "access", texts, children: /* @__PURE__ */ jsx(Stack, { spacing: 1.5, children: groups.map((group) => /* @__PURE__ */ jsx(PermissionGroup, { group, value, onChange, isReadOnly }, group.key)) }) });
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
PermissionMatrix as default
|
|
83
|
+
};
|
|
84
|
+
//# 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';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\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 * @param {object} [props.texts] los textos que cambian, con la forma de `access` en los textos del paquete\n */\nexport default function PermissionMatrix({groups, value, onChange, readOnly = false, texts}) {\n const isReadOnly = readOnly || !onChange;\n return (\n <ComponentTexts namespace=\"access\" texts={texts}>\n <Stack spacing={1.5}>\n {groups.map((group) => <PermissionGroup key={group.key} group={group} value={value} onChange={onChange} isReadOnly={isReadOnly} />)}\n </Stack>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -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;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function allowOnlyUnrestricted(access) {
|
|
2
|
+
return !access;
|
|
3
|
+
}
|
|
4
|
+
function createAccessChecker({ abilities = [], roles = [], policies = {}, context = {} } = {}) {
|
|
5
|
+
const abilitySet = new Set(abilities);
|
|
6
|
+
const roleSet = new Set(roles);
|
|
7
|
+
const passesPolicy = (policyName) => {
|
|
8
|
+
const policy = policies[policyName];
|
|
9
|
+
if (typeof policy !== "function") {
|
|
10
|
+
throw new Error(`La política «${policyName}» no está definida en createAccessChecker({policies})`);
|
|
11
|
+
}
|
|
12
|
+
return Boolean(policy(context));
|
|
13
|
+
};
|
|
14
|
+
return (access) => {
|
|
15
|
+
if (!access) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (access.ability && !abilitySet.has(access.ability)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (access.anyOf && !access.anyOf.some((ability) => abilitySet.has(ability))) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (access.allOf && !access.allOf.every((ability) => abilitySet.has(ability))) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (access.role && !roleSet.has(access.role)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (access.anyRole && !access.anyRole.some((role) => roleSet.has(role))) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (access.policy && !passesPolicy(access.policy)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (access.policies && !access.policies.every(passesPolicy)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (access.check && !access.check(context)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
allowOnlyUnrestricted,
|
|
47
|
+
createAccessChecker
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=accessRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessRules.js","sources":["../../src/access/accessRules.js"],"sourcesContent":["// Quién puede ver qué: el menú, las rutas y los botones preguntan lo mismo con la misma regla («access»).\n//\n// El framework NO sabe de roles ni de permisos: cada proyecto declara sus reglas como le acomode y le da a ToolkitProvider\n// una función canAccess(access) → boolean. Para no programarla cada vez, createAccessChecker la arma con las formas de\n// siempre, y se pueden combinar (todas las que vengan tienen que cumplirse):\n//\n// RBAC por permisos (las `abilities` que manda la sesión):\n// {ability: 'orders.view'} ese permiso\n// {anyOf: ['orders.view', 'orders.admin']} alguno de esos\n// {allOf: ['orders.view', 'reports.view']} todos\n// RBAC por roles:\n// {role: 'admin'} · {anyRole: ['admin', 'supervisor']}\n// ABAC (atributos: dueño del registro, organización, horario…):\n// {policy: 'ownsRecord'} · {policies: ['ownsRecord', 'sameOrganization']} políticas con nombre, que el proyecto\n// define una vez en createAccessChecker\n// {check: (context) => context.user.id === record.ownerId} la regla escrita ahí mismo\n//\n// Sin access (undefined) lo ve cualquiera con sesión. Sin sesión o sin la lista, nada: falla CERRADO.\n//\n// OJO: esto solo decide lo que se PINTA. Lo que cada quien puede hacer lo vuelve a decidir el backend en cada petición;\n// cambiar esto en el navegador no abre nada.\n//\n// Funciones puras, sin React: function (regla de la casa). Se prueban con node --test (accessRules.test.js).\n\n/**\n * El canAccess de un proyecto que no usa permisos: sin access lo ve cualquiera; con access, nadie (falla cerrado, para\n * que una regla escrita y sin conectar se note en lugar de abrir todo).\n *\n * @param {object|undefined|null} access\n * @returns {boolean}\n */\nexport function allowOnlyUnrestricted(access) {\n return !access;\n}\n\n/**\n * Arma el canAccess(access) del proyecto con sus permisos, sus roles y sus políticas.\n *\n * @param {object} [options]\n * @param {string[]} [options.abilities] los permisos de la sesión (p. ej. los `abilities` que manda el backend)\n * @param {string[]} [options.roles] los roles de la sesión\n * @param {Record<string, (context: any) => boolean>} [options.policies] las políticas con nombre (ABAC); reciben el context\n * @param {object} [options.context] lo que reciben las políticas y los check (la persona, su organización…)\n * @returns {(access: object|undefined|null) => boolean}\n */\nexport function createAccessChecker({abilities = [], roles = [], policies = {}, context = {}} = {}) {\n const abilitySet = new Set(abilities);\n const roleSet = new Set(roles);\n\n const passesPolicy = (policyName) => {\n const policy = policies[policyName];\n // una política que nadie definió es un error de configuración: truena en vez de abrir o cerrar en silencio\n if (typeof policy !== 'function') {\n throw new Error(`La política «${policyName}» no está definida en createAccessChecker({policies})`);\n }\n return Boolean(policy(context));\n };\n\n return (access) => {\n if (!access) {\n return true;\n }\n if (access.ability && !abilitySet.has(access.ability)) {\n return false;\n }\n if (access.anyOf && !access.anyOf.some((ability) => abilitySet.has(ability))) {\n return false;\n }\n if (access.allOf && !access.allOf.every((ability) => abilitySet.has(ability))) {\n return false;\n }\n if (access.role && !roleSet.has(access.role)) {\n return false;\n }\n if (access.anyRole && !access.anyRole.some((role) => roleSet.has(role))) {\n return false;\n }\n if (access.policy && !passesPolicy(access.policy)) {\n return false;\n }\n if (access.policies && !access.policies.every(passesPolicy)) {\n return false;\n }\n if (access.check && !access.check(context)) {\n return false;\n }\n return true;\n };\n}\n"],"names":[],"mappings":"AA+BO,SAAS,sBAAsB,QAAQ;AAC1C,SAAO,CAAC;AACZ;AAYO,SAAS,oBAAoB,EAAC,YAAY,CAAA,GAAI,QAAQ,CAAA,GAAI,WAAW,IAAI,UAAU,CAAA,EAAE,IAAI,CAAA,GAAI;AAChG,QAAM,aAAa,IAAI,IAAI,SAAS;AACpC,QAAM,UAAU,IAAI,IAAI,KAAK;AAE7B,QAAM,eAAe,CAAC,eAAe;AACjC,UAAM,SAAS,SAAS,UAAU;AAElC,QAAI,OAAO,WAAW,YAAY;AAC9B,YAAM,IAAI,MAAM,gBAAgB,UAAU,uDAAuD;AAAA,IACrG;AACA,WAAO,QAAQ,OAAO,OAAO,CAAC;AAAA,EAClC;AAEA,SAAO,CAAC,WAAW;AACf,QAAI,CAAC,QAAQ;AACT,aAAO;AAAA,IACX;AACA,QAAI,OAAO,WAAW,CAAC,WAAW,IAAI,OAAO,OAAO,GAAG;AACnD,aAAO;AAAA,IACX;AACA,QAAI,OAAO,SAAS,CAAC,OAAO,MAAM,KAAK,CAAC,YAAY,WAAW,IAAI,OAAO,CAAC,GAAG;AAC1E,aAAO;AAAA,IACX;AACA,QAAI,OAAO,SAAS,CAAC,OAAO,MAAM,MAAM,CAAC,YAAY,WAAW,IAAI,OAAO,CAAC,GAAG;AAC3E,aAAO;AAAA,IACX;AACA,QAAI,OAAO,QAAQ,CAAC,QAAQ,IAAI,OAAO,IAAI,GAAG;AAC1C,aAAO;AAAA,IACX;AACA,QAAI,OAAO,WAAW,CAAC,OAAO,QAAQ,KAAK,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,GAAG;AACrE,aAAO;AAAA,IACX;AACA,QAAI,OAAO,UAAU,CAAC,aAAa,OAAO,MAAM,GAAG;AAC/C,aAAO;AAAA,IACX;AACA,QAAI,OAAO,YAAY,CAAC,OAAO,SAAS,MAAM,YAAY,GAAG;AACzD,aAAO;AAAA,IACX;AACA,QAAI,OAAO,SAAS,CAAC,OAAO,MAAM,OAAO,GAAG;AACxC,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX;AACJ;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const LAST_ORDER = 1e3;
|
|
2
|
+
function composePermissionGroups(menuModules, t) {
|
|
3
|
+
const modules = Array.isArray(menuModules) ? menuModules : Object.values(menuModules);
|
|
4
|
+
return modules.filter((menuModule) => Array.isArray(menuModule.permissions) && menuModule.permissions.length > 0).sort((first, second) => (first.order ?? LAST_ORDER) - (second.order ?? LAST_ORDER)).map((menuModule) => {
|
|
5
|
+
const menuItem = menuModule.buildMenuItem?.({}) ?? {};
|
|
6
|
+
return {
|
|
7
|
+
key: menuItem.to ?? menuModule.permissions[0].key,
|
|
8
|
+
label: menuItem.label ?? t(menuItem.labelKey),
|
|
9
|
+
permissions: menuModule.permissions.map((permission) => ({
|
|
10
|
+
key: permission.key,
|
|
11
|
+
label: permission.label ?? t(permission.labelKey),
|
|
12
|
+
description: permission.description ?? (permission.descriptionKey ? t(permission.descriptionKey) : void 0)
|
|
13
|
+
}))
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function groupStateOf(group, granted) {
|
|
18
|
+
const grantedSet = new Set(granted);
|
|
19
|
+
const grantedCount = group.permissions.filter((permission) => grantedSet.has(permission.key)).length;
|
|
20
|
+
const total = group.permissions.length;
|
|
21
|
+
return { grantedCount, total, isAll: total > 0 && grantedCount === total, isSome: grantedCount > 0 && grantedCount < total };
|
|
22
|
+
}
|
|
23
|
+
function withPermission(granted, permissionKey, shouldGrant) {
|
|
24
|
+
if (shouldGrant) {
|
|
25
|
+
return granted.includes(permissionKey) ? [...granted] : [...granted, permissionKey];
|
|
26
|
+
}
|
|
27
|
+
return granted.filter((key) => key !== permissionKey);
|
|
28
|
+
}
|
|
29
|
+
function withPermissionGroup(granted, group, shouldGrant) {
|
|
30
|
+
const groupKeys = new Set(group.permissions.map((permission) => permission.key));
|
|
31
|
+
if (shouldGrant) {
|
|
32
|
+
const missing = group.permissions.map((permission) => permission.key).filter((key) => !granted.includes(key));
|
|
33
|
+
return [...granted, ...missing];
|
|
34
|
+
}
|
|
35
|
+
return granted.filter((key) => !groupKeys.has(key));
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
composePermissionGroups,
|
|
39
|
+
groupStateOf,
|
|
40
|
+
withPermission,
|
|
41
|
+
withPermissionGroup
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=permissionGroups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionGroups.js","sources":["../../src/access/permissionGroups.js"],"sourcesContent":["// La lógica de la pantalla de perfiles y permisos (PermissionMatrix), sin React: cuántos permisos de un grupo tiene un\n// perfil, y prender o apagar un permiso o un grupo entero.\n//\n// Los permisos son los mismos textos que piden los menu.js y las rutas (access: {ability: 'orders.view'}). Cada módulo\n// declara los suyos en su menu.js y composePermissionGroups los junta (un grupo por módulo, en el orden del menú): la\n// pantalla de perfiles no tiene lista central que editar. Guardar la lista de permisos del perfil es cosa del backend.\n//\n// // modules/orders/menu.js\n// export const permissions = [\n// {key: 'orders.view', labelKey: 'orders:permissions.view', descriptionKey: 'orders:permissions.viewDescription'},\n// {key: 'orders.cancel', labelKey: 'orders:permissions.cancel'},\n// ];\n//\n// Funciones puras, sin React: function (regla de la casa). Se prueban con node --test (permissionGroups.test.js).\n\n// la posición de un módulo que no dice su order: al final (la misma regla que composeMenu)\nconst LAST_ORDER = 1000;\n\n/**\n * Los grupos de permisos que declaran los módulos en su menu.js (`export const permissions`), uno por módulo y en el orden\n * del menú, con el nombre de su entrada del menú como título del grupo.\n *\n * @param {Record<string, any>|any[]} menuModules lo que regresa import.meta.glob(..., {eager: true}) o una lista\n * @param {(key: string, values?: object) => string} t el traductor (para las llaves labelKey y descriptionKey)\n * @returns {Array<{key: string, label: string, permissions: Array<{key: string, label: string, description?: string}>}>}\n */\nexport function composePermissionGroups(menuModules, t) {\n const modules = Array.isArray(menuModules) ? menuModules : Object.values(menuModules);\n return modules\n .filter((menuModule) => Array.isArray(menuModule.permissions) && menuModule.permissions.length > 0)\n .sort((first, second) => (first.order ?? LAST_ORDER) - (second.order ?? LAST_ORDER))\n .map((menuModule) => {\n const menuItem = menuModule.buildMenuItem?.({}) ?? {};\n return {\n key: menuItem.to ?? menuModule.permissions[0].key,\n label: menuItem.label ?? t(menuItem.labelKey),\n permissions: menuModule.permissions.map((permission) => ({\n key: permission.key,\n label: permission.label ?? t(permission.labelKey),\n description: permission.description ?? (permission.descriptionKey ? t(permission.descriptionKey) : undefined),\n })),\n };\n });\n}\n\n/**\n * Cuántos permisos del grupo están dados.\n *\n * @param {{permissions: Array<{key: string}>}} group\n * @param {string[]} granted los permisos del perfil\n * @returns {{grantedCount: number, total: number, isAll: boolean, isSome: boolean}}\n */\nexport function groupStateOf(group, granted) {\n const grantedSet = new Set(granted);\n const grantedCount = group.permissions.filter((permission) => grantedSet.has(permission.key)).length;\n const total = group.permissions.length;\n return {grantedCount, total, isAll: total > 0 && grantedCount === total, isSome: grantedCount > 0 && grantedCount < total};\n}\n\n/**\n * Prende o apaga un permiso. Lo demás se queda en su orden; uno nuevo va al final.\n *\n * @param {string[]} granted\n * @param {string} permissionKey\n * @param {boolean} shouldGrant\n * @returns {string[]} la lista nueva (no cambia la de entrada)\n */\nexport function withPermission(granted, permissionKey, shouldGrant) {\n if (shouldGrant) {\n return granted.includes(permissionKey) ? [...granted] : [...granted, permissionKey];\n }\n return granted.filter((key) => key !== permissionKey);\n}\n\n/**\n * Prende o apaga todos los permisos de un grupo. Los que ya estaban se quedan en su lugar; los que faltan van al final.\n *\n * @param {string[]} granted\n * @param {{permissions: Array<{key: string}>}} group\n * @param {boolean} shouldGrant\n * @returns {string[]}\n */\nexport function withPermissionGroup(granted, group, shouldGrant) {\n const groupKeys = new Set(group.permissions.map((permission) => permission.key));\n if (shouldGrant) {\n const missing = group.permissions.map((permission) => permission.key).filter((key) => !granted.includes(key));\n return [...granted, ...missing];\n }\n return granted.filter((key) => !groupKeys.has(key));\n}\n"],"names":[],"mappings":"AAgBA,MAAM,aAAa;AAUZ,SAAS,wBAAwB,aAAa,GAAG;AACpD,QAAM,UAAU,MAAM,QAAQ,WAAW,IAAI,cAAc,OAAO,OAAO,WAAW;AACpF,SAAO,QACF,OAAO,CAAC,eAAe,MAAM,QAAQ,WAAW,WAAW,KAAK,WAAW,YAAY,SAAS,CAAC,EACjG,KAAK,CAAC,OAAO,YAAY,MAAM,SAAS,eAAe,OAAO,SAAS,WAAW,EAClF,IAAI,CAAC,eAAe;AACjB,UAAM,WAAW,WAAW,gBAAgB,CAAA,CAAE,KAAK,CAAA;AACnD,WAAO;AAAA,MACH,KAAK,SAAS,MAAM,WAAW,YAAY,CAAC,EAAE;AAAA,MAC9C,OAAO,SAAS,SAAS,EAAE,SAAS,QAAQ;AAAA,MAC5C,aAAa,WAAW,YAAY,IAAI,CAAC,gBAAgB;AAAA,QACrD,KAAK,WAAW;AAAA,QAChB,OAAO,WAAW,SAAS,EAAE,WAAW,QAAQ;AAAA,QAChD,aAAa,WAAW,gBAAgB,WAAW,iBAAiB,EAAE,WAAW,cAAc,IAAI;AAAA,MACvH,EAAkB;AAAA,IAClB;AAAA,EACQ,CAAC;AACT;AASO,SAAS,aAAa,OAAO,SAAS;AACzC,QAAM,aAAa,IAAI,IAAI,OAAO;AAClC,QAAM,eAAe,MAAM,YAAY,OAAO,CAAC,eAAe,WAAW,IAAI,WAAW,GAAG,CAAC,EAAE;AAC9F,QAAM,QAAQ,MAAM,YAAY;AAChC,SAAO,EAAC,cAAc,OAAO,OAAO,QAAQ,KAAK,iBAAiB,OAAO,QAAQ,eAAe,KAAK,eAAe,MAAK;AAC7H;AAUO,SAAS,eAAe,SAAS,eAAe,aAAa;AAChE,MAAI,aAAa;AACb,WAAO,QAAQ,SAAS,aAAa,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,SAAS,aAAa;AAAA,EACtF;AACA,SAAO,QAAQ,OAAO,CAAC,QAAQ,QAAQ,aAAa;AACxD;AAUO,SAAS,oBAAoB,SAAS,OAAO,aAAa;AAC7D,QAAM,YAAY,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,eAAe,WAAW,GAAG,CAAC;AAC/E,MAAI,aAAa;AACb,UAAM,UAAU,MAAM,YAAY,IAAI,CAAC,eAAe,WAAW,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,SAAS,GAAG,CAAC;AAC5G,WAAO,CAAC,GAAG,SAAS,GAAG,OAAO;AAAA,EAClC;AACA,SAAO,QAAQ,OAAO,CAAC,QAAQ,CAAC,UAAU,IAAI,GAAG,CAAC;AACtD;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useToolkitSettings } from "../toolkit/toolkitContext.js";
|
|
2
|
+
function useCan(access) {
|
|
3
|
+
return useToolkitSettings().canAccess(access);
|
|
4
|
+
}
|
|
5
|
+
function useAccessChecker() {
|
|
6
|
+
return useToolkitSettings().canAccess;
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
useAccessChecker,
|
|
10
|
+
useCan
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=useCan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCan.js","sources":["../../src/access/useCan.js"],"sourcesContent":["// ¿Esta sesión puede ver esto? Con la regla que el proyecto le dio a ToolkitProvider (canAccess).\n//\n// const canCancel = useCan({ability: 'orders.cancel'});\n// {canCancel && <Button>Cancelar pedido</Button>}\n//\n// Hook genérico del paquete: function (regla de la casa).\nimport {useToolkitSettings} from '@/toolkit/toolkitContext.js';\n\n/**\n * @param {object|undefined|null} access la regla (accessRules.js); sin ella, sí\n * @returns {boolean}\n */\nexport function useCan(access) {\n return useToolkitSettings().canAccess(access);\n}\n\n/**\n * La regla del proyecto, para preguntar por varias cosas a la vez (p. ej. armar el menú).\n *\n * @returns {(access: object|undefined|null) => boolean}\n */\nexport function useAccessChecker() {\n return useToolkitSettings().canAccess;\n}\n"],"names":[],"mappings":";AAYO,SAAS,OAAO,QAAQ;AAC3B,SAAO,mBAAkB,EAAG,UAAU,MAAM;AAChD;AAOO,SAAS,mBAAmB;AAC/B,SAAO,mBAAkB,EAAG;AAChC;"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useState, useCallback, useRef, useEffect, useMemo, useContext } from "react";
|
|
4
|
+
import { missingConnectorFunctionsOf } from "./accountConnector.js";
|
|
5
|
+
import { createAccessChecker } from "../access/accessRules.js";
|
|
6
|
+
import ErrorPage, { ERROR_PAGE_KIND } from "../ui/layout/ErrorPage.js";
|
|
7
|
+
import FullPageLoader from "../ui/layout/FullPageLoader.js";
|
|
8
|
+
const AccountContext = createContext(null);
|
|
9
|
+
const NOT_LOADED = void 0;
|
|
10
|
+
function AccountProvider({ connector, refreshKey, initialSession = NOT_LOADED, children }) {
|
|
11
|
+
const missingFunctions = missingConnectorFunctionsOf(connector);
|
|
12
|
+
if (missingFunctions.length > 0) {
|
|
13
|
+
throw new Error(`Al conector de la cuenta le faltan estas funciones: ${missingFunctions.join(", ")}`);
|
|
14
|
+
}
|
|
15
|
+
const [session, setSession] = useState(initialSession);
|
|
16
|
+
const [loadError, setLoadError] = useState(null);
|
|
17
|
+
const refreshSession = useCallback(async () => {
|
|
18
|
+
try {
|
|
19
|
+
setSession(await connector.loadSession());
|
|
20
|
+
setLoadError(null);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
setLoadError(error);
|
|
23
|
+
}
|
|
24
|
+
}, [connector]);
|
|
25
|
+
const signOut = useCallback(async () => {
|
|
26
|
+
await connector.signOut();
|
|
27
|
+
setSession(null);
|
|
28
|
+
}, [connector]);
|
|
29
|
+
const skipsFirstLoad = useRef(initialSession !== NOT_LOADED);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (skipsFirstLoad.current) {
|
|
32
|
+
skipsFirstLoad.current = false;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
refreshSession();
|
|
36
|
+
}, [refreshSession, refreshKey]);
|
|
37
|
+
const canAccess = useMemo(() => createAccessChecker({ abilities: session?.abilities ?? [], roles: session?.roles ?? [] }), [session]);
|
|
38
|
+
const value = useMemo(() => ({ connector, session: session ?? null, refreshSession, signOut }), [connector, session, refreshSession, signOut]);
|
|
39
|
+
if (loadError && session === NOT_LOADED) {
|
|
40
|
+
return /* @__PURE__ */ jsx(ErrorPage, { kind: ERROR_PAGE_KIND.serverError, text: loadError.message, onRetry: refreshSession });
|
|
41
|
+
}
|
|
42
|
+
if (session === NOT_LOADED) {
|
|
43
|
+
return /* @__PURE__ */ jsx(FullPageLoader, {});
|
|
44
|
+
}
|
|
45
|
+
return /* @__PURE__ */ jsx(AccountContext.Provider, { value, children: children(canAccess) });
|
|
46
|
+
}
|
|
47
|
+
function useAccount() {
|
|
48
|
+
const account = useContext(AccountContext);
|
|
49
|
+
if (!account) {
|
|
50
|
+
throw new Error("useAccount necesita estar dentro de <AccountProvider>");
|
|
51
|
+
}
|
|
52
|
+
return account;
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
AccountProvider as default,
|
|
56
|
+
useAccount
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=AccountProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountProvider.js","sources":["../../src/account/AccountProvider.jsx"],"sourcesContent":["// La cuenta al alcance de toda la app: carga la sesión al abrir (connector.loadSession) y la reparte. Las pantallas de la\n// cuenta y la barra la leen con useAccount; el menú, las rutas y los botones preguntan sus permisos con la regla que sale de\n// aquí (createAccessChecker), que se le pasa a ToolkitProvider:\n//\n// <AccountProvider connector={accountConnector}>\n// {(canAccess) => <ToolkitProvider canAccess={canAccess} …>…</ToolkitProvider>}\n// </AccountProvider>\n//\n// Mientras llega la primera respuesta se ve la pantalla de carga (sin ella, el menú se pintaría vacío un instante); si el\n// servidor no contesta, la página de error con «Intentar de nuevo», no la de entrar (no es que no haya sesión).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';\n\nimport {missingConnectorFunctionsOf} from '@/account/accountConnector.js';\nimport {createAccessChecker} from '@/access/accessRules.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\nimport FullPageLoader from '@/ui/layout/FullPageLoader.jsx';\n\nconst AccountContext = createContext(null);\n// lo que se sabe antes de la primera respuesta: ni dentro ni fuera\nconst NOT_LOADED = undefined;\n\n/**\n * @param {object} props\n * @param {import('@/account/accountConnector.js').AccountConnector} props.connector las llamadas al backend\n * @param {unknown} [props.refreshKey] al cambiar, la sesión se vuelve a leer (p. ej. el idioma, si el backend manda los\n * nombres de los perfiles traducidos)\n * @param {import('@/account/accountConnector.js').AccountSession|null} [props.initialSession] la sesión que ya se conoce\n * (p. ej. la que leyó el servidor al pintar): se usa sin esperar la primera respuesta\n * @param {(canAccess: (access: object|null|undefined) => boolean) => import('react').ReactNode} props.children recibe la\n * regla de permisos de la sesión\n */\nexport default function AccountProvider({connector, refreshKey, initialSession = NOT_LOADED, children}) {\n // guard clause: un conector incompleto es un error de quien lo escribió; se avisa al arrancar y no al picar un botón\n const missingFunctions = missingConnectorFunctionsOf(connector);\n if (missingFunctions.length > 0) {\n throw new Error(`Al conector de la cuenta le faltan estas funciones: ${missingFunctions.join(', ')}`);\n }\n\n const [session, setSession] = useState(initialSession);\n const [loadError, setLoadError] = useState(null);\n\n const refreshSession = useCallback(async () => {\n try {\n setSession(await connector.loadSession());\n setLoadError(null);\n } catch (error) {\n setLoadError(error);\n }\n }, [connector]);\n\n const signOut = useCallback(async () => {\n await connector.signOut();\n setSession(null);\n }, [connector]);\n\n // con la sesión ya conocida no se pide al abrir; sí cuando cambia refreshKey\n const skipsFirstLoad = useRef(initialSession !== NOT_LOADED);\n useEffect(() => {\n if (skipsFirstLoad.current) {\n skipsFirstLoad.current = false;\n return;\n }\n refreshSession();\n }, [refreshSession, refreshKey]);\n\n const canAccess = useMemo(() => createAccessChecker({abilities: session?.abilities ?? [], roles: session?.roles ?? []}), [session]);\n const value = useMemo(() => ({connector, session: session ?? null, refreshSession, signOut}), [connector, session, refreshSession, signOut]);\n\n if (loadError && session === NOT_LOADED) {\n return <ErrorPage kind={ERROR_PAGE_KIND.serverError} text={loadError.message} onRetry={refreshSession} />;\n }\n if (session === NOT_LOADED) {\n return <FullPageLoader />;\n }\n return <AccountContext.Provider value={value}>{children(canAccess)}</AccountContext.Provider>;\n}\n\n/**\n * La cuenta: {session, refreshSession, signOut, connector}. session es null si nadie está dentro.\n *\n * @returns {{session: import('@/account/accountConnector.js').AccountSession|null, refreshSession: () => Promise<void>, signOut: () => Promise<void>, connector: import('@/account/accountConnector.js').AccountConnector}}\n */\nexport function useAccount() {\n const account = useContext(AccountContext);\n if (!account) {\n throw new Error('useAccount necesita estar dentro de <AccountProvider>');\n }\n return account;\n}\n"],"names":[],"mappings":";;;;;;;AAmBA,MAAM,iBAAiB,cAAc,IAAI;AAEzC,MAAM,aAAa;AAYnB,SAAwB,gBAAgB,EAAC,WAAW,YAAY,iBAAiB,YAAY,YAAW;AAEpG,QAAM,mBAAmB,4BAA4B,SAAS;AAC9D,MAAI,iBAAiB,SAAS,GAAG;AAC7B,UAAM,IAAI,MAAM,uDAAuD,iBAAiB,KAAK,IAAI,CAAC,EAAE;AAAA,EACxG;AAEA,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,cAAc;AACrD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAE/C,QAAM,iBAAiB,YAAY,YAAY;AAC3C,QAAI;AACA,iBAAW,MAAM,UAAU,aAAa;AACxC,mBAAa,IAAI;AAAA,IACrB,SAAS,OAAO;AACZ,mBAAa,KAAK;AAAA,IACtB;AAAA,EACJ,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,UAAU,YAAY,YAAY;AACpC,UAAM,UAAU,QAAA;AAChB,eAAW,IAAI;AAAA,EACnB,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,iBAAiB,OAAO,mBAAmB,UAAU;AAC3D,YAAU,MAAM;AACZ,QAAI,eAAe,SAAS;AACxB,qBAAe,UAAU;AACzB;AAAA,IACJ;AACA,mBAAA;AAAA,EACJ,GAAG,CAAC,gBAAgB,UAAU,CAAC;AAE/B,QAAM,YAAY,QAAQ,MAAM,oBAAoB,EAAC,WAAW,SAAS,aAAa,CAAA,GAAI,OAAO,SAAS,SAAS,CAAA,EAAC,CAAE,GAAG,CAAC,OAAO,CAAC;AAClI,QAAM,QAAQ,QAAQ,OAAO,EAAC,WAAW,SAAS,WAAW,MAAM,gBAAgB,QAAA,IAAW,CAAC,WAAW,SAAS,gBAAgB,OAAO,CAAC;AAE3I,MAAI,aAAa,YAAY,YAAY;AACrC,WAAO,oBAAC,aAAU,MAAM,gBAAgB,aAAa,MAAM,UAAU,SAAS,SAAS,eAAA,CAAgB;AAAA,EAC3G;AACA,MAAI,YAAY,YAAY;AACxB,+BAAQ,gBAAA,EAAe;AAAA,EAC3B;AACA,6BAAQ,eAAe,UAAf,EAAwB,OAAe,UAAA,SAAS,SAAS,GAAE;AACvE;AAOO,SAAS,aAAa;AACzB,QAAM,UAAU,WAAW,cAAc;AACzC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,uDAAuD;AAAA,EAC3E;AACA,SAAO;AACX;"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
4
|
+
import Alert from "@mui/material/Alert";
|
|
5
|
+
import Skeleton from "@mui/material/Skeleton";
|
|
6
|
+
import Stack from "@mui/material/Stack";
|
|
7
|
+
import Typography from "@mui/material/Typography";
|
|
8
|
+
import { useAccount } from "./AccountProvider.js";
|
|
9
|
+
import DemoTotpCodeButton from "./DemoTotpCodeButton.js";
|
|
10
|
+
import ChangePasswordForm from "../forms/auth/ChangePasswordForm.js";
|
|
11
|
+
import TwoStepVerificationCard from "../forms/security/TwoStepVerificationCard.js";
|
|
12
|
+
import ActivityLog from "../security/ActivityLog.js";
|
|
13
|
+
import { createPasskey, passkeysSupported } from "../security/passkeys.js";
|
|
14
|
+
import SessionsCard from "../security/SessionsCard.js";
|
|
15
|
+
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
16
|
+
import SectionCard from "../ui/layout/SectionCard.js";
|
|
17
|
+
const FORM_MAX_WIDTH = 520;
|
|
18
|
+
const LOADING_HEIGHT_PIXELS = 220;
|
|
19
|
+
function AccountSecuritySection({ showPasswordChange = true, texts }) {
|
|
20
|
+
const { t } = useToolkitTranslation("account", texts);
|
|
21
|
+
const { connector, session } = useAccount();
|
|
22
|
+
const [security, setSecurity] = useState(null);
|
|
23
|
+
const [sessions, setSessions] = useState(null);
|
|
24
|
+
const [events, setEvents] = useState(null);
|
|
25
|
+
const [loadError, setLoadError] = useState(null);
|
|
26
|
+
const isDemo = typeof connector.demoTotpCode === "function";
|
|
27
|
+
const refreshActivity = useCallback(() => connector.listActivity().then(setEvents).catch((error) => setLoadError(error.message)), [connector]);
|
|
28
|
+
const refreshSessions = useCallback(() => connector.listSessions().then(setSessions).catch((error) => setLoadError(error.message)), [connector]);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
connector.loadSecurity().then(setSecurity).catch((error) => setLoadError(error.message));
|
|
31
|
+
refreshSessions();
|
|
32
|
+
refreshActivity();
|
|
33
|
+
}, [connector, refreshActivity, refreshSessions]);
|
|
34
|
+
const actions = useMemo(() => ({
|
|
35
|
+
addPasskey: async (name) => connector.savePasskey({ name, credential: await createPasskey(await connector.passkeyRegistrationOptions()) }),
|
|
36
|
+
removePasskey: (passkey, password) => connector.removePasskey({ passkeyId: passkey.id, password }),
|
|
37
|
+
startTotp: async () => ({
|
|
38
|
+
...await connector.startTotp(),
|
|
39
|
+
// en la demostración, el atajo del código abajo del campo
|
|
40
|
+
extra: isDemo ? /* @__PURE__ */ jsx(DemoTotpCodeButton, { loadCode: connector.demoTotpCode }) : void 0
|
|
41
|
+
}),
|
|
42
|
+
confirmTotp: (code) => connector.confirmTotp(code),
|
|
43
|
+
disableTotp: (password) => connector.disableTotp(password),
|
|
44
|
+
regenerateRecoveryCodes: (password) => connector.regenerateRecoveryCodes(password)
|
|
45
|
+
}), [connector, isDemo]);
|
|
46
|
+
const changeSecurity = (nextSecurity) => {
|
|
47
|
+
setSecurity(nextSecurity);
|
|
48
|
+
refreshActivity();
|
|
49
|
+
};
|
|
50
|
+
return /* @__PURE__ */ jsxs(Stack, { spacing: 3, children: [
|
|
51
|
+
loadError && /* @__PURE__ */ jsx(Alert, { severity: "error", children: loadError }),
|
|
52
|
+
showPasswordChange && /* @__PURE__ */ jsxs(SectionCard, { title: t("profile.password.title"), children: [
|
|
53
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("profile.password.text") }),
|
|
54
|
+
/* @__PURE__ */ jsx(Stack, { sx: { maxWidth: FORM_MAX_WIDTH }, children: /* @__PURE__ */ jsx(ChangePasswordForm, { onSubmit: async (values) => {
|
|
55
|
+
await connector.changePassword(values);
|
|
56
|
+
refreshActivity();
|
|
57
|
+
} }) })
|
|
58
|
+
] }),
|
|
59
|
+
security ? /* @__PURE__ */ jsx(
|
|
60
|
+
TwoStepVerificationCard,
|
|
61
|
+
{
|
|
62
|
+
security,
|
|
63
|
+
onSecurityChange: changeSecurity,
|
|
64
|
+
actions,
|
|
65
|
+
canUsePasskeys: passkeysSupported(),
|
|
66
|
+
account: session?.user.email,
|
|
67
|
+
passkeyNotice: isDemo ? t("demo.passkeyNote") : void 0
|
|
68
|
+
}
|
|
69
|
+
) : /* @__PURE__ */ jsx(Skeleton, { variant: "rounded", height: LOADING_HEIGHT_PIXELS }),
|
|
70
|
+
isDemo && /* @__PURE__ */ jsx(Alert, { severity: "info", children: t("demo.securityNote") }),
|
|
71
|
+
/* @__PURE__ */ jsx(SessionsCard, { sessions, onCloseOthers: connector.closeOtherSessions, onClosed: () => {
|
|
72
|
+
refreshSessions();
|
|
73
|
+
refreshActivity();
|
|
74
|
+
} }),
|
|
75
|
+
/* @__PURE__ */ jsx(ActivityLog, { events })
|
|
76
|
+
] });
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
AccountSecuritySection as default
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=AccountSecuritySection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountSecuritySection.js","sources":["../../src/account/AccountSecuritySection.jsx"],"sourcesContent":["// La seguridad de la cuenta, completa: cambiar la contraseña (ChangePasswordForm), la verificación en dos pasos\n// (TwoStepVerificationCard: llaves de acceso, app autenticadora y códigos de recuperación), las sesiones abiertas\n// (SessionsCard) y la bitácora (ActivityLog). Todo lo del servidor sale del conector de la cuenta.\n//\n// Las llaves de acceso se crean aquí con el navegador (createPasskey) y la respuesta va al servidor (savePasskey). La\n// bitácora se vuelve a pedir después de cada cambio: así se ve aparecer lo que se acaba de hacer.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useCallback, useEffect, useMemo, useState} from 'react';\nimport Alert from '@mui/material/Alert';\nimport Skeleton from '@mui/material/Skeleton';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport ChangePasswordForm from '@/forms/auth/ChangePasswordForm.jsx';\nimport TwoStepVerificationCard from '@/forms/security/TwoStepVerificationCard.jsx';\nimport ActivityLog from '@/security/ActivityLog.jsx';\nimport {createPasskey, passkeysSupported} from '@/security/passkeys.js';\nimport SessionsCard from '@/security/SessionsCard.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\n\n// lo ancho del formulario de la contraseña: un renglón cómodo\nconst FORM_MAX_WIDTH = 520;\nconst LOADING_HEIGHT_PIXELS = 220;\n\n/**\n * @param {object} props\n * @param {boolean} [props.showPasswordChange] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete\n */\nexport default function AccountSecuritySection({showPasswordChange = true, texts}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session} = useAccount();\n const [security, setSecurity] = useState(null);\n const [sessions, setSessions] = useState(null);\n const [events, setEvents] = useState(null);\n const [loadError, setLoadError] = useState(null);\n const isDemo = typeof connector.demoTotpCode === 'function';\n\n const refreshActivity = useCallback(() => connector.listActivity().then(setEvents).catch((error) => setLoadError(error.message)), [connector]);\n const refreshSessions = useCallback(() => connector.listSessions().then(setSessions).catch((error) => setLoadError(error.message)), [connector]);\n\n useEffect(() => {\n connector.loadSecurity().then(setSecurity).catch((error) => setLoadError(error.message));\n refreshSessions();\n refreshActivity();\n }, [connector, refreshActivity, refreshSessions]);\n\n // lo que hace la tarjeta de dos pasos en cada caso, con el conector\n const actions = useMemo(() => ({\n addPasskey: async (name) => connector.savePasskey({name, credential: await createPasskey(await connector.passkeyRegistrationOptions())}),\n removePasskey: (passkey, password) => connector.removePasskey({passkeyId: passkey.id, password}),\n startTotp: async () => ({\n ...await connector.startTotp(),\n // en la demostración, el atajo del código abajo del campo\n extra: isDemo ? <DemoTotpCodeButton loadCode={connector.demoTotpCode} /> : undefined,\n }),\n confirmTotp: (code) => connector.confirmTotp(code),\n disableTotp: (password) => connector.disableTotp(password),\n regenerateRecoveryCodes: (password) => connector.regenerateRecoveryCodes(password),\n }), [connector, isDemo]);\n\n const changeSecurity = (nextSecurity) => {\n setSecurity(nextSecurity);\n refreshActivity();\n };\n\n return (\n <Stack spacing={3}>\n {loadError && <Alert severity=\"error\">{loadError}</Alert>}\n {showPasswordChange && (\n <SectionCard title={t('profile.password.title')}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{mb: 2}}>{t('profile.password.text')}</Typography>\n <Stack sx={{maxWidth: FORM_MAX_WIDTH}}>\n <ChangePasswordForm onSubmit={async (values) => {\n await connector.changePassword(values);\n refreshActivity();\n }} />\n </Stack>\n </SectionCard>\n )}\n {security\n ? <TwoStepVerificationCard security={security} onSecurityChange={changeSecurity} actions={actions}\n canUsePasskeys={passkeysSupported()} account={session?.user.email}\n // en la demostración la llave es de verdad pero el servidor se olvida al recargar:\n // se avisa antes de crearla para que nadie se quede con una llave huérfana\n passkeyNotice={isDemo ? t('demo.passkeyNote') : undefined} />\n : <Skeleton variant=\"rounded\" height={LOADING_HEIGHT_PIXELS} />}\n {isDemo && <Alert severity=\"info\">{t('demo.securityNote')}</Alert>}\n <SessionsCard sessions={sessions} onCloseOthers={connector.closeOtherSessions} onClosed={() => {\n refreshSessions();\n refreshActivity();\n }} />\n <ActivityLog events={events} />\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}
|