@maxal_studio/kratosjs-react 1.0.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/README.md +44 -0
- package/dist/FieldRenderer.d.ts +13 -0
- package/dist/FieldRenderer.js +62 -0
- package/dist/FormRenderer.d.ts +7 -0
- package/dist/FormRenderer.js +78 -0
- package/dist/TableRenderer.d.ts +2 -0
- package/dist/TableRenderer.js +1 -0
- package/dist/api/actionsApi.d.ts +23 -0
- package/dist/api/actionsApi.js +46 -0
- package/dist/api/authenticatedFetch.d.ts +8 -0
- package/dist/api/authenticatedFetch.js +31 -0
- package/dist/api/exportApi.d.ts +18 -0
- package/dist/api/exportApi.js +50 -0
- package/dist/api/http.d.ts +24 -0
- package/dist/api/http.js +52 -0
- package/dist/api/resourceApi.d.ts +37 -0
- package/dist/api/resourceApi.js +52 -0
- package/dist/api/tableApi.d.ts +83 -0
- package/dist/api/tableApi.js +51 -0
- package/dist/api/urls.d.ts +19 -0
- package/dist/api/urls.js +46 -0
- package/dist/app.d.ts +101 -0
- package/dist/app.js +89 -0
- package/dist/auth/AuthContext.d.ts +22 -0
- package/dist/auth/AuthContext.js +147 -0
- package/dist/auth/LoginPage.d.ts +10 -0
- package/dist/auth/LoginPage.js +179 -0
- package/dist/auth/ProtectedRoute.d.ts +12 -0
- package/dist/auth/ProtectedRoute.js +22 -0
- package/dist/auth/authApiClient.d.ts +24 -0
- package/dist/auth/authApiClient.js +95 -0
- package/dist/auth/types.d.ts +103 -0
- package/dist/auth/types.js +1 -0
- package/dist/components/ActionFormModal.d.ts +22 -0
- package/dist/components/ActionFormModal.js +8 -0
- package/dist/components/AdminPanel.d.ts +11 -0
- package/dist/components/AdminPanel.js +194 -0
- package/dist/components/Checkbox.d.ts +10 -0
- package/dist/components/Checkbox.js +8 -0
- package/dist/components/CheckboxField.d.ts +7 -0
- package/dist/components/CheckboxField.js +26 -0
- package/dist/components/ColorPickerField.d.ts +7 -0
- package/dist/components/ColorPickerField.js +26 -0
- package/dist/components/DateTimePickerField.d.ts +7 -0
- package/dist/components/DateTimePickerField.js +64 -0
- package/dist/components/FileUploadField.d.ts +9 -0
- package/dist/components/FileUploadField.js +478 -0
- package/dist/components/GlobalSearch.d.ts +22 -0
- package/dist/components/GlobalSearch.js +181 -0
- package/dist/components/GroupField.d.ts +7 -0
- package/dist/components/GroupField.js +23 -0
- package/dist/components/HiddenField.d.ts +3 -0
- package/dist/components/HiddenField.js +10 -0
- package/dist/components/ModalBreadcrumb.d.ts +5 -0
- package/dist/components/ModalBreadcrumb.js +33 -0
- package/dist/components/ModalDrawer.d.ts +15 -0
- package/dist/components/ModalDrawer.js +40 -0
- package/dist/components/RadioField.d.ts +7 -0
- package/dist/components/RadioField.js +26 -0
- package/dist/components/RepeaterField.d.ts +3 -0
- package/dist/components/RepeaterField.js +191 -0
- package/dist/components/ResourceModalRenderer.d.ts +10 -0
- package/dist/components/ResourceModalRenderer.js +80 -0
- package/dist/components/RichEditorField.d.ts +3 -0
- package/dist/components/RichEditorField.js +655 -0
- package/dist/components/SectionField.d.ts +9 -0
- package/dist/components/SectionField.js +111 -0
- package/dist/components/SelectField.d.ts +8 -0
- package/dist/components/SelectField.js +523 -0
- package/dist/components/TabsField.d.ts +10 -0
- package/dist/components/TabsField.js +214 -0
- package/dist/components/TagsInputField.d.ts +7 -0
- package/dist/components/TagsInputField.js +172 -0
- package/dist/components/TextInputField.d.ts +7 -0
- package/dist/components/TextInputField.js +44 -0
- package/dist/components/TextareaField.d.ts +7 -0
- package/dist/components/TextareaField.js +31 -0
- package/dist/components/ToggleField.d.ts +7 -0
- package/dist/components/ToggleField.js +57 -0
- package/dist/components/ViewModal.d.ts +25 -0
- package/dist/components/ViewModal.js +159 -0
- package/dist/components/blocks/BlockRenderer.d.ts +7 -0
- package/dist/components/blocks/BlockRenderer.js +36 -0
- package/dist/components/blocks/FormBlockRenderer.d.ts +6 -0
- package/dist/components/blocks/FormBlockRenderer.js +110 -0
- package/dist/components/blocks/TableBlockRenderer.d.ts +6 -0
- package/dist/components/blocks/TableBlockRenderer.js +12 -0
- package/dist/components/blocks/TabsBlockRenderer.d.ts +7 -0
- package/dist/components/blocks/TabsBlockRenderer.js +11 -0
- package/dist/components/blocks/WidgetBlockRenderer.d.ts +6 -0
- package/dist/components/blocks/WidgetBlockRenderer.js +11 -0
- package/dist/components/columns/CheckboxColumnComponent.d.ts +6 -0
- package/dist/components/columns/CheckboxColumnComponent.js +21 -0
- package/dist/components/columns/ColorColumnComponent.d.ts +3 -0
- package/dist/components/columns/ColorColumnComponent.js +11 -0
- package/dist/components/columns/DeeplinkWrapper.d.ts +15 -0
- package/dist/components/columns/DeeplinkWrapper.js +85 -0
- package/dist/components/columns/IconColumnComponent.d.ts +3 -0
- package/dist/components/columns/IconColumnComponent.js +52 -0
- package/dist/components/columns/ImageColumnComponent.d.ts +3 -0
- package/dist/components/columns/ImageColumnComponent.js +98 -0
- package/dist/components/columns/MediaColumnComponent.d.ts +3 -0
- package/dist/components/columns/MediaColumnComponent.js +160 -0
- package/dist/components/columns/SelectColumnComponent.d.ts +6 -0
- package/dist/components/columns/SelectColumnComponent.js +26 -0
- package/dist/components/columns/TagsColumnComponent.d.ts +3 -0
- package/dist/components/columns/TagsColumnComponent.js +18 -0
- package/dist/components/columns/TextColumnComponent.d.ts +11 -0
- package/dist/components/columns/TextColumnComponent.js +107 -0
- package/dist/components/columns/TextInputColumnComponent.d.ts +6 -0
- package/dist/components/columns/TextInputColumnComponent.js +18 -0
- package/dist/components/columns/ToggleColumnComponent.d.ts +6 -0
- package/dist/components/columns/ToggleColumnComponent.js +25 -0
- package/dist/components/columns/VideoColumnComponent.d.ts +3 -0
- package/dist/components/columns/VideoColumnComponent.js +125 -0
- package/dist/components/columns/ViewColumnComponent.d.ts +3 -0
- package/dist/components/columns/ViewColumnComponent.js +7 -0
- package/dist/components/errors/ErrorBoundary.d.ts +23 -0
- package/dist/components/errors/ErrorBoundary.js +33 -0
- package/dist/components/filters/CustomFilterComponent.d.ts +10 -0
- package/dist/components/filters/CustomFilterComponent.js +33 -0
- package/dist/components/filters/DateFilterComponent.d.ts +15 -0
- package/dist/components/filters/DateFilterComponent.js +132 -0
- package/dist/components/filters/QueryBuilderFilterComponent.d.ts +11 -0
- package/dist/components/filters/QueryBuilderFilterComponent.js +200 -0
- package/dist/components/layout/Header.d.ts +10 -0
- package/dist/components/layout/Header.js +70 -0
- package/dist/components/layout/PanelBrandMark.d.ts +8 -0
- package/dist/components/layout/PanelBrandMark.js +28 -0
- package/dist/components/layout/Sidebar.d.ts +35 -0
- package/dist/components/layout/Sidebar.js +125 -0
- package/dist/components/modals/RelationCreateModal.d.ts +19 -0
- package/dist/components/modals/RelationCreateModal.js +57 -0
- package/dist/components/modals/ResourceFormModal.d.ts +37 -0
- package/dist/components/modals/ResourceFormModal.js +44 -0
- package/dist/components/modals/useResourceForm.d.ts +40 -0
- package/dist/components/modals/useResourceForm.js +138 -0
- package/dist/components/modals/view/RecordActions.d.ts +17 -0
- package/dist/components/modals/view/RecordActions.js +16 -0
- package/dist/components/modals/view/RecordDetails.d.ts +13 -0
- package/dist/components/modals/view/RecordDetails.js +29 -0
- package/dist/components/modals/view/RelationPanel.d.ts +18 -0
- package/dist/components/modals/view/RelationPanel.js +16 -0
- package/dist/components/modals/view/RelationTabs.d.ts +32 -0
- package/dist/components/modals/view/RelationTabs.js +42 -0
- package/dist/components/modals/view/useRecordView.d.ts +18 -0
- package/dist/components/modals/view/useRecordView.js +114 -0
- package/dist/components/pages/PageRenderer.d.ts +6 -0
- package/dist/components/pages/PageRenderer.js +107 -0
- package/dist/components/table/ColumnTogglePopup.d.ts +11 -0
- package/dist/components/table/ColumnTogglePopup.js +16 -0
- package/dist/components/table/GridCard.d.ts +21 -0
- package/dist/components/table/GridCard.js +30 -0
- package/dist/components/table/GridView.d.ts +23 -0
- package/dist/components/table/GridView.js +49 -0
- package/dist/components/table/LayoutToggle.d.ts +7 -0
- package/dist/components/table/LayoutToggle.js +9 -0
- package/dist/components/table/TableActionsDropdown.d.ts +13 -0
- package/dist/components/table/TableActionsDropdown.js +46 -0
- package/dist/components/table/TableBulkActions.d.ts +11 -0
- package/dist/components/table/TableBulkActions.js +21 -0
- package/dist/components/table/TableHeader.d.ts +14 -0
- package/dist/components/table/TableHeader.js +23 -0
- package/dist/components/table/TablePagination.d.ts +13 -0
- package/dist/components/table/TablePagination.js +55 -0
- package/dist/components/table/TableRow.d.ts +21 -0
- package/dist/components/table/TableRow.js +32 -0
- package/dist/components/table/TableSearchBar.d.ts +11 -0
- package/dist/components/table/TableSearchBar.js +12 -0
- package/dist/components/table/TableTabs.d.ts +14 -0
- package/dist/components/table/TableTabs.js +8 -0
- package/dist/components/ui/Badge.d.ts +6 -0
- package/dist/components/ui/Badge.js +12 -0
- package/dist/components/ui/Button.d.ts +22 -0
- package/dist/components/ui/Button.js +22 -0
- package/dist/components/ui/Card.d.ts +7 -0
- package/dist/components/ui/Card.js +5 -0
- package/dist/components/ui/ConfirmDialog.d.ts +19 -0
- package/dist/components/ui/ConfirmDialog.js +45 -0
- package/dist/components/ui/EmptyState.d.ts +9 -0
- package/dist/components/ui/EmptyState.js +6 -0
- package/dist/components/ui/ErrorAlert.d.ts +7 -0
- package/dist/components/ui/ErrorAlert.js +9 -0
- package/dist/components/ui/Input.d.ts +11 -0
- package/dist/components/ui/Input.js +10 -0
- package/dist/components/ui/Label.d.ts +5 -0
- package/dist/components/ui/Label.js +5 -0
- package/dist/components/ui/PillButton.d.ts +14 -0
- package/dist/components/ui/PillButton.js +19 -0
- package/dist/components/ui/Select.d.ts +7 -0
- package/dist/components/ui/Select.js +7 -0
- package/dist/components/ui/Spinner.d.ts +8 -0
- package/dist/components/ui/Spinner.js +14 -0
- package/dist/components/ui/Toast.d.ts +21 -0
- package/dist/components/ui/Toast.js +47 -0
- package/dist/components/ui/index.d.ts +24 -0
- package/dist/components/ui/index.js +12 -0
- package/dist/components/utils/HintDisplay.d.ts +11 -0
- package/dist/components/utils/HintDisplay.js +12 -0
- package/dist/components/utils/Icon.d.ts +22 -0
- package/dist/components/utils/Icon.js +22 -0
- package/dist/components/utils/MediaPreviewModal.d.ts +14 -0
- package/dist/components/utils/MediaPreviewModal.js +32 -0
- package/dist/components/utils/ViewFieldWrapper.d.ts +11 -0
- package/dist/components/utils/ViewFieldWrapper.js +9 -0
- package/dist/components/utils/layoutHelpers.d.ts +19 -0
- package/dist/components/utils/layoutHelpers.js +257 -0
- package/dist/components/widgets/ChartWidget.d.ts +16 -0
- package/dist/components/widgets/ChartWidget.js +192 -0
- package/dist/components/widgets/StatsWidget.d.ts +16 -0
- package/dist/components/widgets/StatsWidget.js +39 -0
- package/dist/components/widgets/WidgetRenderer.d.ts +10 -0
- package/dist/components/widgets/WidgetRenderer.js +50 -0
- package/dist/components/widgets/WidgetShell.d.ts +9 -0
- package/dist/components/widgets/WidgetShell.js +7 -0
- package/dist/contexts/AuthChallengeRegistryContext.d.ts +15 -0
- package/dist/contexts/AuthChallengeRegistryContext.js +15 -0
- package/dist/contexts/BlockRegistryContext.d.ts +18 -0
- package/dist/contexts/BlockRegistryContext.js +8 -0
- package/dist/contexts/ColumnRegistryContext.d.ts +8 -0
- package/dist/contexts/ColumnRegistryContext.js +30 -0
- package/dist/contexts/FieldRegistryContext.d.ts +13 -0
- package/dist/contexts/FieldRegistryContext.js +46 -0
- package/dist/contexts/PanelMetadataContext.d.ts +26 -0
- package/dist/contexts/PanelMetadataContext.js +26 -0
- package/dist/contexts/PanelProviders.d.ts +27 -0
- package/dist/contexts/PanelProviders.js +24 -0
- package/dist/contexts/ResourceModalContext.d.ts +26 -0
- package/dist/contexts/ResourceModalContext.js +76 -0
- package/dist/contexts/SlotRegistryContext.d.ts +19 -0
- package/dist/contexts/SlotRegistryContext.js +24 -0
- package/dist/contexts/TableRefreshContext.d.ts +10 -0
- package/dist/contexts/TableRefreshContext.js +30 -0
- package/dist/contexts/WidgetRegistryContext.d.ts +17 -0
- package/dist/contexts/WidgetRegistryContext.js +14 -0
- package/dist/contexts/createRegistryContext.d.ts +19 -0
- package/dist/contexts/createRegistryContext.js +20 -0
- package/dist/hooks/useAfterStateUpdated.d.ts +6 -0
- package/dist/hooks/useAfterStateUpdated.js +62 -0
- package/dist/hooks/useValidation.d.ts +26 -0
- package/dist/hooks/useValidation.js +76 -0
- package/dist/i18n/I18nProvider.d.ts +27 -0
- package/dist/i18n/I18nProvider.js +101 -0
- package/dist/i18n/LocaleSwitcher.d.ts +10 -0
- package/dist/i18n/LocaleSwitcher.js +30 -0
- package/dist/i18n/activeLocale.d.ts +11 -0
- package/dist/i18n/activeLocale.js +34 -0
- package/dist/i18n/buildClientI18n.d.ts +28 -0
- package/dist/i18n/buildClientI18n.js +67 -0
- package/dist/i18n/index.d.ts +11 -0
- package/dist/i18n/index.js +9 -0
- package/dist/i18n/locales/core/en.d.ts +225 -0
- package/dist/i18n/locales/core/en.js +252 -0
- package/dist/i18n/locales/core/index.d.ts +2 -0
- package/dist/i18n/locales/core/index.js +4 -0
- package/dist/i18n/locales/core/sq.d.ts +253 -0
- package/dist/i18n/locales/core/sq.js +255 -0
- package/dist/i18n/useFormatter.d.ts +18 -0
- package/dist/i18n/useFormatter.js +37 -0
- package/dist/i18n/useLocale.d.ts +11 -0
- package/dist/i18n/useLocale.js +11 -0
- package/dist/i18n/useTranslation.d.ts +12 -0
- package/dist/i18n/useTranslation.js +12 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +101 -0
- package/dist/pages/ResourceListPage.d.ts +8 -0
- package/dist/pages/ResourceListPage.js +139 -0
- package/dist/plugin.d.ts +79 -0
- package/dist/plugin.js +34 -0
- package/dist/runtime/conditions.d.ts +35 -0
- package/dist/runtime/conditions.js +97 -0
- package/dist/runtime/formTraversal.d.ts +25 -0
- package/dist/runtime/formTraversal.js +37 -0
- package/dist/runtime/serializedFunctions.d.ts +41 -0
- package/dist/runtime/serializedFunctions.js +264 -0
- package/dist/slots/Slot.d.ts +24 -0
- package/dist/slots/Slot.js +29 -0
- package/dist/slots/SlotCluster.d.ts +22 -0
- package/dist/slots/SlotCluster.js +49 -0
- package/dist/slots/index.d.ts +7 -0
- package/dist/slots/index.js +4 -0
- package/dist/slots/mergeSlots.d.ts +18 -0
- package/dist/slots/mergeSlots.js +35 -0
- package/dist/slots/types.d.ts +87 -0
- package/dist/slots/types.js +30 -0
- package/dist/styles.css +1 -0
- package/dist/table/TableContext.d.ts +36 -0
- package/dist/table/TableContext.js +13 -0
- package/dist/table/TableRenderer.d.ts +29 -0
- package/dist/table/TableRenderer.js +159 -0
- package/dist/table/components/FiltersPanel.d.ts +11 -0
- package/dist/table/components/FiltersPanel.js +52 -0
- package/dist/table/components/TableToolbar.d.ts +28 -0
- package/dist/table/components/TableToolbar.js +27 -0
- package/dist/table/components/TableToolbarButton.d.ts +6 -0
- package/dist/table/components/TableToolbarButton.js +9 -0
- package/dist/table/components/TableView.d.ts +12 -0
- package/dist/table/components/TableView.js +21 -0
- package/dist/table/defaultRowActions.d.ts +21 -0
- package/dist/table/defaultRowActions.js +37 -0
- package/dist/table/hooks/useColumnVisibility.d.ts +13 -0
- package/dist/table/hooks/useColumnVisibility.js +59 -0
- package/dist/table/hooks/useEditableRows.d.ts +22 -0
- package/dist/table/hooks/useEditableRows.js +63 -0
- package/dist/table/hooks/useTableActions.d.ts +54 -0
- package/dist/table/hooks/useTableActions.js +313 -0
- package/dist/table/hooks/useTableData.d.ts +28 -0
- package/dist/table/hooks/useTableData.js +63 -0
- package/dist/table/hooks/useTableLayout.d.ts +12 -0
- package/dist/table/hooks/useTableLayout.js +31 -0
- package/dist/table/hooks/useTableQuery.d.ts +29 -0
- package/dist/table/hooks/useTableQuery.js +135 -0
- package/dist/types/index.d.ts +224 -0
- package/dist/types/index.js +6 -0
- package/dist/utils/classNames.d.ts +7 -0
- package/dist/utils/classNames.js +9 -0
- package/dist/utils/columnMediaDimensions.d.ts +13 -0
- package/dist/utils/columnMediaDimensions.js +29 -0
- package/dist/utils/columnVisibilityStorage.d.ts +22 -0
- package/dist/utils/columnVisibilityStorage.js +56 -0
- package/dist/utils/fieldErrors.d.ts +13 -0
- package/dist/utils/fieldErrors.js +25 -0
- package/dist/utils/formatValue.d.ts +28 -0
- package/dist/utils/formatValue.js +109 -0
- package/dist/utils/layoutStorage.d.ts +23 -0
- package/dist/utils/layoutStorage.js +53 -0
- package/dist/utils/redirectHandler.d.ts +7 -0
- package/dist/utils/redirectHandler.js +25 -0
- package/dist/utils/tableFormatters.d.ts +14 -0
- package/dist/utils/tableFormatters.js +93 -0
- package/dist/utils/widgetVisibilityStorage.d.ts +11 -0
- package/dist/utils/widgetVisibilityStorage.js +39 -0
- package/package.json +101 -0
- package/src/FieldRenderer.test.tsx +44 -0
- package/src/FieldRenderer.tsx +104 -0
- package/src/FormRenderer.containers.test.tsx +121 -0
- package/src/FormRenderer.test.tsx +174 -0
- package/src/FormRenderer.tsx +140 -0
- package/src/TableRenderer.tsx +2 -0
- package/src/api/actionsApi.ts +76 -0
- package/src/api/authenticatedFetch.ts +40 -0
- package/src/api/exportApi.ts +66 -0
- package/src/api/http.test.ts +58 -0
- package/src/api/http.ts +68 -0
- package/src/api/resourceApi.ts +88 -0
- package/src/api/tableApi.test.ts +108 -0
- package/src/api/tableApi.ts +107 -0
- package/src/api/urls.ts +50 -0
- package/src/app.test.tsx +67 -0
- package/src/app.tsx +181 -0
- package/src/auth/AuthContext.tsx +188 -0
- package/src/auth/LoginPage.tsx +380 -0
- package/src/auth/ProtectedRoute.tsx +39 -0
- package/src/auth/authApiClient.ts +109 -0
- package/src/auth/authFlow.test.tsx +168 -0
- package/src/auth/types.ts +104 -0
- package/src/components/ActionFormModal.tsx +45 -0
- package/src/components/AdminPanel.tsx +368 -0
- package/src/components/Checkbox.tsx +59 -0
- package/src/components/CheckboxField.tsx +88 -0
- package/src/components/ColorPickerField.tsx +93 -0
- package/src/components/DateTimePickerField.tsx +112 -0
- package/src/components/FileUploadField.tsx +841 -0
- package/src/components/GlobalSearch.tsx +436 -0
- package/src/components/GroupField.tsx +85 -0
- package/src/components/HiddenField.tsx +14 -0
- package/src/components/ModalBreadcrumb.tsx +74 -0
- package/src/components/ModalDrawer.tsx +137 -0
- package/src/components/RadioField.tsx +80 -0
- package/src/components/RepeaterField.tsx +546 -0
- package/src/components/ResourceModalRenderer.tsx +144 -0
- package/src/components/RichEditorField.tsx +942 -0
- package/src/components/SectionField.tsx +242 -0
- package/src/components/SelectField.tsx +843 -0
- package/src/components/TabsField.test.tsx +151 -0
- package/src/components/TabsField.tsx +386 -0
- package/src/components/TagsInputField.tsx +411 -0
- package/src/components/TextInputField.tsx +91 -0
- package/src/components/TextareaField.tsx +110 -0
- package/src/components/ToggleField.tsx +126 -0
- package/src/components/ViewModal.tsx +353 -0
- package/src/components/blocks/BlockRenderer.tsx +56 -0
- package/src/components/blocks/FormBlockRenderer.tsx +160 -0
- package/src/components/blocks/TableBlockRenderer.tsx +33 -0
- package/src/components/blocks/TabsBlockRenderer.tsx +49 -0
- package/src/components/blocks/WidgetBlockRenderer.tsx +19 -0
- package/src/components/columns/CheckboxColumnComponent.tsx +38 -0
- package/src/components/columns/ColorColumnComponent.tsx +23 -0
- package/src/components/columns/CustomColumn.test.tsx +55 -0
- package/src/components/columns/DeeplinkWrapper.tsx +103 -0
- package/src/components/columns/IconColumnComponent.tsx +55 -0
- package/src/components/columns/ImageColumnComponent.tsx +220 -0
- package/src/components/columns/MediaColumnComponent.tsx +294 -0
- package/src/components/columns/SelectColumnComponent.tsx +49 -0
- package/src/components/columns/TagsColumnComponent.tsx +46 -0
- package/src/components/columns/TextColumnComponent.tsx +191 -0
- package/src/components/columns/TextInputColumnComponent.tsx +35 -0
- package/src/components/columns/ToggleColumnComponent.tsx +56 -0
- package/src/components/columns/VideoColumnComponent.tsx +236 -0
- package/src/components/columns/ViewColumnComponent.tsx +9 -0
- package/src/components/errors/ErrorBoundary.tsx +58 -0
- package/src/components/filters/CustomFilterComponent.tsx +130 -0
- package/src/components/filters/DateFilterComponent.tsx +272 -0
- package/src/components/filters/QueryBuilderFilterComponent.tsx +502 -0
- package/src/components/layout/Header.tsx +212 -0
- package/src/components/layout/PanelBrandMark.tsx +61 -0
- package/src/components/layout/Sidebar.tsx +283 -0
- package/src/components/modals/RelationCreateModal.tsx +107 -0
- package/src/components/modals/ResourceFormModal.test.tsx +119 -0
- package/src/components/modals/ResourceFormModal.tsx +128 -0
- package/src/components/modals/useResourceForm.ts +207 -0
- package/src/components/modals/view/RecordActions.tsx +69 -0
- package/src/components/modals/view/RecordDetails.tsx +60 -0
- package/src/components/modals/view/RelationPanel.tsx +76 -0
- package/src/components/modals/view/RelationTabs.tsx +145 -0
- package/src/components/modals/view/useRecordView.ts +134 -0
- package/src/components/pages/PageRenderer.tsx +173 -0
- package/src/components/table/ColumnTogglePopup.tsx +85 -0
- package/src/components/table/GridCard.tsx +155 -0
- package/src/components/table/GridView.tsx +138 -0
- package/src/components/table/LayoutToggle.tsx +24 -0
- package/src/components/table/TableActionsDropdown.tsx +114 -0
- package/src/components/table/TableBulkActions.tsx +65 -0
- package/src/components/table/TableHeader.tsx +96 -0
- package/src/components/table/TablePagination.tsx +169 -0
- package/src/components/table/TableRow.tsx +155 -0
- package/src/components/table/TableSearchBar.tsx +66 -0
- package/src/components/table/TableTabs.tsx +49 -0
- package/src/components/ui/Badge.tsx +30 -0
- package/src/components/ui/Button.test.tsx +78 -0
- package/src/components/ui/Button.tsx +102 -0
- package/src/components/ui/Card.tsx +23 -0
- package/src/components/ui/ConfirmDialog.tsx +112 -0
- package/src/components/ui/EmptyState.tsx +24 -0
- package/src/components/ui/ErrorAlert.tsx +37 -0
- package/src/components/ui/Input.tsx +48 -0
- package/src/components/ui/Label.tsx +15 -0
- package/src/components/ui/PillButton.tsx +72 -0
- package/src/components/ui/Select.tsx +33 -0
- package/src/components/ui/Spinner.tsx +39 -0
- package/src/components/ui/Toast.tsx +105 -0
- package/src/components/ui/index.ts +24 -0
- package/src/components/utils/HintDisplay.tsx +26 -0
- package/src/components/utils/Icon.tsx +36 -0
- package/src/components/utils/MediaPreviewModal.tsx +114 -0
- package/src/components/utils/ViewFieldWrapper.tsx +23 -0
- package/src/components/utils/layoutHelpers.ts +267 -0
- package/src/components/widgets/ChartWidget.tsx +247 -0
- package/src/components/widgets/StatsWidget.tsx +72 -0
- package/src/components/widgets/WidgetRenderer.tsx +108 -0
- package/src/components/widgets/WidgetShell.tsx +37 -0
- package/src/contexts/AuthChallengeRegistryContext.tsx +29 -0
- package/src/contexts/BlockRegistryContext.tsx +28 -0
- package/src/contexts/ColumnRegistryContext.tsx +38 -0
- package/src/contexts/FieldRegistryContext.tsx +56 -0
- package/src/contexts/PanelMetadataContext.tsx +60 -0
- package/src/contexts/PanelProviders.tsx +85 -0
- package/src/contexts/ResourceModalContext.tsx +137 -0
- package/src/contexts/SlotRegistryContext.tsx +35 -0
- package/src/contexts/TableRefreshContext.tsx +44 -0
- package/src/contexts/WidgetRegistryContext.tsx +34 -0
- package/src/contexts/createRegistryContext.tsx +29 -0
- package/src/hooks/useAfterStateUpdated.ts +70 -0
- package/src/hooks/useValidation.test.ts +59 -0
- package/src/hooks/useValidation.ts +95 -0
- package/src/i18n/I18nProvider.tsx +128 -0
- package/src/i18n/LocaleSwitcher.tsx +50 -0
- package/src/i18n/activeLocale.ts +39 -0
- package/src/i18n/buildClientI18n.ts +101 -0
- package/src/i18n/i18n.test.tsx +140 -0
- package/src/i18n/index.ts +12 -0
- package/src/i18n/locales/core/en.ts +274 -0
- package/src/i18n/locales/core/index.ts +5 -0
- package/src/i18n/locales/core/sq.ts +275 -0
- package/src/i18n/useFormatter.ts +42 -0
- package/src/i18n/useLocale.ts +16 -0
- package/src/i18n/useTranslation.ts +17 -0
- package/src/index.ts +244 -0
- package/src/pages/ResourceListPage.tsx +205 -0
- package/src/plugin.ts +110 -0
- package/src/runtime/conditions.test.ts +99 -0
- package/src/runtime/conditions.ts +148 -0
- package/src/runtime/formTraversal.ts +41 -0
- package/src/runtime/serializedFunctions.test.ts +59 -0
- package/src/runtime/serializedFunctions.ts +284 -0
- package/src/slots/Slot.test.tsx +89 -0
- package/src/slots/Slot.tsx +47 -0
- package/src/slots/SlotCluster.test.tsx +95 -0
- package/src/slots/SlotCluster.tsx +107 -0
- package/src/slots/index.ts +15 -0
- package/src/slots/mergeSlots.test.ts +71 -0
- package/src/slots/mergeSlots.ts +40 -0
- package/src/slots/slotNames.test.ts +21 -0
- package/src/slots/types.ts +119 -0
- package/src/styles.css +437 -0
- package/src/table/TableContext.tsx +41 -0
- package/src/table/TableRenderer.test.tsx +197 -0
- package/src/table/TableRenderer.tsx +390 -0
- package/src/table/components/FiltersPanel.tsx +193 -0
- package/src/table/components/TableToolbar.tsx +153 -0
- package/src/table/components/TableToolbarButton.tsx +14 -0
- package/src/table/components/TableView.tsx +106 -0
- package/src/table/defaultRowActions.ts +43 -0
- package/src/table/hooks/useColumnVisibility.test.ts +51 -0
- package/src/table/hooks/useColumnVisibility.ts +71 -0
- package/src/table/hooks/useEditableRows.test.ts +69 -0
- package/src/table/hooks/useEditableRows.ts +89 -0
- package/src/table/hooks/useTableActions.ts +393 -0
- package/src/table/hooks/useTableData.ts +89 -0
- package/src/table/hooks/useTableLayout.ts +45 -0
- package/src/table/hooks/useTableQuery.test.ts +116 -0
- package/src/table/hooks/useTableQuery.ts +172 -0
- package/src/test/mockFetch.ts +67 -0
- package/src/test/setup.ts +25 -0
- package/src/types/index.ts +228 -0
- package/src/utils/classNames.ts +10 -0
- package/src/utils/columnMediaDimensions.ts +45 -0
- package/src/utils/columnVisibilityStorage.ts +55 -0
- package/src/utils/fieldErrors.test.ts +35 -0
- package/src/utils/fieldErrors.ts +27 -0
- package/src/utils/formatValue.test.tsx +65 -0
- package/src/utils/formatValue.tsx +117 -0
- package/src/utils/layoutStorage.ts +52 -0
- package/src/utils/redirectHandler.ts +29 -0
- package/src/utils/tableFormatters.test.ts +54 -0
- package/src/utils/tableFormatters.ts +104 -0
- package/src/utils/widgetVisibilityStorage.ts +38 -0
- package/tailwind.config.js +9 -0
- package/vite.config.ts +17 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Icon } from '../utils/Icon';
|
|
3
|
+
import { cn } from '../../utils/classNames';
|
|
4
|
+
|
|
5
|
+
export interface WidgetShellProps {
|
|
6
|
+
label?: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Shared card shell for dashboard/table widgets. */
|
|
13
|
+
export function WidgetShell({ label, icon, className, children }: WidgetShellProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
className={cn(
|
|
17
|
+
'flex min-h-[8.5rem] flex-col rounded-xl border border-border bg-surface p-4 transition-colors hover:bg-hover/20',
|
|
18
|
+
className,
|
|
19
|
+
)}>
|
|
20
|
+
{(label || icon) && (
|
|
21
|
+
<div className="mb-3 flex items-start justify-between gap-2">
|
|
22
|
+
{label ? (
|
|
23
|
+
<p className="text-[11px] font-medium uppercase tracking-wider text-fg-muted">{label}</p>
|
|
24
|
+
) : (
|
|
25
|
+
<span />
|
|
26
|
+
)}
|
|
27
|
+
{icon && (
|
|
28
|
+
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-raised text-fg-secondary shadow-soft-sm">
|
|
29
|
+
<Icon name={icon} className="h-4 w-4" />
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
<div className="flex min-h-0 flex-1 flex-col">{children}</div>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AuthChallengeComponent } from '../auth/types';
|
|
3
|
+
import { createRegistryContext } from './createRegistryContext';
|
|
4
|
+
|
|
5
|
+
export type AuthChallengeRegistry = Record<string, AuthChallengeComponent>;
|
|
6
|
+
|
|
7
|
+
// No built-in challenge UIs: challenge components are entirely plugin-provided
|
|
8
|
+
// (e.g. the 2FA plugin registers a '2fa-totp' component).
|
|
9
|
+
const registry = createRegistryContext<AuthChallengeComponent>('AuthChallengeRegistry', {});
|
|
10
|
+
|
|
11
|
+
export const AuthChallengeRegistryContext = registry.Context;
|
|
12
|
+
export const useAuthChallengeRegistry = registry.useRegistry;
|
|
13
|
+
|
|
14
|
+
export interface AuthChallengeRegistryProviderProps {
|
|
15
|
+
customAuthChallenges?: AuthChallengeRegistry;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Provider for challenge UI components keyed by challenge `type`. Lives above the auth gate
|
|
21
|
+
* so the LoginPage (rendered when there is no user) can look up the component for a pending
|
|
22
|
+
* challenge.
|
|
23
|
+
*/
|
|
24
|
+
export function AuthChallengeRegistryProvider({
|
|
25
|
+
customAuthChallenges = {},
|
|
26
|
+
children,
|
|
27
|
+
}: AuthChallengeRegistryProviderProps) {
|
|
28
|
+
return <registry.Provider registry={customAuthChallenges}>{children}</registry.Provider>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRegistryContext } from './createRegistryContext';
|
|
3
|
+
|
|
4
|
+
export interface CustomBlockComponentProps {
|
|
5
|
+
block: any;
|
|
6
|
+
blockData?: Record<string, any>;
|
|
7
|
+
apiBaseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type CustomBlockComponent = React.ComponentType<CustomBlockComponentProps>;
|
|
11
|
+
|
|
12
|
+
export interface BlockRegistry {
|
|
13
|
+
[key: string]: CustomBlockComponent;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const registry = createRegistryContext<CustomBlockComponent>('BlockRegistry', {});
|
|
17
|
+
|
|
18
|
+
interface BlockRegistryProviderProps {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
customBlocks?: BlockRegistry;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function BlockRegistryProvider({ children, customBlocks }: BlockRegistryProviderProps) {
|
|
24
|
+
return <registry.Provider registry={customBlocks}>{children}</registry.Provider>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Returns the flat block registry (custom page blocks keyed by type). */
|
|
28
|
+
export const useBlockRegistry = registry.useRegistry;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRegistryContext } from './createRegistryContext';
|
|
3
|
+
import { TextColumnComponent } from '../components/columns/TextColumnComponent';
|
|
4
|
+
import { IconColumnComponent } from '../components/columns/IconColumnComponent';
|
|
5
|
+
import { ImageColumnComponent } from '../components/columns/ImageColumnComponent';
|
|
6
|
+
import { VideoColumnComponent } from '../components/columns/VideoColumnComponent';
|
|
7
|
+
import { MediaColumnComponent } from '../components/columns/MediaColumnComponent';
|
|
8
|
+
import { ColorColumnComponent } from '../components/columns/ColorColumnComponent';
|
|
9
|
+
import { TagsColumnComponent } from '../components/columns/TagsColumnComponent';
|
|
10
|
+
import { ViewColumnComponent } from '../components/columns/ViewColumnComponent';
|
|
11
|
+
import { CheckboxColumnComponent } from '../components/columns/CheckboxColumnComponent';
|
|
12
|
+
import { ToggleColumnComponent } from '../components/columns/ToggleColumnComponent';
|
|
13
|
+
import { SelectColumnComponent } from '../components/columns/SelectColumnComponent';
|
|
14
|
+
import { TextInputColumnComponent } from '../components/columns/TextInputColumnComponent';
|
|
15
|
+
|
|
16
|
+
export type ColumnComponent = React.ComponentType<any>;
|
|
17
|
+
|
|
18
|
+
export type ColumnRegistry = Record<string, ColumnComponent>;
|
|
19
|
+
|
|
20
|
+
const defaultColumns: ColumnRegistry = {
|
|
21
|
+
text: TextColumnComponent,
|
|
22
|
+
icon: IconColumnComponent,
|
|
23
|
+
image: ImageColumnComponent,
|
|
24
|
+
video: VideoColumnComponent,
|
|
25
|
+
media: MediaColumnComponent,
|
|
26
|
+
color: ColorColumnComponent,
|
|
27
|
+
tags: TagsColumnComponent,
|
|
28
|
+
view: ViewColumnComponent,
|
|
29
|
+
checkbox: CheckboxColumnComponent,
|
|
30
|
+
toggle: ToggleColumnComponent,
|
|
31
|
+
select: SelectColumnComponent,
|
|
32
|
+
textinput: TextInputColumnComponent,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const registry = createRegistryContext<ColumnComponent>('ColumnRegistry', defaultColumns);
|
|
36
|
+
|
|
37
|
+
export const ColumnRegistryProvider = registry.Provider;
|
|
38
|
+
export const useColumnRegistry = registry.useRegistry;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FieldRegistry } from '../types';
|
|
3
|
+
import { createRegistryContext } from './createRegistryContext';
|
|
4
|
+
import { TextInputField } from '../components/TextInputField';
|
|
5
|
+
import { SelectField } from '../components/SelectField';
|
|
6
|
+
import { TextareaField } from '../components/TextareaField';
|
|
7
|
+
import { CheckboxField } from '../components/CheckboxField';
|
|
8
|
+
import { ToggleField } from '../components/ToggleField';
|
|
9
|
+
import { RadioField } from '../components/RadioField';
|
|
10
|
+
import { DateTimePickerField } from '../components/DateTimePickerField';
|
|
11
|
+
import { ColorPickerField } from '../components/ColorPickerField';
|
|
12
|
+
import { RepeaterField } from '../components/RepeaterField';
|
|
13
|
+
import { TagsInputField } from '../components/TagsInputField';
|
|
14
|
+
import { HiddenField } from '../components/HiddenField';
|
|
15
|
+
import { FileUploadField } from '../components/FileUploadField';
|
|
16
|
+
import { RichEditorField } from '../components/RichEditorField';
|
|
17
|
+
import { SectionField } from '../components/SectionField';
|
|
18
|
+
import { GroupField } from '../components/GroupField';
|
|
19
|
+
import { TabsField } from '../components/TabsField';
|
|
20
|
+
|
|
21
|
+
const defaultFields: FieldRegistry = {
|
|
22
|
+
'text-input': TextInputField,
|
|
23
|
+
select: SelectField,
|
|
24
|
+
textarea: TextareaField,
|
|
25
|
+
checkbox: CheckboxField,
|
|
26
|
+
toggle: ToggleField,
|
|
27
|
+
radio: RadioField,
|
|
28
|
+
'date-time-picker': DateTimePickerField,
|
|
29
|
+
'color-picker': ColorPickerField,
|
|
30
|
+
repeater: RepeaterField,
|
|
31
|
+
'tags-input': TagsInputField,
|
|
32
|
+
hidden: HiddenField,
|
|
33
|
+
fileUpload: FileUploadField,
|
|
34
|
+
richEditor: RichEditorField,
|
|
35
|
+
section: SectionField,
|
|
36
|
+
group: GroupField,
|
|
37
|
+
tabs: TabsField,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const registry = createRegistryContext('FieldRegistry', defaultFields);
|
|
41
|
+
|
|
42
|
+
export const FieldRegistryContext = registry.Context;
|
|
43
|
+
export const useFieldRegistry = registry.useRegistry;
|
|
44
|
+
|
|
45
|
+
export interface FieldRegistryProviderProps {
|
|
46
|
+
customFields?: FieldRegistry;
|
|
47
|
+
children: React.ReactNode;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Provider component that manages the field registry.
|
|
52
|
+
* Custom field components (e.g. from plugins) override the built-ins.
|
|
53
|
+
*/
|
|
54
|
+
export function FieldRegistryProvider({ customFields = {}, children }: FieldRegistryProviderProps) {
|
|
55
|
+
return <registry.Provider registry={customFields}>{children}</registry.Provider>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { createContext, useContext, ReactNode } from 'react';
|
|
2
|
+
import type { ResourceMetadata } from '../components/layout/Sidebar';
|
|
3
|
+
|
|
4
|
+
export interface PageMetadata {
|
|
5
|
+
slug: string;
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
navigationGroup?: string;
|
|
9
|
+
navigationSort?: number;
|
|
10
|
+
hidden?: boolean;
|
|
11
|
+
badge?: string | number | null;
|
|
12
|
+
badgeColor?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PanelMetadataContextType {
|
|
16
|
+
resources: ResourceMetadata[];
|
|
17
|
+
pages: PageMetadata[];
|
|
18
|
+
getResourceLabel: (slug: string) => string | undefined;
|
|
19
|
+
getPageLabel: (slug: string) => string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const PanelMetadataContext = createContext<PanelMetadataContextType | undefined>(undefined);
|
|
23
|
+
|
|
24
|
+
export interface PanelMetadataProviderProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
resources: ResourceMetadata[];
|
|
27
|
+
pages: PageMetadata[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function PanelMetadataProvider({ children, resources, pages }: PanelMetadataProviderProps) {
|
|
31
|
+
const getResourceLabel = (slug: string): string | undefined => {
|
|
32
|
+
const resource = resources.find(r => r.slug === slug);
|
|
33
|
+
return resource?.label;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getPageLabel = (slug: string): string | undefined => {
|
|
37
|
+
const page = pages.find(p => p.slug === slug);
|
|
38
|
+
return page?.label;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<PanelMetadataContext.Provider
|
|
43
|
+
value={{
|
|
44
|
+
resources,
|
|
45
|
+
pages,
|
|
46
|
+
getResourceLabel,
|
|
47
|
+
getPageLabel,
|
|
48
|
+
}}>
|
|
49
|
+
{children}
|
|
50
|
+
</PanelMetadataContext.Provider>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function usePanelMetadata() {
|
|
55
|
+
const context = useContext(PanelMetadataContext);
|
|
56
|
+
if (!context) {
|
|
57
|
+
throw new Error('usePanelMetadata must be used within PanelMetadataProvider');
|
|
58
|
+
}
|
|
59
|
+
return context;
|
|
60
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AuthProvider } from '../auth/AuthContext';
|
|
3
|
+
import { ProtectedRoute } from '../auth/ProtectedRoute';
|
|
4
|
+
import { ResourceModalProvider } from './ResourceModalContext';
|
|
5
|
+
import { TableRefreshProvider } from './TableRefreshContext';
|
|
6
|
+
import { BlockRegistryProvider, BlockRegistry } from './BlockRegistryContext';
|
|
7
|
+
import { WidgetRegistryProvider, WidgetRegistry } from './WidgetRegistryContext';
|
|
8
|
+
import { FieldRegistryProvider } from './FieldRegistryContext';
|
|
9
|
+
import { ColumnRegistryProvider, ColumnRegistry } from './ColumnRegistryContext';
|
|
10
|
+
import { AuthChallengeRegistryProvider, AuthChallengeRegistry } from './AuthChallengeRegistryContext';
|
|
11
|
+
import { SlotRegistryProvider } from './SlotRegistryContext';
|
|
12
|
+
import type { ResolvedSlots } from '../slots/types';
|
|
13
|
+
import { ToastProvider } from '../components/ui/Toast';
|
|
14
|
+
import { ConfirmProvider } from '../components/ui/ConfirmDialog';
|
|
15
|
+
import { I18nProvider } from '../i18n/I18nProvider';
|
|
16
|
+
import type { ClientI18nConfig } from '../i18n/buildClientI18n';
|
|
17
|
+
import { FieldRegistry } from '../types';
|
|
18
|
+
|
|
19
|
+
export interface PanelProvidersProps {
|
|
20
|
+
apiBaseUrl: string;
|
|
21
|
+
customFields?: FieldRegistry;
|
|
22
|
+
customColumns?: ColumnRegistry;
|
|
23
|
+
customWidgets?: WidgetRegistry;
|
|
24
|
+
customBlocks?: BlockRegistry;
|
|
25
|
+
customAuthChallenges?: AuthChallengeRegistry;
|
|
26
|
+
customSlots?: ResolvedSlots;
|
|
27
|
+
i18nConfig?: ClientI18nConfig;
|
|
28
|
+
children: React.ReactNode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Composes the auth gate and every panel-level provider (modal stack,
|
|
33
|
+
* table refresh, and the component registries) in one place.
|
|
34
|
+
*
|
|
35
|
+
* The auth-challenge registry wraps the auth gate so the LoginPage — rendered by
|
|
36
|
+
* ProtectedRoute when there is no user — can resolve the component for a pending challenge.
|
|
37
|
+
*/
|
|
38
|
+
export function PanelProviders({
|
|
39
|
+
apiBaseUrl,
|
|
40
|
+
customFields,
|
|
41
|
+
customColumns,
|
|
42
|
+
customWidgets,
|
|
43
|
+
customBlocks,
|
|
44
|
+
customAuthChallenges,
|
|
45
|
+
customSlots,
|
|
46
|
+
i18nConfig,
|
|
47
|
+
children,
|
|
48
|
+
}: PanelProvidersProps) {
|
|
49
|
+
return (
|
|
50
|
+
<I18nProvider config={i18nConfig}>
|
|
51
|
+
<ToastProvider>
|
|
52
|
+
<ConfirmProvider>
|
|
53
|
+
<AuthProvider apiBaseUrl={apiBaseUrl}>
|
|
54
|
+
<AuthChallengeRegistryProvider customAuthChallenges={customAuthChallenges}>
|
|
55
|
+
{/*
|
|
56
|
+
* SlotRegistryProvider wraps ProtectedRoute so the LoginPage —
|
|
57
|
+
* rendered as ProtectedRoute's unauthenticated fallback — can
|
|
58
|
+
* resolve the `login.belowForm` slot. It only supplies the slot
|
|
59
|
+
* map; contributions render at their <Slot> call site and inherit
|
|
60
|
+
* whatever providers sit above that location.
|
|
61
|
+
*/}
|
|
62
|
+
<SlotRegistryProvider slots={customSlots}>
|
|
63
|
+
<ProtectedRoute apiBaseUrl={apiBaseUrl}>
|
|
64
|
+
<ResourceModalProvider>
|
|
65
|
+
<TableRefreshProvider>
|
|
66
|
+
<BlockRegistryProvider customBlocks={customBlocks}>
|
|
67
|
+
<WidgetRegistryProvider customWidgets={customWidgets}>
|
|
68
|
+
<FieldRegistryProvider customFields={customFields}>
|
|
69
|
+
<ColumnRegistryProvider registry={customColumns}>
|
|
70
|
+
{children}
|
|
71
|
+
</ColumnRegistryProvider>
|
|
72
|
+
</FieldRegistryProvider>
|
|
73
|
+
</WidgetRegistryProvider>
|
|
74
|
+
</BlockRegistryProvider>
|
|
75
|
+
</TableRefreshProvider>
|
|
76
|
+
</ResourceModalProvider>
|
|
77
|
+
</ProtectedRoute>
|
|
78
|
+
</SlotRegistryProvider>
|
|
79
|
+
</AuthChallengeRegistryProvider>
|
|
80
|
+
</AuthProvider>
|
|
81
|
+
</ConfirmProvider>
|
|
82
|
+
</ToastProvider>
|
|
83
|
+
</I18nProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ModalState {
|
|
4
|
+
resource: string;
|
|
5
|
+
recordId?: string; // Optional for create mode
|
|
6
|
+
mode: 'view' | 'edit' | 'create' | 'action';
|
|
7
|
+
depth: number;
|
|
8
|
+
// For action modals
|
|
9
|
+
actionName?: string;
|
|
10
|
+
actionLabel?: string;
|
|
11
|
+
// Set by cross-resource deeplinks: the URL that was active before pushState was
|
|
12
|
+
// called to show this modal's URL. Used to restore the URL on close without
|
|
13
|
+
// touching React Router's internal location.
|
|
14
|
+
originUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ResourceModalContextType {
|
|
18
|
+
modalStack: ModalState[];
|
|
19
|
+
modalTitles: Record<string, string>;
|
|
20
|
+
openModal: (
|
|
21
|
+
resource: string,
|
|
22
|
+
mode: 'view' | 'edit' | 'create' | 'action',
|
|
23
|
+
recordId?: string,
|
|
24
|
+
actionName?: string,
|
|
25
|
+
actionLabel?: string,
|
|
26
|
+
originUrl?: string,
|
|
27
|
+
) => void;
|
|
28
|
+
closeModal: () => void; // Closes top modal (pop from stack)
|
|
29
|
+
closeAllModals: () => void;
|
|
30
|
+
clearModalsForResource: (resource: string) => void; // Clear modals for specific resource when navigating away
|
|
31
|
+
setModalTitle: (key: string, title: string) => void;
|
|
32
|
+
removeModalTitle: (key: string) => void;
|
|
33
|
+
clearModalTitles: () => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ResourceModalContext = createContext<ResourceModalContextType | undefined>(undefined);
|
|
37
|
+
|
|
38
|
+
export function ResourceModalProvider({ children }: { children: ReactNode }) {
|
|
39
|
+
const [modalStack, setModalStack] = useState<ModalState[]>([]);
|
|
40
|
+
const [modalTitles, setModalTitles] = useState<Record<string, string>>({});
|
|
41
|
+
|
|
42
|
+
const openModal = useCallback(
|
|
43
|
+
(
|
|
44
|
+
resource: string,
|
|
45
|
+
mode: 'view' | 'edit' | 'create' | 'action',
|
|
46
|
+
recordId?: string,
|
|
47
|
+
actionName?: string,
|
|
48
|
+
actionLabel?: string,
|
|
49
|
+
originUrl?: string,
|
|
50
|
+
) => {
|
|
51
|
+
setModalStack(prev => {
|
|
52
|
+
// Check if this exact modal is already at the top of the stack (prevent duplicates)
|
|
53
|
+
const topModal = prev[prev.length - 1];
|
|
54
|
+
if (
|
|
55
|
+
topModal &&
|
|
56
|
+
topModal.resource === resource &&
|
|
57
|
+
topModal.recordId === recordId &&
|
|
58
|
+
topModal.mode === mode &&
|
|
59
|
+
topModal.actionName === actionName
|
|
60
|
+
) {
|
|
61
|
+
// Same modal already at top, don't add duplicate
|
|
62
|
+
return prev;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Add new modal to stack with auto-calculated depth
|
|
66
|
+
const newModal: ModalState = {
|
|
67
|
+
resource,
|
|
68
|
+
recordId,
|
|
69
|
+
mode,
|
|
70
|
+
depth: prev.length, // depth = current stack length
|
|
71
|
+
actionName,
|
|
72
|
+
actionLabel,
|
|
73
|
+
originUrl,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return [...prev, newModal];
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
[],
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const closeModal = useCallback(() => {
|
|
83
|
+
setModalStack(prev => {
|
|
84
|
+
if (prev.length === 0) return prev;
|
|
85
|
+
// Remove last modal from stack (pop)
|
|
86
|
+
return prev.slice(0, -1);
|
|
87
|
+
});
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const closeAllModals = useCallback(() => {
|
|
91
|
+
setModalStack([]);
|
|
92
|
+
}, []);
|
|
93
|
+
|
|
94
|
+
const clearModalsForResource = useCallback((resource: string) => {
|
|
95
|
+
setModalStack(prev => prev.filter(modal => modal.resource !== resource));
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
const setModalTitle = useCallback((key: string, title: string) => {
|
|
99
|
+
setModalTitles(prev => ({ ...prev, [key]: title }));
|
|
100
|
+
}, []);
|
|
101
|
+
|
|
102
|
+
const removeModalTitle = useCallback((key: string) => {
|
|
103
|
+
setModalTitles(prev => {
|
|
104
|
+
const { [key]: _, ...rest } = prev;
|
|
105
|
+
return rest;
|
|
106
|
+
});
|
|
107
|
+
}, []);
|
|
108
|
+
|
|
109
|
+
const clearModalTitles = useCallback(() => {
|
|
110
|
+
setModalTitles({});
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<ResourceModalContext.Provider
|
|
115
|
+
value={{
|
|
116
|
+
modalStack,
|
|
117
|
+
modalTitles,
|
|
118
|
+
openModal,
|
|
119
|
+
closeModal,
|
|
120
|
+
closeAllModals,
|
|
121
|
+
clearModalsForResource,
|
|
122
|
+
setModalTitle,
|
|
123
|
+
removeModalTitle,
|
|
124
|
+
clearModalTitles,
|
|
125
|
+
}}>
|
|
126
|
+
{children}
|
|
127
|
+
</ResourceModalContext.Provider>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function useResourceModal() {
|
|
132
|
+
const context = useContext(ResourceModalContext);
|
|
133
|
+
if (!context) {
|
|
134
|
+
throw new Error('useResourceModal must be used within ResourceModalProvider');
|
|
135
|
+
}
|
|
136
|
+
return context;
|
|
137
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import type { SlotContribution, ResolvedSlots, SlotName } from '../slots/types';
|
|
3
|
+
import { sortSlots } from '../slots/mergeSlots';
|
|
4
|
+
|
|
5
|
+
const SlotRegistryContext = createContext<ResolvedSlots>({});
|
|
6
|
+
SlotRegistryContext.displayName = 'SlotRegistry';
|
|
7
|
+
|
|
8
|
+
export interface SlotRegistryProviderProps {
|
|
9
|
+
/** Resolved slot map (already merged across plugins + app). */
|
|
10
|
+
slots?: ResolvedSlots;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Provides the merged slot map to the tree. Slots differ from the component
|
|
16
|
+
* registries (`createRegistryContext`): they are 1:many and concatenated rather
|
|
17
|
+
* than overridden, so this provider keeps a sorted array per slot name.
|
|
18
|
+
*/
|
|
19
|
+
export function SlotRegistryProvider({ slots = {}, children }: SlotRegistryProviderProps) {
|
|
20
|
+
const value = useMemo(() => sortSlots({ ...slots }), [slots]);
|
|
21
|
+
return <SlotRegistryContext.Provider value={value}>{children}</SlotRegistryContext.Provider>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Full resolved slot map (for introspection/tests). */
|
|
25
|
+
export function useSlotRegistry(): ResolvedSlots {
|
|
26
|
+
return useContext(SlotRegistryContext);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The sorted contributions for a single slot, or an empty array. */
|
|
30
|
+
export function useSlot(name: SlotName): SlotContribution[] {
|
|
31
|
+
const registry = useContext(SlotRegistryContext);
|
|
32
|
+
return registry[name] ?? [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { SlotRegistryContext };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { createContext, useContext, useCallback, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface TableRefreshContextType {
|
|
4
|
+
refreshTable: (resourceSlug: string) => void;
|
|
5
|
+
registerRefresh: (resourceSlug: string, callback: () => void) => () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const TableRefreshContext = createContext<TableRefreshContextType | undefined>(undefined);
|
|
9
|
+
|
|
10
|
+
export function TableRefreshProvider({ children }: { children: ReactNode }) {
|
|
11
|
+
const refreshCallbacks = React.useRef<Map<string, () => void>>(new Map());
|
|
12
|
+
|
|
13
|
+
const refreshTable = useCallback((resourceSlug: string) => {
|
|
14
|
+
const callback = refreshCallbacks.current.get(resourceSlug);
|
|
15
|
+
if (callback) {
|
|
16
|
+
callback();
|
|
17
|
+
}
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
const registerRefresh = useCallback((resourceSlug: string, callback: () => void) => {
|
|
21
|
+
refreshCallbacks.current.set(resourceSlug, callback);
|
|
22
|
+
return () => {
|
|
23
|
+
refreshCallbacks.current.delete(resourceSlug);
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<TableRefreshContext.Provider value={{ refreshTable, registerRefresh }}>
|
|
29
|
+
{children}
|
|
30
|
+
</TableRefreshContext.Provider>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useTableRefresh() {
|
|
35
|
+
const context = useContext(TableRefreshContext);
|
|
36
|
+
if (!context) {
|
|
37
|
+
// Return no-op functions if context is not available
|
|
38
|
+
return {
|
|
39
|
+
refreshTable: () => {},
|
|
40
|
+
registerRefresh: () => () => {},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return context;
|
|
44
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRegistryContext } from './createRegistryContext';
|
|
3
|
+
import { StatsWidget } from '../components/widgets/StatsWidget';
|
|
4
|
+
import { ChartWidget } from '../components/widgets/ChartWidget';
|
|
5
|
+
|
|
6
|
+
export interface WidgetComponentProps {
|
|
7
|
+
widget: any;
|
|
8
|
+
data: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type WidgetComponent = React.ComponentType<WidgetComponentProps>;
|
|
12
|
+
|
|
13
|
+
export interface WidgetRegistry {
|
|
14
|
+
[key: string]: WidgetComponent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const builtInWidgets: WidgetRegistry = {
|
|
18
|
+
stats: StatsWidget,
|
|
19
|
+
chart: ChartWidget,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const registry = createRegistryContext<WidgetComponent>('WidgetRegistry', builtInWidgets);
|
|
23
|
+
|
|
24
|
+
interface WidgetRegistryProviderProps {
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
customWidgets?: WidgetRegistry;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function WidgetRegistryProvider({ children, customWidgets }: WidgetRegistryProviderProps) {
|
|
30
|
+
return <registry.Provider registry={customWidgets}>{children}</registry.Provider>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Returns the flat widget registry (built-ins merged with custom widgets). */
|
|
34
|
+
export const useWidgetRegistry = registry.useRegistry;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface RegistryProviderProps<T> {
|
|
4
|
+
/** Custom entries; merged over the defaults, custom entries win */
|
|
5
|
+
registry?: Record<string, T>;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Factory for component registries (fields, columns, widgets, blocks).
|
|
11
|
+
* All registries share one pattern: a flat `Record<string, Component>` of
|
|
12
|
+
* defaults that custom (plugin) entries can extend or override.
|
|
13
|
+
*/
|
|
14
|
+
export function createRegistryContext<T>(displayName: string, defaults: Record<string, T>) {
|
|
15
|
+
const Context = createContext<Record<string, T>>(defaults);
|
|
16
|
+
Context.displayName = displayName;
|
|
17
|
+
|
|
18
|
+
function Provider({ registry = {}, children }: RegistryProviderProps<T>) {
|
|
19
|
+
const merged = useMemo(() => ({ ...defaults, ...registry }), [registry]);
|
|
20
|
+
return <Context.Provider value={merged}>{children}</Context.Provider>;
|
|
21
|
+
}
|
|
22
|
+
Provider.displayName = `${displayName}Provider`;
|
|
23
|
+
|
|
24
|
+
function useRegistry(): Record<string, T> {
|
|
25
|
+
return useContext(Context);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { Context, Provider, useRegistry };
|
|
29
|
+
}
|