@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,114 @@
|
|
|
1
|
+
/** Cadence separates defaults, sitemap operations and one-entry edits; the form stays whole. */
|
|
2
|
+
export declare const seoModule: {
|
|
3
|
+
readonly id: "seo";
|
|
4
|
+
readonly requires: {
|
|
5
|
+
readonly seoApi: import("../core/module/token.js").AdminPortToken<import("./ports.js").AdminSeoPort, "admin.seo.api">;
|
|
6
|
+
};
|
|
7
|
+
readonly optional: {
|
|
8
|
+
readonly seoEvents: import("../core/module/token.js").AdminPortToken<import("./ports.js").SeoEventsPort, "admin.seo.events">;
|
|
9
|
+
readonly mediaPicker: import("../core/module/token.js").AdminPortToken<import("../contracts/media-picker.js").MediaPickerPort, "admin.media.picker">;
|
|
10
|
+
};
|
|
11
|
+
readonly messages: {
|
|
12
|
+
readonly "Site defaults": "Site defaults";
|
|
13
|
+
readonly Sitemap: "Sitemap";
|
|
14
|
+
readonly "Pages & posts": "Pages & posts";
|
|
15
|
+
readonly "This site publishes a sitemap.": "This site publishes a sitemap.";
|
|
16
|
+
readonly "This site does not publish a sitemap. Turn it on under Site defaults.": "This site does not publish a sitemap. Turn it on under Site defaults.";
|
|
17
|
+
readonly "Loading entries\u2026": "Loading entries…";
|
|
18
|
+
readonly Entry: "Entry";
|
|
19
|
+
readonly "Choose an entry\u2026": "Choose an entry…";
|
|
20
|
+
readonly Analysis: "Analysis";
|
|
21
|
+
readonly "Score:": "Score:";
|
|
22
|
+
readonly "No issues.": "No issues.";
|
|
23
|
+
readonly "Loading entry SEO\u2026": "Loading entry SEO…";
|
|
24
|
+
readonly "Per-entry overrides": "Per-entry overrides";
|
|
25
|
+
readonly "Fields show the currently-effective value (author override, or site default, or derived from the entry). Only fields you change here are saved as overrides.": "Fields show the currently-effective value (author override, or site default, or derived from the entry). Only fields you change here are saved as overrides.";
|
|
26
|
+
readonly "Empty a field and save to remove its override \u2014 the entry falls back to the site default.": "Empty a field and save to remove its override — the entry falls back to the site default.";
|
|
27
|
+
readonly Title: "Title";
|
|
28
|
+
readonly Description: "Description";
|
|
29
|
+
readonly "Canonical URL": "Canonical URL";
|
|
30
|
+
readonly Noindex: "Noindex";
|
|
31
|
+
readonly Nofollow: "Nofollow";
|
|
32
|
+
readonly "OG title": "OG title";
|
|
33
|
+
readonly "OG description": "OG description";
|
|
34
|
+
readonly "OG image (media ref or URL)": "OG image (media ref or URL)";
|
|
35
|
+
readonly "Twitter title": "Twitter title";
|
|
36
|
+
readonly "Twitter description": "Twitter description";
|
|
37
|
+
readonly "Twitter image (media ref or URL)": "Twitter image (media ref or URL)";
|
|
38
|
+
readonly "Saving\u2026": "Saving…";
|
|
39
|
+
readonly "Save overrides": "Save overrides";
|
|
40
|
+
readonly "Per-entry SEO": "Per-entry SEO";
|
|
41
|
+
readonly "Search appearance": "Search appearance";
|
|
42
|
+
readonly "Title template (must contain %s)": "Title template (must contain %s)";
|
|
43
|
+
readonly "Default meta description": "Default meta description";
|
|
44
|
+
readonly "Social sharing": "Social sharing";
|
|
45
|
+
readonly "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)";
|
|
46
|
+
readonly "Twitter @site handle": "Twitter @site handle";
|
|
47
|
+
readonly Crawling: "Crawling";
|
|
48
|
+
readonly "Default noindex": "Default noindex";
|
|
49
|
+
readonly "Default nofollow": "Default nofollow";
|
|
50
|
+
readonly "Sitemap enabled": "Sitemap enabled";
|
|
51
|
+
readonly "Save settings": "Save settings";
|
|
52
|
+
readonly "Cached sitemap": "Cached sitemap";
|
|
53
|
+
readonly "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.";
|
|
54
|
+
readonly "Working\u2026": "Working…";
|
|
55
|
+
readonly "Regenerate sitemap": "Regenerate sitemap";
|
|
56
|
+
readonly "View sitemap": "View sitemap";
|
|
57
|
+
readonly "Loading SEO settings\u2026": "Loading SEO settings…";
|
|
58
|
+
readonly Marketing: "Marketing";
|
|
59
|
+
readonly "Site-wide defaults for meta titles, descriptions, Open Graph/Twitter cards, and robots directives.": "Site-wide defaults for meta titles, descriptions, Open Graph/Twitter cards, and robots directives.";
|
|
60
|
+
readonly "Choose image": "Choose image";
|
|
61
|
+
readonly Remove: "Remove";
|
|
62
|
+
readonly "Sitemap \u00B7 {count} URLs": "Sitemap · {count} URLs";
|
|
63
|
+
readonly "sitemap.xml \u2197": "sitemap.xml ↗";
|
|
64
|
+
readonly Table: "Table";
|
|
65
|
+
readonly "Raw XML": "Raw XML";
|
|
66
|
+
readonly "The sitemap has no URLs yet.": "The sitemap has no URLs yet.";
|
|
67
|
+
readonly "Filter sitemap URLs": "Filter sitemap URLs";
|
|
68
|
+
readonly "Filter by URL\u2026": "Filter by URL…";
|
|
69
|
+
readonly "No URLs match this filter.": "No URLs match this filter.";
|
|
70
|
+
readonly URL: "URL";
|
|
71
|
+
readonly "Last modified": "Last modified";
|
|
72
|
+
readonly "\u2014": "—";
|
|
73
|
+
readonly "Sitemap is off. Turn on \"Sitemap enabled\" above to publish one.": "Sitemap is off. Turn on \"Sitemap enabled\" above to publish one.";
|
|
74
|
+
readonly "Loading sitemap\u2026": "Loading sitemap…";
|
|
75
|
+
readonly Close: "Close";
|
|
76
|
+
readonly "failed to load entries": "failed to load entries";
|
|
77
|
+
readonly "failed to load entry SEO data": "failed to load entry SEO data";
|
|
78
|
+
readonly "Saved.": "Saved.";
|
|
79
|
+
readonly "failed to save SEO overrides": "failed to save SEO overrides";
|
|
80
|
+
readonly "failed to load SEO settings": "failed to load SEO settings";
|
|
81
|
+
readonly "failed to save SEO settings": "failed to save SEO settings";
|
|
82
|
+
readonly "Sitemap regeneration accepted.": "Sitemap regeneration accepted.";
|
|
83
|
+
readonly "failed to regenerate sitemap": "failed to regenerate sitemap";
|
|
84
|
+
readonly "failed to load the sitemap": "failed to load the sitemap";
|
|
85
|
+
readonly "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).";
|
|
86
|
+
};
|
|
87
|
+
readonly pages: {
|
|
88
|
+
readonly settings: {
|
|
89
|
+
readonly path: "/seo";
|
|
90
|
+
readonly label: "SEO";
|
|
91
|
+
readonly permissions: readonly ["admin.seo.manage"];
|
|
92
|
+
readonly agentReachable: true;
|
|
93
|
+
readonly nav: {
|
|
94
|
+
readonly group: "content";
|
|
95
|
+
readonly icon: "search";
|
|
96
|
+
};
|
|
97
|
+
readonly tabs: {
|
|
98
|
+
readonly defaults: {
|
|
99
|
+
readonly label: "Site defaults";
|
|
100
|
+
readonly agentReachable: true;
|
|
101
|
+
};
|
|
102
|
+
readonly sitemap: {
|
|
103
|
+
readonly label: "Sitemap";
|
|
104
|
+
readonly agentReachable: true;
|
|
105
|
+
};
|
|
106
|
+
readonly entries: {
|
|
107
|
+
readonly label: "Pages & posts";
|
|
108
|
+
readonly agentReachable: true;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=seo.module.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineAdminModule } from '../core/module/index.js';
|
|
2
|
+
import { mediaPickerToken } from '../contracts/media-picker.js';
|
|
3
|
+
import { seoApiToken, seoEventsToken } from './ports.js';
|
|
4
|
+
import { seoMessagesEn } from './messages.en.js';
|
|
5
|
+
/** Cadence separates defaults, sitemap operations and one-entry edits; the form stays whole. */
|
|
6
|
+
export const seoModule = defineAdminModule({
|
|
7
|
+
id: 'seo', requires: { seoApi: seoApiToken }, optional: { seoEvents: seoEventsToken, mediaPicker: mediaPickerToken }, messages: seoMessagesEn,
|
|
8
|
+
pages: { settings: {
|
|
9
|
+
path: '/seo', label: 'SEO', permissions: ['admin.seo.manage'], agentReachable: true,
|
|
10
|
+
nav: { group: 'content', icon: 'search' },
|
|
11
|
+
tabs: { defaults: { label: 'Site defaults', agentReachable: true }, sitemap: { label: 'Sitemap', agentReachable: true }, entries: { label: 'Pages & posts', agentReachable: true } },
|
|
12
|
+
} },
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=seo.module.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useController } from '../../../react/use-controller.js';
|
|
1
|
+
import { useController } from '../../../core/react/use-controller.js';
|
|
2
2
|
import { createSourceControlController } from '../../controllers/source-control.controller.js';
|
|
3
3
|
import { blankSourceControlDraft, sourceControlProviders, defaultSourceControlCredential, sourceControlReady, safeSourceControlUrl } from '../../rules.js';
|
|
4
4
|
import { useSourceControlPorts } from './SourceControlPorts.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 useSourceControlPage(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 { sourceControlModule } from '../source-control.module.js';
|
|
3
3
|
import { SourceControlPortsContext } from './hooks/SourceControlPorts.hooks.js';
|
|
4
4
|
export { useSourceControlPorts } from './hooks/SourceControlPorts.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 SourceControlPage(props: ModulePageProps, _optional?: {}): import("react").JSX.Element;
|
|
3
3
|
export default SourceControlPage;
|
|
4
4
|
//# sourceMappingURL=SourceControlPage.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?: {}): import("react").JSX.Element;
|
|
3
3
|
export default ProvidersTab;
|
|
4
4
|
//# sourceMappingURL=ProvidersTab.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AdminWidgetsPort } from '../ports.js';
|
|
2
|
+
import type { WidgetsRequestOptions } from '../models.js';
|
|
3
|
+
/** Host owns auth, JSON serialization, request deadlines/retries, and status/error decoding. */
|
|
4
|
+
export interface WidgetsTransportPort {
|
|
5
|
+
request<T>(required: {
|
|
6
|
+
path: string;
|
|
7
|
+
method: 'GET' | 'POST' | 'PUT';
|
|
8
|
+
body?: unknown | undefined;
|
|
9
|
+
}, optional?: WidgetsRequestOptions | undefined): Promise<T>;
|
|
10
|
+
url(required: {
|
|
11
|
+
path: string;
|
|
12
|
+
}, optional?: Record<string, never> | undefined): string;
|
|
13
|
+
}
|
|
14
|
+
/** basePath is the host workspace root; the adapter adds /widgets and the shared /trash/items. */
|
|
15
|
+
export declare function createHttpWidgetsApi({ transport, basePath }: {
|
|
16
|
+
transport: WidgetsTransportPort;
|
|
17
|
+
basePath: string;
|
|
18
|
+
}, _optional?: Record<string, never>): AdminWidgetsPort;
|
|
19
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** basePath is the host workspace root; the adapter adds /widgets and the shared /trash/items. */
|
|
2
|
+
export function createHttpWidgetsApi({ transport, basePath }, _optional = {}) {
|
|
3
|
+
const root = basePath.replace(/\/$/, '');
|
|
4
|
+
const base = `${root}/widgets`;
|
|
5
|
+
const request = (path, method, body, options) => {
|
|
6
|
+
options.signal?.throwIfAborted();
|
|
7
|
+
return transport.request({ path, method, ...(body === undefined ? {} : { body }) }, options);
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
listWidgets({ widgetType, includeInactive }, options = {}) {
|
|
11
|
+
const query = new URLSearchParams();
|
|
12
|
+
if (widgetType)
|
|
13
|
+
query.set('widgetType', widgetType);
|
|
14
|
+
if (includeInactive)
|
|
15
|
+
query.set('includeInactive', 'true');
|
|
16
|
+
const suffix = query.toString();
|
|
17
|
+
return request(`${base}${suffix ? `?${suffix}` : ''}`, 'GET', undefined, options);
|
|
18
|
+
},
|
|
19
|
+
getWidget({ id }, options = {}) { return request(`${base}/${encodeURIComponent(id)}`, 'GET', undefined, options); },
|
|
20
|
+
createWidget(input, options = {}) { return request(base, 'POST', input, options); },
|
|
21
|
+
updateWidget({ id, baseVersion, config, title }, options = {}) {
|
|
22
|
+
return request(`${base}/${encodeURIComponent(id)}`, 'PUT', { baseVersion, config, ...(title === undefined ? {} : { title }) }, options);
|
|
23
|
+
},
|
|
24
|
+
trashWidget({ id }, options = {}) { return request(`${root}/trash/items`, 'POST', { type: 'widget', id }, options); },
|
|
25
|
+
listWidgetRegions(_required, options = {}) { return request(`${base}/regions`, 'GET', undefined, options); },
|
|
26
|
+
bindWidgetRegion({ regionKey }, options = {}) { return request(`${base}/regions`, 'POST', { regionKey }, options); },
|
|
27
|
+
getWidgetRegion({ regionKey }, options = {}) { return request(`${base}/regions/${encodeURIComponent(regionKey)}`, 'GET', undefined, options); },
|
|
28
|
+
mutateWidgetRegionPlacements({ regionKey, baseVersion, placements }, options = {}) {
|
|
29
|
+
return request(`${base}/regions/${encodeURIComponent(regionKey)}`, 'PUT', { baseVersion, placements }, options);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AdminWidgetsPort } from '../ports.js';
|
|
2
|
+
import type { AdminWidget, AdminWidgetArea, AdminWidgetPlacement, AdminWidgetRegionBinding, AdminWidgetWhereUsed } from '../models.js';
|
|
3
|
+
export interface MemoryWidgetsSeed {
|
|
4
|
+
widgets?: AdminWidget[] | undefined;
|
|
5
|
+
regions?: AdminWidgetRegionBinding[] | undefined;
|
|
6
|
+
areas?: Record<string, {
|
|
7
|
+
area: AdminWidgetArea;
|
|
8
|
+
placements: AdminWidgetPlacement[];
|
|
9
|
+
}> | undefined;
|
|
10
|
+
whereUsed?: Record<string, AdminWidgetWhereUsed> | undefined;
|
|
11
|
+
skippedCount?: number | undefined;
|
|
12
|
+
skippedIds?: string[] | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** JSON-shaped port snapshots are detached; mutable fixture arrays are explicit on the returned adapter. */
|
|
15
|
+
export declare function createMemoryWidgetsApi({ widgets, regions, areas, whereUsed, skippedCount, skippedIds }?: MemoryWidgetsSeed, { workspaceId, now }?: {
|
|
16
|
+
workspaceId?: string | undefined;
|
|
17
|
+
now?: (() => string) | undefined;
|
|
18
|
+
}): AdminWidgetsPort & {
|
|
19
|
+
readonly widgets: AdminWidget[];
|
|
20
|
+
readonly regions: AdminWidgetRegionBinding[];
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { AdminApiError } from '../../core/transport/errors.js';
|
|
2
|
+
/** JSON-shaped port snapshots are detached; mutable fixture arrays are explicit on the returned adapter. */
|
|
3
|
+
export function createMemoryWidgetsApi({ widgets = [], regions = [], areas = {}, whereUsed = {}, skippedCount, skippedIds } = {}, { workspaceId = 'fake-ws', now = () => new Date(0).toISOString() } = {}) {
|
|
4
|
+
const copy = (value) => structuredClone(value);
|
|
5
|
+
const rows = copy(widgets), bindings = copy(regions), regionRows = new Map(Object.entries(copy(areas)));
|
|
6
|
+
const usage = copy(whereUsed);
|
|
7
|
+
let widgetSequence = rows.length, areaSequence = Math.max(bindings.length, regionRows.size);
|
|
8
|
+
function fail(code, message) { throw new AdminApiError({ message, status: code === 'NOT_FOUND' ? 404 : 409 }, { code }); }
|
|
9
|
+
function instance(id) {
|
|
10
|
+
const index = rows.findIndex(w => w.slug === id);
|
|
11
|
+
const resolved = index < 0 ? rows.findIndex(w => w.id === id) : index;
|
|
12
|
+
if (resolved < 0)
|
|
13
|
+
return fail('NOT_FOUND', `fake widget not found: ${id}`);
|
|
14
|
+
return { index: resolved, widget: rows[resolved] };
|
|
15
|
+
}
|
|
16
|
+
function region(regionKey) {
|
|
17
|
+
const result = regionRows.get(regionKey);
|
|
18
|
+
return result ?? fail('NOT_FOUND', `fake widget region not found: ${regionKey}`);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
widgets: rows, regions: bindings,
|
|
22
|
+
async listWidgets({ widgetType, includeInactive }, options = {}) {
|
|
23
|
+
options.signal?.throwIfAborted();
|
|
24
|
+
return { widgets: copy(rows.filter(w => (!widgetType || w.widgetType === widgetType) && (includeInactive || w.status === 'active'))), ...(skippedCount === undefined ? {} : { skippedCount }), ...(skippedIds === undefined ? {} : { skippedIds: copy(skippedIds) }) };
|
|
25
|
+
},
|
|
26
|
+
async getWidget({ id }, options = {}) {
|
|
27
|
+
options.signal?.throwIfAborted();
|
|
28
|
+
const { widget } = instance(id);
|
|
29
|
+
return copy({ widget, whereUsed: usage[widget.id] ?? { count: 0, references: [] } });
|
|
30
|
+
},
|
|
31
|
+
async createWidget(input, options = {}) {
|
|
32
|
+
options.signal?.throwIfAborted();
|
|
33
|
+
let id;
|
|
34
|
+
do {
|
|
35
|
+
id = `fake-${++widgetSequence}`;
|
|
36
|
+
} while (rows.some(w => w.id === id || w.slug === `fake-slug-${widgetSequence}`));
|
|
37
|
+
const widget = { id, workspaceId, slug: `fake-slug-${widgetSequence}`, title: input.title, status: 'active', widgetType: input.widgetType, config: copy(input.config), updatedAt: now(), version: 1 };
|
|
38
|
+
rows.push(widget);
|
|
39
|
+
return { widget: copy(widget) };
|
|
40
|
+
},
|
|
41
|
+
async updateWidget({ id, baseVersion, config, title }, options = {}) {
|
|
42
|
+
options.signal?.throwIfAborted();
|
|
43
|
+
const { index, widget } = instance(id);
|
|
44
|
+
if (widget.version !== baseVersion)
|
|
45
|
+
fail('WIDGETS_VERSION_CONFLICT', 'Widget version conflict');
|
|
46
|
+
const updated = { ...widget, config: copy(config), title: title ?? widget.title, updatedAt: now(), version: widget.version + 1 };
|
|
47
|
+
rows[index] = updated;
|
|
48
|
+
return { widget: copy(updated) };
|
|
49
|
+
},
|
|
50
|
+
async trashWidget({ id }, options = {}) {
|
|
51
|
+
options.signal?.throwIfAborted();
|
|
52
|
+
const { index, widget } = instance(id);
|
|
53
|
+
// Shared Trash owns restoration and permanent removal; this API only moves status.
|
|
54
|
+
rows[index] = { ...widget, status: 'trash', version: widget.version + 1, updatedAt: now() };
|
|
55
|
+
return { ok: true, version: rows[index].version };
|
|
56
|
+
},
|
|
57
|
+
async listWidgetRegions(_required, options = {}) { options.signal?.throwIfAborted(); return { regions: copy(bindings) }; },
|
|
58
|
+
async bindWidgetRegion({ regionKey }, options = {}) {
|
|
59
|
+
options.signal?.throwIfAborted();
|
|
60
|
+
if (regionRows.has(regionKey) || bindings.some(b => b.regionKey === regionKey))
|
|
61
|
+
fail('WIDGETS_REGION_BOUND', 'Region already bound');
|
|
62
|
+
let id;
|
|
63
|
+
do {
|
|
64
|
+
id = `fake-area-${++areaSequence}`;
|
|
65
|
+
} while (bindings.some(b => b.areaEntryId === id) || [...regionRows.values()].some(r => r.area.id === id));
|
|
66
|
+
const area = { id, workspaceId, regionKey, updatedAt: now(), version: 1 };
|
|
67
|
+
bindings.push({ workspaceId, regionKey, areaEntryId: id, updatedAt: area.updatedAt, placementCount: 0 });
|
|
68
|
+
regionRows.set(regionKey, { area, placements: [] });
|
|
69
|
+
return { area: copy(area) };
|
|
70
|
+
},
|
|
71
|
+
async getWidgetRegion({ regionKey }, options = {}) { options.signal?.throwIfAborted(); return copy(region(regionKey)); },
|
|
72
|
+
async mutateWidgetRegionPlacements({ regionKey, baseVersion, placements }, options = {}) {
|
|
73
|
+
options.signal?.throwIfAborted();
|
|
74
|
+
const entry = region(regionKey);
|
|
75
|
+
if (entry.area.version !== baseVersion)
|
|
76
|
+
fail('WIDGETS_AREA_CONFLICT', 'Region version conflict');
|
|
77
|
+
const area = { ...entry.area, version: entry.area.version + 1, updatedAt: now() };
|
|
78
|
+
// Ordered rows retain identity and allow repeated widget refs; broken refs stay visible.
|
|
79
|
+
const saved = placements.map(p => {
|
|
80
|
+
const widget = rows.find(w => w.id === p.widgetEntryId && w.status === 'active');
|
|
81
|
+
return { ...p, widgetTitle: widget?.title ?? null, widgetType: widget?.widgetType ?? null, broken: !widget };
|
|
82
|
+
});
|
|
83
|
+
regionRows.set(regionKey, { area, placements: saved });
|
|
84
|
+
const binding = bindings.find(b => b.regionKey === regionKey);
|
|
85
|
+
if (binding) {
|
|
86
|
+
binding.placementCount = saved.length;
|
|
87
|
+
binding.updatedAt = area.updatedAt;
|
|
88
|
+
}
|
|
89
|
+
return { area: copy(area) };
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AdminWidgetsPort } from '../ports.js';
|
|
2
|
+
/** Mutates an isolated adapter. Returns named checks and throws at the first contract failure. */
|
|
3
|
+
export declare function runWidgetsApiConformance({ api }: {
|
|
4
|
+
api: AdminWidgetsPort;
|
|
5
|
+
}, _optional?: Record<string, never>): Promise<readonly string[]>;
|
|
6
|
+
//# sourceMappingURL=widgets-api.conformance.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Mutates an isolated adapter. Returns named checks and throws at the first contract failure. */
|
|
2
|
+
export async function runWidgetsApiConformance({ api }, _optional = {}) {
|
|
3
|
+
const checks = [];
|
|
4
|
+
function assert(condition, name) { if (!condition)
|
|
5
|
+
throw new Error(`Widgets API conformance: ${name}`); checks.push(name); }
|
|
6
|
+
async function rejects(run, name) { let rejected = false; try {
|
|
7
|
+
await run();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
rejected = true;
|
|
11
|
+
} assert(rejected, name); }
|
|
12
|
+
const input = { widgetType: 'text', title: 'Conformance widget', config: { body: 'initial' } };
|
|
13
|
+
const { widget } = await api.createWidget(input);
|
|
14
|
+
assert(widget.id.length > 0 && widget.slug.length > 0 && widget.status === 'active', 'create active instance');
|
|
15
|
+
input.config.body = 'caller changed';
|
|
16
|
+
assert((await api.getWidget({ id: widget.id })).widget.config.body === 'initial', 'create copies config input');
|
|
17
|
+
assert((await api.getWidget({ id: widget.slug })).widget.id === widget.id, 'get resolves slug or id');
|
|
18
|
+
const firstList = await api.listWidgets({});
|
|
19
|
+
assert(firstList.widgets.some(w => w.id === widget.id), 'active list includes created instance');
|
|
20
|
+
assert((await api.listWidgets({ widgetType: 'social-links' })).widgets.every(w => w.widgetType === 'social-links'), 'type filter');
|
|
21
|
+
const { widget: updated } = await api.updateWidget({ id: widget.id, baseVersion: widget.version, config: { body: 'updated' } });
|
|
22
|
+
assert(updated.title === widget.title && updated.version > widget.version, 'omitted title preserved and version advances');
|
|
23
|
+
assert(widget.config.body === 'initial' && firstList.widgets.find(w => w.id === widget.id)?.version === widget.version, 'prior snapshots stay detached');
|
|
24
|
+
await rejects(() => api.updateWidget({ id: widget.id, baseVersion: widget.version, config: {} }), 'stale instance write rejects');
|
|
25
|
+
const regionKey = `conformance-${widget.id}`;
|
|
26
|
+
const { area } = await api.bindWidgetRegion({ regionKey });
|
|
27
|
+
const initialAreaVersion = area.version;
|
|
28
|
+
assert((await api.listWidgetRegions({})).regions.some(r => r.regionKey === regionKey), 'bound region listed');
|
|
29
|
+
assert((await api.getWidgetRegion({ regionKey })).placements.length === 0, 'new region empty');
|
|
30
|
+
const placements = [
|
|
31
|
+
{ placementId: 'p-one', widgetEntryId: widget.id, enabled: false },
|
|
32
|
+
{ placementId: 'p-two', widgetEntryId: widget.id, enabled: true },
|
|
33
|
+
{ placementId: 'p-broken', widgetEntryId: 'missing-conformance-widget', enabled: true },
|
|
34
|
+
];
|
|
35
|
+
const { area: savedArea } = await api.mutateWidgetRegionPlacements({ regionKey, baseVersion: area.version, placements });
|
|
36
|
+
assert(savedArea.version > area.version && area.version === initialAreaVersion, 'region version advances without mutating old snapshot');
|
|
37
|
+
const placed = await api.getWidgetRegion({ regionKey });
|
|
38
|
+
assert(placed.placements.map(p => p.placementId).join() === placements.map(p => p.placementId).join(), 'ordered placement identities and repeated refs retained');
|
|
39
|
+
assert(placed.placements[0]?.enabled === false && placed.placements[1]?.widgetTitle === updated.title, 'placement enabled and title projection');
|
|
40
|
+
assert(placed.placements[2]?.broken === true, 'broken reference remains visible');
|
|
41
|
+
assert((await api.listWidgetRegions({})).regions.find(r => r.regionKey === regionKey)?.placementCount === placements.length, 'region list placement count updates');
|
|
42
|
+
await rejects(() => api.mutateWidgetRegionPlacements({ regionKey, baseVersion: area.version, placements: [] }), 'stale region write rejects');
|
|
43
|
+
const abort = new AbortController();
|
|
44
|
+
abort.abort();
|
|
45
|
+
await rejects(() => api.listWidgets({}, { signal: abort.signal }), 'aborted list rejects');
|
|
46
|
+
await rejects(() => api.updateWidget({ id: widget.id, baseVersion: updated.version, title: 'must not save', config: {} }, { signal: abort.signal }), 'aborted write rejects');
|
|
47
|
+
assert((await api.getWidget({ id: widget.id })).widget.title === widget.title, 'aborted write has no effects');
|
|
48
|
+
await rejects(() => api.getWidget({ id: 'missing-conformance-widget' }), 'missing instance rejects');
|
|
49
|
+
await rejects(() => api.getWidgetRegion({ regionKey: 'missing-conformance-region' }), 'missing region rejects');
|
|
50
|
+
await api.trashWidget({ id: widget.id });
|
|
51
|
+
assert(!(await api.listWidgets({})).widgets.some(w => w.id === widget.id), 'trash removes active listing');
|
|
52
|
+
assert((await api.listWidgets({ includeInactive: true })).widgets.find(w => w.id === widget.id)?.status === 'trash', 'trash retained for shared lifecycle');
|
|
53
|
+
return checks;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=widgets-api.conformance.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AdminWidgetsPort } from '../ports.js';
|
|
2
|
+
import type { AdminWidget, AdminWidgetWhereUsed, AdminWidgetType, WidgetsTranslate, WidgetEditorParams, WidgetSlugRedirectPath } from '../models.js';
|
|
3
|
+
export interface WidgetInstanceEditorState {
|
|
4
|
+
isNew: boolean;
|
|
5
|
+
widget: AdminWidget | null;
|
|
6
|
+
whereUsed: AdminWidgetWhereUsed;
|
|
7
|
+
title: string;
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
message: string | null;
|
|
10
|
+
error: string | null;
|
|
11
|
+
fieldErrors: Array<{
|
|
12
|
+
field: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
}>;
|
|
15
|
+
loading: boolean;
|
|
16
|
+
saving: boolean;
|
|
17
|
+
widgetType: AdminWidgetType | null | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Editor identity includes both route params. Reads and saves cannot overwrite a different editor. */
|
|
20
|
+
export declare function createWidgetInstanceEditorController({ api, params: initialParams, defaultConfig }: {
|
|
21
|
+
api: AdminWidgetsPort;
|
|
22
|
+
params: WidgetEditorParams;
|
|
23
|
+
defaultConfig: (type: AdminWidgetType) => Record<string, unknown>;
|
|
24
|
+
}, { t, navigate, slugRedirectPath, getEntityKey }?: {
|
|
25
|
+
t?: WidgetsTranslate | undefined;
|
|
26
|
+
navigate?: ((path: string, options?: {
|
|
27
|
+
replace?: boolean;
|
|
28
|
+
}) => void) | undefined;
|
|
29
|
+
slugRedirectPath?: WidgetSlugRedirectPath | undefined;
|
|
30
|
+
getEntityKey?: (() => string) | undefined;
|
|
31
|
+
}): {
|
|
32
|
+
getSnapshot: () => Readonly<WidgetInstanceEditorState>;
|
|
33
|
+
subscribe: ({ listener }: {
|
|
34
|
+
listener: () => void;
|
|
35
|
+
}) => () => void;
|
|
36
|
+
load: (_required?: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
37
|
+
save: (_required?: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
38
|
+
setParams({ params: next }: {
|
|
39
|
+
params: WidgetEditorParams;
|
|
40
|
+
}, _optional?: Record<string, never>): void;
|
|
41
|
+
setTitle({ title }: {
|
|
42
|
+
title: string;
|
|
43
|
+
}, _optional?: Record<string, never>): void;
|
|
44
|
+
setConfig({ config }: {
|
|
45
|
+
config: Record<string, unknown>;
|
|
46
|
+
}, _optional?: Record<string, never>): void;
|
|
47
|
+
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=instance-editor.controller.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createControllerStore } from '../../core/module/controller-store.js';
|
|
2
|
+
import { describeApiError } from '../../core/transport/errors.js';
|
|
3
|
+
import { resolveEditorWidgetType, resolveWidgetSaveError, widgetApiError, widgetSlugRedirectPath, widgetEntityKey } from '../rules.js';
|
|
4
|
+
import { widgetsEnglish } from '../messages.en.js';
|
|
5
|
+
/** Editor identity includes both route params. Reads and saves cannot overwrite a different editor. */
|
|
6
|
+
export function createWidgetInstanceEditorController({ api, params: initialParams, defaultConfig }, { t = widgetsEnglish, navigate, slugRedirectPath, getEntityKey } = {}) {
|
|
7
|
+
let params = initialParams;
|
|
8
|
+
const key = () => widgetEntityKey({ params });
|
|
9
|
+
const currentKey = () => getEntityKey?.() ?? activeKey;
|
|
10
|
+
let activeKey = key(), generation = 0;
|
|
11
|
+
const isNew = params.widgetId === null;
|
|
12
|
+
const store = createControllerStore({ initial: {
|
|
13
|
+
isNew, widget: null, whereUsed: { count: 0, references: [] }, title: '',
|
|
14
|
+
config: isNew ? defaultConfig(params.widgetType ?? 'text') : {}, message: null, error: null, fieldErrors: [],
|
|
15
|
+
loading: !isNew, saving: false, widgetType: resolveEditorWidgetType({ isNew, queryWidgetType: params.widgetType, widget: null }),
|
|
16
|
+
} });
|
|
17
|
+
async function load(_required = {}, _optional = {}) {
|
|
18
|
+
const ticket = ++generation;
|
|
19
|
+
const isNew = params.widgetId === null;
|
|
20
|
+
store.set({ patch: { isNew, saving: false } });
|
|
21
|
+
if (isNew) {
|
|
22
|
+
store.set({ patch: { widget: null, title: '', config: defaultConfig(params.widgetType ?? 'text'), whereUsed: { count: 0, references: [] }, loading: false, widgetType: params.widgetType } });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const requestedId = params.widgetId;
|
|
26
|
+
store.set({ patch: { loading: true, error: null } });
|
|
27
|
+
try {
|
|
28
|
+
const result = await api.getWidget({ id: requestedId }, { signal: store.signal });
|
|
29
|
+
if (ticket !== generation || store.signal.aborted)
|
|
30
|
+
return;
|
|
31
|
+
store.set({ patch: { widget: result.widget, title: result.widget.title, config: result.widget.config, whereUsed: result.whereUsed, widgetType: result.widget.widgetType } });
|
|
32
|
+
// Replace rather than push: an old id bookmark should not add a Back-button stop.
|
|
33
|
+
const redirect = widgetSlugRedirectPath({ requestedId, widget: result.widget }, { slugRedirectPath });
|
|
34
|
+
if (redirect)
|
|
35
|
+
navigate?.(redirect, { replace: true });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (ticket === generation && !store.signal.aborted)
|
|
39
|
+
store.set({ patch: { error: describeApiError({ e: widgetApiError({ error }) ?? error, fallback: t('failed to load widget') }) } });
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
if (ticket === generation && !store.signal.aborted)
|
|
43
|
+
store.set({ patch: { loading: false } });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function save(_required = {}, _optional = {}) {
|
|
47
|
+
const { widgetType, isNew, widget, title, config } = store.getSnapshot();
|
|
48
|
+
if (!widgetType)
|
|
49
|
+
return;
|
|
50
|
+
const savingFor = currentKey();
|
|
51
|
+
store.set({ patch: { saving: true, message: null, error: null, fieldErrors: [] } });
|
|
52
|
+
try {
|
|
53
|
+
if (isNew) {
|
|
54
|
+
const { widget: created } = await api.createWidget({ widgetType, title, config }, { signal: store.signal });
|
|
55
|
+
// Creation intentionally navigates even if route identity changed while it was in flight.
|
|
56
|
+
navigate?.(`/widgets/${created.slug}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!widget)
|
|
60
|
+
return;
|
|
61
|
+
const { widget: saved } = await api.updateWidget({ id: widget.id, baseVersion: widget.version, title, config }, { signal: store.signal });
|
|
62
|
+
if (currentKey() !== savingFor || store.signal.aborted)
|
|
63
|
+
return;
|
|
64
|
+
store.set({ patch: { widget: saved, title: saved.title, config: saved.config, widgetType: saved.widgetType, message: t('Saved · version {version}').replace('{version}', String(saved.version)) } });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (currentKey() === savingFor && !store.signal.aborted)
|
|
68
|
+
store.set({ patch: resolveWidgetSaveError({ error }, { t }) });
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
if (currentKey() === savingFor && !store.signal.aborted)
|
|
72
|
+
store.set({ patch: { saving: false } });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load, save,
|
|
77
|
+
setParams({ params: next }, _optional = {}) {
|
|
78
|
+
params = next;
|
|
79
|
+
activeKey = key();
|
|
80
|
+
void load();
|
|
81
|
+
},
|
|
82
|
+
setTitle({ title }, _optional = {}) { store.set({ patch: { title } }); },
|
|
83
|
+
setConfig({ config }, _optional = {}) { store.set({ patch: { config } }); },
|
|
84
|
+
dispose(_required = {}, _optional = {}) { generation++; activeKey = ''; store.dispose(); },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=instance-editor.controller.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AdminWidgetsPort } from '../ports.js';
|
|
2
|
+
import type { AdminWidget, AdminWidgetType, WidgetsTranslate } from '../models.js';
|
|
3
|
+
export interface WidgetsLibraryState {
|
|
4
|
+
widgets: AdminWidget[] | null;
|
|
5
|
+
error: string | null;
|
|
6
|
+
skippedCount: number;
|
|
7
|
+
skippedIds: string[];
|
|
8
|
+
createType: AdminWidgetType;
|
|
9
|
+
pendingTrash: AdminWidget | null;
|
|
10
|
+
trashingId: string | null;
|
|
11
|
+
}
|
|
12
|
+
/** Active-only library. Latest read wins across mount, refresh and write-triggered reads. */
|
|
13
|
+
export declare function createWidgetsLibraryController({ api }: {
|
|
14
|
+
api: AdminWidgetsPort;
|
|
15
|
+
}, { t }?: {
|
|
16
|
+
t?: WidgetsTranslate | undefined;
|
|
17
|
+
}): {
|
|
18
|
+
getSnapshot: () => Readonly<WidgetsLibraryState>;
|
|
19
|
+
subscribe: ({ listener }: {
|
|
20
|
+
listener: () => void;
|
|
21
|
+
}) => () => void;
|
|
22
|
+
load: (_required?: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
23
|
+
confirmTrash: (_required?: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
24
|
+
setCreateType({ type }: {
|
|
25
|
+
type: AdminWidgetType;
|
|
26
|
+
}, _optional?: Record<string, never>): void;
|
|
27
|
+
requestTrash({ widget }: {
|
|
28
|
+
widget: AdminWidget;
|
|
29
|
+
}, _optional?: Record<string, never>): void;
|
|
30
|
+
cancelTrash(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
31
|
+
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=library.controller.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createControllerStore } from '../../core/module/controller-store.js';
|
|
2
|
+
import { describeApiError } from '../../core/transport/errors.js';
|
|
3
|
+
import { widgetApiError } from '../rules.js';
|
|
4
|
+
import { widgetsEnglish } from '../messages.en.js';
|
|
5
|
+
/** Active-only library. Latest read wins across mount, refresh and write-triggered reads. */
|
|
6
|
+
export function createWidgetsLibraryController({ api }, { t = widgetsEnglish } = {}) {
|
|
7
|
+
const store = createControllerStore({ initial: { widgets: null, error: null, skippedCount: 0, skippedIds: [], createType: 'text', pendingTrash: null, trashingId: null } });
|
|
8
|
+
let generation = 0;
|
|
9
|
+
async function load(_required = {}, _optional = {}) {
|
|
10
|
+
const ticket = ++generation;
|
|
11
|
+
try {
|
|
12
|
+
// No includeInactive: trashed widgets belong to the shared Trash screen.
|
|
13
|
+
const result = await api.listWidgets({}, { signal: store.signal });
|
|
14
|
+
if (ticket !== generation || store.signal.aborted)
|
|
15
|
+
return;
|
|
16
|
+
store.set({ patch: { widgets: result.widgets, skippedCount: result.skippedCount ?? 0, skippedIds: result.skippedIds ?? [] } });
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
if (ticket === generation && !store.signal.aborted)
|
|
20
|
+
store.set({ patch: { error: describeApiError({ e: widgetApiError({ error: e }) ?? e, fallback: t('failed to load widgets') }) } });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function confirmTrash(_required = {}, _optional = {}) {
|
|
24
|
+
const widget = store.getSnapshot().pendingTrash;
|
|
25
|
+
if (!widget)
|
|
26
|
+
return;
|
|
27
|
+
store.set({ patch: { trashingId: widget.id, error: null } });
|
|
28
|
+
try {
|
|
29
|
+
await api.trashWidget({ id: widget.id }, { signal: store.signal });
|
|
30
|
+
void load();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const e = widgetApiError({ error });
|
|
34
|
+
if (e?.code === 'NOT_FOUND')
|
|
35
|
+
void load();
|
|
36
|
+
else
|
|
37
|
+
store.set({ patch: { error: e?.code === 'TRASH_VERSION_CHANGED' ? t('This item changed since you loaded it. Reload and try again.') : describeApiError({ e: e ?? error, fallback: t('delete failed') }) } });
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
// A's completion cannot close a newly opened confirmation for B.
|
|
41
|
+
const current = store.getSnapshot();
|
|
42
|
+
store.set({ patch: { trashingId: current.trashingId === widget.id ? null : current.trashingId, pendingTrash: current.pendingTrash?.id === widget.id ? null : current.pendingTrash } });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load, confirmTrash,
|
|
47
|
+
setCreateType({ type }, _optional = {}) { store.set({ patch: { createType: type } }); },
|
|
48
|
+
requestTrash({ widget }, _optional = {}) { store.set({ patch: { error: null, pendingTrash: widget } }); },
|
|
49
|
+
cancelTrash(_required = {}, _optional = {}) { store.set({ patch: { pendingTrash: null } }); },
|
|
50
|
+
dispose(_required = {}, _optional = {}) { generation++; store.dispose(); },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=library.controller.js.map
|