@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
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @maxal_studio/kratosjs-react
|
|
2
|
+
|
|
3
|
+
React components for KratosJs. Render dynamic forms and tables from JSON schemas with React Hook Form and Tailwind CSS.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
📚 **[View Documentation](./docs/README.md)**
|
|
8
|
+
|
|
9
|
+
### Key Topics
|
|
10
|
+
|
|
11
|
+
- [Getting Started](./docs/getting-started.md)
|
|
12
|
+
|
|
13
|
+
### Related Documentation
|
|
14
|
+
|
|
15
|
+
- [Forms Documentation](../docs/forms/overview.md) - Form fields and components
|
|
16
|
+
- [Custom Fields](../docs/forms/custom-fields.md) - Creating custom form fields
|
|
17
|
+
- [Tables Documentation](../docs/tables/overview.md) - Table columns and features
|
|
18
|
+
- [Custom Columns](../docs/tables/custom-columns.md) - Creating custom table columns
|
|
19
|
+
- [Custom Widgets](../docs/resources/custom-widgets.md) - Creating custom widgets
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @maxal_studio/kratosjs-react react-hook-form
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Peer Dependencies:**
|
|
28
|
+
|
|
29
|
+
- `react` ^18.0.0
|
|
30
|
+
- `react-dom` ^18.0.0
|
|
31
|
+
- `react-hook-form` ^7.0.0
|
|
32
|
+
|
|
33
|
+
**Styling:**
|
|
34
|
+
|
|
35
|
+
Import the pre-built styles in your app:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
// In your main.tsx or App.tsx
|
|
39
|
+
import '@maxal_studio/kratosjs-react/styles.css';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
ISC
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FieldRendererProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* FieldRenderer component
|
|
5
|
+
* Dynamically renders the correct field component based on type
|
|
6
|
+
*/
|
|
7
|
+
export declare function FieldRenderer({ field, apiBaseUrl, resource, operation, mode, value, }: FieldRendererProps & {
|
|
8
|
+
apiBaseUrl?: string;
|
|
9
|
+
resource?: string;
|
|
10
|
+
operation?: 'create' | 'edit' | 'view';
|
|
11
|
+
mode?: 'edit' | 'view';
|
|
12
|
+
value?: any;
|
|
13
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useWatch, useFormContext } from 'react-hook-form';
|
|
3
|
+
import { useFieldRegistry } from './contexts/FieldRegistryContext';
|
|
4
|
+
import { evaluateCondition } from './runtime/conditions';
|
|
5
|
+
import { useAfterStateUpdated } from './hooks/useAfterStateUpdated';
|
|
6
|
+
import { getColumnClasses } from './components/utils/layoutHelpers';
|
|
7
|
+
import { translate } from './i18n/activeLocale';
|
|
8
|
+
/**
|
|
9
|
+
* FieldRenderer component
|
|
10
|
+
* Dynamically renders the correct field component based on type
|
|
11
|
+
*/
|
|
12
|
+
export function FieldRenderer({ field, apiBaseUrl, resource, operation, mode = 'edit', value, }) {
|
|
13
|
+
const registry = useFieldRegistry();
|
|
14
|
+
const FieldComponent = registry[field.type];
|
|
15
|
+
// In view mode, we don't need form context
|
|
16
|
+
let formState = {};
|
|
17
|
+
if (mode === 'edit') {
|
|
18
|
+
const { control } = useFormContext();
|
|
19
|
+
// Watch form state for conditional visibility/disabled evaluation
|
|
20
|
+
formState = useWatch({ control }) || {};
|
|
21
|
+
// Execute afterStateUpdated callback when field value changes (if provided)
|
|
22
|
+
useAfterStateUpdated(field.name, field.afterStateUpdatedFn);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// In view mode, create a simple form state from the value prop for conditional evaluation
|
|
26
|
+
// This allows conditional visibility to work based on field values
|
|
27
|
+
if (field.name && value !== undefined) {
|
|
28
|
+
formState = { [field.name]: value };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Unknown field type
|
|
32
|
+
if (!FieldComponent) {
|
|
33
|
+
console.warn(`Unknown field type: ${field.type}`);
|
|
34
|
+
return (_jsx("div", { className: "mb-4 p-4 bg-yellow-50 border border-yellow-200 rounded-lg", children: _jsxs("p", { className: "text-sm text-yellow-800", children: [_jsxs("strong", { children: [translate('core:common.warning'), ":"] }), ' ', translate('core:state.unknown_field', { type: field.type, name: field.name })] }) }));
|
|
35
|
+
}
|
|
36
|
+
// Evaluate conditional hidden state — hiddenWhen is the structured-AST form
|
|
37
|
+
// (no code execution), hiddenFn the serialized-function form.
|
|
38
|
+
const isHidden = evaluateCondition(field.hiddenWhen ?? field.hiddenFn ?? field.hidden, formState, operation);
|
|
39
|
+
// Evaluate conditional disabled state
|
|
40
|
+
const isDisabled = evaluateCondition(field.disabledWhen ?? field.disabledFn ?? field.disabled, formState, operation);
|
|
41
|
+
// Hidden field
|
|
42
|
+
if (isHidden) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
// Update field props with evaluated disabled state, API base URL, resource, mode, operation, and value
|
|
46
|
+
const fieldWithEvaluatedProps = {
|
|
47
|
+
...field,
|
|
48
|
+
disabled: isDisabled,
|
|
49
|
+
apiBaseUrl,
|
|
50
|
+
resource,
|
|
51
|
+
mode,
|
|
52
|
+
operation,
|
|
53
|
+
value: value !== undefined ? value : mode === 'view' ? undefined : undefined,
|
|
54
|
+
};
|
|
55
|
+
// Get column layout classes using shared helper
|
|
56
|
+
const columnClasses = getColumnClasses(fieldWithEvaluatedProps.columnSpan, fieldWithEvaluatedProps.columnStart);
|
|
57
|
+
// Render the field component
|
|
58
|
+
if (columnClasses) {
|
|
59
|
+
return (_jsx("div", { className: columnClasses, children: _jsx(FieldComponent, { ...fieldWithEvaluatedProps }) }));
|
|
60
|
+
}
|
|
61
|
+
return _jsx(FieldComponent, { ...fieldWithEvaluatedProps });
|
|
62
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormRendererProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* FormRenderer component
|
|
5
|
+
* Main component that accepts JSON schema and renders the form
|
|
6
|
+
*/
|
|
7
|
+
export declare function FormRenderer({ schema, onSubmit, defaultValues, className, apiBaseUrl, resource, operation, children, }: FormRendererProps): React.JSX.Element;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useForm, FormProvider } from 'react-hook-form';
|
|
4
|
+
import { FieldRenderer } from './FieldRenderer';
|
|
5
|
+
import { cn } from './utils/classNames';
|
|
6
|
+
import { getGridClasses } from './components/utils/layoutHelpers';
|
|
7
|
+
import { Button } from './components/ui/Button';
|
|
8
|
+
import { getChildComponents, isArrayScope, isLayout } from './runtime/formTraversal';
|
|
9
|
+
import { useTranslation } from './i18n/useTranslation';
|
|
10
|
+
import { Slot } from './slots/Slot';
|
|
11
|
+
/**
|
|
12
|
+
* Extract default values from a schema using the declarative children contract.
|
|
13
|
+
* Layout containers are transparent (recurse into children); array-scope
|
|
14
|
+
* containers (repeaters) seed their own array value from the item template; leaf
|
|
15
|
+
* fields contribute their `default`.
|
|
16
|
+
*/
|
|
17
|
+
function extractDefaultValues(components) {
|
|
18
|
+
const defaults = {};
|
|
19
|
+
components.forEach(component => {
|
|
20
|
+
// Array-scope container (Repeater): seed the array value, never leak item fields.
|
|
21
|
+
if (isArrayScope(component)) {
|
|
22
|
+
if (!component.name)
|
|
23
|
+
return;
|
|
24
|
+
const template = getChildComponents(component);
|
|
25
|
+
if (component.default !== undefined && Array.isArray(component.default)) {
|
|
26
|
+
defaults[component.name] = component.default;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const count = typeof component.defaultItems === 'number' && component.defaultItems > 0
|
|
30
|
+
? component.defaultItems
|
|
31
|
+
: typeof component.minItems === 'number' && component.minItems > 0
|
|
32
|
+
? component.minItems
|
|
33
|
+
: 0;
|
|
34
|
+
if (count > 0 && template.length > 0) {
|
|
35
|
+
const itemDefaults = extractDefaultValues(template);
|
|
36
|
+
defaults[component.name] = Array.from({ length: count }, () => ({ ...itemDefaults }));
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Layout container: transparent, recurse into children.
|
|
41
|
+
if (isLayout(component)) {
|
|
42
|
+
Object.assign(defaults, extractDefaultValues(getChildComponents(component)));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Leaf field with a default value.
|
|
46
|
+
if (component.name && component.default !== undefined) {
|
|
47
|
+
defaults[component.name] = component.default;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return defaults;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* FormRenderer component
|
|
54
|
+
* Main component that accepts JSON schema and renders the form
|
|
55
|
+
*/
|
|
56
|
+
export function FormRenderer({ schema, onSubmit, defaultValues = {}, className, apiBaseUrl, resource, operation, children, }) {
|
|
57
|
+
const { t } = useTranslation();
|
|
58
|
+
// Extract default values from schema and merge with user-provided defaults
|
|
59
|
+
const mergedDefaults = useMemo(() => {
|
|
60
|
+
const schemaDefaults = extractDefaultValues(schema.components);
|
|
61
|
+
return { ...schemaDefaults, ...defaultValues };
|
|
62
|
+
}, [schema.components, defaultValues]);
|
|
63
|
+
const methods = useForm({
|
|
64
|
+
defaultValues: mergedDefaults,
|
|
65
|
+
mode: 'onChange', // Validate and re-validate on change
|
|
66
|
+
});
|
|
67
|
+
const handleSubmit = async (data) => {
|
|
68
|
+
try {
|
|
69
|
+
await onSubmit(data);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Form submission error:', error);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
// Calculate grid classes based on the columns prop (static class maps — purge-safe)
|
|
76
|
+
const formGridClasses = !schema.columns || schema.columns === 1 ? 'space-y-6' : `${getGridClasses(schema.columns)} gap-y-4`;
|
|
77
|
+
return (_jsxs(FormProvider, { ...methods, children: [children, _jsxs("form", { onSubmit: methods.handleSubmit(handleSubmit), className: cn(className), noValidate: true, children: [_jsx(Slot, { name: "form.header", context: { resourceSlug: resource, record: defaultValues, schema }, as: "div", className: "mb-4 space-y-3 empty:hidden" }), _jsx("div", { className: formGridClasses, children: schema.components.map((field, index) => (_jsx(FieldRenderer, { field: field, apiBaseUrl: apiBaseUrl, resource: resource, operation: operation, mode: "edit" }, field.name || index))) }), _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-3 pt-6", children: [_jsx(Slot, { name: "form.footer", context: { resourceSlug: resource, record: defaultValues, schema }, as: "div", className: "mr-auto flex flex-wrap items-center gap-2 empty:hidden" }), _jsx(Button, { variant: "secondary", onClick: () => methods.reset(), children: t('core:common.reset') }), _jsx(Button, { type: "submit", loading: methods.formState.isSubmitting, children: methods.formState.isSubmitting ? t('core:common.submitting') : t('core:common.submit') })] })] })] }));
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TableRenderer } from './table/TableRenderer';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ActionResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
message?: string;
|
|
4
|
+
data?: any;
|
|
5
|
+
redirect?: string;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Execute a single row action
|
|
10
|
+
* @param apiUrl - The base API URL for the resource (e.g., http://localhost:3001/api/users)
|
|
11
|
+
* @param actionName - The name of the action to execute
|
|
12
|
+
* @param recordId - The record ID (backend will populate the full record)
|
|
13
|
+
* @param formData - Optional form data from the action form
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeAction(apiUrl: string, actionName: string, recordId: string, formData?: any): Promise<ActionResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Execute a bulk action on multiple rows
|
|
18
|
+
* @param apiUrl - The base API URL for the resource (e.g., http://localhost:3001/api/users)
|
|
19
|
+
* @param actionName - The name of the action to execute
|
|
20
|
+
* @param recordIds - Array of record IDs (backend will populate the full records)
|
|
21
|
+
* @param formData - Optional form data from the action form
|
|
22
|
+
*/
|
|
23
|
+
export declare function executeBulkAction(apiUrl: string, actionName: string, recordIds: string[], formData?: any): Promise<ActionResult>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ApiError, apiPost } from './http';
|
|
2
|
+
import { deriveApiBaseUrl } from './urls';
|
|
3
|
+
import { translate } from '../i18n/activeLocale';
|
|
4
|
+
async function runAction(apiUrl, actionName, recordIds, formData, isBulk) {
|
|
5
|
+
try {
|
|
6
|
+
const result = await apiPost(`${apiUrl}/actions`, {
|
|
7
|
+
action: actionName,
|
|
8
|
+
data: { recordIds, formData: formData || {} },
|
|
9
|
+
...(isBulk ? { isBulk: true } : {}),
|
|
10
|
+
}, deriveApiBaseUrl(apiUrl));
|
|
11
|
+
return {
|
|
12
|
+
...result,
|
|
13
|
+
success: result.success !== false,
|
|
14
|
+
message: result.message,
|
|
15
|
+
data: result.data,
|
|
16
|
+
redirect: result.redirect,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
const fallback = isBulk ? translate('core:error.action_failed_bulk') : translate('core:error.action_failed');
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
message: error instanceof ApiError ? error.message : error?.message || fallback,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Execute a single row action
|
|
29
|
+
* @param apiUrl - The base API URL for the resource (e.g., http://localhost:3001/api/users)
|
|
30
|
+
* @param actionName - The name of the action to execute
|
|
31
|
+
* @param recordId - The record ID (backend will populate the full record)
|
|
32
|
+
* @param formData - Optional form data from the action form
|
|
33
|
+
*/
|
|
34
|
+
export function executeAction(apiUrl, actionName, recordId, formData) {
|
|
35
|
+
return runAction(apiUrl, actionName, [recordId], formData, false);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Execute a bulk action on multiple rows
|
|
39
|
+
* @param apiUrl - The base API URL for the resource (e.g., http://localhost:3001/api/users)
|
|
40
|
+
* @param actionName - The name of the action to execute
|
|
41
|
+
* @param recordIds - Array of record IDs (backend will populate the full records)
|
|
42
|
+
* @param formData - Optional form data from the action form
|
|
43
|
+
*/
|
|
44
|
+
export function executeBulkAction(apiUrl, actionName, recordIds, formData) {
|
|
45
|
+
return runAction(apiUrl, actionName, recordIds, formData, true);
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch wrapper that automatically retries with a silent token refresh on 401.
|
|
3
|
+
* Auth tokens are carried by HTTP-only cookies — no Authorization header needed.
|
|
4
|
+
*
|
|
5
|
+
* Sends `X-KratosJs-Locale` so the server localizes labels/schemas/action
|
|
6
|
+
* messages to the admin's current UI locale.
|
|
7
|
+
*/
|
|
8
|
+
export declare function authenticatedFetch(url: string, options: RequestInit, apiBaseUrl: string): Promise<Response>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AuthApiClient } from '../auth/authApiClient';
|
|
2
|
+
import { getActiveLocale } from '../i18n/activeLocale';
|
|
3
|
+
/**
|
|
4
|
+
* Fetch wrapper that automatically retries with a silent token refresh on 401.
|
|
5
|
+
* Auth tokens are carried by HTTP-only cookies — no Authorization header needed.
|
|
6
|
+
*
|
|
7
|
+
* Sends `X-KratosJs-Locale` so the server localizes labels/schemas/action
|
|
8
|
+
* messages to the admin's current UI locale.
|
|
9
|
+
*/
|
|
10
|
+
export async function authenticatedFetch(url, options = {}, apiBaseUrl) {
|
|
11
|
+
const headers = new Headers({
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
'X-KratosJs-Locale': getActiveLocale(),
|
|
14
|
+
...options.headers,
|
|
15
|
+
});
|
|
16
|
+
let response = await fetch(url, { ...options, headers, credentials: 'include' });
|
|
17
|
+
if (response.status === 401) {
|
|
18
|
+
const authClient = new AuthApiClient(apiBaseUrl);
|
|
19
|
+
const tokens = await authClient.refreshToken();
|
|
20
|
+
if (tokens) {
|
|
21
|
+
response = await fetch(url, { ...options, headers, credentials: 'include' });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (response.ok && response.headers.get('X-KratosJs-Refresh-Badges')) {
|
|
28
|
+
window.dispatchEvent(new CustomEvent('kratosjs-refresh-badges'));
|
|
29
|
+
}
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ExportOptions {
|
|
2
|
+
/** Export format, e.g. 'csv'. */
|
|
3
|
+
format: string;
|
|
4
|
+
/** Originating action name (used for server-side per-action authorization). */
|
|
5
|
+
action?: string;
|
|
6
|
+
/** Current table query (search/filters/sort) — exports all matching rows. */
|
|
7
|
+
query?: Record<string, any>;
|
|
8
|
+
/** Specific record ids — exports only these (bulk "export selected"). */
|
|
9
|
+
recordIds?: any[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* POST to a resource's `/export` endpoint and trigger a browser download of the
|
|
13
|
+
* returned file. Used by header/bulk actions marked with `exportsTo(format)`.
|
|
14
|
+
*
|
|
15
|
+
* @param resourceUrl - The resource endpoint (e.g. `${apiBaseUrl}/users`)
|
|
16
|
+
* @param apiBaseUrl - Panel API base (for token refresh)
|
|
17
|
+
*/
|
|
18
|
+
export declare function downloadExport(resourceUrl: string, apiBaseUrl: string, options: ExportOptions): Promise<void>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { authenticatedFetch } from './authenticatedFetch';
|
|
2
|
+
/**
|
|
3
|
+
* POST to a resource's `/export` endpoint and trigger a browser download of the
|
|
4
|
+
* returned file. Used by header/bulk actions marked with `exportsTo(format)`.
|
|
5
|
+
*
|
|
6
|
+
* @param resourceUrl - The resource endpoint (e.g. `${apiBaseUrl}/users`)
|
|
7
|
+
* @param apiBaseUrl - Panel API base (for token refresh)
|
|
8
|
+
*/
|
|
9
|
+
export async function downloadExport(resourceUrl, apiBaseUrl, options) {
|
|
10
|
+
const { format, action, query, recordIds } = options;
|
|
11
|
+
const url = `${resourceUrl.replace(/\/$/, '')}/export`;
|
|
12
|
+
const body = { format, ...(query || {}) };
|
|
13
|
+
if (action) {
|
|
14
|
+
body.action = action;
|
|
15
|
+
}
|
|
16
|
+
if (recordIds && recordIds.length > 0) {
|
|
17
|
+
body.recordIds = recordIds;
|
|
18
|
+
}
|
|
19
|
+
const response = await authenticatedFetch(url, { method: 'POST', body: JSON.stringify(body) }, apiBaseUrl);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
let message = `Export failed (${response.status})`;
|
|
22
|
+
try {
|
|
23
|
+
const errorBody = await response.json();
|
|
24
|
+
message = errorBody.message || message;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// response had no JSON body
|
|
28
|
+
}
|
|
29
|
+
throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
const blob = await response.blob();
|
|
32
|
+
const filename = parseContentDispositionFilename(response.headers.get('Content-Disposition')) || `export.${format}`;
|
|
33
|
+
triggerBrowserDownload(blob, filename);
|
|
34
|
+
}
|
|
35
|
+
function parseContentDispositionFilename(header) {
|
|
36
|
+
if (!header)
|
|
37
|
+
return undefined;
|
|
38
|
+
const match = /filename\*?=(?:UTF-8'')?["']?([^"';]+)["']?/i.exec(header);
|
|
39
|
+
return match ? decodeURIComponent(match[1]) : undefined;
|
|
40
|
+
}
|
|
41
|
+
function triggerBrowserDownload(blob, filename) {
|
|
42
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
43
|
+
const anchor = document.createElement('a');
|
|
44
|
+
anchor.href = objectUrl;
|
|
45
|
+
anchor.download = filename;
|
|
46
|
+
document.body.appendChild(anchor);
|
|
47
|
+
anchor.click();
|
|
48
|
+
anchor.remove();
|
|
49
|
+
URL.revokeObjectURL(objectUrl);
|
|
50
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error thrown by apiFetch for any non-2xx response.
|
|
3
|
+
* Carries the HTTP status and whatever the server put in the body so
|
|
4
|
+
* callers can map field-level validation errors or show the message.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ApiError extends Error {
|
|
7
|
+
readonly status: number;
|
|
8
|
+
readonly details?: unknown;
|
|
9
|
+
constructor(message: string, status: number, details?: unknown);
|
|
10
|
+
get isUnauthorized(): boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface ApiFetchOptions extends RequestInit {
|
|
13
|
+
/** Base URL of the panel API, used for token refresh on 401 */
|
|
14
|
+
apiBaseUrl: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* JSON fetch with auth + token refresh + uniform error handling.
|
|
18
|
+
* Throws ApiError on any non-ok response, preserving the server message.
|
|
19
|
+
*/
|
|
20
|
+
export declare function apiFetch<T = unknown>(url: string, options: ApiFetchOptions): Promise<T>;
|
|
21
|
+
/** Convenience JSON POST */
|
|
22
|
+
export declare function apiPost<T = unknown>(url: string, payload: unknown, apiBaseUrl: string): Promise<T>;
|
|
23
|
+
/** Convenience JSON GET */
|
|
24
|
+
export declare function apiGet<T = unknown>(url: string, apiBaseUrl: string): Promise<T>;
|
package/dist/api/http.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { authenticatedFetch } from './authenticatedFetch';
|
|
2
|
+
/**
|
|
3
|
+
* Typed error thrown by apiFetch for any non-2xx response.
|
|
4
|
+
* Carries the HTTP status and whatever the server put in the body so
|
|
5
|
+
* callers can map field-level validation errors or show the message.
|
|
6
|
+
*/
|
|
7
|
+
export class ApiError extends Error {
|
|
8
|
+
constructor(message, status, details) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'ApiError';
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.details = details;
|
|
13
|
+
}
|
|
14
|
+
get isUnauthorized() {
|
|
15
|
+
return this.status === 401;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* JSON fetch with auth + token refresh + uniform error handling.
|
|
20
|
+
* Throws ApiError on any non-ok response, preserving the server message.
|
|
21
|
+
*/
|
|
22
|
+
export async function apiFetch(url, options) {
|
|
23
|
+
const { apiBaseUrl, ...init } = options;
|
|
24
|
+
const response = await authenticatedFetch(url, init, apiBaseUrl);
|
|
25
|
+
let body = null;
|
|
26
|
+
const text = await response.text();
|
|
27
|
+
if (text) {
|
|
28
|
+
try {
|
|
29
|
+
body = JSON.parse(text);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
body = text;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const message = response.status === 401
|
|
37
|
+
? 'Unauthorized - Please login again'
|
|
38
|
+
: (body && typeof body === 'object' && (body.message || body.error)) ||
|
|
39
|
+
response.statusText ||
|
|
40
|
+
`Request failed with status ${response.status}`;
|
|
41
|
+
throw new ApiError(message, response.status, body);
|
|
42
|
+
}
|
|
43
|
+
return body;
|
|
44
|
+
}
|
|
45
|
+
/** Convenience JSON POST */
|
|
46
|
+
export function apiPost(url, payload, apiBaseUrl) {
|
|
47
|
+
return apiFetch(url, { method: 'POST', body: JSON.stringify(payload), apiBaseUrl });
|
|
48
|
+
}
|
|
49
|
+
/** Convenience JSON GET */
|
|
50
|
+
export function apiGet(url, apiBaseUrl) {
|
|
51
|
+
return apiFetch(url, { apiBaseUrl });
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed endpoints for the panel's resource API.
|
|
3
|
+
* All functions take the panel apiBaseUrl (e.g. http://host/kratosjs/api) and a resource slug.
|
|
4
|
+
*/
|
|
5
|
+
export interface RecordEnvelope<T = any> {
|
|
6
|
+
data: T;
|
|
7
|
+
metadata?: {
|
|
8
|
+
recordTitle?: string;
|
|
9
|
+
refreshBadges?: boolean;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** GET /:slug/:id */
|
|
14
|
+
export declare function getRecord(apiBaseUrl: string, slug: string, id: string | number): Promise<RecordEnvelope>;
|
|
15
|
+
/** POST /:slug */
|
|
16
|
+
export declare function createRecord(apiBaseUrl: string, slug: string, payload: any): Promise<RecordEnvelope>;
|
|
17
|
+
/** POST /:slug/update/:id */
|
|
18
|
+
export declare function updateRecord(apiBaseUrl: string, slug: string, id: string | number, payload: any): Promise<RecordEnvelope>;
|
|
19
|
+
/** POST /:slug/bulk-delete */
|
|
20
|
+
export declare function bulkDelete(apiBaseUrl: string, slug: string, ids: any[]): Promise<{
|
|
21
|
+
deleted?: any[];
|
|
22
|
+
metadata?: {
|
|
23
|
+
refreshBadges?: boolean;
|
|
24
|
+
};
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}>;
|
|
27
|
+
/** GET /:slug/schema/form — returns the serialized form schema */
|
|
28
|
+
export declare function getFormSchema(apiBaseUrl: string, slug: string): Promise<any>;
|
|
29
|
+
/**
|
|
30
|
+
* GET /:slug/schema/table — returns the serialized table schema with
|
|
31
|
+
* the resource capability flags merged in (as TableRenderer expects).
|
|
32
|
+
*/
|
|
33
|
+
export declare function getTableSchema(apiBaseUrl: string, slug: string): Promise<any>;
|
|
34
|
+
/** GET /:slug/relations — relation metadata for the view modal */
|
|
35
|
+
export declare function getRelations(apiBaseUrl: string, slug: string): Promise<any[]>;
|
|
36
|
+
/** POST /:parentSlug/:parentId/relations/:relationName */
|
|
37
|
+
export declare function createRelationRecord(apiBaseUrl: string, parentSlug: string, parentId: string | number, relationName: string, payload: any): Promise<RecordEnvelope>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { apiGet, apiPost } from './http';
|
|
2
|
+
/** Normalize bare-record responses into the `{ data, metadata }` envelope. */
|
|
3
|
+
function toEnvelope(result) {
|
|
4
|
+
if (result && typeof result === 'object' && 'data' in result) {
|
|
5
|
+
return result;
|
|
6
|
+
}
|
|
7
|
+
return { data: result };
|
|
8
|
+
}
|
|
9
|
+
/** GET /:slug/:id */
|
|
10
|
+
export async function getRecord(apiBaseUrl, slug, id) {
|
|
11
|
+
return toEnvelope(await apiGet(`${apiBaseUrl}/${slug}/${id}`, apiBaseUrl));
|
|
12
|
+
}
|
|
13
|
+
/** POST /:slug */
|
|
14
|
+
export async function createRecord(apiBaseUrl, slug, payload) {
|
|
15
|
+
return toEnvelope(await apiPost(`${apiBaseUrl}/${slug}`, payload, apiBaseUrl));
|
|
16
|
+
}
|
|
17
|
+
/** POST /:slug/update/:id */
|
|
18
|
+
export async function updateRecord(apiBaseUrl, slug, id, payload) {
|
|
19
|
+
return toEnvelope(await apiPost(`${apiBaseUrl}/${slug}/update/${id}`, payload, apiBaseUrl));
|
|
20
|
+
}
|
|
21
|
+
/** POST /:slug/bulk-delete */
|
|
22
|
+
export function bulkDelete(apiBaseUrl, slug, ids) {
|
|
23
|
+
return apiPost(`${apiBaseUrl}/${slug}/bulk-delete`, { ids }, apiBaseUrl);
|
|
24
|
+
}
|
|
25
|
+
/** GET /:slug/schema/form — returns the serialized form schema */
|
|
26
|
+
export async function getFormSchema(apiBaseUrl, slug) {
|
|
27
|
+
const result = await apiGet(`${apiBaseUrl}/${slug}/schema/form`, apiBaseUrl);
|
|
28
|
+
return result?.schema || result;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /:slug/schema/table — returns the serialized table schema with
|
|
32
|
+
* the resource capability flags merged in (as TableRenderer expects).
|
|
33
|
+
*/
|
|
34
|
+
export async function getTableSchema(apiBaseUrl, slug) {
|
|
35
|
+
const result = await apiGet(`${apiBaseUrl}/${slug}/schema/table`, apiBaseUrl);
|
|
36
|
+
return {
|
|
37
|
+
...(result?.schema || result),
|
|
38
|
+
canCreate: result?.canCreate,
|
|
39
|
+
canEdit: result?.canEdit,
|
|
40
|
+
canDelete: result?.canDelete,
|
|
41
|
+
canView: result?.canView,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** GET /:slug/relations — relation metadata for the view modal */
|
|
45
|
+
export async function getRelations(apiBaseUrl, slug) {
|
|
46
|
+
const result = await apiGet(`${apiBaseUrl}/${slug}/relations`, apiBaseUrl);
|
|
47
|
+
return result?.relations || [];
|
|
48
|
+
}
|
|
49
|
+
/** POST /:parentSlug/:parentId/relations/:relationName */
|
|
50
|
+
export async function createRelationRecord(apiBaseUrl, parentSlug, parentId, relationName, payload) {
|
|
51
|
+
return toEnvelope(await apiPost(`${apiBaseUrl}/${parentSlug}/${parentId}/relations/${relationName}`, payload, apiBaseUrl));
|
|
52
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query parameters for table API requests
|
|
3
|
+
*/
|
|
4
|
+
export interface QueryParams {
|
|
5
|
+
page?: number;
|
|
6
|
+
perPage?: number;
|
|
7
|
+
search?: string;
|
|
8
|
+
sort?: string;
|
|
9
|
+
sortDirection?: 'asc' | 'desc';
|
|
10
|
+
filters?: Record<string, any>;
|
|
11
|
+
queryBuilders?: Record<string, any[]>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Standard pagination metadata
|
|
15
|
+
*/
|
|
16
|
+
export interface PaginationMeta {
|
|
17
|
+
/** Current page number (1-indexed) */
|
|
18
|
+
page: number;
|
|
19
|
+
/** Number of items per page */
|
|
20
|
+
limit: number;
|
|
21
|
+
/** Total number of items across all pages */
|
|
22
|
+
total: number;
|
|
23
|
+
/** Total number of pages */
|
|
24
|
+
pages: number;
|
|
25
|
+
/** Whether there's a next page */
|
|
26
|
+
hasNext: boolean;
|
|
27
|
+
/** Whether there's a previous page */
|
|
28
|
+
hasPrev: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Result structure for table API responses
|
|
32
|
+
*/
|
|
33
|
+
export interface QueryResult {
|
|
34
|
+
data: any[];
|
|
35
|
+
pagination: PaginationMeta;
|
|
36
|
+
widgets?: Record<string, any>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* API client for communicating with the table backend
|
|
40
|
+
*/
|
|
41
|
+
export declare class TableApiClient {
|
|
42
|
+
private baseUrl;
|
|
43
|
+
private apiBaseUrl;
|
|
44
|
+
private fetchPath;
|
|
45
|
+
/**
|
|
46
|
+
* @param apiBaseUrl - Base URL for the panel API (used for token refresh)
|
|
47
|
+
* @param baseUrl - Base URL of the resource endpoint (e.g. 'http://localhost:3001/api/users')
|
|
48
|
+
* @param fetchPath - Path appended for list queries ('/list' for resources, '' for custom endpoints)
|
|
49
|
+
*/
|
|
50
|
+
constructor(apiBaseUrl: string, baseUrl: string, fetchPath?: string);
|
|
51
|
+
/**
|
|
52
|
+
* Fetch table data with filtering, sorting, and pagination
|
|
53
|
+
*/
|
|
54
|
+
fetchData(params: QueryParams): Promise<QueryResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Update a single record. Unwraps the `{ data, metadata }` envelope.
|
|
57
|
+
*/
|
|
58
|
+
updateRecord(id: any, data: any): Promise<any>;
|
|
59
|
+
/**
|
|
60
|
+
* Delete records (bulk or single).
|
|
61
|
+
* Returns the full response body (including metadata e.g. refreshBadges) so callers can react to it.
|
|
62
|
+
*/
|
|
63
|
+
deleteRecords(ids: any[]): Promise<{
|
|
64
|
+
deleted?: any[];
|
|
65
|
+
metadata?: {
|
|
66
|
+
refreshBadges?: boolean;
|
|
67
|
+
};
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Bulk delete records (alias for deleteRecords)
|
|
72
|
+
*/
|
|
73
|
+
bulkDelete(ids: any[]): Promise<{
|
|
74
|
+
deleted?: any[];
|
|
75
|
+
metadata?: {
|
|
76
|
+
refreshBadges?: boolean;
|
|
77
|
+
};
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
}>;
|
|
80
|
+
getBaseUrl(): string;
|
|
81
|
+
getFetchPath(): string;
|
|
82
|
+
getApiBaseUrl(): string;
|
|
83
|
+
}
|