@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,179 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
3
|
+
import { AuthApiClient } from './authApiClient';
|
|
4
|
+
import { useAuth } from './AuthContext';
|
|
5
|
+
import { useAuthChallengeRegistry } from '../contexts/AuthChallengeRegistryContext';
|
|
6
|
+
import { Icon } from '../components/utils/Icon';
|
|
7
|
+
import { cn } from '../utils/classNames';
|
|
8
|
+
import { Button, IconButton, Input, Label, ErrorAlert, Spinner } from '../components/ui';
|
|
9
|
+
import { PanelBrandMark } from '../components/layout/PanelBrandMark';
|
|
10
|
+
import { Moon, Sun, ArrowLeft } from 'lucide-react';
|
|
11
|
+
import { useTranslation } from '../i18n/useTranslation';
|
|
12
|
+
import { LocaleSwitcher } from '../i18n/LocaleSwitcher';
|
|
13
|
+
import { Slot } from '../slots/Slot';
|
|
14
|
+
import { translate } from '../i18n/activeLocale';
|
|
15
|
+
function useDarkMode() {
|
|
16
|
+
const [darkMode, setDarkMode] = useState(() => {
|
|
17
|
+
const stored = localStorage.getItem('darkMode');
|
|
18
|
+
if (stored !== null) {
|
|
19
|
+
return stored === 'true';
|
|
20
|
+
}
|
|
21
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
22
|
+
});
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
document.documentElement.classList.toggle('dark', darkMode);
|
|
25
|
+
localStorage.setItem('darkMode', String(darkMode));
|
|
26
|
+
}, [darkMode]);
|
|
27
|
+
return [darkMode, setDarkMode];
|
|
28
|
+
}
|
|
29
|
+
/** Returns the i18n key for the login subtitle (translated at the call site). */
|
|
30
|
+
function getSubtitleKey(providers, selectedProvider) {
|
|
31
|
+
if (providers.length > 1 && !selectedProvider) {
|
|
32
|
+
return 'core:auth.choose_provider';
|
|
33
|
+
}
|
|
34
|
+
const provider = selectedProvider ?? providers[0];
|
|
35
|
+
if (provider?.type === 'oauth') {
|
|
36
|
+
return 'core:auth.continue';
|
|
37
|
+
}
|
|
38
|
+
return 'core:auth.enter_credentials';
|
|
39
|
+
}
|
|
40
|
+
function ProviderButton({ provider, onSelect }) {
|
|
41
|
+
const hasCustomStyle = Boolean(provider.buttonStyle?.backgroundColor);
|
|
42
|
+
return (_jsx(Button, { type: "button", variant: hasCustomStyle ? 'primary' : 'secondary', className: cn('w-full h-11', hasCustomStyle && 'border-transparent'), style: hasCustomStyle
|
|
43
|
+
? {
|
|
44
|
+
backgroundColor: provider.buttonStyle.backgroundColor,
|
|
45
|
+
color: provider.buttonStyle.textColor || '#ffffff',
|
|
46
|
+
borderColor: provider.buttonStyle.borderColor || provider.buttonStyle.backgroundColor,
|
|
47
|
+
}
|
|
48
|
+
: undefined, icon: provider.icon ? (_jsx(Icon, { name: provider.icon, className: cn('h-4 w-4', !hasCustomStyle && 'text-fg') })) : undefined, onClick: () => onSelect(provider), children: provider.label }));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Renders the active login challenge (e.g. 2FA) using the plugin-registered component for
|
|
52
|
+
* its `type`. Owns the per-attempt submitting/error state and wires the challenge UI to
|
|
53
|
+
* `verifyChallenge` / `cancelChallenge` from the auth context.
|
|
54
|
+
*/
|
|
55
|
+
function ChallengeStep({ challenge }) {
|
|
56
|
+
const { t } = useTranslation();
|
|
57
|
+
const { verifyChallenge, cancelChallenge } = useAuth();
|
|
58
|
+
const registry = useAuthChallengeRegistry();
|
|
59
|
+
const ChallengeComponent = registry[challenge.type];
|
|
60
|
+
const [error, setError] = useState(null);
|
|
61
|
+
const [submitting, setSubmitting] = useState(false);
|
|
62
|
+
if (!ChallengeComponent) {
|
|
63
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(ErrorAlert, { message: `No UI is registered for challenge type "${challenge.type}".` }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "-ml-2 h-8 px-2 text-fg-secondary", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: cancelChallenge, children: t('core:auth.back_to_signin') })] }));
|
|
64
|
+
}
|
|
65
|
+
const handleSubmit = async (payload) => {
|
|
66
|
+
setSubmitting(true);
|
|
67
|
+
setError(null);
|
|
68
|
+
try {
|
|
69
|
+
await verifyChallenge(payload);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
setError(err.message || t('core:auth.verification_failed'));
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
setSubmitting(false);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
return (_jsx(ChallengeComponent, { data: challenge.data, onSubmit: handleSubmit, onCancel: cancelChallenge, error: error, submitting: submitting }));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* LoginPage - Displays authentication providers and handles login
|
|
82
|
+
*/
|
|
83
|
+
export function LoginPage({ apiBaseUrl, onSuccess }) {
|
|
84
|
+
const { t } = useTranslation();
|
|
85
|
+
const { login, pendingChallenge } = useAuth();
|
|
86
|
+
const [providers, setProviders] = useState([]);
|
|
87
|
+
const [loading, setLoading] = useState(true);
|
|
88
|
+
const [error, setError] = useState(null);
|
|
89
|
+
const [selectedProvider, setSelectedProvider] = useState(null);
|
|
90
|
+
const [credentials, setCredentials] = useState({ email: '', password: '' });
|
|
91
|
+
const [submitting, setSubmitting] = useState(false);
|
|
92
|
+
const [panelBranding, setPanelBranding] = useState({});
|
|
93
|
+
const [darkMode, setDarkMode] = useDarkMode();
|
|
94
|
+
const apiClient = useMemo(() => new AuthApiClient(apiBaseUrl), [apiBaseUrl]);
|
|
95
|
+
const showProviderPicker = providers.length > 1 && !selectedProvider;
|
|
96
|
+
const activeProvider = selectedProvider ?? (providers.length === 1 ? providers[0] : null);
|
|
97
|
+
const showCredentialsForm = activeProvider?.type === 'credentials';
|
|
98
|
+
const showOAuthPrompt = activeProvider?.type === 'oauth' && !showProviderPicker;
|
|
99
|
+
const showBackLink = providers.length > 1 && selectedProvider?.type === 'credentials';
|
|
100
|
+
const subtitle = useMemo(() => t(getSubtitleKey(providers, selectedProvider)), [providers, selectedProvider, t]);
|
|
101
|
+
// Load panel branding for the login screen (meta endpoint allows unauthenticated access)
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const fetchBranding = async () => {
|
|
104
|
+
try {
|
|
105
|
+
const response = await fetch(`${apiBaseUrl}/meta`);
|
|
106
|
+
if (!response.ok)
|
|
107
|
+
return;
|
|
108
|
+
const meta = await response.json();
|
|
109
|
+
setPanelBranding({
|
|
110
|
+
title: meta.title,
|
|
111
|
+
icon: meta.icon,
|
|
112
|
+
favicon: meta.favicon,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Branding is optional — fall back to defaults
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
fetchBranding();
|
|
120
|
+
}, [apiBaseUrl]);
|
|
121
|
+
// Fetch available providers
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const fetchProviders = async () => {
|
|
124
|
+
try {
|
|
125
|
+
const providerList = await apiClient.getProviders();
|
|
126
|
+
setProviders(providerList);
|
|
127
|
+
if (providerList.length === 1) {
|
|
128
|
+
setSelectedProvider(providerList[0]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
setError(err.message || t('core:auth.providers_load_failed'));
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
setLoading(false);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
fetchProviders();
|
|
139
|
+
}, [apiClient]);
|
|
140
|
+
const handleProviderSelect = (provider) => {
|
|
141
|
+
if (provider.type === 'oauth') {
|
|
142
|
+
const redirectUri = encodeURIComponent(window.location.origin + window.location.pathname);
|
|
143
|
+
const authUrl = `${apiBaseUrl}/auth/oauth/${provider.name}?redirect_uri=${redirectUri}`;
|
|
144
|
+
window.location.href = authUrl;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
setSelectedProvider(provider);
|
|
148
|
+
setError(null);
|
|
149
|
+
};
|
|
150
|
+
const handleSubmit = async (e) => {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
if (!activeProvider)
|
|
153
|
+
return;
|
|
154
|
+
setSubmitting(true);
|
|
155
|
+
setError(null);
|
|
156
|
+
try {
|
|
157
|
+
await login(activeProvider.name, credentials);
|
|
158
|
+
onSuccess?.();
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
setError(err.message || t('core:auth.login_failed'));
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
setSubmitting(false);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
if (loading) {
|
|
168
|
+
return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-base px-6", children: _jsxs("div", { className: "text-center", children: [_jsx(Spinner, { size: "lg", className: "mx-auto text-accent" }), _jsx("p", { className: "mt-4 text-sm text-fg-secondary", children: translate('core:auth.preparing') })] }) }));
|
|
169
|
+
}
|
|
170
|
+
return (_jsxs("div", { className: "relative flex min-h-screen items-center justify-center bg-base px-6 py-12", children: [_jsxs("div", { className: "pointer-events-none absolute inset-0 overflow-hidden", "aria-hidden": "true", children: [_jsx("div", { className: "absolute -top-32 left-1/2 h-80 w-80 -translate-x-1/2 rounded-full bg-accent-soft/50 blur-3xl" }), _jsx("div", { className: "absolute bottom-0 right-0 h-72 w-72 translate-x-1/4 translate-y-1/4 rounded-full bg-accent-soft/25 blur-3xl" })] }), _jsx(IconButton, { variant: "secondary", size: "sm", "aria-label": darkMode ? t('core:panel.toggle_light') : t('core:panel.toggle_dark'), title: darkMode ? t('core:panel.toggle_light') : t('core:panel.toggle_dark'), onClick: () => setDarkMode(!darkMode), className: "absolute right-4 top-4 z-10 sm:right-6 sm:top-6", children: darkMode ? _jsx(Sun, { className: "h-4 w-4 text-warning" }) : _jsx(Moon, { className: "h-4 w-4" }) }), _jsxs("div", { className: "relative w-full max-w-[420px]", children: [_jsxs("header", { className: "mb-8 text-center", children: [_jsx("div", { className: "mx-auto mb-5 flex justify-center", children: _jsx(PanelBrandMark, { icon: panelBranding.icon, favicon: panelBranding.favicon, size: "lg" }) }), _jsx("h1", { className: "text-2xl font-semibold tracking-tight text-fg", children: pendingChallenge
|
|
171
|
+
? t('core:auth.verify_identity')
|
|
172
|
+
: panelBranding.title
|
|
173
|
+
? t('core:auth.sign_in_to', { title: panelBranding.title })
|
|
174
|
+
: t('core:auth.welcome_back') }), _jsx("p", { className: "mt-2 text-sm text-fg-secondary", children: pendingChallenge ? 'Complete the additional step to finish signing in' : subtitle })] }), _jsx(Slot, { name: "login.top", as: "div", className: "mb-6 space-y-4 empty:hidden" }), _jsxs("div", { className: "rounded-xl border border-border bg-surface p-6 shadow-soft sm:p-8", children: [pendingChallenge && _jsx(ChallengeStep, { challenge: pendingChallenge }), !pendingChallenge && error && (_jsx(ErrorAlert, { message: error, onDismiss: () => setError(null), className: "mb-6" })), !pendingChallenge && showProviderPicker && (_jsx("div", { className: "space-y-3", children: providers.map(provider => (_jsx(ProviderButton, { provider: provider, onSelect: handleProviderSelect }, provider.name))) })), !pendingChallenge && showOAuthPrompt && activeProvider && (_jsxs("div", { className: "space-y-4", children: [_jsx(ProviderButton, { provider: activeProvider, onSelect: handleProviderSelect }), _jsxs("p", { className: "text-center text-xs text-fg-muted", children: ["You will be redirected to ", activeProvider.label, " to complete sign in."] })] })), !pendingChallenge && showCredentialsForm && (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [showBackLink && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "-ml-2 h-8 px-2 text-fg-secondary", icon: _jsx(ArrowLeft, { className: "h-4 w-4" }), onClick: () => {
|
|
175
|
+
setSelectedProvider(null);
|
|
176
|
+
setError(null);
|
|
177
|
+
setCredentials({ email: '', password: '' });
|
|
178
|
+
}, children: t('core:auth.back_to_options') })), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "email", required: true, children: t('core:auth.email') }), _jsx(Input, { id: "email", type: "email", required: true, value: credentials.email, onChange: e => setCredentials({ ...credentials, email: e.target.value }), placeholder: t('core:auth.email_placeholder'), autoComplete: "email", autoFocus: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "password", required: true, children: t('core:auth.password') }), _jsx(Input, { id: "password", type: "password", required: true, value: credentials.password, onChange: e => setCredentials({ ...credentials, password: e.target.value }), placeholder: t('core:auth.password_placeholder'), autoComplete: "current-password" })] }), _jsx(Button, { type: "submit", loading: submitting, className: "w-full h-11", children: t('core:auth.sign_in') })] })), !pendingChallenge && !showProviderPicker && !showOAuthPrompt && !showCredentialsForm && (_jsx("p", { className: "text-center text-sm text-fg-secondary", children: t('core:auth.no_providers') }))] }), _jsx(Slot, { name: "login.belowForm", as: "div", className: "mt-6 space-y-4 empty:hidden" }), _jsx("div", { className: "mt-6 flex justify-center", children: _jsx(LocaleSwitcher, {}) })] })] }));
|
|
179
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ProtectedRouteProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
apiBaseUrl: string;
|
|
5
|
+
fallback?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ProtectedRoute - Wraps content that requires authentication
|
|
9
|
+
* Shows LoginPage if not authenticated, otherwise shows children
|
|
10
|
+
*/
|
|
11
|
+
export declare function ProtectedRoute({ children, apiBaseUrl, fallback }: ProtectedRouteProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useAuth } from './AuthContext';
|
|
3
|
+
import { Loader2 } from 'lucide-react';
|
|
4
|
+
import { LoginPage } from './LoginPage';
|
|
5
|
+
import { translate } from '../i18n/activeLocale';
|
|
6
|
+
/**
|
|
7
|
+
* ProtectedRoute - Wraps content that requires authentication
|
|
8
|
+
* Shows LoginPage if not authenticated, otherwise shows children
|
|
9
|
+
*/
|
|
10
|
+
export function ProtectedRoute({ children, apiBaseUrl, fallback }) {
|
|
11
|
+
const { user, loading } = useAuth();
|
|
12
|
+
if (loading) {
|
|
13
|
+
return (_jsx("div", { className: "min-h-screen bg-base flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx(Loader2, { className: "w-12 h-12 text-accent animate-spin mx-auto" }), _jsx("p", { className: "mt-4 text-fg-secondary", children: translate('core:common.loading_ellipsis') })] }) }));
|
|
14
|
+
}
|
|
15
|
+
if (!user) {
|
|
16
|
+
if (fallback) {
|
|
17
|
+
return _jsx(_Fragment, { children: fallback });
|
|
18
|
+
}
|
|
19
|
+
return _jsx(LoginPage, { apiBaseUrl: apiBaseUrl });
|
|
20
|
+
}
|
|
21
|
+
return _jsx(_Fragment, { children: children });
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AuthUser, AuthProvider, AuthTokens, LoginCredentials, LoginResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* API client for authentication endpoints.
|
|
4
|
+
* Tokens are managed via HTTP-only cookies set by the server — no localStorage involved.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AuthApiClient {
|
|
7
|
+
private apiBaseUrl;
|
|
8
|
+
constructor(apiBaseUrl: string);
|
|
9
|
+
getProviders(): Promise<AuthProvider[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Attempt login. Returns a discriminated result: `authenticated` (session cookie set)
|
|
12
|
+
* or `challenge` (a verification step like 2FA is required before tokens are issued).
|
|
13
|
+
*/
|
|
14
|
+
login(provider: string, credentials: LoginCredentials): Promise<LoginResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Respond to a pending login challenge. Returns the next `LoginResult` — either
|
|
17
|
+
* `authenticated` (all steps cleared) or another `challenge` (chained step).
|
|
18
|
+
*/
|
|
19
|
+
verifyChallenge(challengeToken: string, type: string, payload: unknown): Promise<LoginResult>;
|
|
20
|
+
getCurrentUser(): Promise<AuthUser | null>;
|
|
21
|
+
refreshToken(): Promise<AuthTokens | null>;
|
|
22
|
+
logout(): Promise<void>;
|
|
23
|
+
getAuthHeaders(): HeadersInit;
|
|
24
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API client for authentication endpoints.
|
|
3
|
+
* Tokens are managed via HTTP-only cookies set by the server — no localStorage involved.
|
|
4
|
+
*/
|
|
5
|
+
export class AuthApiClient {
|
|
6
|
+
constructor(apiBaseUrl) {
|
|
7
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
8
|
+
}
|
|
9
|
+
async getProviders() {
|
|
10
|
+
const response = await fetch(`${this.apiBaseUrl}/auth/providers`, {
|
|
11
|
+
credentials: 'include',
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
throw new Error('Failed to fetch providers');
|
|
15
|
+
}
|
|
16
|
+
const data = await response.json();
|
|
17
|
+
return data.providers || [];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Attempt login. Returns a discriminated result: `authenticated` (session cookie set)
|
|
21
|
+
* or `challenge` (a verification step like 2FA is required before tokens are issued).
|
|
22
|
+
*/
|
|
23
|
+
async login(provider, credentials) {
|
|
24
|
+
const response = await fetch(`${this.apiBaseUrl}/auth/login`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
credentials: 'include',
|
|
28
|
+
body: JSON.stringify({ provider, ...credentials }),
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const error = await response.json();
|
|
32
|
+
throw new Error(error.error || 'Login failed');
|
|
33
|
+
}
|
|
34
|
+
return response.json();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Respond to a pending login challenge. Returns the next `LoginResult` — either
|
|
38
|
+
* `authenticated` (all steps cleared) or another `challenge` (chained step).
|
|
39
|
+
*/
|
|
40
|
+
async verifyChallenge(challengeToken, type, payload) {
|
|
41
|
+
const response = await fetch(`${this.apiBaseUrl}/auth/challenge`, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
credentials: 'include',
|
|
45
|
+
body: JSON.stringify({ challengeToken, type, payload }),
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const error = await response.json();
|
|
49
|
+
throw new Error(error.error || 'Verification failed');
|
|
50
|
+
}
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
async getCurrentUser() {
|
|
54
|
+
const response = await fetch(`${this.apiBaseUrl}/auth/me`, {
|
|
55
|
+
credentials: 'include',
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
if (response.status === 401) {
|
|
59
|
+
const error = new Error('Unauthorized');
|
|
60
|
+
error.status = 401;
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
throw new Error('Failed to get current user');
|
|
64
|
+
}
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
return data.user || null;
|
|
67
|
+
}
|
|
68
|
+
async refreshToken() {
|
|
69
|
+
const response = await fetch(`${this.apiBaseUrl}/auth/refresh`, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
credentials: 'include',
|
|
73
|
+
body: JSON.stringify({}),
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const data = await response.json();
|
|
79
|
+
return data.tokens || null;
|
|
80
|
+
}
|
|
81
|
+
async logout() {
|
|
82
|
+
try {
|
|
83
|
+
await fetch(`${this.apiBaseUrl}/auth/logout`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
credentials: 'include',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Ignore errors — server-side cookie clearing is best-effort
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
getAuthHeaders() {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Authenticated user interface
|
|
4
|
+
*/
|
|
5
|
+
export interface AuthUser {
|
|
6
|
+
/** Unique identifier */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Email address */
|
|
9
|
+
email: string;
|
|
10
|
+
/** Display name */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** Role/title (e.g., 'admin', 'editor') */
|
|
13
|
+
role?: string;
|
|
14
|
+
/** Avatar image URL */
|
|
15
|
+
avatarUrl?: string;
|
|
16
|
+
/** Preferred theme */
|
|
17
|
+
theme?: string;
|
|
18
|
+
/** Provider-specific metadata */
|
|
19
|
+
_auth?: Record<string, any>;
|
|
20
|
+
/** Additional custom fields */
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Authentication provider configuration
|
|
25
|
+
*/
|
|
26
|
+
export interface AuthProvider {
|
|
27
|
+
/** Provider name */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Display label */
|
|
30
|
+
label: string;
|
|
31
|
+
/** Icon name (Lucide) */
|
|
32
|
+
icon?: string;
|
|
33
|
+
/** Provider type */
|
|
34
|
+
type: 'credentials' | 'oauth';
|
|
35
|
+
/** Button styling */
|
|
36
|
+
buttonStyle?: {
|
|
37
|
+
backgroundColor?: string;
|
|
38
|
+
textColor?: string;
|
|
39
|
+
borderColor?: string;
|
|
40
|
+
};
|
|
41
|
+
/** Required fields for credentials type */
|
|
42
|
+
fields?: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Authentication tokens
|
|
46
|
+
*/
|
|
47
|
+
export interface AuthTokens {
|
|
48
|
+
/** JWT access token */
|
|
49
|
+
accessToken: string;
|
|
50
|
+
/** JWT refresh token */
|
|
51
|
+
refreshToken: string;
|
|
52
|
+
/** Access token expiration in seconds */
|
|
53
|
+
expiresIn: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Login credentials
|
|
57
|
+
*/
|
|
58
|
+
export interface LoginCredentials {
|
|
59
|
+
email: string;
|
|
60
|
+
password: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A pending login challenge returned by the server (e.g. 2FA). The `challengeToken` is an
|
|
64
|
+
* opaque continuation token the client must echo back to `/auth/challenge` — never decode
|
|
65
|
+
* it for trust decisions. `data` carries non-secret hints for the challenge UI.
|
|
66
|
+
*/
|
|
67
|
+
export interface PendingChallenge {
|
|
68
|
+
type: string;
|
|
69
|
+
challengeToken: string;
|
|
70
|
+
data?: unknown;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Discriminated result of a login attempt or a challenge verification, mirroring the
|
|
74
|
+
* backend `LoginResult`. `authenticated` → the session cookie is set; `challenge` → one or
|
|
75
|
+
* more steps remain and no session cookie was set.
|
|
76
|
+
*/
|
|
77
|
+
export type LoginResult = {
|
|
78
|
+
status: 'authenticated';
|
|
79
|
+
user: AuthUser;
|
|
80
|
+
tokens: {
|
|
81
|
+
expiresIn: number;
|
|
82
|
+
};
|
|
83
|
+
} | {
|
|
84
|
+
status: 'challenge';
|
|
85
|
+
challenge: PendingChallenge;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Props passed to a challenge UI component registered under `authChallenges`.
|
|
89
|
+
*/
|
|
90
|
+
export interface AuthChallengeProps {
|
|
91
|
+
/** Non-secret data sent by the server with the challenge. */
|
|
92
|
+
data?: unknown;
|
|
93
|
+
/** Submit the user's response; resolves when verified (or rejects on error). */
|
|
94
|
+
onSubmit: (payload: unknown) => Promise<void>;
|
|
95
|
+
/** Abandon the challenge and return to the login form. */
|
|
96
|
+
onCancel: () => void;
|
|
97
|
+
/** Verification error to display, if any. */
|
|
98
|
+
error?: string | null;
|
|
99
|
+
/** Whether a verification request is in flight. */
|
|
100
|
+
submitting?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/** A React component that renders a challenge step. */
|
|
103
|
+
export type AuthChallengeComponent = ComponentType<AuthChallengeProps>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SerializedForm } from '@maxal_studio/kratosjs';
|
|
3
|
+
export interface ActionFormModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
actionName: string;
|
|
7
|
+
actionLabel?: string;
|
|
8
|
+
formSchema: SerializedForm;
|
|
9
|
+
recordIds: string[];
|
|
10
|
+
isBulk?: boolean;
|
|
11
|
+
requiresConfirmation?: boolean;
|
|
12
|
+
modalDescription?: string;
|
|
13
|
+
apiBaseUrl: string;
|
|
14
|
+
resourceSlug: string;
|
|
15
|
+
onSuccess?: () => void;
|
|
16
|
+
depth?: number;
|
|
17
|
+
onCloseAll?: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Thin wrapper over ResourceFormModal for actions that collect form input.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ActionFormModal(props: ActionFormModalProps): React.JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ResourceFormModal } from './modals/ResourceFormModal';
|
|
3
|
+
/**
|
|
4
|
+
* Thin wrapper over ResourceFormModal for actions that collect form input.
|
|
5
|
+
*/
|
|
6
|
+
export function ActionFormModal(props) {
|
|
7
|
+
return (_jsx(ResourceFormModal, { isOpen: props.isOpen, onClose: props.onClose, mode: "action", resourceSlug: props.resourceSlug, apiBaseUrl: props.apiBaseUrl, formSchema: props.formSchema, recordIds: props.recordIds, actionName: props.actionName, actionLabel: props.actionLabel, isBulk: props.isBulk, requiresConfirmation: props.requiresConfirmation, modalDescription: props.modalDescription, onSuccess: props.onSuccess, depth: props.depth, onCloseAll: props.onCloseAll }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AdminPanelProps } from '../types';
|
|
3
|
+
export interface PageMetadata {
|
|
4
|
+
slug: string;
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
navigationGroup?: string;
|
|
8
|
+
navigationSort?: number;
|
|
9
|
+
hidden?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function AdminPanel({ apiBaseUrl, panelId, customFields, customColumns, customWidgets, customBlocks, customAuthChallenges, customSlots, i18nConfig, }: AdminPanelProps): React.JSX.Element;
|