@pilotiq/pilotiq 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/CHANGELOG.md +142 -0
- package/CLAUDE.md +59 -3
- package/dist/Pilotiq.d.ts +83 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +39 -0
- package/dist/Pilotiq.js.map +1 -1
- package/dist/actions/Action.d.ts +27 -99
- package/dist/actions/Action.d.ts.map +1 -1
- package/dist/actions/Action.js +52 -754
- package/dist/actions/Action.js.map +1 -1
- package/dist/actions/bulkFactories.d.ts +46 -0
- package/dist/actions/bulkFactories.d.ts.map +1 -0
- package/dist/actions/bulkFactories.js +144 -0
- package/dist/actions/bulkFactories.js.map +1 -0
- package/dist/actions/crudFactories.d.ts +94 -0
- package/dist/actions/crudFactories.d.ts.map +1 -0
- package/dist/actions/crudFactories.js +209 -0
- package/dist/actions/crudFactories.js.map +1 -0
- package/dist/actions/factoryHelpers.d.ts +108 -0
- package/dist/actions/factoryHelpers.d.ts.map +1 -0
- package/dist/actions/factoryHelpers.js +138 -0
- package/dist/actions/factoryHelpers.js.map +1 -0
- package/dist/actions/m2mFactories.d.ts +47 -0
- package/dist/actions/m2mFactories.d.ts.map +1 -0
- package/dist/actions/m2mFactories.js +173 -0
- package/dist/actions/m2mFactories.js.map +1 -0
- package/dist/actions/relationFactories.d.ts +93 -0
- package/dist/actions/relationFactories.d.ts.map +1 -0
- package/dist/actions/relationFactories.js +321 -0
- package/dist/actions/relationFactories.js.map +1 -0
- package/dist/elements/dispatchForm.js +1 -1
- package/dist/elements/dispatchForm.js.map +1 -1
- package/dist/elements/dispatchTable.js +1 -1
- package/dist/elements/dispatchTable.js.map +1 -1
- package/dist/fields/Field.d.ts +31 -0
- package/dist/fields/Field.d.ts.map +1 -1
- package/dist/fields/Field.js +25 -0
- package/dist/fields/Field.js.map +1 -1
- package/dist/pageData/breadcrumbs.d.ts +42 -0
- package/dist/pageData/breadcrumbs.d.ts.map +1 -0
- package/dist/pageData/breadcrumbs.js +172 -0
- package/dist/pageData/breadcrumbs.js.map +1 -0
- package/dist/pageData/forms.d.ts +137 -0
- package/dist/pageData/forms.d.ts.map +1 -0
- package/dist/pageData/forms.js +427 -0
- package/dist/pageData/forms.js.map +1 -0
- package/dist/pageData/helpers.d.ts +239 -0
- package/dist/pageData/helpers.d.ts.map +1 -0
- package/dist/pageData/helpers.js +703 -0
- package/dist/pageData/helpers.js.map +1 -0
- package/dist/pageData/misc.d.ts +76 -0
- package/dist/pageData/misc.d.ts.map +1 -0
- package/dist/pageData/misc.js +263 -0
- package/dist/pageData/misc.js.map +1 -0
- package/dist/pageData/navigation.d.ts +292 -0
- package/dist/pageData/navigation.d.ts.map +1 -0
- package/dist/pageData/navigation.js +591 -0
- package/dist/pageData/navigation.js.map +1 -0
- package/dist/pageData/relationPages.d.ts +172 -0
- package/dist/pageData/relationPages.d.ts.map +1 -0
- package/dist/pageData/relationPages.js +867 -0
- package/dist/pageData/relationPages.js.map +1 -0
- package/dist/pageData/relationTabs.d.ts +65 -0
- package/dist/pageData/relationTabs.d.ts.map +1 -0
- package/dist/pageData/relationTabs.js +258 -0
- package/dist/pageData/relationTabs.js.map +1 -0
- package/dist/pageData/resourcePages.d.ts +48 -0
- package/dist/pageData/resourcePages.d.ts.map +1 -0
- package/dist/pageData/resourcePages.js +504 -0
- package/dist/pageData/resourcePages.js.map +1 -0
- package/dist/pageData.d.ts +12 -792
- package/dist/pageData.d.ts.map +1 -1
- package/dist/pageData.js +24 -3797
- package/dist/pageData.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js +11 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/CollabExtensionFactoryRegistry.d.ts +47 -0
- package/dist/react/CollabExtensionFactoryRegistry.d.ts.map +1 -0
- package/dist/react/CollabExtensionFactoryRegistry.js +14 -0
- package/dist/react/CollabExtensionFactoryRegistry.js.map +1 -0
- package/dist/react/CollabRoomContext.d.ts +37 -0
- package/dist/react/CollabRoomContext.d.ts.map +1 -0
- package/dist/react/CollabRoomContext.js +12 -0
- package/dist/react/CollabRoomContext.js.map +1 -0
- package/dist/react/FormCollabBindingRegistry.d.ts +62 -0
- package/dist/react/FormCollabBindingRegistry.d.ts.map +1 -0
- package/dist/react/FormCollabBindingRegistry.js +14 -0
- package/dist/react/FormCollabBindingRegistry.js.map +1 -0
- package/dist/react/RecordWrapperGate.d.ts +25 -0
- package/dist/react/RecordWrapperGate.d.ts.map +1 -0
- package/dist/react/RecordWrapperGate.js +30 -0
- package/dist/react/RecordWrapperGate.js.map +1 -0
- package/dist/react/RecordWrapperRegistry.d.ts +31 -0
- package/dist/react/RecordWrapperRegistry.d.ts.map +1 -0
- package/dist/react/RecordWrapperRegistry.js +15 -0
- package/dist/react/RecordWrapperRegistry.js.map +1 -0
- package/dist/react/SchemaRenderer.d.ts +17 -23
- package/dist/react/SchemaRenderer.d.ts.map +1 -1
- package/dist/react/SchemaRenderer.js +71 -3647
- package/dist/react/SchemaRenderer.js.map +1 -1
- package/dist/react/component-slots.d.ts +103 -0
- package/dist/react/component-slots.d.ts.map +1 -0
- package/dist/react/component-slots.js +18 -0
- package/dist/react/component-slots.js.map +1 -0
- package/dist/react/fields/BuilderInput.d.ts.map +1 -1
- package/dist/react/fields/BuilderInput.js +21 -117
- package/dist/react/fields/BuilderInput.js.map +1 -1
- package/dist/react/fields/MarkdownInput.d.ts.map +1 -1
- package/dist/react/fields/MarkdownInput.js +1 -3
- package/dist/react/fields/MarkdownInput.js.map +1 -1
- package/dist/react/fields/RepeaterInput.d.ts.map +1 -1
- package/dist/react/fields/RepeaterInput.js +22 -127
- package/dist/react/fields/RepeaterInput.js.map +1 -1
- package/dist/react/fields/rowState.d.ts +40 -0
- package/dist/react/fields/rowState.d.ts.map +1 -0
- package/dist/react/fields/rowState.js +60 -0
- package/dist/react/fields/rowState.js.map +1 -0
- package/dist/react/fields/useRowReorderDnd.d.ts +28 -0
- package/dist/react/fields/useRowReorderDnd.d.ts.map +1 -0
- package/dist/react/fields/useRowReorderDnd.js +51 -0
- package/dist/react/fields/useRowReorderDnd.js.map +1 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +8 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/layouts/TopbarLayout.d.ts +1 -1
- package/dist/react/layouts/TopbarLayout.d.ts.map +1 -1
- package/dist/react/layouts/TopbarLayout.js +19 -11
- package/dist/react/layouts/TopbarLayout.js.map +1 -1
- package/dist/react/parseRecordEditUrl.d.ts +29 -0
- package/dist/react/parseRecordEditUrl.d.ts.map +1 -0
- package/dist/react/parseRecordEditUrl.js +25 -0
- package/dist/react/parseRecordEditUrl.js.map +1 -0
- package/dist/react/persistedState.d.ts +19 -0
- package/dist/react/persistedState.d.ts.map +1 -0
- package/dist/react/persistedState.js +51 -0
- package/dist/react/persistedState.js.map +1 -0
- package/dist/react/schemaRenderer/AlertRenderer.d.ts +12 -0
- package/dist/react/schemaRenderer/AlertRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/AlertRenderer.js +61 -0
- package/dist/react/schemaRenderer/AlertRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/EntryRenderer.d.ts +13 -0
- package/dist/react/schemaRenderer/EntryRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/EntryRenderer.js +277 -0
- package/dist/react/schemaRenderer/EntryRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/SectionRenderer.d.ts +16 -0
- package/dist/react/schemaRenderer/SectionRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/SectionRenderer.js +62 -0
- package/dist/react/schemaRenderer/SectionRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/SimpleElements.d.ts +25 -0
- package/dist/react/schemaRenderer/SimpleElements.d.ts.map +1 -0
- package/dist/react/schemaRenderer/SimpleElements.js +147 -0
- package/dist/react/schemaRenderer/SimpleElements.js.map +1 -0
- package/dist/react/schemaRenderer/TabsRenderer.d.ts +17 -0
- package/dist/react/schemaRenderer/TabsRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/TabsRenderer.js +31 -0
- package/dist/react/schemaRenderer/TabsRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/WizardRenderer.d.ts +34 -0
- package/dist/react/schemaRenderer/WizardRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/WizardRenderer.js +208 -0
- package/dist/react/schemaRenderer/WizardRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/action/ActionGroupTrigger.d.ts +21 -0
- package/dist/react/schemaRenderer/action/ActionGroupTrigger.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/ActionGroupTrigger.js +82 -0
- package/dist/react/schemaRenderer/action/ActionGroupTrigger.js.map +1 -0
- package/dist/react/schemaRenderer/action/ActionModalDialog.d.ts +30 -0
- package/dist/react/schemaRenderer/action/ActionModalDialog.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/ActionModalDialog.js +182 -0
- package/dist/react/schemaRenderer/action/ActionModalDialog.js.map +1 -0
- package/dist/react/schemaRenderer/action/ConfirmActionDialog.d.ts +17 -0
- package/dist/react/schemaRenderer/action/ConfirmActionDialog.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/ConfirmActionDialog.js +19 -0
- package/dist/react/schemaRenderer/action/ConfirmActionDialog.js.map +1 -0
- package/dist/react/schemaRenderer/action/HandlerActionButton.d.ts +16 -0
- package/dist/react/schemaRenderer/action/HandlerActionButton.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/HandlerActionButton.js +16 -0
- package/dist/react/schemaRenderer/action/HandlerActionButton.js.map +1 -0
- package/dist/react/schemaRenderer/action/MethodActionButton.d.ts +22 -0
- package/dist/react/schemaRenderer/action/MethodActionButton.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/MethodActionButton.js +26 -0
- package/dist/react/schemaRenderer/action/MethodActionButton.js.map +1 -0
- package/dist/react/schemaRenderer/action/buttons.d.ts +18 -0
- package/dist/react/schemaRenderer/action/buttons.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/buttons.js +74 -0
- package/dist/react/schemaRenderer/action/buttons.js.map +1 -0
- package/dist/react/schemaRenderer/action/helpers.d.ts +26 -0
- package/dist/react/schemaRenderer/action/helpers.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/helpers.js +126 -0
- package/dist/react/schemaRenderer/action/helpers.js.map +1 -0
- package/dist/react/schemaRenderer/action/renderAction.d.ts +21 -0
- package/dist/react/schemaRenderer/action/renderAction.d.ts.map +1 -0
- package/dist/react/schemaRenderer/action/renderAction.js +102 -0
- package/dist/react/schemaRenderer/action/renderAction.js.map +1 -0
- package/dist/react/schemaRenderer/columnFormat.d.ts +10 -0
- package/dist/react/schemaRenderer/columnFormat.d.ts.map +1 -0
- package/dist/react/schemaRenderer/columnFormat.js +76 -0
- package/dist/react/schemaRenderer/columnFormat.js.map +1 -0
- package/dist/react/schemaRenderer/constants.d.ts +8 -0
- package/dist/react/schemaRenderer/constants.d.ts.map +1 -0
- package/dist/react/schemaRenderer/constants.js +45 -0
- package/dist/react/schemaRenderer/constants.js.map +1 -0
- package/dist/react/schemaRenderer/form/FormRenderer.d.ts +29 -0
- package/dist/react/schemaRenderer/form/FormRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/form/FormRenderer.js +152 -0
- package/dist/react/schemaRenderer/form/FormRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/form/renderField.d.ts +6 -0
- package/dist/react/schemaRenderer/form/renderField.d.ts.map +1 -0
- package/dist/react/schemaRenderer/form/renderField.js +239 -0
- package/dist/react/schemaRenderer/form/renderField.js.map +1 -0
- package/dist/react/schemaRenderer/helpers.d.ts +32 -0
- package/dist/react/schemaRenderer/helpers.d.ts.map +1 -0
- package/dist/react/schemaRenderer/helpers.js +52 -0
- package/dist/react/schemaRenderer/helpers.js.map +1 -0
- package/dist/react/schemaRenderer/table/CardsLayoutBody.d.ts +60 -0
- package/dist/react/schemaRenderer/table/CardsLayoutBody.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/CardsLayoutBody.js +189 -0
- package/dist/react/schemaRenderer/table/CardsLayoutBody.js.map +1 -0
- package/dist/react/schemaRenderer/table/TableRenderer.d.ts +29 -0
- package/dist/react/schemaRenderer/table/TableRenderer.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/TableRenderer.js +85 -0
- package/dist/react/schemaRenderer/table/TableRenderer.js.map +1 -0
- package/dist/react/schemaRenderer/table/TableRendererBody.d.ts +18 -0
- package/dist/react/schemaRenderer/table/TableRendererBody.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/TableRendererBody.js +555 -0
- package/dist/react/schemaRenderer/table/TableRendererBody.js.map +1 -0
- package/dist/react/schemaRenderer/table/filters.d.ts +263 -0
- package/dist/react/schemaRenderer/table/filters.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/filters.js +497 -0
- package/dist/react/schemaRenderer/table/filters.js.map +1 -0
- package/dist/react/schemaRenderer/table/formatCell.d.ts +11 -0
- package/dist/react/schemaRenderer/table/formatCell.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/formatCell.js +172 -0
- package/dist/react/schemaRenderer/table/formatCell.js.map +1 -0
- package/dist/react/schemaRenderer/table/links.d.ts +42 -0
- package/dist/react/schemaRenderer/table/links.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/links.js +55 -0
- package/dist/react/schemaRenderer/table/links.js.map +1 -0
- package/dist/react/schemaRenderer/table/renderRowActions.d.ts +13 -0
- package/dist/react/schemaRenderer/table/renderRowActions.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/renderRowActions.js +25 -0
- package/dist/react/schemaRenderer/table/renderRowActions.js.map +1 -0
- package/dist/react/schemaRenderer/table/url.d.ts +41 -0
- package/dist/react/schemaRenderer/table/url.d.ts.map +1 -0
- package/dist/react/schemaRenderer/table/url.js +114 -0
- package/dist/react/schemaRenderer/table/url.js.map +1 -0
- package/dist/routes/globals.d.ts +13 -0
- package/dist/routes/globals.d.ts.map +1 -0
- package/dist/routes/globals.js +131 -0
- package/dist/routes/globals.js.map +1 -0
- package/dist/routes/helpers.d.ts +217 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +498 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/pages.d.ts +15 -0
- package/dist/routes/pages.d.ts.map +1 -0
- package/dist/routes/pages.js +145 -0
- package/dist/routes/pages.js.map +1 -0
- package/dist/routes/panel.d.ts +19 -0
- package/dist/routes/panel.d.ts.map +1 -0
- package/dist/routes/panel.js +191 -0
- package/dist/routes/panel.js.map +1 -0
- package/dist/routes/relations.d.ts +21 -0
- package/dist/routes/relations.d.ts.map +1 -0
- package/dist/routes/relations.js +1239 -0
- package/dist/routes/relations.js.map +1 -0
- package/dist/routes/resources.d.ts +28 -0
- package/dist/routes/resources.d.ts.map +1 -0
- package/dist/routes/resources.js +741 -0
- package/dist/routes/resources.js.map +1 -0
- package/dist/routes/theme.d.ts +12 -0
- package/dist/routes/theme.d.ts.map +1 -0
- package/dist/routes/theme.js +82 -0
- package/dist/routes/theme.js.map +1 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +64 -3078
- package/dist/routes.js.map +1 -1
- package/dist/vite.d.ts +1 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +26 -5
- package/dist/vite.js.map +1 -1
- package/package.json +2 -1
- package/src/Pilotiq.ts +95 -0
- package/src/actions/Action.ts +79 -723
- package/src/actions/bulkFactories.ts +168 -0
- package/src/actions/crudFactories.ts +220 -0
- package/src/actions/factoryHelpers.ts +177 -0
- package/src/actions/m2mFactories.ts +193 -0
- package/src/actions/relationFactories.ts +372 -0
- package/src/elements/dispatchForm.ts +1 -1
- package/src/elements/dispatchTable.ts +1 -1
- package/src/fields/Field.ts +39 -0
- package/src/pageData/breadcrumbs.ts +288 -0
- package/src/pageData/forms.ts +578 -0
- package/src/pageData/helpers.ts +764 -0
- package/src/pageData/misc.ts +347 -0
- package/src/pageData/navigation.ts +779 -0
- package/src/pageData/relationPages.ts +1246 -0
- package/src/pageData/relationTabs.ts +286 -0
- package/src/pageData/resourcePages.ts +593 -0
- package/src/pageData.ts +122 -4731
- package/src/react/AppShell.tsx +27 -1
- package/src/react/CollabExtensionFactoryRegistry.ts +55 -0
- package/src/react/CollabRoomContext.ts +42 -0
- package/src/react/FormCollabBindingRegistry.ts +72 -0
- package/src/react/RecordWrapperGate.tsx +40 -0
- package/src/react/RecordWrapperRegistry.ts +39 -0
- package/src/react/SchemaRenderer.tsx +230 -6479
- package/src/react/component-slots.test.ts +103 -0
- package/src/react/component-slots.ts +116 -0
- package/src/react/fields/BuilderInput.tsx +29 -117
- package/src/react/fields/MarkdownInput.tsx +0 -1
- package/src/react/fields/RepeaterInput.tsx +29 -130
- package/src/react/fields/rowState.ts +106 -0
- package/src/react/fields/useRowReorderDnd.ts +78 -0
- package/src/react/index.ts +38 -0
- package/src/react/layouts/SidebarLayout.tsx +39 -28
- package/src/react/layouts/TopbarLayout.tsx +70 -57
- package/src/react/parseRecordEditUrl.test.ts +75 -0
- package/src/react/parseRecordEditUrl.ts +55 -0
- package/src/react/persistedState.ts +40 -0
- package/src/react/schemaRenderer/AlertRenderer.tsx +112 -0
- package/src/react/schemaRenderer/EntryRenderer.tsx +501 -0
- package/src/react/schemaRenderer/SectionRenderer.tsx +120 -0
- package/src/react/schemaRenderer/SimpleElements.tsx +306 -0
- package/src/react/schemaRenderer/TabsRenderer.tsx +62 -0
- package/src/react/schemaRenderer/WizardRenderer.tsx +338 -0
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +177 -0
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +273 -0
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +61 -0
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +43 -0
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +64 -0
- package/src/react/schemaRenderer/action/buttons.tsx +99 -0
- package/src/react/schemaRenderer/action/helpers.ts +140 -0
- package/src/react/schemaRenderer/action/renderAction.tsx +245 -0
- package/src/react/schemaRenderer/columnFormat.ts +65 -0
- package/src/react/schemaRenderer/constants.ts +50 -0
- package/src/react/schemaRenderer/form/FormRenderer.tsx +233 -0
- package/src/react/schemaRenderer/form/renderField.tsx +511 -0
- package/src/react/schemaRenderer/helpers.tsx +81 -0
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +308 -0
- package/src/react/schemaRenderer/table/TableRenderer.tsx +123 -0
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +974 -0
- package/src/react/schemaRenderer/table/filters.tsx +1233 -0
- package/src/react/schemaRenderer/table/formatCell.tsx +264 -0
- package/src/react/schemaRenderer/table/links.tsx +112 -0
- package/src/react/schemaRenderer/table/renderRowActions.tsx +52 -0
- package/src/react/schemaRenderer/table/url.tsx +143 -0
- package/src/routes/globals.ts +154 -0
- package/src/routes/helpers.ts +668 -0
- package/src/routes/pages.ts +173 -0
- package/src/routes/panel.ts +204 -0
- package/src/routes/relations.ts +1219 -0
- package/src/routes/resources.ts +786 -0
- package/src/routes/theme.ts +109 -0
- package/src/routes.test.ts +1 -1
- package/src/routes.ts +64 -3176
- package/src/schema/TableWidget.test.ts +2 -2
- package/src/theme/migrate.test.ts +178 -0
- package/src/vite.test.ts +184 -0
- package/src/vite.ts +26 -4
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M2M relation Action factories — `relationAttach` (header, modal-form
|
|
3
|
+
* picker → POST `_action/relationAttach`), `relationDetach` (row, direct
|
|
4
|
+
* POST to `_detach/:childId`), `relationBulkDetach` (bulk, handler-
|
|
5
|
+
* dispatched).
|
|
6
|
+
*
|
|
7
|
+
* Sibling of `relationCreate / Edit / Delete` for every M2M mode
|
|
8
|
+
* (`belongsToMany`, `morphToMany` (owning polymorphic side),
|
|
9
|
+
* `morphedByMany` (inverse polymorphic side)). All three modes share
|
|
10
|
+
* the same `attach` / `detach` / `sync` accessor surface — the rudder
|
|
11
|
+
* ORM stamps + filters the polymorphic discriminator on the morph
|
|
12
|
+
* variants automatically, so pilotiq's pivot factories are mode-agnostic
|
|
13
|
+
* beyond the visibility gate.
|
|
14
|
+
*
|
|
15
|
+
* All three auto-hide outside any M2M mode so dropping a factory into
|
|
16
|
+
* a non-M2M manager is a no-op (visible=false) instead of a confusing
|
|
17
|
+
* 404.
|
|
18
|
+
*
|
|
19
|
+
* The first and third route through the manager-scoped
|
|
20
|
+
* `_action/:actionName` endpoint (added in routes.ts) so handlers
|
|
21
|
+
* see `ctx.relation = { parent, parentId, relationship }`.
|
|
22
|
+
*
|
|
23
|
+
* See `docs/plans/action-split.md` for the split plan.
|
|
24
|
+
*/
|
|
25
|
+
import { Action } from './Action.js';
|
|
26
|
+
import { safeManagerPolicy, } from '../RelationManager.js';
|
|
27
|
+
import { resolveM2MAccessor } from '../orm/m2mAccessor.js';
|
|
28
|
+
import { buildAttachModalSchema } from './attachFactory.js';
|
|
29
|
+
import { isM2MMode, relationUrlPrefix } from './factoryHelpers.js';
|
|
30
|
+
/** Resolve the M2M accessor on `rel.parent`, null-check the requested
|
|
31
|
+
* method, run it, and shape the per-failure-mode error envelope.
|
|
32
|
+
* Used by `relationAttachAction` and `relationBulkDetachAction` —
|
|
33
|
+
* both follow the same pattern (resolve → null-check method →
|
|
34
|
+
* try/catch). Keeps the "Pivot accessor missing on …" error string
|
|
35
|
+
* consistent across both call sites. */
|
|
36
|
+
async function callM2MAccessor(rel, method, ids, failureLabel) {
|
|
37
|
+
const accessor = resolveM2MAccessor(rel.parent, rel.relationship);
|
|
38
|
+
const fn = accessor?.[method];
|
|
39
|
+
if (typeof fn !== 'function') {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
result: { notify: { title: `Pivot accessor missing on ${rel.relationship} — wrong relation type or ORM version?`, type: 'error' } },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await fn(ids);
|
|
47
|
+
return { ok: true };
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
result: { notify: { title: `${failureLabel}: ${err instanceof Error ? err.message : String(err)}`, type: 'error' } },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Header-placement attach factory — opens a modal with a SelectField
|
|
57
|
+
* listing related records that aren't already attached, and POSTs the
|
|
58
|
+
* selected id to the manager's `_action/relationAttach` endpoint.
|
|
59
|
+
*
|
|
60
|
+
* Visibility delegates to `M.canAttach(user, parentRecord)` AND
|
|
61
|
+
* guards against being dropped into a non-M2M manager. */
|
|
62
|
+
export function relationAttachAction(M, ctx) {
|
|
63
|
+
const labelSingular = M.getLabelSingular();
|
|
64
|
+
const a = Action.make('relationAttach')
|
|
65
|
+
.label(`Attach ${labelSingular}`)
|
|
66
|
+
.header()
|
|
67
|
+
.modalHeading(`Attach ${labelSingular}`)
|
|
68
|
+
.modalSubmitLabel('Attach')
|
|
69
|
+
.modalCancelLabel('Cancel')
|
|
70
|
+
.handler(async (hctx) => {
|
|
71
|
+
const rel = hctx.relation;
|
|
72
|
+
if (!rel) {
|
|
73
|
+
return { notify: { title: 'Attach handler missing parent context — manager-scoped _action route not wired', type: 'error' } };
|
|
74
|
+
}
|
|
75
|
+
const Related = ctx.related;
|
|
76
|
+
if (!Related?.model) {
|
|
77
|
+
return { notify: { title: 'Cannot attach: related Resource has no model', type: 'error' } };
|
|
78
|
+
}
|
|
79
|
+
const idStr = String(hctx.values?.['_attachId'] ?? '');
|
|
80
|
+
if (idStr.length === 0) {
|
|
81
|
+
return { notify: { title: 'Pick a record to attach', type: 'error' } };
|
|
82
|
+
}
|
|
83
|
+
const call = await callM2MAccessor(rel, 'attach', [idStr], 'Attach failed');
|
|
84
|
+
if (!call.ok)
|
|
85
|
+
return call.result;
|
|
86
|
+
return { notify: { title: `${labelSingular} attached`, type: 'success' } };
|
|
87
|
+
})
|
|
88
|
+
.visible(({ user }) => {
|
|
89
|
+
if (!isM2MMode(ctx.mode))
|
|
90
|
+
return false;
|
|
91
|
+
return safeManagerPolicy(M, 'canAttach', ctx.related, user, ctx.parentRecord);
|
|
92
|
+
});
|
|
93
|
+
// Build the modal-form schema only when this is actually an M2M
|
|
94
|
+
// manager — non-M2M drops keep the action hidden via the visibility
|
|
95
|
+
// predicate, but still need a schema-less Action so the meta walker
|
|
96
|
+
// doesn't blow up. Static import is fine: `attachFactory` only
|
|
97
|
+
// depends on `SelectField` + ORM helpers, no cycle back to Action.
|
|
98
|
+
if (isM2MMode(ctx.mode) && ctx.related?.model) {
|
|
99
|
+
a.schema(buildAttachModalSchema({
|
|
100
|
+
Related: ctx.related,
|
|
101
|
+
relationship: ctx.relationship,
|
|
102
|
+
recordTitleAttr: M.getRecordTitleAttribute() ?? ctx.related.recordTitleAttribute,
|
|
103
|
+
labelSingular,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
return a;
|
|
107
|
+
}
|
|
108
|
+
/** Row-placement detach factory — POSTs to
|
|
109
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/_detach`,
|
|
110
|
+
* destructive style with a confirmation prompt that says "Detach"
|
|
111
|
+
* (not "Delete") so users understand the target record stays.
|
|
112
|
+
* Visibility delegates to `M.canDetach`. */
|
|
113
|
+
export function relationDetachAction(M, ctx, recordId) {
|
|
114
|
+
const id = recordId ?? ':id';
|
|
115
|
+
const singular = M.getLabelSingular().toLowerCase();
|
|
116
|
+
return Action.make('relationDetach')
|
|
117
|
+
.label('Detach')
|
|
118
|
+
.destructive()
|
|
119
|
+
.method('post')
|
|
120
|
+
.action(`${relationUrlPrefix(ctx)}/${id}/_detach`)
|
|
121
|
+
.confirm(`Detach this ${singular}? The ${singular} record stays in place; only the link is removed.`)
|
|
122
|
+
.visible(async ({ user, record }) => {
|
|
123
|
+
if (!isM2MMode(ctx.mode))
|
|
124
|
+
return false;
|
|
125
|
+
return safeManagerPolicy(M, 'canDetach', ctx.related, user, ctx.parentRecord, record);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** Bulk-placement bulk-detach factory — handler-dispatched. Calls
|
|
129
|
+
* `parent.related(rel).detach(ids)` for the selected rows. Visibility
|
|
130
|
+
* delegates to `M.canAttach` (acts like a "manager admin" gate; we
|
|
131
|
+
* intentionally don't enforce per-row `canDetach` on the visibility
|
|
132
|
+
* side because the bulk button needs to be visible before the user
|
|
133
|
+
* has selected anything — per-row gating happens inside the handler). */
|
|
134
|
+
export function relationBulkDetachAction(M, ctx) {
|
|
135
|
+
const labelPlural = M.getLabel().toLowerCase();
|
|
136
|
+
return Action.make('relationBulkDetach')
|
|
137
|
+
.label('Detach selected')
|
|
138
|
+
.destructive()
|
|
139
|
+
.bulk()
|
|
140
|
+
.confirm(`Detach the selected ${labelPlural}? The records stay in place; only the links are removed.`)
|
|
141
|
+
.handler(async (hctx) => {
|
|
142
|
+
const rel = hctx.relation;
|
|
143
|
+
if (!rel) {
|
|
144
|
+
return { notify: { title: 'Bulk-detach handler missing parent context — manager-scoped _action route not wired', type: 'error' } };
|
|
145
|
+
}
|
|
146
|
+
const records = hctx.records ?? [];
|
|
147
|
+
// Parallelize the per-row policy probes; the accessor call itself stays a single batched op.
|
|
148
|
+
const allowedFlags = await Promise.all(records.map(r => safeManagerPolicy(M, 'canDetach', ctx.related, hctx.user, ctx.parentRecord, r)));
|
|
149
|
+
const ids = [];
|
|
150
|
+
for (let i = 0; i < records.length; i++) {
|
|
151
|
+
if (!allowedFlags[i])
|
|
152
|
+
continue;
|
|
153
|
+
const id = String(records[i].id ?? '');
|
|
154
|
+
if (id)
|
|
155
|
+
ids.push(id);
|
|
156
|
+
}
|
|
157
|
+
if (ids.length === 0) {
|
|
158
|
+
return { notify: { title: 'Nothing to detach (no permitted rows)', type: 'warning' } };
|
|
159
|
+
}
|
|
160
|
+
const call = await callM2MAccessor(rel, 'detach', ids, 'Bulk detach failed');
|
|
161
|
+
if (!call.ok)
|
|
162
|
+
return call.result;
|
|
163
|
+
return { notify: { title: `${ids.length} ${labelPlural} detached`, type: 'success' } };
|
|
164
|
+
})
|
|
165
|
+
.visible(({ user }) => {
|
|
166
|
+
if (!isM2MMode(ctx.mode))
|
|
167
|
+
return false;
|
|
168
|
+
// Bulk gate uses canAttach as a stand-in for "manager admin" —
|
|
169
|
+
// per-row canDetach is enforced inside the handler.
|
|
170
|
+
return safeManagerPolicy(M, 'canAttach', ctx.related, user, ctx.parentRecord);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=m2mFactories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"m2mFactories.js","sourceRoot":"","sources":["../../src/actions/m2mFactories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation-manager Action factories — `relationCreate / relationEdit /
|
|
3
|
+
* relationDelete / relationRestore / relationForceDelete` (hasMany +
|
|
4
|
+
* morphMany) and `relationReplicate / relationBulkReplicate` (clone
|
|
5
|
+
* with force-pinned parent attachment).
|
|
6
|
+
*
|
|
7
|
+
* Designed to be called inside `RelationManager.static table()` — the
|
|
8
|
+
* page-data builder pipes `RelationManagerContext` into that
|
|
9
|
+
* configurator so users get `basePath`, `parentId`, and the discovered
|
|
10
|
+
* Related resource without threading them by hand.
|
|
11
|
+
*
|
|
12
|
+
* Visibility predicates use `safeManagerPolicy` so the manager's
|
|
13
|
+
* `canX` (when overridden) wins, otherwise falls through to the
|
|
14
|
+
* related Resource's `canX`. Throws absorb as `false`.
|
|
15
|
+
*
|
|
16
|
+
* M2M factories (`relationAttach / relationDetach / relationBulkDetach`)
|
|
17
|
+
* live in `m2mFactories.ts`.
|
|
18
|
+
*
|
|
19
|
+
* See `docs/plans/action-split.md` for the split plan.
|
|
20
|
+
*/
|
|
21
|
+
import { Action, type ReplicateOptions } from './Action.js';
|
|
22
|
+
import { type RelationManager, type RelationManagerContext } from '../RelationManager.js';
|
|
23
|
+
/** Relation create-action factory — link to
|
|
24
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/create`.
|
|
25
|
+
*
|
|
26
|
+
* Visibility delegates to `M.canCreate(user, parentRecord)` (or the
|
|
27
|
+
* related Resource's `canCreate(user)` when the manager hasn't
|
|
28
|
+
* overridden). Drop into `headerActions([...])` from inside
|
|
29
|
+
* `RelationManager.table(table, ctx)`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function relationCreateAction(M: typeof RelationManager, ctx: RelationManagerContext): Action;
|
|
32
|
+
/** Relation edit-action factory — link to
|
|
33
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/edit`.
|
|
34
|
+
*
|
|
35
|
+
* Same `recordId` semantics as `editAction`: omit for row context
|
|
36
|
+
* so the renderer substitutes `:id` per row; pass explicitly when
|
|
37
|
+
* building actions for a single-record context. Visibility delegates
|
|
38
|
+
* to `M.canEdit(user, child, parentRecord)` with fall-through to the
|
|
39
|
+
* related Resource's `canEdit(user, record)`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function relationEditAction(M: typeof RelationManager, ctx: RelationManagerContext, recordId?: string): Action;
|
|
42
|
+
/** Relation delete-action factory — POST to
|
|
43
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/delete`,
|
|
44
|
+
* destructive style with a labeled confirmation. Visibility delegates
|
|
45
|
+
* to `M.canDelete(user, child, parentRecord)` with fall-through to the
|
|
46
|
+
* related Resource's `canDelete(user, record)`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function relationDeleteAction(M: typeof RelationManager, ctx: RelationManagerContext, recordId?: string): Action;
|
|
49
|
+
/**
|
|
50
|
+
* Plan #13 polish — Restore factory for relation managers. POSTs to
|
|
51
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/restore`,
|
|
52
|
+
* success-styled, no confirm prompt. Auto-hides on live (non-trashed)
|
|
53
|
+
* rows AND when `M.canRestore` (or related Resource fall-through)
|
|
54
|
+
* denies. Drop into `recordActions([...])` from `RelationManager.table(table, ctx)`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function relationRestoreAction(M: typeof RelationManager, ctx: RelationManagerContext, recordId?: string): Action;
|
|
57
|
+
/**
|
|
58
|
+
* Plan #13 polish — Force-delete factory for relation managers. POSTs
|
|
59
|
+
* to `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/force-delete`,
|
|
60
|
+
* destructive style with a permanence-aware confirmation. Auto-hides on
|
|
61
|
+
* live (non-trashed) rows and when policy denies.
|
|
62
|
+
*/
|
|
63
|
+
export declare function relationForceDeleteAction(M: typeof RelationManager, ctx: RelationManagerContext, recordId?: string): Action;
|
|
64
|
+
/**
|
|
65
|
+
* Relation row-replicate factory. Clones the row's child record
|
|
66
|
+
* inside the manager's parent scope.
|
|
67
|
+
*
|
|
68
|
+
* Strips the related model's primary key, soft-delete column, and
|
|
69
|
+
* `opts.excludeAttributes`. Re-applies the parent attachment columns
|
|
70
|
+
* after the strip + before the optional `beforeReplicaSaved` hook,
|
|
71
|
+
* so user code can still mutate non-FK fields without accidentally
|
|
72
|
+
* unlinking the replica.
|
|
73
|
+
*
|
|
74
|
+
* On success the manager-scoped route falls back to the manager
|
|
75
|
+
* list URL (`${base}/${parentSlug}/${parentId}/${relationship}`)
|
|
76
|
+
* because no explicit `redirect` is returned — same default as the
|
|
77
|
+
* other handler-style relation factories.
|
|
78
|
+
*
|
|
79
|
+
* `recordId` kept in the signature for parity with the rest of the
|
|
80
|
+
* relation factory family. The dispatcher resolves the source row
|
|
81
|
+
* from the request body, so it isn't referenced here.
|
|
82
|
+
*/
|
|
83
|
+
export declare function relationReplicateAction(M: typeof RelationManager, ctx: RelationManagerContext, recordId?: string, opts?: ReplicateOptions): Action;
|
|
84
|
+
/**
|
|
85
|
+
* Bulk sibling — replicates every selected child row inside the
|
|
86
|
+
* manager's parent scope. Same strip + force-pin pipeline applied
|
|
87
|
+
* per row. Per-row `safeManagerPolicy(M, 'canCreate', …)` runs
|
|
88
|
+
* inside the loop so a partially-permitted selection still proceeds
|
|
89
|
+
* for the rows that pass. Rows that throw are skipped silently —
|
|
90
|
+
* the toast count reflects only successful creates.
|
|
91
|
+
*/
|
|
92
|
+
export declare function relationBulkReplicateAction(M: typeof RelationManager, ctx: RelationManagerContext, opts?: ReplicateOptions): Action;
|
|
93
|
+
//# sourceMappingURL=relationFactories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationFactories.d.ts","sourceRoot":"","sources":["../../src/actions/relationFactories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,MAAM,EAGN,KAAK,gBAAgB,EAEtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAA;AAqH9B;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAI,OAAO,eAAe,EAC3B,GAAG,EAAE,sBAAsB,GAC1B,MAAM,CAcR;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,EAAS,OAAO,eAAe,EAChC,GAAG,EAAO,sBAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAYR;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAS,OAAO,eAAe,EAChC,GAAG,EAAO,sBAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAmBR;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,EAAS,OAAO,eAAe,EAChC,GAAG,EAAO,sBAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAYR;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,CAAC,EAAS,OAAO,eAAe,EAChC,GAAG,EAAO,sBAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAcR;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,CAAC,EAAS,OAAO,eAAe,EAChC,GAAG,EAAO,sBAAsB,EAChC,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,GAAM,gBAAqB,GAC9B,MAAM,CAaR;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,CAAC,EAAK,OAAO,eAAe,EAC5B,GAAG,EAAG,sBAAsB,EAC5B,IAAI,GAAE,gBAAqB,GAC1B,MAAM,CAmCR"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation-manager Action factories — `relationCreate / relationEdit /
|
|
3
|
+
* relationDelete / relationRestore / relationForceDelete` (hasMany +
|
|
4
|
+
* morphMany) and `relationReplicate / relationBulkReplicate` (clone
|
|
5
|
+
* with force-pinned parent attachment).
|
|
6
|
+
*
|
|
7
|
+
* Designed to be called inside `RelationManager.static table()` — the
|
|
8
|
+
* page-data builder pipes `RelationManagerContext` into that
|
|
9
|
+
* configurator so users get `basePath`, `parentId`, and the discovered
|
|
10
|
+
* Related resource without threading them by hand.
|
|
11
|
+
*
|
|
12
|
+
* Visibility predicates use `safeManagerPolicy` so the manager's
|
|
13
|
+
* `canX` (when overridden) wins, otherwise falls through to the
|
|
14
|
+
* related Resource's `canX`. Throws absorb as `false`.
|
|
15
|
+
*
|
|
16
|
+
* M2M factories (`relationAttach / relationDetach / relationBulkDetach`)
|
|
17
|
+
* live in `m2mFactories.ts`.
|
|
18
|
+
*
|
|
19
|
+
* See `docs/plans/action-split.md` for the split plan.
|
|
20
|
+
*/
|
|
21
|
+
import { Action, } from './Action.js';
|
|
22
|
+
import { safeManagerPolicy, } from '../RelationManager.js';
|
|
23
|
+
import { computeMorphPayload, getMorphRelationDescriptor, getParentRelationDescriptor, } from '../orm/modelDefaults.js';
|
|
24
|
+
import { buildReplica, forEachAllowed, isM2MMode, isTrashed, relationUrlPrefix } from './factoryHelpers.js';
|
|
25
|
+
/**
|
|
26
|
+
* Compute the parent-attachment payload to force-pin onto a relation
|
|
27
|
+
* replica. For `hasMany`, returns `{ [foreignKey]: parentId }` from the
|
|
28
|
+
* parent's `static relations[name]` descriptor. For `morphMany` /
|
|
29
|
+
* `morphOne`, returns `{ <morphName>Id, <morphName>Type }` via
|
|
30
|
+
* `computeMorphPayload(parentRecord)`. Returns `{}` when no descriptor
|
|
31
|
+
* matches — the route dispatcher already auto-hides under M2M / morphTo,
|
|
32
|
+
* so missing descriptors there are a no-op rather than an error. Pure;
|
|
33
|
+
* exported for tests and re-used by both factories.
|
|
34
|
+
*/
|
|
35
|
+
function computeRelationPin(ctx) {
|
|
36
|
+
const parentModel = ctx.parentRecord?.constructor;
|
|
37
|
+
if (!parentModel)
|
|
38
|
+
return {};
|
|
39
|
+
const rel = ctx.relationship;
|
|
40
|
+
// Polymorphic owner side first — `morphMany` carries no foreignKey
|
|
41
|
+
// and would fail the hasMany descriptor's gate.
|
|
42
|
+
if (ctx.mode === 'morphMany') {
|
|
43
|
+
const morph = getMorphRelationDescriptor(parentModel, rel);
|
|
44
|
+
if (!morph)
|
|
45
|
+
return {};
|
|
46
|
+
try {
|
|
47
|
+
return computeMorphPayload(ctx.parentRecord, morph);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const desc = getParentRelationDescriptor(parentModel, rel);
|
|
54
|
+
if (!desc)
|
|
55
|
+
return {};
|
|
56
|
+
return { [desc.foreignKey]: ctx.parentId };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build + persist a single relation replica. Runs the strip set
|
|
60
|
+
* (PK + soft-delete column on the **related** Resource +
|
|
61
|
+
* `opts.excludeAttributes`), force-pins the parent attachment columns,
|
|
62
|
+
* runs the optional `beforeReplicaSaved` hook, and calls
|
|
63
|
+
* `Related.model.create(...)`. Returns the model's create result so
|
|
64
|
+
* callers can read its primary key for redirect targeting.
|
|
65
|
+
*
|
|
66
|
+
* Throws when the related Resource has no model — caller (single-row
|
|
67
|
+
* factory) catches and surfaces an error notification; bulk caller
|
|
68
|
+
* checks the model presence ahead of the loop.
|
|
69
|
+
*/
|
|
70
|
+
async function persistRelationReplica(_M, ctx, source, opts) {
|
|
71
|
+
const Related = ctx.related;
|
|
72
|
+
if (!Related?.model || typeof Related.model.create !== 'function') {
|
|
73
|
+
throw new Error('Related Resource has no model.create');
|
|
74
|
+
}
|
|
75
|
+
const M2 = Related.model;
|
|
76
|
+
// Force-pin the parent attachment via `pin` so `beforeReplicaSaved` can
|
|
77
|
+
// still read / override the FK if it really wants to (rare); tampered
|
|
78
|
+
// source rows can't slip a different parent in by riding their own FK
|
|
79
|
+
// column — the pin overwrites whatever value was there.
|
|
80
|
+
const { replica } = await buildReplica(source, M2, {
|
|
81
|
+
excludeAttributes: opts.excludeAttributes,
|
|
82
|
+
deletedAtColumn: Related.deletedAtColumn,
|
|
83
|
+
pin: computeRelationPin(ctx),
|
|
84
|
+
beforeReplicaSaved: opts.beforeReplicaSaved,
|
|
85
|
+
});
|
|
86
|
+
return M2.create(replica);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Single-row dispatch for `relationReplicateAction`. Resolves
|
|
90
|
+
* `ctx.record` (loaded by the route's resolveRecord hook), validates,
|
|
91
|
+
* persists the replica, and shapes the success notification. Errors
|
|
92
|
+
* are caught and surfaced as error toasts.
|
|
93
|
+
*/
|
|
94
|
+
async function runRelationReplicateRow(M, ctx, hctx, opts) {
|
|
95
|
+
const source = hctx.record;
|
|
96
|
+
if (!source || typeof source !== 'object') {
|
|
97
|
+
return { notify: { title: 'Replicate failed: source record missing', type: 'error' } };
|
|
98
|
+
}
|
|
99
|
+
const Related = ctx.related;
|
|
100
|
+
if (!Related?.model || typeof Related.model.create !== 'function') {
|
|
101
|
+
return { notify: { title: 'Replicate not configured (related Resource has no model.create)', type: 'error' } };
|
|
102
|
+
}
|
|
103
|
+
let created;
|
|
104
|
+
try {
|
|
105
|
+
created = await persistRelationReplica(M, ctx, source, opts);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return { notify: { title: `Replicate failed: ${err instanceof Error ? err.message : String(err)}`, type: 'error' } };
|
|
109
|
+
}
|
|
110
|
+
const overrideTitle = opts.getCreatedNotificationTitle
|
|
111
|
+
? await opts.getCreatedNotificationTitle({ replica: created, source })
|
|
112
|
+
: undefined;
|
|
113
|
+
const title = overrideTitle !== undefined ? overrideTitle : `${M.getLabelSingular()} replicated`;
|
|
114
|
+
// The manager-scoped `_action/:actionName` route falls back to the
|
|
115
|
+
// manager list URL when `result.redirect` is undefined, so we only
|
|
116
|
+
// emit `redirect` when the user override returned a string. That
|
|
117
|
+
// way default behavior (route owns the fallback) is unchanged.
|
|
118
|
+
const overrideRedirect = opts.getRedirectUrl
|
|
119
|
+
? await opts.getRedirectUrl({ replica: created, source })
|
|
120
|
+
: undefined;
|
|
121
|
+
return {
|
|
122
|
+
...(overrideRedirect !== undefined ? { redirect: overrideRedirect } : {}),
|
|
123
|
+
notify: { title, type: 'success' },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Relation create-action factory — link to
|
|
127
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/create`.
|
|
128
|
+
*
|
|
129
|
+
* Visibility delegates to `M.canCreate(user, parentRecord)` (or the
|
|
130
|
+
* related Resource's `canCreate(user)` when the manager hasn't
|
|
131
|
+
* overridden). Drop into `headerActions([...])` from inside
|
|
132
|
+
* `RelationManager.table(table, ctx)`.
|
|
133
|
+
*/
|
|
134
|
+
export function relationCreateAction(M, ctx) {
|
|
135
|
+
const labelSingular = M.getLabelSingular();
|
|
136
|
+
return Action.make('create')
|
|
137
|
+
.label(`New ${labelSingular}`)
|
|
138
|
+
.href(`${relationUrlPrefix(ctx)}/create`)
|
|
139
|
+
.visible(({ user }) => {
|
|
140
|
+
// M2M managers don't have a per-pivot-row create surface — the
|
|
141
|
+
// related record is created via its own Resource, then attached
|
|
142
|
+
// via `relationAttach`. Auto-hide so dropping this factory into
|
|
143
|
+
// any M2M manager (belongsToMany / morphToMany / morphedByMany)
|
|
144
|
+
// is a no-op (visible=false) instead of a 404-on-click foot-gun.
|
|
145
|
+
if (isM2MMode(ctx.mode))
|
|
146
|
+
return false;
|
|
147
|
+
return safeManagerPolicy(M, 'canCreate', ctx.related, user, ctx.parentRecord);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Relation edit-action factory — link to
|
|
151
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/edit`.
|
|
152
|
+
*
|
|
153
|
+
* Same `recordId` semantics as `editAction`: omit for row context
|
|
154
|
+
* so the renderer substitutes `:id` per row; pass explicitly when
|
|
155
|
+
* building actions for a single-record context. Visibility delegates
|
|
156
|
+
* to `M.canEdit(user, child, parentRecord)` with fall-through to the
|
|
157
|
+
* related Resource's `canEdit(user, record)`.
|
|
158
|
+
*/
|
|
159
|
+
export function relationEditAction(M, ctx, recordId) {
|
|
160
|
+
const id = recordId ?? ':id';
|
|
161
|
+
return Action.make('edit')
|
|
162
|
+
.label('Edit')
|
|
163
|
+
.href(`${relationUrlPrefix(ctx)}/${id}/edit`)
|
|
164
|
+
.visible(({ user, record }) => {
|
|
165
|
+
// M2M: per-pivot-row "edit" doesn't exist; users edit the
|
|
166
|
+
// related record via its own Resource. Auto-hide for every M2M
|
|
167
|
+
// mode (belongsToMany / morphToMany / morphedByMany).
|
|
168
|
+
if (isM2MMode(ctx.mode))
|
|
169
|
+
return false;
|
|
170
|
+
return safeManagerPolicy(M, 'canEdit', ctx.related, user, ctx.parentRecord, record);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/** Relation delete-action factory — POST to
|
|
174
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/delete`,
|
|
175
|
+
* destructive style with a labeled confirmation. Visibility delegates
|
|
176
|
+
* to `M.canDelete(user, child, parentRecord)` with fall-through to the
|
|
177
|
+
* related Resource's `canDelete(user, record)`.
|
|
178
|
+
*/
|
|
179
|
+
export function relationDeleteAction(M, ctx, recordId) {
|
|
180
|
+
const id = recordId ?? ':id';
|
|
181
|
+
const singular = M.getLabelSingular().toLowerCase();
|
|
182
|
+
return Action.make('delete')
|
|
183
|
+
.label('Delete')
|
|
184
|
+
.destructive()
|
|
185
|
+
.method('post')
|
|
186
|
+
.action(`${relationUrlPrefix(ctx)}/${id}/delete`)
|
|
187
|
+
.confirm(`Delete this ${singular}?`)
|
|
188
|
+
.visible(async ({ user, record }) => {
|
|
189
|
+
// M2M: "delete" of the related record is destructive in a way
|
|
190
|
+
// that "detach" isn't — surface only `relationDetach` on every
|
|
191
|
+
// M2M manager (belongsToMany / morphToMany / morphedByMany).
|
|
192
|
+
// Users who genuinely want to delete the related record reach
|
|
193
|
+
// for `Action.delete(R)` on the related Resource instead.
|
|
194
|
+
if (isM2MMode(ctx.mode))
|
|
195
|
+
return false;
|
|
196
|
+
if (ctx.related?.softDeletes && isTrashed(record, ctx.related))
|
|
197
|
+
return false;
|
|
198
|
+
return safeManagerPolicy(M, 'canDelete', ctx.related, user, ctx.parentRecord, record);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Plan #13 polish — Restore factory for relation managers. POSTs to
|
|
203
|
+
* `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/restore`,
|
|
204
|
+
* success-styled, no confirm prompt. Auto-hides on live (non-trashed)
|
|
205
|
+
* rows AND when `M.canRestore` (or related Resource fall-through)
|
|
206
|
+
* denies. Drop into `recordActions([...])` from `RelationManager.table(table, ctx)`.
|
|
207
|
+
*/
|
|
208
|
+
export function relationRestoreAction(M, ctx, recordId) {
|
|
209
|
+
const id = recordId ?? ':id';
|
|
210
|
+
return Action.make('restore')
|
|
211
|
+
.label('Restore')
|
|
212
|
+
.color('success')
|
|
213
|
+
.method('post')
|
|
214
|
+
.action(`${relationUrlPrefix(ctx)}/${id}/restore`)
|
|
215
|
+
.visible(async ({ user, record }) => {
|
|
216
|
+
if (!ctx.related?.softDeletes)
|
|
217
|
+
return false;
|
|
218
|
+
if (!isTrashed(record, ctx.related))
|
|
219
|
+
return false;
|
|
220
|
+
return safeManagerPolicy(M, 'canRestore', ctx.related, user, ctx.parentRecord, record);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Plan #13 polish — Force-delete factory for relation managers. POSTs
|
|
225
|
+
* to `${base}/${parentSlug}/${parentId}/${relationship}/${recordId ?? ':id'}/force-delete`,
|
|
226
|
+
* destructive style with a permanence-aware confirmation. Auto-hides on
|
|
227
|
+
* live (non-trashed) rows and when policy denies.
|
|
228
|
+
*/
|
|
229
|
+
export function relationForceDeleteAction(M, ctx, recordId) {
|
|
230
|
+
const id = recordId ?? ':id';
|
|
231
|
+
const singular = M.getLabelSingular().toLowerCase();
|
|
232
|
+
return Action.make('forceDelete')
|
|
233
|
+
.label('Delete forever')
|
|
234
|
+
.destructive()
|
|
235
|
+
.method('post')
|
|
236
|
+
.action(`${relationUrlPrefix(ctx)}/${id}/force-delete`)
|
|
237
|
+
.confirm(`Permanently delete this ${singular}? This cannot be undone.`)
|
|
238
|
+
.visible(async ({ user, record }) => {
|
|
239
|
+
if (!ctx.related?.softDeletes)
|
|
240
|
+
return false;
|
|
241
|
+
if (!isTrashed(record, ctx.related))
|
|
242
|
+
return false;
|
|
243
|
+
return safeManagerPolicy(M, 'canForceDelete', ctx.related, user, ctx.parentRecord, record);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Relation row-replicate factory. Clones the row's child record
|
|
248
|
+
* inside the manager's parent scope.
|
|
249
|
+
*
|
|
250
|
+
* Strips the related model's primary key, soft-delete column, and
|
|
251
|
+
* `opts.excludeAttributes`. Re-applies the parent attachment columns
|
|
252
|
+
* after the strip + before the optional `beforeReplicaSaved` hook,
|
|
253
|
+
* so user code can still mutate non-FK fields without accidentally
|
|
254
|
+
* unlinking the replica.
|
|
255
|
+
*
|
|
256
|
+
* On success the manager-scoped route falls back to the manager
|
|
257
|
+
* list URL (`${base}/${parentSlug}/${parentId}/${relationship}`)
|
|
258
|
+
* because no explicit `redirect` is returned — same default as the
|
|
259
|
+
* other handler-style relation factories.
|
|
260
|
+
*
|
|
261
|
+
* `recordId` kept in the signature for parity with the rest of the
|
|
262
|
+
* relation factory family. The dispatcher resolves the source row
|
|
263
|
+
* from the request body, so it isn't referenced here.
|
|
264
|
+
*/
|
|
265
|
+
export function relationReplicateAction(M, ctx, recordId, opts = {}) {
|
|
266
|
+
void recordId;
|
|
267
|
+
return Action.make('relationReplicate')
|
|
268
|
+
.label('Replicate')
|
|
269
|
+
.row()
|
|
270
|
+
.handler(async (hctx) => {
|
|
271
|
+
const result = await runRelationReplicateRow(M, ctx, hctx, opts);
|
|
272
|
+
return result;
|
|
273
|
+
})
|
|
274
|
+
.visible(({ user }) => {
|
|
275
|
+
if (isM2MMode(ctx.mode) || ctx.mode === 'morphTo')
|
|
276
|
+
return false;
|
|
277
|
+
return safeManagerPolicy(M, 'canCreate', ctx.related, user, ctx.parentRecord);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Bulk sibling — replicates every selected child row inside the
|
|
282
|
+
* manager's parent scope. Same strip + force-pin pipeline applied
|
|
283
|
+
* per row. Per-row `safeManagerPolicy(M, 'canCreate', …)` runs
|
|
284
|
+
* inside the loop so a partially-permitted selection still proceeds
|
|
285
|
+
* for the rows that pass. Rows that throw are skipped silently —
|
|
286
|
+
* the toast count reflects only successful creates.
|
|
287
|
+
*/
|
|
288
|
+
export function relationBulkReplicateAction(M, ctx, opts = {}) {
|
|
289
|
+
const labelPlural = M.getLabel().toLowerCase();
|
|
290
|
+
const labelSingular = M.getLabelSingular().toLowerCase();
|
|
291
|
+
return Action.make('relationBulkReplicate')
|
|
292
|
+
.label('Replicate selected')
|
|
293
|
+
.bulk()
|
|
294
|
+
.confirm(`Replicate the selected ${labelPlural}?`)
|
|
295
|
+
.handler(async (hctx) => {
|
|
296
|
+
const Related = ctx.related;
|
|
297
|
+
if (!Related?.model || typeof Related.model.create !== 'function') {
|
|
298
|
+
return { notify: { title: 'Replicate not configured (related Resource has no model.create)', type: 'error' } };
|
|
299
|
+
}
|
|
300
|
+
const records = hctx.records ?? [];
|
|
301
|
+
// Per-row predicate eval preserved — users may write stateful predicates that gate per-attempt.
|
|
302
|
+
const n = await forEachAllowed(records, () => safeManagerPolicy(M, 'canCreate', Related, hctx.user, ctx.parentRecord), async (_id, source) => { await persistRelationReplica(M, ctx, source, opts); });
|
|
303
|
+
if (n === 0) {
|
|
304
|
+
return { notify: { title: `Nothing to replicate (no permitted rows)`, type: 'warning' } };
|
|
305
|
+
}
|
|
306
|
+
const defaultTitle = `${n} ${n === 1 ? labelSingular : labelPlural} replicated`;
|
|
307
|
+
const overrideTitle = opts.getCreatedNotificationTitle
|
|
308
|
+
? await opts.getCreatedNotificationTitle({ count: n, records })
|
|
309
|
+
: undefined;
|
|
310
|
+
const title = overrideTitle !== undefined ? overrideTitle : defaultTitle;
|
|
311
|
+
return {
|
|
312
|
+
notify: { title, type: 'success' },
|
|
313
|
+
};
|
|
314
|
+
})
|
|
315
|
+
.visible(({ user }) => {
|
|
316
|
+
if (isM2MMode(ctx.mode) || ctx.mode === 'morphTo')
|
|
317
|
+
return false;
|
|
318
|
+
return safeManagerPolicy(M, 'canCreate', ctx.related, user, ctx.parentRecord);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=relationFactories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationFactories.js","sourceRoot":"","sources":["../../src/actions/relationFactories.ts"],"names":[],"mappings":"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"}
|
|
@@ -1490,7 +1490,7 @@ async function persistRelationshipRows(parent, deferral, parentModel) {
|
|
|
1490
1490
|
await afterUpdate(updatedRecord, buildRowCtx(idx));
|
|
1491
1491
|
}
|
|
1492
1492
|
else {
|
|
1493
|
-
let createdRecord
|
|
1493
|
+
let createdRecord;
|
|
1494
1494
|
if (attachment.kind === 'hasMany') {
|
|
1495
1495
|
payload[attachment.foreignKey] = parentPk;
|
|
1496
1496
|
createdRecord = await model.create(payload);
|