@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,294 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { ColumnProps } from './TextColumnComponent';
|
|
3
|
+
import { formatValue } from '../../utils/tableFormatters';
|
|
4
|
+
import { getColumnMediaDimensions } from '../../utils/columnMediaDimensions';
|
|
5
|
+
import { Icon } from '../utils/Icon';
|
|
6
|
+
import { MediaPreviewModal } from '../utils/MediaPreviewModal';
|
|
7
|
+
import { translate } from '../../i18n/activeLocale';
|
|
8
|
+
|
|
9
|
+
type MediaType = 'image' | 'video' | 'audio' | null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve media type from column config
|
|
13
|
+
*/
|
|
14
|
+
function resolveMediaType(column: ColumnProps['column'], record: Record<string, any>): MediaType {
|
|
15
|
+
const rawValue = record[column.name];
|
|
16
|
+
|
|
17
|
+
// Check for media type function (serialized as string)
|
|
18
|
+
if (column.mediaTypeFn) {
|
|
19
|
+
try {
|
|
20
|
+
// eslint-disable-next-line no-new-func
|
|
21
|
+
const mediaTypeFn = new Function('return ' + column.mediaTypeFn)();
|
|
22
|
+
const result = mediaTypeFn(rawValue, record);
|
|
23
|
+
if (result === 'image' || result === 'video' || result === 'audio') return result;
|
|
24
|
+
return 'image';
|
|
25
|
+
} catch {
|
|
26
|
+
console.warn('Failed to execute mediaType function');
|
|
27
|
+
return 'image';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Static media type
|
|
32
|
+
if (column.mediaType === 'image' || column.mediaType === 'video' || column.mediaType === 'audio') {
|
|
33
|
+
return column.mediaType;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Default to image
|
|
37
|
+
return 'image';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve thumbnail URL from column config
|
|
42
|
+
* Supports: field name string, function string (serialized), variants, or default thumbnail
|
|
43
|
+
*/
|
|
44
|
+
function resolveThumbnail(column: ColumnProps['column'], record: Record<string, any>): string | null {
|
|
45
|
+
const rawValue = record[column.name];
|
|
46
|
+
|
|
47
|
+
// Check for variants.thumbnail.url in new format
|
|
48
|
+
if (rawValue && typeof rawValue === 'object' && rawValue.variants?.thumbnail?.url) {
|
|
49
|
+
return rawValue.variants.thumbnail.url;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check for thumbnail function (serialized as string)
|
|
53
|
+
if (column.thumbnailFn) {
|
|
54
|
+
try {
|
|
55
|
+
// eslint-disable-next-line no-new-func
|
|
56
|
+
const thumbnailFn = new Function('return ' + column.thumbnailFn)();
|
|
57
|
+
const result = thumbnailFn(rawValue, record);
|
|
58
|
+
if (result) return result;
|
|
59
|
+
} catch {
|
|
60
|
+
console.warn('Failed to execute thumbnail function');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check for thumbnail field name
|
|
65
|
+
if (column.thumbnailField) {
|
|
66
|
+
const fieldName = column.thumbnailField as string;
|
|
67
|
+
// Support nested field access (e.g., 'mediaFile.thumbnailUrl')
|
|
68
|
+
const fieldValue = fieldName.split('.').reduce((obj: any, key) => obj?.[key], record);
|
|
69
|
+
if (fieldValue) {
|
|
70
|
+
// If it's a string, use it directly; otherwise check for new format
|
|
71
|
+
if (typeof fieldValue === 'string') {
|
|
72
|
+
return fieldValue;
|
|
73
|
+
}
|
|
74
|
+
if (typeof fieldValue === 'object' && fieldValue?.url) {
|
|
75
|
+
return fieldValue.url;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Fallback to default thumbnail
|
|
81
|
+
if (column.defaultThumbnail) {
|
|
82
|
+
return column.defaultThumbnail as string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function MediaColumnComponent({ column, record }: ColumnProps) {
|
|
89
|
+
const [previewOpen, setPreviewOpen] = useState(false);
|
|
90
|
+
|
|
91
|
+
const rawValue = record[column.name];
|
|
92
|
+
// Apply formatter if present
|
|
93
|
+
const formattedValue = formatValue(rawValue, column, record);
|
|
94
|
+
|
|
95
|
+
// Extract URL from new format: { key, storage, url }
|
|
96
|
+
let mediaUrl: string | null = null;
|
|
97
|
+
if (formattedValue) {
|
|
98
|
+
if (typeof formattedValue === 'object' && formattedValue !== null && formattedValue.url) {
|
|
99
|
+
mediaUrl = formattedValue.url;
|
|
100
|
+
} else if (typeof formattedValue === 'string') {
|
|
101
|
+
mediaUrl = formattedValue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Resolve media type
|
|
106
|
+
const mediaType = resolveMediaType(column, record);
|
|
107
|
+
|
|
108
|
+
// Get thumbnail URL (for videos)
|
|
109
|
+
const thumbnailUrl = resolveThumbnail(column, record);
|
|
110
|
+
|
|
111
|
+
// Get default image URL (for images)
|
|
112
|
+
const defaultImageUrl = column.defaultImageUrl as string | undefined;
|
|
113
|
+
|
|
114
|
+
// Aspect ratio (default 16/9; circular columns force 1:1 via getColumnMediaDimensions)
|
|
115
|
+
const dimensions = getColumnMediaDimensions(column, 40);
|
|
116
|
+
const placeholderIcon =
|
|
117
|
+
(column.placeholderIcon as string) ||
|
|
118
|
+
(mediaType === 'video' ? 'Video' : mediaType === 'audio' ? 'Music' : 'Image');
|
|
119
|
+
const isClickable = column.clickable !== false;
|
|
120
|
+
|
|
121
|
+
const getContainerClasses = () => {
|
|
122
|
+
const classes = ['relative', 'flex', 'items-center', 'justify-center', 'overflow-hidden'];
|
|
123
|
+
|
|
124
|
+
if (column.circular) {
|
|
125
|
+
classes.push('rounded-full');
|
|
126
|
+
} else if (column.square) {
|
|
127
|
+
classes.push('rounded-none');
|
|
128
|
+
} else {
|
|
129
|
+
classes.push('rounded');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (isClickable && mediaUrl) {
|
|
133
|
+
classes.push('cursor-pointer', 'hover:opacity-80', 'transition-opacity');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (mediaType === 'video') {
|
|
137
|
+
classes.push('bg-gray-100', 'dark:bg-gray-800', 'group');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return classes.join(' ');
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const handleClick = () => {
|
|
144
|
+
if (!isClickable || !mediaUrl) return;
|
|
145
|
+
|
|
146
|
+
if (column.clickAction === 'link') {
|
|
147
|
+
window.open(mediaUrl, '_blank');
|
|
148
|
+
} else {
|
|
149
|
+
setPreviewOpen(true);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// If media type is null (hidden), show nothing
|
|
154
|
+
if (mediaType === null) {
|
|
155
|
+
return <span className="text-fg-secondary">-</span>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// If no media URL
|
|
159
|
+
if (!mediaUrl) {
|
|
160
|
+
// For images, check default image URL
|
|
161
|
+
if (mediaType === 'image' && defaultImageUrl) {
|
|
162
|
+
return (
|
|
163
|
+
<>
|
|
164
|
+
<img
|
|
165
|
+
src={defaultImageUrl}
|
|
166
|
+
alt=""
|
|
167
|
+
className={`object-cover ${getContainerClasses()}`}
|
|
168
|
+
style={dimensions}
|
|
169
|
+
onClick={handleClick}
|
|
170
|
+
/>
|
|
171
|
+
{isClickable && (
|
|
172
|
+
<MediaPreviewModal
|
|
173
|
+
isOpen={previewOpen}
|
|
174
|
+
onClose={() => setPreviewOpen(false)}
|
|
175
|
+
mediaUrl={defaultImageUrl}
|
|
176
|
+
mediaType="image"
|
|
177
|
+
title={column.previewTitle as string | undefined}
|
|
178
|
+
/>
|
|
179
|
+
)}
|
|
180
|
+
</>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Show placeholder for video/audio
|
|
185
|
+
if (mediaType === 'video' || mediaType === 'audio') {
|
|
186
|
+
return (
|
|
187
|
+
<div
|
|
188
|
+
className={`${getContainerClasses()} opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800`}
|
|
189
|
+
style={dimensions}>
|
|
190
|
+
<Icon name={placeholderIcon} size={20} className="text-gray-400" />
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return <span className="text-fg-secondary">{translate('core:file.no_image')}</span>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Render video
|
|
199
|
+
if (mediaType === 'video') {
|
|
200
|
+
return (
|
|
201
|
+
<>
|
|
202
|
+
<div
|
|
203
|
+
className={`${getContainerClasses()} bg-gray-100 dark:bg-gray-800`}
|
|
204
|
+
style={dimensions}
|
|
205
|
+
onClick={handleClick}>
|
|
206
|
+
{thumbnailUrl ? (
|
|
207
|
+
<>
|
|
208
|
+
<img
|
|
209
|
+
src={thumbnailUrl}
|
|
210
|
+
alt={translate('core:common.video_thumbnail')}
|
|
211
|
+
className="w-full h-full object-cover"
|
|
212
|
+
/>
|
|
213
|
+
{/* Play overlay */}
|
|
214
|
+
<div className="absolute inset-0 flex items-center justify-center bg-black/30 group-hover:bg-black/40 transition-colors">
|
|
215
|
+
<div className="w-8 h-8 flex items-center justify-center bg-white/90 rounded-full">
|
|
216
|
+
<Icon name="Play" size={16} className="text-gray-800 ml-0.5" />
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</>
|
|
220
|
+
) : (
|
|
221
|
+
<>
|
|
222
|
+
<Icon name={placeholderIcon} size={24} className="text-gray-500 dark:text-gray-400" />
|
|
223
|
+
{/* Play indicator */}
|
|
224
|
+
<div className="absolute bottom-1 right-1 w-4 h-4 flex items-center justify-center bg-accent rounded-full">
|
|
225
|
+
<Icon name="Play" size={10} className="text-white ml-0.5" />
|
|
226
|
+
</div>
|
|
227
|
+
</>
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<MediaPreviewModal
|
|
232
|
+
isOpen={previewOpen}
|
|
233
|
+
onClose={() => setPreviewOpen(false)}
|
|
234
|
+
mediaUrl={mediaUrl}
|
|
235
|
+
mediaType="video"
|
|
236
|
+
title={column.previewTitle as string | undefined}
|
|
237
|
+
autoplay={column.autoplay as boolean | undefined}
|
|
238
|
+
controls={column.controls !== false}
|
|
239
|
+
loop={column.loop as boolean | undefined}
|
|
240
|
+
muted={column.muted as boolean | undefined}
|
|
241
|
+
/>
|
|
242
|
+
</>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Render audio
|
|
247
|
+
if (mediaType === 'audio') {
|
|
248
|
+
return (
|
|
249
|
+
<>
|
|
250
|
+
<div
|
|
251
|
+
className={`${getContainerClasses()} bg-linear-to-br from-blue-600 to-purple-600`}
|
|
252
|
+
style={dimensions}
|
|
253
|
+
onClick={handleClick}>
|
|
254
|
+
<Icon name={placeholderIcon} size={24} className="text-white" />
|
|
255
|
+
{/* Play indicator */}
|
|
256
|
+
<div className="absolute bottom-1 right-1 w-4 h-4 flex items-center justify-center bg-white/90 rounded-full">
|
|
257
|
+
<Icon name="Play" size={10} className="text-gray-800 ml-0.5" />
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<MediaPreviewModal
|
|
262
|
+
isOpen={previewOpen}
|
|
263
|
+
onClose={() => setPreviewOpen(false)}
|
|
264
|
+
mediaUrl={mediaUrl}
|
|
265
|
+
mediaType="audio"
|
|
266
|
+
title={column.previewTitle as string | undefined}
|
|
267
|
+
autoplay={column.autoplay as boolean | undefined}
|
|
268
|
+
controls={column.controls !== false}
|
|
269
|
+
loop={column.loop as boolean | undefined}
|
|
270
|
+
/>
|
|
271
|
+
</>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Render single image
|
|
276
|
+
return (
|
|
277
|
+
<>
|
|
278
|
+
<img
|
|
279
|
+
src={mediaUrl}
|
|
280
|
+
alt=""
|
|
281
|
+
className={`object-cover ${getContainerClasses()}`}
|
|
282
|
+
style={dimensions}
|
|
283
|
+
onClick={handleClick}
|
|
284
|
+
/>
|
|
285
|
+
<MediaPreviewModal
|
|
286
|
+
isOpen={previewOpen}
|
|
287
|
+
onClose={() => setPreviewOpen(false)}
|
|
288
|
+
mediaUrl={mediaUrl}
|
|
289
|
+
mediaType="image"
|
|
290
|
+
title={column.previewTitle as string | undefined}
|
|
291
|
+
/>
|
|
292
|
+
</>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { ColumnProps } from './TextColumnComponent';
|
|
3
|
+
|
|
4
|
+
export interface EditableColumnProps extends ColumnProps {
|
|
5
|
+
onCellChange?: (value: any) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function SelectColumnComponent({ column, record, onCellChange }: EditableColumnProps) {
|
|
9
|
+
const [value, setValue] = useState(record[column.name] || '');
|
|
10
|
+
const isDisabled = column.disabled;
|
|
11
|
+
|
|
12
|
+
// Update local value when record changes (e.g., after reset)
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setValue(record[column.name] || '');
|
|
15
|
+
}, [record[column.name]]);
|
|
16
|
+
|
|
17
|
+
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
18
|
+
if (isDisabled) return;
|
|
19
|
+
|
|
20
|
+
const newValue = e.target.value;
|
|
21
|
+
setValue(newValue);
|
|
22
|
+
|
|
23
|
+
// Notify parent of change
|
|
24
|
+
if (onCellChange) {
|
|
25
|
+
onCellChange(newValue);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<select
|
|
31
|
+
value={value}
|
|
32
|
+
onChange={handleChange}
|
|
33
|
+
disabled={isDisabled}
|
|
34
|
+
className="k-input text-sm py-1.5 px-3 pr-8 rounded-md border border-border focus:outline-none focus:ring-2 focus:ring-ring focus:border-accent disabled:opacity-50 disabled:cursor-not-allowed transition-colors appearance-none bg-no-repeat bg-right"
|
|
35
|
+
style={{
|
|
36
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E")`,
|
|
37
|
+
backgroundPosition: 'right 0.5rem center',
|
|
38
|
+
backgroundSize: '1.5em 1.5em',
|
|
39
|
+
}}>
|
|
40
|
+
{column.placeholder && column.selectablePlaceholder && <option value="">{column.placeholder}</option>}
|
|
41
|
+
{column.options &&
|
|
42
|
+
Object.entries(column.options).map(([key, label]) => (
|
|
43
|
+
<option key={key} value={key}>
|
|
44
|
+
{label}
|
|
45
|
+
</option>
|
|
46
|
+
))}
|
|
47
|
+
</select>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ColumnProps } from './TextColumnComponent';
|
|
3
|
+
import { cn } from '../../utils/classNames';
|
|
4
|
+
import { formatValue } from '../../utils/tableFormatters';
|
|
5
|
+
|
|
6
|
+
export function TagsColumnComponent({ column, record }: ColumnProps) {
|
|
7
|
+
const rawValue = record[column.name];
|
|
8
|
+
// Apply formatter if present
|
|
9
|
+
const value = formatValue(rawValue, column, record);
|
|
10
|
+
|
|
11
|
+
if (!value || (Array.isArray(value) && value.length === 0)) {
|
|
12
|
+
return <span className="text-fg-secondary">-</span>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const tags = Array.isArray(value) ? value : [value];
|
|
16
|
+
const displayTags = column.limit ? tags.slice(0, column.limit) : tags;
|
|
17
|
+
|
|
18
|
+
// If no tags to display, return empty
|
|
19
|
+
if (!displayTags || displayTags.length === 0) {
|
|
20
|
+
return <></>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="flex flex-wrap gap-1">
|
|
25
|
+
{displayTags.map((tag, idx) => (
|
|
26
|
+
<span
|
|
27
|
+
key={idx}
|
|
28
|
+
className={cn(
|
|
29
|
+
'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium',
|
|
30
|
+
'bg-accent-soft dark:bg-accent-soft text-accent',
|
|
31
|
+
)}>
|
|
32
|
+
{String(tag)}
|
|
33
|
+
</span>
|
|
34
|
+
))}
|
|
35
|
+
{column.limit && tags.length > column.limit && (
|
|
36
|
+
<span
|
|
37
|
+
className={cn(
|
|
38
|
+
'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium',
|
|
39
|
+
'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300',
|
|
40
|
+
)}>
|
|
41
|
+
+{tags.length - column.limit}
|
|
42
|
+
</span>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SerializedColumn } from '@maxal_studio/kratosjs';
|
|
3
|
+
import { cn } from '../../utils/classNames';
|
|
4
|
+
import { formatValue } from '../../utils/tableFormatters';
|
|
5
|
+
import { DeeplinkWrapper } from './DeeplinkWrapper';
|
|
6
|
+
|
|
7
|
+
export interface ColumnProps {
|
|
8
|
+
column: SerializedColumn;
|
|
9
|
+
record: any;
|
|
10
|
+
rowIndex: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* TextColumn component for displaying text values
|
|
15
|
+
*/
|
|
16
|
+
export function TextColumnComponent({ column, record, rowIndex }: ColumnProps) {
|
|
17
|
+
const value = record[column.name];
|
|
18
|
+
|
|
19
|
+
// Handle row index
|
|
20
|
+
if (column.rowIndex) {
|
|
21
|
+
const displayIndex = column.rowIndexFromZero ? rowIndex : rowIndex + 1;
|
|
22
|
+
return <span className="text-fg">{displayIndex}</span>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Format value (pass entire record for formatStateUsing function)
|
|
26
|
+
const formattedValue = formatValue(value, column, record);
|
|
27
|
+
|
|
28
|
+
if (!formattedValue) {
|
|
29
|
+
return <></>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const hasDeeplink = !!column.deeplink;
|
|
33
|
+
|
|
34
|
+
// Handle arrays
|
|
35
|
+
if (Array.isArray(formattedValue)) {
|
|
36
|
+
const items = column.limit ? formattedValue.slice(0, column.limit) : formattedValue;
|
|
37
|
+
const shouldRenderHtml = column.stripHtml === false;
|
|
38
|
+
|
|
39
|
+
if (column.bulleted) {
|
|
40
|
+
return (
|
|
41
|
+
<ul className="list-disc list-inside space-y-1">
|
|
42
|
+
{items.map((item, idx) => {
|
|
43
|
+
const itemText = String(item);
|
|
44
|
+
return (
|
|
45
|
+
<li key={idx} className="text-fg text-sm">
|
|
46
|
+
{shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: itemText }} /> : itemText}
|
|
47
|
+
</li>
|
|
48
|
+
);
|
|
49
|
+
})}
|
|
50
|
+
{column.limit && formattedValue.length > column.limit && (
|
|
51
|
+
<li className="text-fg-secondary text-sm italic">
|
|
52
|
+
+{formattedValue.length - column.limit} more
|
|
53
|
+
</li>
|
|
54
|
+
)}
|
|
55
|
+
</ul>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (column.listWithLineBreaks) {
|
|
60
|
+
return (
|
|
61
|
+
<div className="space-y-1">
|
|
62
|
+
{items.map((item, idx) => {
|
|
63
|
+
const itemText = String(item);
|
|
64
|
+
return (
|
|
65
|
+
<div key={idx} className="text-fg text-sm">
|
|
66
|
+
{shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: itemText }} /> : itemText}
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
})}
|
|
70
|
+
{column.limit && formattedValue.length > column.limit && (
|
|
71
|
+
<div className="text-fg-secondary text-sm italic">
|
|
72
|
+
+{formattedValue.length - column.limit} more
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Default: comma-separated
|
|
80
|
+
const joinedText = items.join(', ');
|
|
81
|
+
return (
|
|
82
|
+
<span className="text-fg">
|
|
83
|
+
{shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: joinedText }} /> : joinedText}
|
|
84
|
+
</span>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get styling classes
|
|
89
|
+
const getTextClasses = () => {
|
|
90
|
+
const classes = ['text-fg'];
|
|
91
|
+
|
|
92
|
+
if (column.weight) {
|
|
93
|
+
classes.push(`font-${column.weight}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (column.fontFamily) {
|
|
97
|
+
classes.push(`font-${column.fontFamily}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (column.size) {
|
|
101
|
+
if (typeof column.size === 'string') {
|
|
102
|
+
classes.push(`text-${column.size}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (column.lineClamp) {
|
|
107
|
+
classes.push(`line-clamp-${column.lineClamp}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!column.wrap) {
|
|
111
|
+
classes.push('truncate');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return cn(classes);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Check if HTML should be rendered (stripHtml defaults to true in backend)
|
|
118
|
+
const shouldRenderHtml = column.stripHtml === false;
|
|
119
|
+
const textContent = String(formattedValue);
|
|
120
|
+
|
|
121
|
+
// Render badge
|
|
122
|
+
if (column.badge) {
|
|
123
|
+
let badgeColor = 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200';
|
|
124
|
+
|
|
125
|
+
if (column.color) {
|
|
126
|
+
if (typeof column.color === 'object') {
|
|
127
|
+
// Color mapping based on value
|
|
128
|
+
const colorKey = column.color[value];
|
|
129
|
+
if (colorKey) {
|
|
130
|
+
badgeColor = getBadgeColorClasses(colorKey);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
badgeColor = getBadgeColorClasses(column.color);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const badgeElement = (
|
|
138
|
+
<span
|
|
139
|
+
className={cn(
|
|
140
|
+
'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium',
|
|
141
|
+
badgeColor,
|
|
142
|
+
hasDeeplink && 'hover:opacity-80',
|
|
143
|
+
)}>
|
|
144
|
+
{shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: textContent }} /> : textContent}
|
|
145
|
+
</span>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// Wrap badge in deeplink if exists
|
|
149
|
+
if (hasDeeplink) {
|
|
150
|
+
return (
|
|
151
|
+
<DeeplinkWrapper column={column} record={record} value={value} className="inline-block">
|
|
152
|
+
{badgeElement}
|
|
153
|
+
</DeeplinkWrapper>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return badgeElement;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Regular text - render as HTML if stripHtml is false
|
|
161
|
+
const textElement = shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: textContent }} /> : textContent;
|
|
162
|
+
|
|
163
|
+
// Wrap in deeplink if exists
|
|
164
|
+
if (hasDeeplink) {
|
|
165
|
+
return (
|
|
166
|
+
<DeeplinkWrapper column={column} record={record} value={value} className={getTextClasses()}>
|
|
167
|
+
{textElement}
|
|
168
|
+
</DeeplinkWrapper>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<span className={getTextClasses()}>
|
|
174
|
+
{shouldRenderHtml ? <span dangerouslySetInnerHTML={{ __html: textContent }} /> : textContent}
|
|
175
|
+
</span>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getBadgeColorClasses(color: string): string {
|
|
180
|
+
const colorMap: Record<string, string> = {
|
|
181
|
+
primary: 'bg-accent-soft dark:bg-accent-soft text-accent',
|
|
182
|
+
secondary: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200',
|
|
183
|
+
success: 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300',
|
|
184
|
+
danger: 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300',
|
|
185
|
+
warning: 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300',
|
|
186
|
+
info: 'bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-300',
|
|
187
|
+
gray: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200',
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return colorMap[color] || colorMap.gray;
|
|
191
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { ColumnProps } from './TextColumnComponent';
|
|
3
|
+
|
|
4
|
+
export interface EditableColumnProps extends ColumnProps {
|
|
5
|
+
onCellChange?: (value: any) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function TextInputColumnComponent({ column, record, onCellChange }: EditableColumnProps) {
|
|
9
|
+
const [value, setValue] = useState(record[column.name] || '');
|
|
10
|
+
const isDisabled = column.disabled;
|
|
11
|
+
|
|
12
|
+
// Update local value when record changes (e.g., after reset)
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setValue(record[column.name] || '');
|
|
15
|
+
}, [record[column.name]]);
|
|
16
|
+
|
|
17
|
+
const handleChange = (newValue: string) => {
|
|
18
|
+
setValue(newValue);
|
|
19
|
+
// Notify parent of change
|
|
20
|
+
if (onCellChange) {
|
|
21
|
+
onCellChange(newValue);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<input
|
|
27
|
+
type={column.inputType || 'text'}
|
|
28
|
+
value={value}
|
|
29
|
+
onChange={e => handleChange(e.target.value)}
|
|
30
|
+
disabled={isDisabled}
|
|
31
|
+
placeholder={column.placeholder}
|
|
32
|
+
className="k-input text-sm py-1.5 px-3 w-full rounded-md border border-border focus:outline-none focus:ring-2 focus:ring-ring focus:border-accent disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { ColumnProps } from './TextColumnComponent';
|
|
3
|
+
import { Icon } from '../utils/Icon';
|
|
4
|
+
import { cn } from '../../utils/classNames';
|
|
5
|
+
|
|
6
|
+
export interface EditableColumnProps extends ColumnProps {
|
|
7
|
+
onCellChange?: (value: any) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ToggleColumnComponent({ column, record, onCellChange }: EditableColumnProps) {
|
|
11
|
+
const [value, setValue] = useState(Boolean(record[column.name]));
|
|
12
|
+
const isDisabled = column.disabled;
|
|
13
|
+
|
|
14
|
+
// Update local value when record changes (e.g., after reset)
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setValue(Boolean(record[column.name]));
|
|
17
|
+
}, [record[column.name]]);
|
|
18
|
+
|
|
19
|
+
const handleToggle = () => {
|
|
20
|
+
if (isDisabled) return;
|
|
21
|
+
|
|
22
|
+
const newValue = !value;
|
|
23
|
+
setValue(newValue);
|
|
24
|
+
|
|
25
|
+
// Notify parent of change
|
|
26
|
+
if (onCellChange) {
|
|
27
|
+
onCellChange(newValue);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Get colors
|
|
32
|
+
const trackClasses =
|
|
33
|
+
(value ? column.onColor : column.offColor) ?? (value ? 'bg-accent' : 'bg-gray-200 dark:bg-gray-700');
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
onClick={handleToggle}
|
|
39
|
+
disabled={isDisabled}
|
|
40
|
+
className={cn(
|
|
41
|
+
'relative inline-flex h-6 w-11 items-center rounded-full transition-colors',
|
|
42
|
+
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
43
|
+
'disabled:opacity-50 disabled:cursor-not-allowed',
|
|
44
|
+
...trackClasses.split(/\s+/),
|
|
45
|
+
)}>
|
|
46
|
+
<span
|
|
47
|
+
className={cn(
|
|
48
|
+
'inline-flex items-center justify-center h-4 w-4 transform rounded-full bg-white transition-transform',
|
|
49
|
+
value ? 'translate-x-6' : 'translate-x-1',
|
|
50
|
+
)}>
|
|
51
|
+
{column.onIcon && value && <Icon name={column.onIcon} size={10} className="text-green-600" />}
|
|
52
|
+
{column.offIcon && !value && <Icon name={column.offIcon} size={10} className="text-gray-400" />}
|
|
53
|
+
</span>
|
|
54
|
+
</button>
|
|
55
|
+
);
|
|
56
|
+
}
|