@jini-ai/admin 0.4.2 → 0.4.3
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/CHANGELOG.md +11 -0
- package/README.md +7 -0
- package/dist/agent-plugins/react/components/AgentPluginListPanel.d.ts +1 -1
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +1 -1
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +1 -1
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +1 -1
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +1 -1
- package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.d.ts +1 -1
- package/dist/agent-plugins/react/index.js +1 -1
- package/dist/agent-plugins/react/pages/AgentPluginsPage.d.ts +1 -1
- package/dist/agent-plugins/react/tabs/DownloadedTab.d.ts +1 -1
- package/dist/agent-plugins/react/tabs/InstalledTab.d.ts +1 -1
- package/dist/agent-plugins/react/tabs/MarketplaceTab.d.ts +1 -1
- package/dist/comments/adapters/http.d.ts +29 -0
- package/dist/comments/adapters/http.js +50 -0
- package/dist/comments/adapters/memory.d.ts +17 -0
- package/dist/comments/adapters/memory.js +61 -0
- package/dist/comments/comments.module.d.ts +73 -0
- package/dist/comments/comments.module.js +16 -0
- package/dist/comments/conformance/comments-api.conformance.d.ts +9 -0
- package/dist/comments/conformance/comments-api.conformance.js +63 -0
- package/dist/comments/controllers/comment-queue.controller.d.ts +48 -0
- package/dist/comments/controllers/comment-queue.controller.js +164 -0
- package/dist/comments/controllers/comment-settings.controller.d.ts +32 -0
- package/dist/comments/controllers/comment-settings.controller.js +77 -0
- package/dist/comments/controllers/comments.controller.d.ts +16 -0
- package/dist/comments/controllers/comments.controller.js +16 -0
- package/dist/comments/index.d.ts +13 -0
- package/dist/comments/index.js +8 -0
- package/dist/comments/messages.en.d.ts +54 -0
- package/dist/comments/messages.en.js +56 -0
- package/dist/comments/models.d.ts +22 -0
- package/dist/comments/models.js +2 -0
- package/dist/comments/ports.d.ts +14 -0
- package/dist/comments/ports.js +5 -0
- package/dist/comments/react/components/QueueSection.d.ts +30 -0
- package/dist/comments/react/components/QueueSection.js +57 -0
- package/dist/comments/react/components/SettingsSection.d.ts +14 -0
- package/dist/comments/react/components/SettingsSection.js +23 -0
- package/dist/comments/react/hooks/CommentsPage.hooks.d.ts +9 -0
- package/dist/comments/react/hooks/CommentsPage.hooks.js +10 -0
- package/dist/comments/react/hooks/CommentsPorts.hooks.d.ts +13 -0
- package/dist/comments/react/hooks/CommentsPorts.hooks.js +15 -0
- package/dist/comments/react/hooks/QueueSection.hooks.d.ts +62 -0
- package/dist/comments/react/hooks/QueueSection.hooks.js +57 -0
- package/dist/comments/react/hooks/SettingsSection.hooks.d.ts +12 -0
- package/dist/comments/react/hooks/SettingsSection.hooks.js +21 -0
- package/dist/comments/react/hooks/use-comment-queue.hooks.d.ts +34 -0
- package/dist/comments/react/hooks/use-comment-queue.hooks.js +47 -0
- package/dist/comments/react/hooks/use-comment-settings.hooks.d.ts +22 -0
- package/dist/comments/react/hooks/use-comment-settings.hooks.js +30 -0
- package/dist/comments/react/hooks/use-comments.hooks.d.ts +15 -0
- package/dist/comments/react/hooks/use-comments.hooks.js +20 -0
- package/dist/comments/react/index.d.ts +316 -0
- package/dist/comments/react/index.js +35 -0
- package/dist/comments/react/pages/CommentsPage.d.ts +12 -0
- package/dist/comments/react/pages/CommentsPage.js +15 -0
- package/dist/comments/rules.d.ts +140 -0
- package/dist/comments/rules.js +199 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.js +1 -0
- package/dist/core/ledger-slice.d.ts +90 -0
- package/dist/core/ledger-slice.js +81 -0
- package/dist/core/ports/comments.d.ts +2 -0
- package/dist/core/ports/forms.d.ts +19 -7
- package/dist/core/ports/forms.js +4 -4
- package/dist/core/ports/index.d.ts +1 -1
- package/dist/core/ports/seo.d.ts +33 -6
- package/dist/core/react/bind-react.d.ts +46 -0
- package/dist/core/react/bind-react.js +28 -0
- package/dist/core/react/index.d.ts +3 -0
- package/dist/core/react/index.js +3 -0
- package/dist/core/react/use-controller.d.ts +16 -0
- package/dist/core/react/use-controller.js +18 -0
- package/dist/forms/adapters/http.d.ts +26 -0
- package/dist/forms/adapters/http.js +43 -0
- package/dist/forms/adapters/memory.d.ts +14 -0
- package/dist/forms/adapters/memory.js +77 -0
- package/dist/forms/conformance/forms-api.conformance.d.ts +17 -0
- package/dist/forms/conformance/forms-api.conformance.js +71 -0
- package/dist/forms/controllers/draft-store.d.ts +18 -0
- package/dist/forms/controllers/draft-store.js +17 -0
- package/dist/forms/controllers/field-attributes-dialog.controller.d.ts +37 -0
- package/dist/forms/controllers/field-attributes-dialog.controller.js +27 -0
- package/dist/forms/controllers/form-editor.controller.d.ts +36 -0
- package/dist/forms/controllers/form-editor.controller.js +22 -0
- package/dist/forms/controllers/form-fields-editor.controller.d.ts +20 -0
- package/dist/forms/controllers/form-fields-editor.controller.js +10 -0
- package/dist/forms/controllers/form-submission-detail.controller.d.ts +20 -0
- package/dist/forms/controllers/form-submission-detail.controller.js +10 -0
- package/dist/forms/controllers/form-submissions.controller.d.ts +25 -0
- package/dist/forms/controllers/form-submissions.controller.js +10 -0
- package/dist/forms/controllers/forms-list.controller.d.ts +22 -0
- package/dist/forms/controllers/forms-list.controller.js +10 -0
- package/dist/forms/forms.module.d.ts +137 -0
- package/dist/forms/forms.module.js +17 -0
- package/dist/forms/html-rules.d.ts +20 -0
- package/dist/forms/html-rules.js +24 -0
- package/dist/forms/index.d.ts +14 -0
- package/dist/forms/index.js +12 -0
- package/dist/forms/messages.en.d.ts +100 -0
- package/dist/forms/messages.en.js +104 -0
- package/dist/forms/models.d.ts +29 -0
- package/dist/forms/models.js +8 -0
- package/dist/forms/ports.d.ts +26 -0
- package/dist/forms/ports.js +6 -0
- package/dist/forms/react/components/FieldAttributesDialog.d.ts +14 -0
- package/dist/forms/react/components/FieldAttributesDialog.js +47 -0
- package/dist/forms/react/components/FormEditorFieldsBody.d.ts +28 -0
- package/dist/forms/react/components/FormEditorFieldsBody.js +24 -0
- package/dist/forms/react/components/FormEditorHeaderText.d.ts +7 -0
- package/dist/forms/react/components/FormEditorHeaderText.js +8 -0
- package/dist/forms/react/components/FormEditorMainPanel.d.ts +12 -0
- package/dist/forms/react/components/FormEditorMainPanel.js +13 -0
- package/dist/forms/react/components/FormEditorTabStrip.d.ts +13 -0
- package/dist/forms/react/components/FormEditorTabStrip.js +14 -0
- package/dist/forms/react/components/FormFieldsEditor.d.ts +13 -0
- package/dist/forms/react/components/FormFieldsEditor.js +39 -0
- package/dist/forms/react/components/FormSubmissionDate.d.ts +8 -0
- package/dist/forms/react/components/FormSubmissionDate.js +5 -0
- package/dist/forms/react/components/FormSubmissionDetail.d.ts +13 -0
- package/dist/forms/react/components/FormSubmissionDetail.js +29 -0
- package/dist/forms/react/components/FormSubmissions.d.ts +12 -0
- package/dist/forms/react/components/FormSubmissions.js +46 -0
- package/dist/forms/react/hooks/FormsPorts.hooks.d.ts +41 -0
- package/dist/forms/react/hooks/FormsPorts.hooks.js +16 -0
- package/dist/forms/react/hooks/forms-view.hooks.d.ts +122 -0
- package/dist/forms/react/hooks/forms-view.hooks.js +79 -0
- package/dist/forms/react/hooks/use-field-attributes-dialog.hooks.d.ts +31 -0
- package/dist/forms/react/hooks/use-field-attributes-dialog.hooks.js +22 -0
- package/dist/forms/react/hooks/use-form-editor.hooks.d.ts +118 -0
- package/dist/forms/react/hooks/use-form-editor.hooks.js +208 -0
- package/dist/forms/react/hooks/use-form-fields-editor.hooks.d.ts +34 -0
- package/dist/forms/react/hooks/use-form-fields-editor.hooks.js +36 -0
- package/dist/forms/react/hooks/use-form-submission-date.hooks.d.ts +12 -0
- package/dist/forms/react/hooks/use-form-submission-date.hooks.js +9 -0
- package/dist/forms/react/hooks/use-form-submission-detail.hooks.d.ts +68 -0
- package/dist/forms/react/hooks/use-form-submission-detail.hooks.js +81 -0
- package/dist/forms/react/hooks/use-form-submissions.hooks.d.ts +67 -0
- package/dist/forms/react/hooks/use-form-submissions.hooks.js +110 -0
- package/dist/forms/react/hooks/use-forms-list.hooks.d.ts +78 -0
- package/dist/forms/react/hooks/use-forms-list.hooks.js +103 -0
- package/dist/forms/react/index.d.ts +449 -0
- package/dist/forms/react/index.js +35 -0
- package/dist/forms/react/pages/FormEditor.d.ts +19 -0
- package/dist/forms/react/pages/FormEditor.js +40 -0
- package/dist/forms/react/pages/FormsList.d.ts +39 -0
- package/dist/forms/react/pages/FormsList.js +55 -0
- package/dist/forms/rules.d.ts +291 -0
- package/dist/forms/rules.js +338 -0
- package/dist/media/react/hooks/EditMediaPanel.hooks.js +1 -1
- package/dist/media/react/hooks/LibraryTab.hooks.d.ts +1 -1
- package/dist/media/react/hooks/LibraryTab.hooks.js +1 -1
- package/dist/media/react/hooks/MediaCard.hooks.js +6 -20
- package/dist/media/react/hooks/MediaGrid.hooks.d.ts +2 -2
- package/dist/media/react/hooks/MediaPage.hooks.d.ts +1 -1
- package/dist/media/react/hooks/MediaPage.hooks.js +1 -1
- package/dist/media/react/hooks/MediaPicker.hooks.js +1 -1
- package/dist/media/react/index.js +1 -1
- package/dist/media/react/tabs/LibraryTab.d.ts +1 -1
- package/dist/media/react/tabs/ProvidersTab.d.ts +1 -1
- package/dist/playground/react/components/Canvas.d.ts +1 -1
- package/dist/playground/react/hooks/Canvas.hooks.d.ts +1 -1
- package/dist/playground/react/hooks/Canvas.hooks.js +1 -1
- package/dist/playground/react/hooks/PlaygroundPage.hooks.d.ts +1 -1
- package/dist/playground/react/index.js +1 -1
- package/dist/playground/react/pages/PlaygroundPage.d.ts +1 -1
- package/dist/playground/react/tabs/CanvasTab.d.ts +1 -1
- package/dist/react/bind-react.d.ts +1 -45
- package/dist/react/bind-react.js +2 -27
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +22 -5
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +2 -2
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +17 -55
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +33 -70
- package/dist/react/use-controller.d.ts +1 -15
- package/dist/react/use-controller.js +2 -17
- package/dist/redirects/adapters/http.d.ts +20 -0
- package/dist/redirects/adapters/http.js +31 -0
- package/dist/redirects/adapters/memory.d.ts +13 -0
- package/dist/redirects/adapters/memory.js +83 -0
- package/dist/redirects/conformance/redirects-api.conformance.d.ts +12 -0
- package/dist/redirects/conformance/redirects-api.conformance.js +66 -0
- package/dist/redirects/controllers/hit-count.controller.d.ts +14 -0
- package/dist/redirects/controllers/hit-count.controller.js +10 -0
- package/dist/redirects/controllers/import-redirects.controller.d.ts +28 -0
- package/dist/redirects/controllers/import-redirects.controller.js +29 -0
- package/dist/redirects/controllers/redirects.controller.d.ts +37 -0
- package/dist/redirects/controllers/redirects.controller.js +38 -0
- package/dist/redirects/index.d.ts +11 -0
- package/dist/redirects/index.js +10 -0
- package/dist/redirects/messages.en.d.ts +56 -0
- package/dist/redirects/messages.en.js +55 -0
- package/dist/redirects/models.d.ts +14 -0
- package/dist/redirects/models.js +2 -0
- package/dist/redirects/ports.d.ts +9 -0
- package/dist/redirects/ports.js +4 -0
- package/dist/redirects/react/components/HitCountCell.d.ts +19 -0
- package/dist/redirects/react/components/HitCountCell.js +19 -0
- package/dist/redirects/react/components/ImportRedirectsForm.d.ts +17 -0
- package/dist/redirects/react/components/ImportRedirectsForm.js +12 -0
- package/dist/redirects/react/hooks/RedirectsOptions.hooks.d.ts +27 -0
- package/dist/redirects/react/hooks/RedirectsOptions.hooks.js +15 -0
- package/dist/redirects/react/hooks/RedirectsPage.hooks.d.ts +50 -0
- package/dist/redirects/react/hooks/RedirectsPage.hooks.js +30 -0
- package/dist/redirects/react/hooks/RedirectsPorts.hooks.d.ts +10 -0
- package/dist/redirects/react/hooks/RedirectsPorts.hooks.js +11 -0
- package/dist/redirects/react/hooks/use-hit-count-cell.hooks.d.ts +19 -0
- package/dist/redirects/react/hooks/use-hit-count-cell.hooks.js +15 -0
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.d.ts +21 -0
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.js +25 -0
- package/dist/redirects/react/hooks/use-redirects.hooks.d.ts +34 -0
- package/dist/redirects/react/hooks/use-redirects.hooks.js +63 -0
- package/dist/redirects/react/hooks/wired.hooks.d.ts +55 -0
- package/dist/redirects/react/hooks/wired.hooks.js +31 -0
- package/dist/redirects/react/index.d.ts +316 -0
- package/dist/redirects/react/index.js +28 -0
- package/dist/redirects/react/pages/RedirectsPage.d.ts +15 -0
- package/dist/redirects/react/pages/RedirectsPage.js +20 -0
- package/dist/redirects/redirects.module.d.ts +75 -0
- package/dist/redirects/redirects.module.js +13 -0
- package/dist/redirects/rules.d.ts +131 -0
- package/dist/redirects/rules.js +134 -0
- package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +1 -1
- package/dist/security/react/hooks/AccessTokensTab.hooks.js +1 -1
- package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +1 -1
- package/dist/security/react/hooks/RootKeyTab.hooks.js +1 -1
- package/dist/security/react/hooks/SecurityPage.hooks.d.ts +1 -1
- package/dist/security/react/index.js +1 -1
- package/dist/security/react/pages/SecurityPage.d.ts +1 -1
- package/dist/security/react/tabs/AccessTokensTab.d.ts +1 -1
- package/dist/security/react/tabs/RootKeyTab.d.ts +1 -1
- package/dist/seo/adapters/http.d.ts +31 -0
- package/dist/seo/adapters/http.js +37 -0
- package/dist/seo/adapters/memory.d.ts +28 -0
- package/dist/seo/adapters/memory.js +129 -0
- package/dist/seo/conformance/seo-api.conformance.d.ts +8 -0
- package/dist/seo/conformance/seo-api.conformance.js +44 -0
- package/dist/seo/controllers/entry-picker.controller.d.ts +21 -0
- package/dist/seo/controllers/entry-picker.controller.js +17 -0
- package/dist/seo/controllers/entry-section.controller.d.ts +20 -0
- package/dist/seo/controllers/entry-section.controller.js +7 -0
- package/dist/seo/controllers/media-ref.controller.d.ts +26 -0
- package/dist/seo/controllers/media-ref.controller.js +14 -0
- package/dist/seo/controllers/seo-entry.controller.d.ts +31 -0
- package/dist/seo/controllers/seo-entry.controller.js +52 -0
- package/dist/seo/controllers/seo.controller.d.ts +29 -0
- package/dist/seo/controllers/seo.controller.js +50 -0
- package/dist/seo/controllers/sitemap.controller.d.ts +25 -0
- package/dist/seo/controllers/sitemap.controller.js +27 -0
- package/dist/seo/index.d.ts +14 -0
- package/dist/seo/index.js +12 -0
- package/dist/seo/messages.en.d.ts +78 -0
- package/dist/seo/messages.en.js +78 -0
- package/dist/seo/models.d.ts +179 -0
- package/dist/seo/models.js +8 -0
- package/dist/seo/ports.d.ts +11 -0
- package/dist/seo/ports.js +4 -0
- package/dist/seo/react/components/MediaPickerBridge.d.ts +4 -0
- package/dist/seo/react/components/MediaPickerBridge.js +8 -0
- package/dist/seo/react/components/MediaRefField.d.ts +36 -0
- package/dist/seo/react/components/MediaRefField.js +12 -0
- package/dist/seo/react/components/SeoIcons.d.ts +13 -0
- package/dist/seo/react/components/SeoIcons.js +32 -0
- package/dist/seo/react/components/SitemapModal.d.ts +48 -0
- package/dist/seo/react/components/SitemapModal.js +70 -0
- package/dist/seo/react/hooks/MediaPickerBridge.hooks.d.ts +6 -0
- package/dist/seo/react/hooks/MediaPickerBridge.hooks.js +27 -0
- package/dist/seo/react/hooks/MediaRefField.hooks.d.ts +22 -0
- package/dist/seo/react/hooks/MediaRefField.hooks.js +30 -0
- package/dist/seo/react/hooks/SeoModuleTabs.d.ts +14 -0
- package/dist/seo/react/hooks/SeoModuleTabs.js +18 -0
- package/dist/seo/react/hooks/SeoPage.hooks.d.ts +69 -0
- package/dist/seo/react/hooks/SeoPage.hooks.js +37 -0
- package/dist/seo/react/hooks/SeoPorts.hooks.d.ts +19 -0
- package/dist/seo/react/hooks/SeoPorts.hooks.js +22 -0
- package/dist/seo/react/hooks/SitemapModal.hooks.d.ts +26 -0
- package/dist/seo/react/hooks/SitemapModal.hooks.js +20 -0
- package/dist/seo/react/hooks/use-entry-picker.hooks.d.ts +11 -0
- package/dist/seo/react/hooks/use-entry-picker.hooks.js +20 -0
- package/dist/seo/react/hooks/use-seo-entry-panel.hooks.d.ts +14 -0
- package/dist/seo/react/hooks/use-seo-entry-panel.hooks.js +26 -0
- package/dist/seo/react/hooks/use-seo-entry-section.hooks.d.ts +4 -0
- package/dist/seo/react/hooks/use-seo-entry-section.hooks.js +7 -0
- package/dist/seo/react/hooks/use-seo.hooks.d.ts +11 -0
- package/dist/seo/react/hooks/use-seo.hooks.js +29 -0
- package/dist/seo/react/hooks/use-sitemap-modal.hooks.d.ts +10 -0
- package/dist/seo/react/hooks/use-sitemap-modal.hooks.js +18 -0
- package/dist/seo/react/index.d.ts +366 -0
- package/dist/seo/react/index.js +30 -0
- package/dist/seo/react/options.d.ts +19 -0
- package/dist/seo/react/options.js +2 -0
- package/dist/seo/react/pages/SeoPage.d.ts +161 -0
- package/dist/seo/react/pages/SeoPage.js +215 -0
- package/dist/seo/rules.d.ts +136 -0
- package/dist/seo/rules.js +212 -0
- package/dist/seo/seo.module.d.ts +114 -0
- package/dist/seo/seo.module.js +14 -0
- package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +1 -1
- package/dist/source-control/react/hooks/ProvidersTab.hooks.js +1 -1
- package/dist/source-control/react/hooks/SourceControlPage.hooks.d.ts +1 -1
- package/dist/source-control/react/index.js +1 -1
- package/dist/source-control/react/pages/SourceControlPage.d.ts +1 -1
- package/dist/source-control/react/tabs/ProvidersTab.d.ts +1 -1
- package/dist/widgets/adapters/http.d.ts +19 -0
- package/dist/widgets/adapters/http.js +33 -0
- package/dist/widgets/adapters/memory.d.ts +22 -0
- package/dist/widgets/adapters/memory.js +93 -0
- package/dist/widgets/conformance/widgets-api.conformance.d.ts +6 -0
- package/dist/widgets/conformance/widgets-api.conformance.js +55 -0
- package/dist/widgets/controllers/instance-editor.controller.d.ts +49 -0
- package/dist/widgets/controllers/instance-editor.controller.js +87 -0
- package/dist/widgets/controllers/library.controller.d.ts +33 -0
- package/dist/widgets/controllers/library.controller.js +53 -0
- package/dist/widgets/controllers/region-editor.controller.d.ts +42 -0
- package/dist/widgets/controllers/region-editor.controller.js +69 -0
- package/dist/widgets/controllers/regions.controller.d.ts +27 -0
- package/dist/widgets/controllers/regions.controller.js +44 -0
- package/dist/widgets/index.d.ts +11 -0
- package/dist/widgets/index.js +9 -0
- package/dist/widgets/messages.en.d.ts +78 -0
- package/dist/widgets/messages.en.js +83 -0
- package/dist/widgets/models.d.ts +62 -0
- package/dist/widgets/models.js +2 -0
- package/dist/widgets/ports.d.ts +79 -0
- package/dist/widgets/ports.js +5 -0
- package/dist/widgets/react/components/WidgetInstanceNotices.d.ts +14 -0
- package/dist/widgets/react/components/WidgetInstanceNotices.js +25 -0
- package/dist/widgets/react/components/WidgetRegionEditorHeaderActions.d.ts +22 -0
- package/dist/widgets/react/components/WidgetRegionEditorHeaderActions.js +18 -0
- package/dist/widgets/react/components/WidgetsLibraryNotices.d.ts +13 -0
- package/dist/widgets/react/components/WidgetsLibraryNotices.js +10 -0
- package/dist/widgets/react/hooks/WidgetsPorts.hooks.d.ts +270 -0
- package/dist/widgets/react/hooks/WidgetsPorts.hooks.js +17 -0
- package/dist/widgets/react/hooks/navigation.hooks.d.ts +9 -0
- package/dist/widgets/react/hooks/navigation.hooks.js +6 -0
- package/dist/widgets/react/hooks/page-views.hooks.d.ts +87 -0
- package/dist/widgets/react/hooks/page-views.hooks.js +30 -0
- package/dist/widgets/react/hooks/use-widget-instance-editor.hooks.d.ts +56 -0
- package/dist/widgets/react/hooks/use-widget-instance-editor.hooks.js +38 -0
- package/dist/widgets/react/hooks/use-widget-region-editor.hooks.d.ts +32 -0
- package/dist/widgets/react/hooks/use-widget-region-editor.hooks.js +22 -0
- package/dist/widgets/react/hooks/use-widget-regions.hooks.d.ts +23 -0
- package/dist/widgets/react/hooks/use-widget-regions.hooks.js +22 -0
- package/dist/widgets/react/hooks/use-widgets-library.hooks.d.ts +37 -0
- package/dist/widgets/react/hooks/use-widgets-library.hooks.js +23 -0
- package/dist/widgets/react/index.d.ts +391 -0
- package/dist/widgets/react/index.js +31 -0
- package/dist/widgets/react/pages/WidgetInstanceEditor.d.ts +23 -0
- package/dist/widgets/react/pages/WidgetInstanceEditor.js +37 -0
- package/dist/widgets/react/pages/WidgetRegionEditor.d.ts +22 -0
- package/dist/widgets/react/pages/WidgetRegionEditor.js +25 -0
- package/dist/widgets/react/pages/WidgetRegions.d.ts +21 -0
- package/dist/widgets/react/pages/WidgetRegions.js +31 -0
- package/dist/widgets/react/pages/WidgetsLibrary.d.ts +24 -0
- package/dist/widgets/react/pages/WidgetsLibrary.js +61 -0
- package/dist/widgets/rules.d.ts +94 -0
- package/dist/widgets/rules.js +83 -0
- package/dist/widgets/widgets.module.d.ts +122 -0
- package/dist/widgets/widgets.module.js +21 -0
- package/package.json +206 -9
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { AdminApiError as ApiError, describeApiError as describeCoreApiError } from "../core/transport/errors.js";
|
|
2
|
+
const describeApiError = (e, fallback) => describeCoreApiError({ e, fallback });
|
|
3
|
+
/**
|
|
4
|
+
* @file Pure logic for the `forms` feature (`FormEditor.tsx` — see `FormsList.tsx`'s own
|
|
5
|
+
* `rules.ts`/hook for the list screen's extraction) — everything that computes a value rather than
|
|
6
|
+
* rendering one. Follows the convention `features/posts/rules.ts` establishes: no React, no
|
|
7
|
+
* hooks, importable and directly testable.
|
|
8
|
+
*
|
|
9
|
+
* One deliberate exception to "pure", same as `collections/rules.ts`'s `nextRowId`:
|
|
10
|
+
* {@link nextAttrRowId} is a module-level counter `attrRowsFromField`/`addAttrRow` advance. Only
|
|
11
|
+
* `FieldAttributesDialog` (via `use-field-attributes-dialog.hooks.ts`) consumes it today, so it
|
|
12
|
+
* would be equally correct sitting in that hook file — kept here instead for the same reason
|
|
13
|
+
* `collections/rules.ts` keeps its row-id counter alongside its other draft-list transforms: one
|
|
14
|
+
* place for "how draft rows get local keys" per feature, not split by which hook happens to use it
|
|
15
|
+
* first.
|
|
16
|
+
*
|
|
17
|
+
* `KEYS` (fetch-query migration, 2026-08-12): forms and form-submissions are two independent
|
|
18
|
+
* resources (separate ports, no method overlap — see `core/ports/forms.ts`/`form-submissions-
|
|
19
|
+
* port.hooks.ts`'s own doc comments), so they get two entirely separate top-level key namespaces
|
|
20
|
+
* rather than sharing one grandparent. Within each, `list`/`detail(id)` (and `submissionsList(formId)`/
|
|
21
|
+
* `submissionDetail(formId, id)`) are SIBLINGS, not parent/child — `@jini-ai/ui/fetch-query`'s
|
|
22
|
+
* `QueryKey` doc warns that invalidation matches by prefix, and `collections/rules.ts`'s own `KEYS`
|
|
23
|
+
* doc records the regression that bit the predecessor when a detail key nested under its list: every
|
|
24
|
+
* save silently fired 3 extra background requests because invalidating the list also invalidated the
|
|
25
|
+
* editor's own currently-open read. Fixed second-array-element ("list" vs "detail") rather than
|
|
26
|
+
* nesting keeps `KEYS.list`'s invalidation from ever touching an open `KEYS.form(id)`/
|
|
27
|
+
* `KEYS.submissionDetail(...)` read, regardless of what `id` happens to be.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* This screen's name on `lib/content-refresh-bus.ts` — see `taxonomy/rules.ts`'s `TAXONOMY_RESOURCE`
|
|
31
|
+
* for why this is a plain colocated constant rather than a shared registry. `forms_create_definition`/
|
|
32
|
+
* `forms_update_definition`/`forms_set_definition_status` (`apps/website/src/features/forms/agent-
|
|
33
|
+
* tools.ts`) are agent-callable, so `FormsList.tsx` needs the same "an assistant write shows up
|
|
34
|
+
* without a reload" fix `use-taxonomy.hooks.ts` shipped first.
|
|
35
|
+
*/
|
|
36
|
+
export const FORMS_LIST_RESOURCE = "forms";
|
|
37
|
+
/** The list has no sort control: recently edited forms belong first. Copy before sorting so
|
|
38
|
+
* the query cache and injected repository keep their own order; ties retain response order. */
|
|
39
|
+
export function newestUpdatedForms({ forms }, _optional = {}) {
|
|
40
|
+
return [...forms].sort((a, b) => (Date.parse(b.updatedAt) || 0) - (Date.parse(a.updatedAt) || 0));
|
|
41
|
+
}
|
|
42
|
+
/** One form event's compact local date and full tooltip. Shared by definitions and submissions;
|
|
43
|
+
* malformed legacy values stay visible as a dash rather than throwing during table rendering. */
|
|
44
|
+
export function formDateDisplay({ iso, locale }, { timeZone } = {}) {
|
|
45
|
+
const date = new Date(iso);
|
|
46
|
+
if (Number.isNaN(date.getTime()))
|
|
47
|
+
return { text: "—", full: "—", dateTime: undefined };
|
|
48
|
+
return {
|
|
49
|
+
text: new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "short", timeZone }).format(date),
|
|
50
|
+
full: new Intl.DateTimeFormat(locale, {
|
|
51
|
+
year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "2-digit", timeZone,
|
|
52
|
+
}).format(date),
|
|
53
|
+
dateTime: date.toISOString(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Form-specific date copy. The shared admin timestamp helper intentionally slices ISO text
|
|
57
|
+
* and its relative helper is English-only; these two events need the operator's locale and
|
|
58
|
+
* browser time zone. Absolute dates remain accurate while the list stays open without a timer.
|
|
59
|
+
*
|
|
60
|
+
* Owner 2026-10-05: line 1 created, line 2 updated, each a compact short date + time with no event
|
|
61
|
+
* word; one line when updated shows the same date and minute as created. The comparison is on the
|
|
62
|
+
* displayed short text, so edits within the same minute collapse and the rule follows the locale's
|
|
63
|
+
* own precision. Intl picks the date order — never a hand-built "M/D/YY".
|
|
64
|
+
*
|
|
65
|
+
* @complexity O(1) time and space — two dates, fixed-size formatting.
|
|
66
|
+
*/
|
|
67
|
+
export function formDatesLines({ form, locale, t }, options = {}) {
|
|
68
|
+
const created = formDateDisplay({ iso: form.createdAt, locale }, options);
|
|
69
|
+
const updated = formDateDisplay({ iso: form.updatedAt, locale }, options);
|
|
70
|
+
if (created.text === updated.text) {
|
|
71
|
+
const label = t("Created {created} · Updated {updated}")
|
|
72
|
+
.replace("{created}", created.full)
|
|
73
|
+
.replace("{updated}", updated.full);
|
|
74
|
+
return [{ kind: "both", text: created.text, dateTime: created.dateTime, label }];
|
|
75
|
+
}
|
|
76
|
+
return [
|
|
77
|
+
{ kind: "created", text: created.text, dateTime: created.dateTime, label: t("Created {date}").replace("{date}", created.full) },
|
|
78
|
+
{ kind: "updated", text: updated.text, dateTime: updated.dateTime, label: t("Updated {date}").replace("{date}", updated.full) },
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
export const KEYS = {
|
|
82
|
+
list: ["forms", "list"],
|
|
83
|
+
form: (id) => ["forms", "detail", id],
|
|
84
|
+
submissionsList: (formId) => ["form-submissions", "list", formId],
|
|
85
|
+
submissionDetail: (formId, submissionId) => [
|
|
86
|
+
"form-submissions",
|
|
87
|
+
"detail",
|
|
88
|
+
formId,
|
|
89
|
+
submissionId,
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* `useFormEditor`'s error banner, extracted out of that hook (`refactor/fetch-query` complexity
|
|
94
|
+
* pass, 2026-08-12 — same reason `collections/rules.ts`'s `visibleEntryEditorError` was extracted:
|
|
95
|
+
* the hook's own precedence chain over four sources pushed it past the complexity ceiling).
|
|
96
|
+
*
|
|
97
|
+
* Precedence: an active write's own failure (update/create/status, in that order — mirrors
|
|
98
|
+
* `redirects/rules.ts`'s `firstWriteError` array-order precedence, since `update`/`status` can both
|
|
99
|
+
* apply to the SAME loaded form) always wins. The list-load failure only surfaces before the form
|
|
100
|
+
* has ever loaded — once `hasForm` is true, a later BACKGROUND refresh failure must not blank an
|
|
101
|
+
* editor the operator is actively using (same "a later failure must not erase what already
|
|
102
|
+
* rendered" guard `FormEditor.tsx`'s own file header already documents at the render layer; this is
|
|
103
|
+
* its data-layer half).
|
|
104
|
+
*
|
|
105
|
+
* @complexity Time/space: O(1) — four fixed checks, no iteration.
|
|
106
|
+
*/
|
|
107
|
+
export function visibleFormEditorError(params, _optional = {}) {
|
|
108
|
+
// Two distinct fallback strings, matching the pre-migration `handleSave`/`handleStatusToggle`
|
|
109
|
+
// catch blocks verbatim ("save failed" vs "status update failed") — not one shared string.
|
|
110
|
+
if (params.updateError)
|
|
111
|
+
return describeApiError(params.updateError, params.saveFallback);
|
|
112
|
+
if (params.createError)
|
|
113
|
+
return describeApiError(params.createError, params.saveFallback);
|
|
114
|
+
if (params.statusError)
|
|
115
|
+
return describeApiError(params.statusError, params.statusUpdateFallback);
|
|
116
|
+
if (params.hasForm)
|
|
117
|
+
return null;
|
|
118
|
+
return params.listError ? describeApiError(params.listError, params.loadFormFallback) : null;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* `useFormsList`'s error banner: the row-toggle write's own failure outranks a background
|
|
122
|
+
* list-refresh failure, same precedence `redirects/rules.ts`'s `visibleRedirectsError` documents.
|
|
123
|
+
* Two sources only (not the three-plus that pushed `visibleFormEditorError`/`visibleTaxonomyError`
|
|
124
|
+
* out to `rules.ts`), kept here anyway rather than inlined so the hook body doesn't grow a nested
|
|
125
|
+
* ternary chain (`@jini-ai/ui/fetch-query`'s `resolveFetchQueryStatus` doc explains why a flat
|
|
126
|
+
* extraction beats a nested ternary of the same branch count for the complexity gate).
|
|
127
|
+
*
|
|
128
|
+
* @complexity Time/space: O(1) — two fixed checks, no iteration.
|
|
129
|
+
*/
|
|
130
|
+
export function formsListError(params, _optional = {}) {
|
|
131
|
+
// The delete's own failure outranks both the toggle's and a background list-refresh failure —
|
|
132
|
+
// same precedence tier `use-posts.hooks.ts`'s `removePost` gives its own delete, and a 404
|
|
133
|
+
// "already gone" resolves to `message: null` here so it never reaches this banner at all (see
|
|
134
|
+
// `describeTrashError`'s own doc for why).
|
|
135
|
+
const deleteMessage = describeTrashError({ error: params.deleteError, fallback: params.deleteFallback, versionChangedMessage: params.versionChangedMessage }).message;
|
|
136
|
+
if (deleteMessage)
|
|
137
|
+
return deleteMessage;
|
|
138
|
+
if (params.toggleError)
|
|
139
|
+
return describeApiError(params.toggleError, params.statusUpdateFallback);
|
|
140
|
+
if (params.hasForms)
|
|
141
|
+
return null;
|
|
142
|
+
return params.listError ? describeApiError(params.listError, params.loadFormsFallback) : null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Classifies a failed `api.trash` call — shared by `useFormsList`'s `removeForm` (forms) and
|
|
146
|
+
* `useFormSubmissionDetail`'s `confirmDelete` (submissions), since both routes now go through the
|
|
147
|
+
* same generic `POST /trash/items` (`routes/trash/items.ts`) and its 404/409 contract:
|
|
148
|
+
*
|
|
149
|
+
* - 404 (`NOT_FOUND`/`FORMS_SUBMISSION_NOT_FOUND`/…): the row is already gone — another tab,
|
|
150
|
+
* another operator, or a prior click that actually succeeded before a flaky response read as a
|
|
151
|
+
* failure. `alreadyGone: true`, `message: null` — the caller's job is a quiet list refresh, not
|
|
152
|
+
* an error banner blaming the operator for something that already happened.
|
|
153
|
+
* - 409 `TRASH_VERSION_CHANGED`: the row changed under the operator since this screen last read
|
|
154
|
+
* it. Specific reload-and-retry copy, not the generic fallback.
|
|
155
|
+
* - Anything else (network failure, an unrelated `ApiError`, …): falls through to
|
|
156
|
+
* `describeApiError`'s generic fallback message.
|
|
157
|
+
*
|
|
158
|
+
* @complexity O(1) — one `instanceof` check plus two fixed comparisons.
|
|
159
|
+
*/
|
|
160
|
+
export function describeTrashError({ error: e, fallback, versionChangedMessage }, _optional = {}) {
|
|
161
|
+
if (!e)
|
|
162
|
+
return { alreadyGone: false, message: null };
|
|
163
|
+
if (e instanceof ApiError || ("status" in e && typeof e.status === "number")) {
|
|
164
|
+
// Existing host transports may retain their own ApiError constructor; status/code are wire fields.
|
|
165
|
+
if (e.status === 404)
|
|
166
|
+
return { alreadyGone: true, message: null };
|
|
167
|
+
if ("code" in e && e.code === "TRASH_VERSION_CHANGED") {
|
|
168
|
+
return { alreadyGone: false, message: versionChangedMessage };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { alreadyGone: false, message: describeApiError(e, fallback) };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The row-action menu for one form. `RowMenu` has no per-item `disabled` — the in-flight guard lives
|
|
175
|
+
* in `use-forms-list.hooks.ts`'s own `toggleStatus` (a no-op while `rowSavingId` is already set), the
|
|
176
|
+
* same shape `use-redirects.hooks.ts`'s `onToggleStatus` uses for its identical `if (saving) return;`
|
|
177
|
+
* guard. (CORRECTED 2026-09-05: this comment previously said the guard "stays in the caller's
|
|
178
|
+
* `onToggleStatus` closure (`FormsList.tsx`'s own `if (rowSavingId) return;`)" and claimed that was
|
|
179
|
+
* the same shape `Redirects.tsx` uses — false; `Redirects.tsx` never had such a guard inline, only its
|
|
180
|
+
* hook does. Flagged by the 2026-09-05 Gemini admin-tooling audit as a standing no-logic-in-`.tsx`
|
|
181
|
+
* violation; moving the guard into the hook also fixed the comment's own false precedent claim.)
|
|
182
|
+
*
|
|
183
|
+
* @complexity Time/space: O(1) — three fixed entries, no iteration.
|
|
184
|
+
*/
|
|
185
|
+
export function formRowMenuItems({ form, handlers, t }, _optional = {}) {
|
|
186
|
+
return [
|
|
187
|
+
// Slug, not id — the admin URL reads `/admin/forms/<slug>` (ui-fixes-backlog.md #8); the GET
|
|
188
|
+
// route still resolves an id too, so this is not a behavior change for any existing bookmark.
|
|
189
|
+
{ key: "edit", label: t("Edit"), onSelect: () => handlers.onEdit(form) },
|
|
190
|
+
{
|
|
191
|
+
key: "toggle-status",
|
|
192
|
+
label: form.status === "active" ? t("Disable") : t("Enable"),
|
|
193
|
+
tone: form.status === "active" ? "warning" : "default",
|
|
194
|
+
onSelect: () => handlers.onToggleStatus(form),
|
|
195
|
+
},
|
|
196
|
+
// Opens `FormsList.tsx`'s `ConfirmDialog` — no network call from this selection itself, same
|
|
197
|
+
// "a click alone can never delete" contract `use-form-submission-detail.hooks.ts`'s
|
|
198
|
+
// `requestDelete` already documents for the sibling submission-delete flow.
|
|
199
|
+
{ key: "delete", label: t("Delete"), tone: "danger", onSelect: () => handlers.onDelete(form) },
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
export const FIELD_TYPES = ["text", "email", "textarea", "checkbox"];
|
|
203
|
+
/** The two tab-panel views on an existing form's editor (`formId !== "new"`). */
|
|
204
|
+
export const FORM_TABS = [
|
|
205
|
+
{ id: "fields", label: "Fields" },
|
|
206
|
+
{ id: "submissions", label: "Submissions" },
|
|
207
|
+
];
|
|
208
|
+
/**
|
|
209
|
+
* Roving-tabindex arrow-key step for the Fields/Submissions tablist — ArrowLeft/ArrowRight cycle
|
|
210
|
+
* between the two tabs, Home/End jump to the first/last.
|
|
211
|
+
*
|
|
212
|
+
* @complexity O(1) — `FORM_TABS` is a fixed 2-item array.
|
|
213
|
+
*/
|
|
214
|
+
export function nextTabIndex({ key, currentIndex }, _optional = {}) {
|
|
215
|
+
if (key === "ArrowRight")
|
|
216
|
+
return (currentIndex + 1) % FORM_TABS.length;
|
|
217
|
+
if (key === "ArrowLeft")
|
|
218
|
+
return (currentIndex - 1 + FORM_TABS.length) % FORM_TABS.length;
|
|
219
|
+
if (key === "Home")
|
|
220
|
+
return 0;
|
|
221
|
+
if (key === "End")
|
|
222
|
+
return FORM_TABS.length - 1;
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
export function blankField(_required = {}, _optional = {}) {
|
|
226
|
+
return { id: "", label: "", type: "text", required: false };
|
|
227
|
+
}
|
|
228
|
+
/** Shared "what do we call this field in a title/label" fallback — a blank draft field has neither
|
|
229
|
+
* a label nor an id yet, so both the kebab's `aria-label` and the modal's own `<h2>` need the same
|
|
230
|
+
* `label -> id -> "Field N"` chain rather than risking the two drifting apart. */
|
|
231
|
+
export function fieldDisplayName({ field, index }, _optional = {}) {
|
|
232
|
+
return field.label || field.id || `Field ${index + 1}`;
|
|
233
|
+
}
|
|
234
|
+
/** @complexity O(n) in `fields.length`. */
|
|
235
|
+
export function updateFormField({ fields, index, patch }, _optional = {}) {
|
|
236
|
+
return fields.map((f, i) => (i === index ? { ...f, ...patch } : f));
|
|
237
|
+
}
|
|
238
|
+
/** @complexity O(n) in `fields.length`. */
|
|
239
|
+
export function addFormField({ fields }, _optional = {}) {
|
|
240
|
+
return [...fields, blankField()];
|
|
241
|
+
}
|
|
242
|
+
/** @complexity O(n) in `fields.length`. */
|
|
243
|
+
export function removeFormField({ fields, index }, _optional = {}) {
|
|
244
|
+
return fields.filter((_, i) => i !== index);
|
|
245
|
+
}
|
|
246
|
+
/** The already-persisted field ids on a form — `FormFieldsEditor` disables the id input and the
|
|
247
|
+
* Remove button for these (a saved field's id cannot be changed or removed once created). `null`
|
|
248
|
+
* (form not loaded yet, or the "new form" case) has no existing ids. */
|
|
249
|
+
export function existingFieldIdsOf({ form }, _optional = {}) {
|
|
250
|
+
return form ? form.fields.map((f) => f.id) : [];
|
|
251
|
+
}
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Field attributes modal (per-field CSS classes + HTML attributes)
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
/** Mirrors `forms.ts`'s `ATTRIBUTE_NAME_PATTERN` exactly — see `FormEditor.tsx`'s own header
|
|
256
|
+
* comment for why this is a fast-reject-only duplicate, not the authoritative check. Keep in sync
|
|
257
|
+
* by hand if the server allowlist changes. */
|
|
258
|
+
export const ATTRIBUTE_NAME_PATTERN = /^(aria-[a-z0-9-]+|data-[a-z0-9-]+|placeholder|autocomplete|inputmode|pattern|title|min|max|step|minlength|spellcheck|readonly)$/;
|
|
259
|
+
/** Same bounds as `forms.ts`'s `MAX_CLASS_NAME_LENGTH`/`MAX_ATTRIBUTES_PER_FIELD` — client-side
|
|
260
|
+
* early-reject only, not enforcement (see `ATTRIBUTE_NAME_PATTERN` above). */
|
|
261
|
+
export const MAX_CLASS_NAME_LENGTH = 300;
|
|
262
|
+
export const MAX_ATTRIBUTES_PER_FIELD = 12;
|
|
263
|
+
/** A handful of the allowlisted names as real, pickable suggestions (the modal's own "here's what
|
|
264
|
+
* you can do" surface — an operator has no other way to discover the allowlist) rather than every
|
|
265
|
+
* one: `aria-*`/`data-*` are open namespaces, so `aria-label`/`data-testid` stand in for the whole
|
|
266
|
+
* prefix family instead of listing every field-specific `aria-*` name that doesn't exist yet. */
|
|
267
|
+
export const ATTRIBUTE_NAME_SUGGESTIONS = [
|
|
268
|
+
"aria-label",
|
|
269
|
+
"aria-describedby",
|
|
270
|
+
"data-testid",
|
|
271
|
+
"placeholder",
|
|
272
|
+
"autocomplete",
|
|
273
|
+
"inputmode",
|
|
274
|
+
"pattern",
|
|
275
|
+
"title",
|
|
276
|
+
"min",
|
|
277
|
+
"max",
|
|
278
|
+
"step",
|
|
279
|
+
"minlength",
|
|
280
|
+
"spellcheck",
|
|
281
|
+
"readonly",
|
|
282
|
+
];
|
|
283
|
+
/** Local-only row key for the modal's attribute list, so React can key a row before it has a
|
|
284
|
+
* stable identity — same `_rowId`/module-counter pattern `collections/rules.ts`'s
|
|
285
|
+
* `EditFieldsDialog` support uses for its own draft field rows. */
|
|
286
|
+
let nextAttrRowId = 0;
|
|
287
|
+
export function attrRowsFromField({ field }, _optional = {}) {
|
|
288
|
+
return Object.entries(field.attributes ?? {}).map(([name, value]) => ({ _rowId: nextAttrRowId++, name, value }));
|
|
289
|
+
}
|
|
290
|
+
/** @complexity O(n) in `rows.length`. */
|
|
291
|
+
export function updateAttrRow({ rows, rowId, patch }, _optional = {}) {
|
|
292
|
+
return rows.map((r) => (r._rowId === rowId ? { ...r, ...patch } : r));
|
|
293
|
+
}
|
|
294
|
+
/** @complexity O(n) in `rows.length`. */
|
|
295
|
+
export function removeAttrRow({ rows, rowId }, _optional = {}) {
|
|
296
|
+
return rows.filter((r) => r._rowId !== rowId);
|
|
297
|
+
}
|
|
298
|
+
/** @complexity O(n) in `rows.length`. */
|
|
299
|
+
export function addAttrRow({ rows }, _optional = {}) {
|
|
300
|
+
return [...rows, { _rowId: nextAttrRowId++, name: "", value: "" }];
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Validates + shapes `FieldAttributesDialog`'s draft into the `Partial<AdminFormField>` patch
|
|
304
|
+
* `onSave` applies: a class-name length cap, then every named attribute row against the allowlist
|
|
305
|
+
* (blank names are silently skipped — an empty trailing row is not an error), then a total-count
|
|
306
|
+
* cap on the surviving attributes. The security-relevant check is server-side (`forms.ts`'s
|
|
307
|
+
* `validateFieldDescriptors`); this is the fast, pre-save rejection only — see this feature's own
|
|
308
|
+
* `ATTRIBUTE_NAME_PATTERN` doc.
|
|
309
|
+
*
|
|
310
|
+
* @complexity O(n) in `rows.length`, short-circuiting on the first disallowed name.
|
|
311
|
+
*/
|
|
312
|
+
export function buildFieldAttributesPatch(draft, _optional = {}) {
|
|
313
|
+
const trimmedClassName = draft.className.trim();
|
|
314
|
+
if (trimmedClassName.length > MAX_CLASS_NAME_LENGTH) {
|
|
315
|
+
return { ok: false, error: `CSS classes must be at most ${MAX_CLASS_NAME_LENGTH} characters.` };
|
|
316
|
+
}
|
|
317
|
+
const attributes = {};
|
|
318
|
+
for (const row of draft.rows) {
|
|
319
|
+
const name = row.name.trim();
|
|
320
|
+
if (!name)
|
|
321
|
+
continue;
|
|
322
|
+
if (!ATTRIBUTE_NAME_PATTERN.test(name)) {
|
|
323
|
+
return { ok: false, error: `Attribute "${name}" isn't allowed. Use aria-*, data-*, or one of the suggested names.` };
|
|
324
|
+
}
|
|
325
|
+
attributes[name] = row.value;
|
|
326
|
+
}
|
|
327
|
+
if (Object.keys(attributes).length > MAX_ATTRIBUTES_PER_FIELD) {
|
|
328
|
+
return { ok: false, error: `At most ${MAX_ATTRIBUTES_PER_FIELD} attributes are allowed per field.` };
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
ok: true,
|
|
332
|
+
patch: {
|
|
333
|
+
className: trimmedClassName || undefined,
|
|
334
|
+
attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
-
import { useController } from '../../../react/use-controller.js';
|
|
2
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
3
3
|
import { createEditMediaController } from '../../controllers/edit-media.controller.js';
|
|
4
4
|
import { canReplaceMedia, mediaEmbedSnippet, parseOptionalPixelSize, safeMediaUrl } from '../../rules.js';
|
|
5
5
|
import { parseMediaHtmlAttributes, describeMediaHtmlAttributeError } from '../../html-attributes.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
3
3
|
import type { MediaAsset } from '../../models.js';
|
|
4
4
|
export declare function useLibraryTab({ params, permissions }: TabViewProps, _optional?: Record<string, never>): {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
-
import { useController } from '../../../react/use-controller.js';
|
|
2
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
3
3
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
4
4
|
import { useSharedMediaLibrary } from './MediaPage.hooks.js';
|
|
5
5
|
import { useMediaPorts } from './MediaPorts.hooks.js';
|
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { safeMediaUrl, formatByteSize, formatUploadDate, mediaRowHandles } from '../../rules.js';
|
|
3
3
|
export function useMediaCard(props, _optional = {}) {
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* render-and-fall-back chain (`<img>` → onError → `<video>` → onError → placeholder) rather than a
|
|
10
|
-
* HEAD probe per card. Chosen over the HEAD approach because: (1) the byte route's documented
|
|
11
|
-
* contract covers GET — sniffing/Range were specified for that, not for HEAD, so building on HEAD
|
|
12
|
-
* would be assuming a behavior nobody confirmed; (2) a HEAD-first design means every card blocks on
|
|
13
|
-
* a round trip before any pixel paints, working against the fixed-aspect-box + lazy-loading this
|
|
14
|
-
* grid needs anyway, whereas the optimistic path costs nothing extra for the common case (a real
|
|
15
|
-
* image just loads) and only "wastes" a request for the video/unsupported minority — and even then,
|
|
16
|
-
* a browser's image decoder typically fails off the header bytes rather than pulling the whole
|
|
17
|
-
* file; (3) it composes for free with the server's security defusal: a sniffed HTML/SVG comes back
|
|
18
|
-
* as `application/octet-stream` with `Content-Disposition: attachment`, which is not a valid image
|
|
19
|
-
* OR video MIME, so it fails both probes and lands on the placeholder with zero special-casing —
|
|
20
|
-
* this file never needs to detect "is this the defused case" itself.
|
|
21
|
-
*/
|
|
4
|
+
/** Preview optimistically: image -> video -> placeholder. The list supplies no reliable media
|
|
5
|
+
* kind, and the byte route guarantees GET rather than HEAD, so probing headers would assume an
|
|
6
|
+
* unsupported contract and delay every card's first paint. Images load directly; failed decoders
|
|
7
|
+
* usually stop at header bytes. Defused HTML/SVG served as octet-stream attachments fails both
|
|
8
|
+
* decoders and reaches the placeholder without content-specific handling. */
|
|
22
9
|
const src = safeMediaUrl({ url: props.api.originalUrl({ id: props.item.id, version: props.item.version }) });
|
|
23
10
|
const [probe, setProbe] = useState({ src, stage: 'image' });
|
|
24
11
|
// New bytes can change media type under the same id. Retry the fallback from image
|
|
@@ -45,8 +32,7 @@ export function useMediaCard(props, _optional = {}) {
|
|
|
45
32
|
menuItems: [
|
|
46
33
|
...(props.onEdit ? [{ id: 'edit', label: 'Edit metadata', onPress: props.onEdit, disabled: props.busy === true }] : []),
|
|
47
34
|
...(props.onTrash && props.item.status !== 'trashed' ? [{ id: 'trash', label: 'Trash', onPress: props.onTrash, disabled: props.busy === true }] : []),
|
|
48
|
-
// Restore
|
|
49
|
-
// the card itself keeps the legacy look and active cards' menus stay legacy-identical.
|
|
35
|
+
// Restore belongs only in a trashed card's menu; active cards have nothing to restore.
|
|
50
36
|
...(props.onRestore && props.item.status === 'trashed' ? [{ id: 'restore', label: 'Restore', onPress: props.onRestore, disabled: props.busy === true }] : []),
|
|
51
37
|
...(props.onPurge && props.item.status === 'trashed' ? [{ id: 'purge', label: 'Delete permanently', attrs: { 'data-jini-variant': 'danger' }, onPress: props.onPurge, disabled: props.busy === true }] : []),
|
|
52
38
|
],
|
|
@@ -11,13 +11,13 @@ export declare function useMediaGrid(props: MediaGridProps, _optional?: Record<s
|
|
|
11
11
|
actions: {
|
|
12
12
|
handleBase: string;
|
|
13
13
|
busy?: boolean;
|
|
14
|
-
|
|
14
|
+
onPurge?: () => void;
|
|
15
15
|
locale?: string;
|
|
16
|
+
item: import("../../models.js").MediaAsset;
|
|
16
17
|
onEdit?: () => void;
|
|
17
18
|
onPreview?: () => void;
|
|
18
19
|
onTrash?: () => void;
|
|
19
20
|
onRestore?: () => void;
|
|
20
|
-
onPurge?: () => void;
|
|
21
21
|
onChoose?: () => void;
|
|
22
22
|
}[];
|
|
23
23
|
gridRef?: Ref<HTMLDivElement>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { ModulePageProps } from '../../../react/bind-react.js';
|
|
2
|
+
import type { ModulePageProps } from '../../../core/react/bind-react.js';
|
|
3
3
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
4
4
|
import type { LibraryState } from '../../controllers/library.controller.js';
|
|
5
5
|
export declare const MediaLibraryContext: import("react").Context<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, createContext, useContext, useEffect, useState } from 'react';
|
|
2
|
-
import { useController } from '../../../react/use-controller.js';
|
|
2
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
3
3
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
4
4
|
import { useMediaPorts } from './MediaPorts.hooks.js';
|
|
5
5
|
import { AllIcon, ImageIcon, VideoIcon, CloudIcon } from '../components/MediaIcons.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useController } from '../../../react/use-controller.js';
|
|
1
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
2
2
|
import { createLibraryController } from '../../controllers/library.controller.js';
|
|
3
3
|
import { acceptsMedia } from '../../rules.js';
|
|
4
4
|
export function useMediaPicker(props, _optional = {}) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement } from 'react';
|
|
2
|
-
import { bindReact } from '../../react/bind-react.js';
|
|
2
|
+
import { bindReact } from '../../core/react/bind-react.js';
|
|
3
3
|
import { mediaModule } from '../media.module.js';
|
|
4
4
|
import { MediaPortsContext } from './hooks/MediaPorts.hooks.js';
|
|
5
5
|
export { useMediaPorts } from './hooks/MediaPorts.hooks.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function LibraryTab(props: TabViewProps, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
3
3
|
export default LibraryTab;
|
|
4
4
|
//# sourceMappingURL=LibraryTab.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function ProvidersTab(_props: TabViewProps, _optional?: Record<string, never>): import("react").JSX.Element;
|
|
3
3
|
export default ProvidersTab;
|
|
4
4
|
//# sourceMappingURL=ProvidersTab.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function Canvas(props: TabViewProps, _optional?: {}): import("react").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=Canvas.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function useCanvas({ permissions }: TabViewProps, _optional?: {}): {
|
|
3
3
|
denied: boolean;
|
|
4
4
|
registerCanvas: (node: HTMLDivElement | null) => void | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
import { useController } from '../../../react/use-controller.js';
|
|
2
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
3
3
|
import { createPlaygroundController } from '../../controllers/playground.controller.js';
|
|
4
4
|
import { canMountPlayground } from '../../rules.js';
|
|
5
5
|
import { usePlaygroundPorts } from './PlaygroundPorts.hooks.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ModulePageProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { ModulePageProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function usePlaygroundPage(props: ModulePageProps, _optional?: {}): {
|
|
3
3
|
denied: boolean;
|
|
4
4
|
ActiveTab: import("react").LazyExoticComponent<import("react").ComponentType<import("../../../react/bind-react.js").TabViewProps>> | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bindReact } from '../../react/bind-react.js';
|
|
1
|
+
import { bindReact } from '../../core/react/bind-react.js';
|
|
2
2
|
import { playgroundModule } from '../playground.module.js';
|
|
3
3
|
import { PlaygroundPortsContext } from './hooks/PlaygroundPorts.hooks.js';
|
|
4
4
|
export { usePlaygroundPorts } from './hooks/PlaygroundPorts.hooks.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ModulePageProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { ModulePageProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function PlaygroundPage(props: ModulePageProps, _optional?: {}): import("react").JSX.Element;
|
|
3
3
|
export default PlaygroundPage;
|
|
4
4
|
//# sourceMappingURL=PlaygroundPage.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TabViewProps } from '../../../react/bind-react.js';
|
|
1
|
+
import type { TabViewProps } from '../../../core/react/bind-react.js';
|
|
2
2
|
export declare function CanvasTab(props: TabViewProps, _optional?: {}): import("react").JSX.Element;
|
|
3
3
|
export default CanvasTab;
|
|
4
4
|
//# sourceMappingURL=CanvasTab.d.ts.map
|
|
@@ -1,46 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import type { AdminInstance, AdminModule, ScopedPorts } from '../core/module/types.js';
|
|
3
|
-
export interface TabViewProps {
|
|
4
|
-
readonly params: Readonly<Record<string, unknown>>;
|
|
5
|
-
readonly permissions?: readonly string[];
|
|
6
|
-
}
|
|
7
|
-
export interface ModulePageProps {
|
|
8
|
-
readonly tabs: Readonly<Record<string, LazyExoticComponent<ComponentType<TabViewProps>>>>;
|
|
9
|
-
readonly description: ReturnType<AdminInstance['describe']>['pages'][number];
|
|
10
|
-
readonly requestedTab?: string;
|
|
11
|
-
readonly onTabChange?: (required: {
|
|
12
|
-
tab: string;
|
|
13
|
-
}, optional?: Record<string, never>) => void;
|
|
14
|
-
}
|
|
15
|
-
type Loader<P> = () => Promise<{
|
|
16
|
-
default: ComponentType<P>;
|
|
17
|
-
}>;
|
|
18
|
-
export type ReactViews<M extends AdminModule> = {
|
|
19
|
-
readonly [P in keyof M['pages']]: {
|
|
20
|
-
readonly page: Loader<ModulePageProps>;
|
|
21
|
-
readonly tabs: {
|
|
22
|
-
readonly [T in keyof M['pages'][P]['tabs']]: Loader<TabViewProps>;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
/** Every page and tab is lazy. The only port context is private to this binding;
|
|
27
|
-
* a sibling module can never read another module's dependencies through a global locator. */
|
|
28
|
-
export declare function bindReact<const M extends AdminModule>({ module, views }: {
|
|
29
|
-
module: M;
|
|
30
|
-
views: ReactViews<M>;
|
|
31
|
-
}, { context }?: {
|
|
32
|
-
context?: ReactContext<ScopedPorts<M> | null>;
|
|
33
|
-
}): {
|
|
34
|
-
module: M;
|
|
35
|
-
pages: { [P in keyof M["pages"]]: {
|
|
36
|
-
Page: LazyExoticComponent<ComponentType<ModulePageProps>>;
|
|
37
|
-
tabs: { [T in keyof M["pages"][P]["tabs"]]: LazyExoticComponent<ComponentType<TabViewProps>>; };
|
|
38
|
-
}; };
|
|
39
|
-
Provider: ({ admin, children }: {
|
|
40
|
-
admin: AdminInstance;
|
|
41
|
-
children: ReactNode;
|
|
42
|
-
}, _optional?: Record<string, never>) => import("react").FunctionComponentElement<import("react").ProviderProps<ScopedPorts<M> | null>>;
|
|
43
|
-
usePorts: (_required?: Record<string, never>, _optional?: Record<string, never>) => ScopedPorts<M>;
|
|
44
|
-
};
|
|
45
|
-
export {};
|
|
1
|
+
export * from '../core/react/bind-react.js';
|
|
46
2
|
//# sourceMappingURL=bind-react.d.ts.map
|
package/dist/react/bind-react.js
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** Every page and tab is lazy. The only port context is private to this binding;
|
|
4
|
-
* a sibling module can never read another module's dependencies through a global locator. */
|
|
5
|
-
export function bindReact({ module, views }, { context } = {}) {
|
|
6
|
-
const Context = context ?? createContext(null);
|
|
7
|
-
const pages = Object.fromEntries(Object.entries(views).map(([id, raw]) => {
|
|
8
|
-
const view = raw;
|
|
9
|
-
return [
|
|
10
|
-
id,
|
|
11
|
-
{
|
|
12
|
-
Page: lazy(view.page),
|
|
13
|
-
tabs: Object.fromEntries(Object.entries(view.tabs).map(([tab, load]) => [tab, lazy(load)])),
|
|
14
|
-
},
|
|
15
|
-
];
|
|
16
|
-
}));
|
|
17
|
-
function usePorts(_required = {}, _optional = {}) {
|
|
18
|
-
const ports = useContext(Context);
|
|
19
|
-
if (!ports)
|
|
20
|
-
throw new AdminConfigError({ issues: [`React scope unavailable: ${module.id}`] });
|
|
21
|
-
return ports;
|
|
22
|
-
}
|
|
23
|
-
function Provider({ admin, children }, _optional = {}) {
|
|
24
|
-
return createElement(Context.Provider, { value: admin.scope({ module }) }, children);
|
|
25
|
-
}
|
|
26
|
-
return { module, pages, Provider, usePorts };
|
|
27
|
-
}
|
|
1
|
+
// Compatibility path; the shared implementation lives in core.
|
|
2
|
+
export * from '../core/react/bind-react.js';
|
|
28
3
|
//# sourceMappingURL=bind-react.js.map
|