@cosmicdrift/kumiko-renderer 0.388.0 → 0.390.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/dist/app/base-path-context.d.ts +9 -0
- package/dist/app/base-path-context.js +13 -0
- package/dist/app/base-path.d.ts +3 -0
- package/dist/app/base-path.js +27 -0
- package/dist/app/config-edit-body.d.ts +1 -1
- package/dist/app/config-edit-body.js +15 -6
- package/dist/app/config-edit-without-secret-fields.d.ts +2 -0
- package/dist/app/config-edit-without-secret-fields.js +28 -0
- package/dist/app/entity-list-facet-specs.d.ts +3 -0
- package/dist/app/entity-list-facet-specs.js +65 -0
- package/dist/app/entity-list-screen.js +74 -206
- package/dist/app/kumiko-screen.js +6 -14
- package/dist/app/list-bulk-actions.d.ts +18 -0
- package/dist/app/list-bulk-actions.js +54 -0
- package/dist/app/locked-screen-header.d.ts +9 -0
- package/dist/app/locked-screen-header.js +33 -0
- package/dist/app/projection-detail-body.js +59 -394
- package/dist/app/projection-detail-header-model.d.ts +11 -0
- package/dist/app/projection-detail-header-model.js +33 -0
- package/dist/app/projection-detail-header-region.d.ts +28 -0
- package/dist/app/projection-detail-header-region.js +81 -0
- package/dist/app/projection-detail-header.d.ts +29 -0
- package/dist/app/projection-detail-header.js +84 -0
- package/dist/app/projection-detail-navigation.d.ts +13 -0
- package/dist/app/projection-detail-navigation.js +91 -0
- package/dist/app/projection-detail-states.d.ts +22 -0
- package/dist/app/projection-detail-states.js +26 -0
- package/dist/app/projection-drawer-host.d.ts +12 -0
- package/dist/app/projection-drawer-host.js +10 -0
- package/dist/app/projection-list-body.d.ts +1 -1
- package/dist/app/projection-list-body.js +82 -197
- package/dist/app/projection-list-render-props.d.ts +56 -0
- package/dist/app/projection-list-render-props.js +47 -0
- package/dist/app/projection-list-render.d.ts +26 -0
- package/dist/app/projection-list-render.js +20 -0
- package/dist/app/projection-list-row-click.d.ts +12 -0
- package/dist/app/projection-list-row-click.js +14 -0
- package/dist/app/row-actions.d.ts +3 -0
- package/dist/app/row-actions.js +10 -5
- package/dist/app/screen-shared.js +9 -2
- package/dist/app/use-entity-range-facets.d.ts +24 -0
- package/dist/app/use-entity-range-facets.js +64 -0
- package/dist/app/use-projection-date-range.d.ts +12 -0
- package/dist/app/use-projection-date-range.js +21 -0
- package/dist/app/use-projection-detail-actions.d.ts +35 -0
- package/dist/app/use-projection-detail-actions.js +156 -0
- package/dist/app/use-projection-detail-data.d.ts +19 -0
- package/dist/app/use-projection-detail-data.js +47 -0
- package/dist/app/use-projection-detail-layout.d.ts +17 -0
- package/dist/app/use-projection-detail-layout.js +23 -0
- package/dist/app/use-projection-list-actions.d.ts +31 -0
- package/dist/app/use-projection-list-actions.js +73 -0
- package/dist/app/use-projection-list-data.d.ts +20 -0
- package/dist/app/use-projection-list-data.js +26 -0
- package/dist/app/use-projection-list-definitions.d.ts +11 -0
- package/dist/app/use-projection-list-definitions.js +20 -0
- package/dist/app/use-projection-list-query.d.ts +28 -0
- package/dist/app/use-projection-list-query.js +83 -0
- package/dist/app/use-screen-list-rows.d.ts +37 -0
- package/dist/app/use-screen-list-rows.js +104 -0
- package/dist/app/use-screen-list-table.d.ts +24 -0
- package/dist/app/use-screen-list-table.js +46 -0
- package/dist/components/list-group-page-bridges.d.ts +3 -0
- package/dist/components/list-group-page-bridges.js +31 -0
- package/dist/components/list-state-store.d.ts +16 -0
- package/dist/components/list-state-store.js +31 -0
- package/dist/components/related-list-section.js +37 -89
- package/dist/components/render-edit-banners.d.ts +12 -0
- package/dist/components/render-edit-banners.js +90 -0
- package/dist/components/render-edit-draft-save-helpers.d.ts +19 -0
- package/dist/components/render-edit-draft-save-helpers.js +42 -0
- package/dist/components/render-edit-field-grid.d.ts +4 -0
- package/dist/components/render-edit-field-grid.js +40 -0
- package/dist/components/render-edit-fields-section.d.ts +4 -0
- package/dist/components/render-edit-fields-section.js +76 -0
- package/dist/components/render-edit-form-actions.d.ts +4 -0
- package/dist/components/render-edit-form-actions.js +66 -0
- package/dist/components/render-edit-header-actions.d.ts +11 -0
- package/dist/components/render-edit-header-actions.js +120 -0
- package/dist/components/render-edit-layout-flags.d.ts +29 -0
- package/dist/components/render-edit-layout-flags.js +106 -0
- package/dist/components/render-edit-layout.d.ts +4 -0
- package/dist/components/render-edit-layout.js +79 -0
- package/dist/components/render-edit-render-model.d.ts +63 -0
- package/dist/components/render-edit-render-model.js +14 -0
- package/dist/components/render-edit-section-kinds.d.ts +4 -0
- package/dist/components/render-edit-section-kinds.js +115 -0
- package/dist/components/render-edit-submit-result.d.ts +8 -0
- package/dist/components/render-edit-submit-result.js +77 -0
- package/dist/components/render-edit-submit.d.ts +7 -0
- package/dist/components/render-edit-submit.js +113 -0
- package/dist/components/render-edit-titles.d.ts +17 -0
- package/dist/components/render-edit-titles.js +99 -0
- package/dist/components/render-edit-wizard-navigation.d.ts +11 -0
- package/dist/components/render-edit-wizard-navigation.js +115 -0
- package/dist/components/render-edit.d.ts +2 -2
- package/dist/components/render-edit.js +63 -1128
- package/dist/components/render-field-choice-inputs.d.ts +7 -0
- package/dist/components/render-field-choice-inputs.js +52 -0
- package/dist/components/render-field-control.d.ts +12 -0
- package/dist/components/render-field-control.js +93 -0
- package/dist/components/render-field-display-text.d.ts +4 -0
- package/dist/components/render-field-display-text.js +48 -0
- package/dist/components/render-field-fill-action.d.ts +13 -0
- package/dist/components/render-field-fill-action.js +63 -0
- package/dist/components/render-field-input-shared.d.ts +39 -0
- package/dist/components/render-field-input-shared.js +20 -0
- package/dist/components/render-field-input.d.ts +3 -0
- package/dist/components/render-field-input.js +34 -0
- package/dist/components/render-field-meta.d.ts +6 -0
- package/dist/components/render-field-meta.js +51 -0
- package/dist/components/render-field-read-only.d.ts +11 -0
- package/dist/components/render-field-read-only.js +75 -0
- package/dist/components/render-field-reference.d.ts +15 -0
- package/dist/components/render-field-reference.js +103 -0
- package/dist/components/render-field-scalar-inputs.d.ts +10 -0
- package/dist/components/render-field-scalar-inputs.js +35 -0
- package/dist/components/render-field-text-inputs.d.ts +3 -0
- package/dist/components/render-field-text-inputs.js +34 -0
- package/dist/components/render-field-values.d.ts +18 -0
- package/dist/components/render-field-values.js +111 -0
- package/dist/components/render-field-write-only.d.ts +9 -0
- package/dist/components/render-field-write-only.js +29 -0
- package/dist/components/render-field.d.ts +2 -2
- package/dist/components/render-field.js +39 -669
- package/dist/components/render-list-header-slot.d.ts +5 -0
- package/dist/components/render-list-header-slot.js +30 -0
- package/dist/components/render-list-reference-bridge.d.ts +3 -0
- package/dist/components/render-list-reference-bridge.js +25 -0
- package/dist/components/render-list-reference-columns.d.ts +25 -0
- package/dist/components/render-list-reference-columns.js +137 -0
- package/dist/components/render-list-table-props.d.ts +52 -0
- package/dist/components/render-list-table-props.js +53 -0
- package/dist/components/render-list-toolbar-action.d.ts +27 -0
- package/dist/components/render-list-toolbar-action.js +40 -0
- package/dist/components/render-list-toolbar-model.d.ts +42 -0
- package/dist/components/render-list-toolbar-model.js +82 -0
- package/dist/components/render-list-toolbar.d.ts +38 -0
- package/dist/components/render-list-toolbar.js +40 -0
- package/dist/components/render-list-types.d.ts +113 -0
- package/dist/components/render-list-types.js +1 -0
- package/dist/components/render-list.d.ts +5 -130
- package/dist/components/render-list.js +95 -319
- package/dist/components/use-reference-input-state.d.ts +20 -0
- package/dist/components/use-reference-input-state.js +85 -0
- package/dist/components/use-render-edit-controlled-sync.d.ts +3 -0
- package/dist/components/use-render-edit-controlled-sync.js +26 -0
- package/dist/components/use-render-edit-draft-save.d.ts +29 -0
- package/dist/components/use-render-edit-draft-save.js +141 -0
- package/dist/components/use-render-edit-form.d.ts +10 -0
- package/dist/components/use-render-edit-form.js +101 -0
- package/dist/components/use-render-edit-sections.d.ts +15 -0
- package/dist/components/use-render-edit-sections.js +100 -0
- package/dist/components/use-render-edit-state.d.ts +65 -0
- package/dist/components/use-render-edit-state.js +158 -0
- package/dist/components/use-render-edit-steps.d.ts +13 -0
- package/dist/components/use-render-edit-steps.js +52 -0
- package/dist/components/use-render-list-columns.d.ts +18 -0
- package/dist/components/use-render-list-columns.js +41 -0
- package/dist/components/use-render-list-search.d.ts +4 -0
- package/dist/components/use-render-list-search.js +50 -0
- package/dist/current-user.d.ts +2 -0
- package/dist/data-table-aggregate-types.d.ts +47 -0
- package/dist/data-table-aggregate-types.js +1 -0
- package/dist/data-table-bulk-types.d.ts +27 -0
- package/dist/data-table-bulk-types.js +1 -0
- package/dist/data-table-facet-types.d.ts +36 -0
- package/dist/data-table-facet-types.js +1 -0
- package/dist/data-table-view-types.d.ts +73 -0
- package/dist/data-table-view-types.js +1 -0
- package/dist/headless/view-model/edit.js +3 -1
- package/dist/headless/view-model/types.d.ts +4 -2
- package/dist/hooks/list-column-layout.d.ts +19 -0
- package/dist/hooks/list-column-layout.js +36 -0
- package/dist/hooks/list-group-pages.d.ts +26 -0
- package/dist/hooks/list-group-pages.js +37 -0
- package/dist/hooks/list-reset.d.ts +8 -0
- package/dist/hooks/list-reset.js +15 -0
- package/dist/hooks/list-server-groups.d.ts +39 -0
- package/dist/hooks/list-server-groups.js +84 -0
- package/dist/hooks/list-state-schema.d.ts +28 -0
- package/dist/hooks/list-state-schema.js +76 -0
- package/dist/hooks/use-bulk-run.d.ts +41 -0
- package/dist/hooks/use-bulk-run.js +65 -0
- package/dist/hooks/use-group-load-state.d.ts +11 -0
- package/dist/hooks/use-group-load-state.js +31 -0
- package/dist/hooks/use-list-aggregates.d.ts +38 -0
- package/dist/hooks/use-list-aggregates.js +107 -0
- package/dist/hooks/use-list-table.d.ts +38 -0
- package/dist/hooks/use-list-table.js +91 -0
- package/dist/hooks/use-list-view-state.d.ts +43 -0
- package/dist/hooks/use-list-view-state.js +161 -0
- package/dist/hooks/use-related-list-rows.d.ts +27 -0
- package/dist/hooks/use-related-list-rows.js +81 -0
- package/dist/hooks/use-related-list-state.d.ts +15 -0
- package/dist/hooks/use-related-list-state.js +31 -0
- package/dist/hooks/use-remembered-list-params.d.ts +13 -0
- package/dist/hooks/use-remembered-list-params.js +53 -0
- package/dist/hooks/use-remembered-local-list-state.d.ts +26 -0
- package/dist/hooks/use-remembered-local-list-state.js +63 -0
- package/dist/i18n-defaults.js +53 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/primitives.d.ts +11 -47
- package/dist/web/app/create-app.d.ts +5 -0
- package/dist/web/app/create-app.js +7 -4
- package/dist/web/app/dashboard-body.d.ts +1 -1
- package/dist/web/app/dashboard-body.js +42 -246
- package/dist/web/app/dashboard-header.d.ts +34 -0
- package/dist/web/app/dashboard-header.js +58 -0
- package/dist/web/app/dashboard-screen-controls.d.ts +11 -0
- package/dist/web/app/dashboard-screen-controls.js +42 -0
- package/dist/web/app/dashboard-screen-tiles.d.ts +8 -0
- package/dist/web/app/dashboard-screen-tiles.js +42 -0
- package/dist/web/app/dashboard-visibility.d.ts +42 -0
- package/dist/web/app/dashboard-visibility.js +102 -0
- package/dist/web/app/history-leave-guard.d.ts +6 -0
- package/dist/web/app/history-leave-guard.js +115 -0
- package/dist/web/app/list-state-store-boot.d.ts +6 -0
- package/dist/web/app/list-state-store-boot.js +15 -0
- package/dist/web/app/nav.js +7 -54
- package/dist/web/app/session-list-state-store.d.ts +15 -0
- package/dist/web/app/session-list-state-store.js +117 -0
- package/dist/web/app/use-dashboard-screen-state.d.ts +35 -0
- package/dist/web/app/use-dashboard-screen-state.js +69 -0
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +1 -0
- package/dist/web/lib/export-xlsx-request.d.ts +11 -0
- package/dist/web/lib/export-xlsx-request.js +46 -0
- package/dist/web/primitives/data-table/actions-column.d.ts +16 -0
- package/dist/web/primitives/data-table/actions-column.js +35 -0
- package/dist/web/primitives/data-table/bulk-selection-bar.d.ts +20 -0
- package/dist/web/primitives/data-table/bulk-selection-bar.js +37 -0
- package/dist/web/primitives/data-table/card-body.d.ts +6 -0
- package/dist/web/primitives/data-table/card-body.js +32 -0
- package/dist/web/primitives/data-table/card-row.d.ts +5 -0
- package/dist/web/primitives/data-table/card-row.js +31 -0
- package/dist/web/primitives/data-table/card-sort-select.d.ts +14 -0
- package/dist/web/primitives/data-table/card-sort-select.js +40 -0
- package/dist/web/primitives/data-table/card-view.d.ts +3 -0
- package/dist/web/primitives/data-table/card-view.js +13 -0
- package/dist/web/primitives/data-table/column-layout-mode.d.ts +5 -0
- package/dist/web/primitives/data-table/column-layout-mode.js +10 -0
- package/dist/web/primitives/data-table/column-picker-section.d.ts +7 -0
- package/dist/web/primitives/data-table/column-picker-section.js +35 -0
- package/dist/web/primitives/data-table/column-resize-handle.d.ts +14 -0
- package/dist/web/primitives/data-table/column-resize-handle.js +48 -0
- package/dist/web/primitives/data-table/data-cell-props.d.ts +7 -0
- package/dist/web/primitives/data-table/data-cell-props.js +8 -0
- package/dist/web/primitives/data-table/density.d.ts +14 -0
- package/dist/web/primitives/data-table/density.js +20 -0
- package/dist/web/primitives/data-table/export-button.d.ts +5 -0
- package/dist/web/primitives/data-table/export-button.js +37 -0
- package/dist/web/primitives/data-table/facet-cluster.d.ts +8 -0
- package/dist/web/primitives/data-table/facet-cluster.js +37 -0
- package/dist/web/primitives/data-table/group-band.d.ts +28 -0
- package/dist/web/primitives/data-table/group-band.js +53 -0
- package/dist/web/primitives/data-table/measure-value.d.ts +10 -0
- package/dist/web/primitives/data-table/measure-value.js +28 -0
- package/dist/web/primitives/data-table/pin-section.d.ts +8 -0
- package/dist/web/primitives/data-table/pin-section.js +20 -0
- package/dist/web/primitives/data-table/reset-all-button.d.ts +4 -0
- package/dist/web/primitives/data-table/reset-all-button.js +8 -0
- package/dist/web/primitives/data-table/row-render-parts.d.ts +8 -0
- package/dist/web/primitives/data-table/row-render-parts.js +35 -0
- package/dist/web/primitives/data-table/server-group-header.d.ts +11 -0
- package/dist/web/primitives/data-table/server-group-header.js +51 -0
- package/dist/web/primitives/data-table/sortable-header.d.ts +17 -0
- package/dist/web/primitives/data-table/sortable-header.js +41 -0
- package/dist/web/primitives/data-table/table-body.d.ts +3 -0
- package/dist/web/primitives/data-table/table-body.js +32 -0
- package/dist/web/primitives/data-table/table-chrome.d.ts +13 -0
- package/dist/web/primitives/data-table/table-chrome.js +30 -0
- package/dist/web/primitives/data-table/table-content.d.ts +3 -0
- package/dist/web/primitives/data-table/table-content.js +41 -0
- package/dist/web/primitives/data-table/table-data-cell.d.ts +4 -0
- package/dist/web/primitives/data-table/table-data-cell.js +25 -0
- package/dist/web/primitives/data-table/table-footer.d.ts +7 -0
- package/dist/web/primitives/data-table/table-footer.js +20 -0
- package/dist/web/primitives/data-table/table-header-row.d.ts +3 -0
- package/dist/web/primitives/data-table/table-header-row.js +21 -0
- package/dist/web/primitives/data-table/table-view.d.ts +3 -0
- package/dist/web/primitives/data-table/table-view.js +25 -0
- package/dist/web/primitives/data-table/toolbar-end-cluster.d.ts +10 -0
- package/dist/web/primitives/data-table/toolbar-end-cluster.js +13 -0
- package/dist/web/primitives/data-table/toolbar.d.ts +6 -0
- package/dist/web/primitives/data-table/toolbar.js +53 -0
- package/dist/web/primitives/data-table/totals-footer.d.ts +24 -0
- package/dist/web/primitives/data-table/totals-footer.js +48 -0
- package/dist/web/primitives/data-table/use-bulk-selection.d.ts +21 -0
- package/dist/web/primitives/data-table/use-bulk-selection.js +66 -0
- package/dist/web/primitives/data-table/use-column-pins.d.ts +32 -0
- package/dist/web/primitives/data-table/use-column-pins.js +117 -0
- package/dist/web/primitives/data-table/use-column-sizing.d.ts +22 -0
- package/dist/web/primitives/data-table/use-column-sizing.js +44 -0
- package/dist/web/primitives/data-table/use-data-table-state.d.ts +44 -0
- package/dist/web/primitives/data-table/use-data-table-state.js +123 -0
- package/dist/web/primitives/data-table/use-measured-column-widths.d.ts +15 -0
- package/dist/web/primitives/data-table/use-measured-column-widths.js +83 -0
- package/dist/web/primitives/data-table/use-row-keyboard-navigation.d.ts +22 -0
- package/dist/web/primitives/data-table/use-row-keyboard-navigation.js +65 -0
- package/dist/web/primitives/data-table/use-row-selection.d.ts +14 -0
- package/dist/web/primitives/data-table/use-row-selection.js +48 -0
- package/dist/web/primitives/data-table/use-view-columns.d.ts +6 -0
- package/dist/web/primitives/data-table/use-view-columns.js +17 -0
- package/dist/web/primitives/data-table/view-menu.d.ts +8 -0
- package/dist/web/primitives/data-table/view-menu.js +45 -0
- package/dist/web/primitives/data-table-cell.d.ts +0 -22
- package/dist/web/primitives/data-table-cell.js +1 -58
- package/dist/web/primitives/data-table.d.ts +3 -4
- package/dist/web/primitives/data-table.js +30 -272
- package/dist/web/primitives/file-value-list.d.ts +1 -1
- package/dist/web/primitives/file-value-list.js +5 -5
- package/dist/web/primitives/form-footer-parts.d.ts +25 -0
- package/dist/web/primitives/form-footer-parts.js +55 -0
- package/dist/web/primitives/form.js +33 -43
- package/dist/web/primitives/input-choice-kinds.d.ts +4 -0
- package/dist/web/primitives/input-choice-kinds.js +67 -0
- package/dist/web/primitives/input-file-kinds.d.ts +3 -0
- package/dist/web/primitives/input-file-kinds.js +6 -0
- package/dist/web/primitives/input-number-kinds.d.ts +4 -0
- package/dist/web/primitives/input-number-kinds.js +16 -0
- package/dist/web/primitives/input-optional-props.d.ts +20 -0
- package/dist/web/primitives/input-optional-props.js +24 -0
- package/dist/web/primitives/input-select-presentation.d.ts +13 -0
- package/dist/web/primitives/input-select-presentation.js +19 -0
- package/dist/web/primitives/input-shared.d.ts +22 -0
- package/dist/web/primitives/input-shared.js +10 -0
- package/dist/web/primitives/input-temporal-kinds.d.ts +5 -0
- package/dist/web/primitives/input-temporal-kinds.js +10 -0
- package/dist/web/primitives/input-text-kinds.d.ts +7 -0
- package/dist/web/primitives/input-text-kinds.js +33 -0
- package/dist/web/primitives/input.js +35 -161
- package/dist/web/primitives/number-range-facet.d.ts +7 -0
- package/dist/web/primitives/number-range-facet.js +33 -0
- package/dist/web/widgets/bounded-load-cache.d.ts +5 -1
- package/dist/web/widgets/bounded-load-cache.js +48 -26
- package/dist/web/widgets/chart-data.d.ts +35 -0
- package/dist/web/widgets/chart-data.js +37 -0
- package/dist/web/widgets/chart-markers.d.ts +26 -0
- package/dist/web/widgets/chart-markers.js +64 -0
- package/dist/web/widgets/chart-parts.d.ts +20 -0
- package/dist/web/widgets/chart-parts.js +15 -0
- package/dist/web/widgets/charts.d.ts +5 -78
- package/dist/web/widgets/charts.js +7 -485
- package/dist/web/widgets/drawer-panel-class.d.ts +3 -0
- package/dist/web/widgets/drawer-panel-class.js +40 -0
- package/dist/web/widgets/drawer-resize-controls.d.ts +11 -0
- package/dist/web/widgets/drawer-resize-controls.js +12 -0
- package/dist/web/widgets/drawer-sizing.d.ts +19 -0
- package/dist/web/widgets/drawer-sizing.js +60 -0
- package/dist/web/widgets/drawer.js +17 -116
- package/dist/web/widgets/pdf-preview.js +9 -4
- package/dist/web/widgets/stacked-area-brush.d.ts +13 -0
- package/dist/web/widgets/stacked-area-brush.js +91 -0
- package/dist/web/widgets/stacked-area-chart.d.ts +6 -0
- package/dist/web/widgets/stacked-area-chart.js +45 -0
- package/dist/web/widgets/stacked-area-chrome.d.ts +7 -0
- package/dist/web/widgets/stacked-area-chrome.js +77 -0
- package/dist/web/widgets/stacked-area-geometry.d.ts +54 -0
- package/dist/web/widgets/stacked-area-geometry.js +83 -0
- package/dist/web/widgets/stacked-area-model.d.ts +11 -0
- package/dist/web/widgets/stacked-area-model.js +1 -0
- package/dist/web/widgets/stacked-area-plot.d.ts +3 -0
- package/dist/web/widgets/stacked-area-plot.js +51 -0
- package/dist/web/widgets/stacked-area-props.d.ts +83 -0
- package/dist/web/widgets/stacked-area-props.js +16 -0
- package/dist/web/widgets/stacked-area-svg.d.ts +3 -0
- package/dist/web/widgets/stacked-area-svg.js +38 -0
- package/dist/web/widgets/stacked-area-tooltip.d.ts +3 -0
- package/dist/web/widgets/stacked-area-tooltip.js +86 -0
- package/dist/web/widgets/use-drawer-resize.d.ts +22 -0
- package/dist/web/widgets/use-drawer-resize.js +52 -0
- package/dist/web/widgets/use-stacked-area-tooltip.d.ts +9 -0
- package/dist/web/widgets/use-stacked-area-tooltip.js +34 -0
- package/dist/web/widgets/use-stacked-area-window.d.ts +20 -0
- package/dist/web/widgets/use-stacked-area-window.js +76 -0
- package/package.json +9 -9
- package/src/changes.json +163 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/** Provides the URL prefix the app is mounted under to components outside the NavProvider
|
|
3
|
+
* (auth gates and pages). `createKumikoApp({ basePath })` mounts it. */
|
|
4
|
+
export declare function BasePathProvider({ basePath, children, }: {
|
|
5
|
+
readonly basePath: string | undefined;
|
|
6
|
+
readonly children: ReactNode;
|
|
7
|
+
}): ReactNode;
|
|
8
|
+
/** Normalized base path ("" when the app is served from the root). */
|
|
9
|
+
export declare function useBasePath(): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
import { normalizeBasePath } from "./base-path.js";
|
|
4
|
+
const BasePathContext = createContext("");
|
|
5
|
+
/** Provides the URL prefix the app is mounted under to components outside the NavProvider
|
|
6
|
+
* (auth gates and pages). `createKumikoApp({ basePath })` mounts it. */
|
|
7
|
+
export function BasePathProvider({ basePath, children, }) {
|
|
8
|
+
return (_jsx(BasePathContext.Provider, { value: normalizeBasePath(basePath), children: children }));
|
|
9
|
+
}
|
|
10
|
+
/** Normalized base path ("" when the app is served from the root). */
|
|
11
|
+
export function useBasePath() {
|
|
12
|
+
return useContext(BasePathContext);
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// basePath mounts an app under a URL prefix (for example, `/admin`). Pure helpers shared by the
|
|
2
|
+
// browser nav adapter and the auth pages, which sit outside the NavProvider.
|
|
3
|
+
export function normalizeBasePath(raw) {
|
|
4
|
+
if (raw === undefined || raw === "" || raw === "/")
|
|
5
|
+
return "";
|
|
6
|
+
const withLeading = raw.startsWith("/") ? raw : `/${raw}`;
|
|
7
|
+
return withLeading.endsWith("/") ? withLeading.slice(0, -1) : withLeading;
|
|
8
|
+
}
|
|
9
|
+
// Returns the in-app (basePath-relative) path when `path` is under basePath; otherwise
|
|
10
|
+
// `undefined`. The segment boundary is strict: "/administrator" does not match "/admin".
|
|
11
|
+
export function stripBasePath(path, basePath) {
|
|
12
|
+
if (basePath === "")
|
|
13
|
+
return path;
|
|
14
|
+
if (path === basePath)
|
|
15
|
+
return "/";
|
|
16
|
+
if (path.startsWith(`${basePath}/`))
|
|
17
|
+
return path.slice(basePath.length);
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
export function prependBasePath(path, basePath) {
|
|
21
|
+
if (basePath === "")
|
|
22
|
+
return path;
|
|
23
|
+
// An in-app path is absolute: "/" or "/screen-id" or "/screen-id/entity-id". "/" becomes basePath.
|
|
24
|
+
if (path === "/" || path === "")
|
|
25
|
+
return basePath;
|
|
26
|
+
return `${basePath}${path}`;
|
|
27
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { ConfigEditScreenDefinition } from "@cosmicdrift/kumiko-framework/u
|
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
import type { Translate } from "../headless/index.ts";
|
|
4
4
|
import type { FeatureSchema } from "./feature-schema.ts";
|
|
5
|
-
export declare function ConfigEditBody({ schema, screen, translate, }: {
|
|
5
|
+
export declare function ConfigEditBody({ schema, screen: declaredScreen, translate, }: {
|
|
6
6
|
readonly schema: FeatureSchema;
|
|
7
7
|
readonly screen: ConfigEditScreenDefinition;
|
|
8
8
|
readonly translate?: Translate;
|
|
@@ -11,6 +11,7 @@ import { useTranslation } from "../i18n.js";
|
|
|
11
11
|
import { usePrimitives } from "../primitives.js";
|
|
12
12
|
import { screenFillsHeight } from "../screen-fills-height.js";
|
|
13
13
|
import { buildConfigEditSchema, synthesizeConfigEditEntity, synthesizeConfigEditScreen, } from "./config-edit-shim.js";
|
|
14
|
+
import { configEditWithoutSecretFields } from "./config-edit-without-secret-fields.js";
|
|
14
15
|
import { buildInitialValues } from "./entity-edit-prefill.js";
|
|
15
16
|
import { layoutEditFields } from "./layout-fields.js";
|
|
16
17
|
import { QueryErrorBanner, QueryLoadingBanner } from "./query-state-banners.js";
|
|
@@ -89,7 +90,7 @@ function isEmptyNumericFormValue(value) {
|
|
|
89
90
|
return true;
|
|
90
91
|
return typeof value === "number" && !Number.isFinite(value);
|
|
91
92
|
}
|
|
92
|
-
export function ConfigEditBody({ schema, screen, translate, }) {
|
|
93
|
+
export function ConfigEditBody({ schema, screen: declaredScreen, translate, }) {
|
|
93
94
|
const { ConfigCascadeView } = usePrimitives();
|
|
94
95
|
const t = useTranslation();
|
|
95
96
|
const effectiveTranslate = translate ?? t;
|
|
@@ -98,13 +99,17 @@ export function ConfigEditBody({ schema, screen, translate, }) {
|
|
|
98
99
|
// We map them via screen.configKeys from short to qualified name onto our
|
|
99
100
|
// form field values.
|
|
100
101
|
const valuesQuery = useQuery("config:query:values", {
|
|
101
|
-
scope:
|
|
102
|
+
scope: declaredScreen.scope,
|
|
102
103
|
});
|
|
103
104
|
const cascadeQuery = useQuery("config:query:cascade", {
|
|
104
|
-
scope:
|
|
105
|
+
scope: declaredScreen.scope,
|
|
105
106
|
});
|
|
106
|
-
const
|
|
107
|
-
|
|
107
|
+
const secretsQuery = useQuery("secrets:query:list", {}, { enabled: declaredScreen.secretKeys !== undefined });
|
|
108
|
+
// The form screen's access is the union of config and secrets access, so a viewer may write
|
|
109
|
+
// the config keys without being allowed to list secrets: that must not take the form down.
|
|
110
|
+
const secretsDenied = secretsQuery.error?.code === "access_denied";
|
|
111
|
+
const screen = useMemo(() => (secretsDenied ? configEditWithoutSecretFields(declaredScreen) : declaredScreen), [secretsDenied, declaredScreen]);
|
|
112
|
+
const secretKeys = secretsDenied ? undefined : declaredScreen.secretKeys;
|
|
108
113
|
const synthEntity = useMemo(() => synthesizeConfigEditEntity(screen.fields), [screen.fields]);
|
|
109
114
|
const synthScreen = useMemo(() => synthesizeConfigEditScreen(screen), [screen]);
|
|
110
115
|
const boundsSchema = useMemo(() => buildConfigEditSchema(screen.fields), [screen.fields]);
|
|
@@ -304,7 +309,11 @@ export function ConfigEditBody({ schema, screen, translate, }) {
|
|
|
304
309
|
]);
|
|
305
310
|
if (valuesQuery.loading && valuesQuery.data === null)
|
|
306
311
|
return _jsx(QueryLoadingBanner, {});
|
|
307
|
-
const failedQuery = valuesQuery.error
|
|
312
|
+
const failedQuery = valuesQuery.error
|
|
313
|
+
? valuesQuery
|
|
314
|
+
: secretsQuery.error && !secretsDenied
|
|
315
|
+
? secretsQuery
|
|
316
|
+
: null;
|
|
308
317
|
if (failedQuery?.error) {
|
|
309
318
|
return (_jsx(QueryErrorBanner, { error: failedQuery.error, translate: effectiveTranslate, onRetry: failedQuery.refetch }));
|
|
310
319
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isFieldsEditSection, normalizeEditField } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
// A merged provider form carries the secret-backed fields of a secrets feature the viewer may
|
|
3
|
+
// not read. Without the secrets list those fields cannot show or save a state, so the form
|
|
4
|
+
// drops them and stays usable for the config keys.
|
|
5
|
+
export function configEditWithoutSecretFields(screen) {
|
|
6
|
+
const secretFieldNames = new Set(Object.keys(screen.secretKeys ?? {}));
|
|
7
|
+
if (secretFieldNames.size === 0)
|
|
8
|
+
return screen;
|
|
9
|
+
const keepSpec = (spec) => !secretFieldNames.has(normalizeEditField(spec).field);
|
|
10
|
+
const fields = Object.fromEntries(Object.entries(screen.fields).filter(([name]) => !secretFieldNames.has(name)));
|
|
11
|
+
const sections = screen.layout.sections.flatMap((section) => {
|
|
12
|
+
if (!isFieldsEditSection(section))
|
|
13
|
+
return [section];
|
|
14
|
+
if ("groups" in section) {
|
|
15
|
+
const groups = section.groups
|
|
16
|
+
.map((group) => ({ ...group, fields: group.fields.filter(keepSpec) }))
|
|
17
|
+
.filter((group) => group.fields.length > 0);
|
|
18
|
+
return groups.length === 0 ? [] : [{ ...section, groups }];
|
|
19
|
+
}
|
|
20
|
+
const kept = section.fields.filter(keepSpec);
|
|
21
|
+
return kept.length === 0 ? [] : [{ ...section, fields: kept }];
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
...screen,
|
|
25
|
+
fields,
|
|
26
|
+
layout: { ...screen.layout, sections },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Translate } from "../headless/index.ts";
|
|
2
|
+
import type { ResolvedFacetSpec } from "./list-facets.ts";
|
|
3
|
+
export declare function resolveEntityFacetSpecs(fields: Readonly<Record<string, unknown>>, featureName: string, entityName: string, translate: Translate): ResolvedFacetSpec[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { parseRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
3
|
+
import { fieldLabelKey, fieldOptionLabelKey } from "../headless/index.js";
|
|
4
|
+
// entityList adapter — one DataTableFacet per filterable select/boolean
|
|
5
|
+
// entity field, labels via the standard field/option i18n convention.
|
|
6
|
+
export function resolveEntityFacetSpecs(fields, featureName, entityName, translate) {
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const [field, rawDef] of Object.entries(fields)) {
|
|
9
|
+
// entity.fields is weakly typed at the renderer layer (deserialized from the schema).
|
|
10
|
+
const def = {
|
|
11
|
+
type: propertyOf(rawDef, "type"),
|
|
12
|
+
filterable: propertyOf(rawDef, "filterable"),
|
|
13
|
+
options: propertyOf(rawDef, "options"),
|
|
14
|
+
entity: propertyOf(rawDef, "entity"),
|
|
15
|
+
labelField: propertyOf(rawDef, "labelField"),
|
|
16
|
+
};
|
|
17
|
+
if (def.filterable !== true)
|
|
18
|
+
continue;
|
|
19
|
+
const label = translate(fieldLabelKey(featureName, entityName, field));
|
|
20
|
+
if (def.type === "select" && Array.isArray(def.options)) {
|
|
21
|
+
const optionValues = def.options.filter((value) => typeof value === "string");
|
|
22
|
+
out.push({
|
|
23
|
+
field,
|
|
24
|
+
type: "select",
|
|
25
|
+
label,
|
|
26
|
+
options: optionValues.map((value) => ({
|
|
27
|
+
value,
|
|
28
|
+
label: translate(fieldOptionLabelKey(featureName, entityName, field, value)),
|
|
29
|
+
})),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else if (def.type === "boolean") {
|
|
33
|
+
out.push({
|
|
34
|
+
field,
|
|
35
|
+
type: "boolean",
|
|
36
|
+
label,
|
|
37
|
+
options: [
|
|
38
|
+
{
|
|
39
|
+
value: "true",
|
|
40
|
+
label: translate(fieldOptionLabelKey(featureName, entityName, field, "true")),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: "false",
|
|
44
|
+
label: translate(fieldOptionLabelKey(featureName, entityName, field, "false")),
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else if (def.type === "reference" && typeof def.entity === "string") {
|
|
50
|
+
const target = parseRefTarget(def.entity, featureName);
|
|
51
|
+
out.push({
|
|
52
|
+
field,
|
|
53
|
+
type: "reference",
|
|
54
|
+
label,
|
|
55
|
+
options: [],
|
|
56
|
+
reference: {
|
|
57
|
+
refEntity: target.entityName,
|
|
58
|
+
refFeature: target.featureName,
|
|
59
|
+
labelField: typeof def.labelField === "string" ? def.labelField : "id",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { evalFieldCondition
|
|
2
|
+
import { evalFieldCondition } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
3
|
import { resolveActionIcon } from "@cosmicdrift/kumiko-types/action-icon";
|
|
4
4
|
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
5
|
-
import { useCallback, useEffect, useMemo,
|
|
5
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
6
|
+
import { ListGroupPageBridges } from "../components/list-group-page-bridges.js";
|
|
6
7
|
import { RenderList } from "../components/render-list.js";
|
|
7
8
|
import { useOptionalDispatcher } from "../context/dispatcher-context.js";
|
|
8
9
|
import { useIsEmbeddedScreen } from "../context/embedded-screen-context.js";
|
|
9
10
|
import { useUserRoles } from "../context/user-roles-context.js";
|
|
10
11
|
import { rendererWarn } from "../dev-console.js";
|
|
11
|
-
import { computeRelatedListSectionViewModel
|
|
12
|
+
import { computeRelatedListSectionViewModel } from "../headless/index.js";
|
|
12
13
|
import { useListUrlState } from "../hooks/use-list-url-state.js";
|
|
13
|
-
import { useQuery } from "../hooks/use-query.js";
|
|
14
14
|
import { useTranslation } from "../i18n.js";
|
|
15
15
|
import { usePrimitives } from "../primitives.js";
|
|
16
16
|
import { screenFillsHeight } from "../screen-fills-height.js";
|
|
@@ -18,73 +18,21 @@ import { DrawerHost, useDrawerAction } from "./action-form-body.js";
|
|
|
18
18
|
import { useAppFeatures } from "./app-features-context.js";
|
|
19
19
|
import { useClientActionRuntime } from "./client-actions.js";
|
|
20
20
|
import { EntityListExpandedRow } from "./entity-list-expanded-row.js";
|
|
21
|
+
import { resolveEntityFacetSpecs } from "./entity-list-facet-specs.js";
|
|
21
22
|
import { FacetCountBridges } from "./facet-count-bridge.js";
|
|
23
|
+
import { useListBulk } from "./list-bulk-actions.js";
|
|
22
24
|
import { isDefaultFilterActive, isListNarrowed, useListEmptyContent, } from "./list-empty-content.js";
|
|
23
25
|
import { buildEntityFilterFacets, buildFacetCountRequests, buildFilterPayload, mergeReferenceFacetOptions, normalizeDefaultFilters, } from "./list-facets.js";
|
|
24
26
|
import { useNav } from "./nav.js";
|
|
25
27
|
import { QueryErrorBanner, QueryLoadingBanner } from "./query-state-banners.js";
|
|
26
28
|
import { ReferenceFacetBridges } from "./reference-facet-bridge.js";
|
|
27
29
|
import { navigateWithReturnTo, useReturnHost } from "./return-to.js";
|
|
28
|
-
import { buildClientActionRowAction, buildDefaultEditRowAction, buildDrawerRowAction, buildProjectionToolbarActions,
|
|
30
|
+
import { buildClientActionRowAction, buildDefaultEditRowAction, buildDrawerRowAction, buildProjectionToolbarActions, buildWriteHandlerRowAction, findRowClickAction, navigateActionSearchParams, runDrawerRowAction, } from "./row-actions.js";
|
|
29
31
|
import { findEditScreenFor } from "./screen-access.js";
|
|
30
|
-
import { buildListQueryPayload, entityQueryCommand, isEntityEditScreenOfEntity,
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
function resolveEntityFacetSpecs(fields, featureName, entityName, translate) {
|
|
35
|
-
const out = [];
|
|
36
|
-
for (const [field, rawDef] of Object.entries(fields)) {
|
|
37
|
-
// entity.fields is weakly typed at the renderer layer (Record<string,
|
|
38
|
-
// unknown>, deserialized from the schema); boundary cast like buildInitialValues.
|
|
39
|
-
const def = rawDef;
|
|
40
|
-
if (def.filterable !== true)
|
|
41
|
-
continue;
|
|
42
|
-
const label = translate(fieldLabelKey(featureName, entityName, field));
|
|
43
|
-
if (def.type === "select" && Array.isArray(def.options)) {
|
|
44
|
-
out.push({
|
|
45
|
-
field,
|
|
46
|
-
type: "select",
|
|
47
|
-
label,
|
|
48
|
-
options: def.options.map((value) => ({
|
|
49
|
-
value,
|
|
50
|
-
label: translate(fieldOptionLabelKey(featureName, entityName, field, value)),
|
|
51
|
-
})),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
else if (def.type === "boolean") {
|
|
55
|
-
out.push({
|
|
56
|
-
field,
|
|
57
|
-
type: "boolean",
|
|
58
|
-
label,
|
|
59
|
-
options: [
|
|
60
|
-
{
|
|
61
|
-
value: "true",
|
|
62
|
-
label: translate(fieldOptionLabelKey(featureName, entityName, field, "true")),
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
value: "false",
|
|
66
|
-
label: translate(fieldOptionLabelKey(featureName, entityName, field, "false")),
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
else if (def.type === "reference" && def.entity !== undefined) {
|
|
72
|
-
const target = parseRefTarget(def.entity, featureName);
|
|
73
|
-
out.push({
|
|
74
|
-
field,
|
|
75
|
-
type: "reference",
|
|
76
|
-
label,
|
|
77
|
-
options: [],
|
|
78
|
-
reference: {
|
|
79
|
-
refEntity: target.entityName,
|
|
80
|
-
refFeature: target.featureName,
|
|
81
|
-
labelField: def.labelField ?? "id",
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
32
|
+
import { buildListQueryPayload, entityQueryCommand, isEntityEditScreenOfEntity, useNavigateToCreateFor, } from "./screen-shared.js";
|
|
33
|
+
import { useEntityRangeFacets } from "./use-entity-range-facets.js";
|
|
34
|
+
import { listPager, useScreenListRows } from "./use-screen-list-rows.js";
|
|
35
|
+
import { useScreenListTable } from "./use-screen-list-table.js";
|
|
88
36
|
export function EntityListScreen({ schema, screen, translate, onRowClick, }) {
|
|
89
37
|
const { Banner, Text } = usePrimitives();
|
|
90
38
|
const entity = schema.entities[screen.entity];
|
|
@@ -120,29 +68,17 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
120
68
|
const paginationMode = screen.pagination ?? "pages";
|
|
121
69
|
const usePager = paginationMode === "pages";
|
|
122
70
|
const useInfinite = paginationMode === "infinite";
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// Reset rows + cursor on a sort/q change, before the next useQuery so the
|
|
135
|
-
// reload starts with cursor=undefined.
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
if (!useInfinite)
|
|
138
|
-
return;
|
|
139
|
-
if (sortQRef.current === sortQKey)
|
|
140
|
-
return;
|
|
141
|
-
sortQRef.current = sortQKey;
|
|
142
|
-
setAccumulated([]);
|
|
143
|
-
setCursor(undefined);
|
|
144
|
-
setHasMore(true);
|
|
145
|
-
}, [useInfinite, sortQKey]);
|
|
71
|
+
// Hook order: ALL hooks before the early return for loading/error,
|
|
72
|
+
// otherwise the hook slots collide between renders.
|
|
73
|
+
const t = useTranslation();
|
|
74
|
+
const effectiveTranslate = translate ?? t;
|
|
75
|
+
const range = useEntityRangeFacets({
|
|
76
|
+
fields: entity.fields,
|
|
77
|
+
screen,
|
|
78
|
+
featureName,
|
|
79
|
+
translate: effectiveTranslate,
|
|
80
|
+
urlState,
|
|
81
|
+
});
|
|
146
82
|
// User-selected faceted filters from the URL state -> payload.filters.
|
|
147
83
|
// typeOf reads the field type straight from entity.fields (not gated on
|
|
148
84
|
// filterable, deliberately permissive; see the buildFilterPayload doc).
|
|
@@ -162,7 +98,7 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
162
98
|
usePager,
|
|
163
99
|
page: urlState.page,
|
|
164
100
|
useInfinite,
|
|
165
|
-
cursor,
|
|
101
|
+
cursor: undefined,
|
|
166
102
|
});
|
|
167
103
|
// Screen filter (tier 2.7c), declared by the author on the schema and
|
|
168
104
|
// independent of the user's q search. Several buckets of the same entity
|
|
@@ -171,9 +107,9 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
171
107
|
if (screen.filter !== undefined) {
|
|
172
108
|
payload["filter"] = screen.filter;
|
|
173
109
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
110
|
+
const filters = [...filterPayload, ...range.rangeFilters];
|
|
111
|
+
if (filters.length > 0)
|
|
112
|
+
payload["filters"] = filters;
|
|
177
113
|
return payload;
|
|
178
114
|
}, [
|
|
179
115
|
limit,
|
|
@@ -181,82 +117,51 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
181
117
|
effectiveSort,
|
|
182
118
|
screen.filter,
|
|
183
119
|
filterPayload,
|
|
120
|
+
range.rangeFilters,
|
|
184
121
|
usePager,
|
|
185
122
|
urlState.page,
|
|
186
123
|
useInfinite,
|
|
187
|
-
cursor,
|
|
188
124
|
]);
|
|
189
|
-
const rowsQuery = useQuery(queryType, queryPayload, { live: true });
|
|
190
125
|
// Facet counts come from their own queries, which a write leaves untouched.
|
|
191
126
|
const [facetCountRefreshNonce, setFacetCountRefreshNonce] = useState(0);
|
|
192
127
|
const refreshFacetCounts = useCallback(() => setFacetCountRefreshNonce((n) => n + 1), []);
|
|
193
|
-
const refreshRowsAfterWrite = useCallback(async () => {
|
|
194
|
-
refreshFacetCounts();
|
|
195
|
-
if (useInfinite) {
|
|
196
|
-
setAccumulated([]);
|
|
197
|
-
setCursor(undefined);
|
|
198
|
-
setHasMore(true);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
await refetchAfterWrite(rowsQuery.refetch);
|
|
202
|
-
}, [useInfinite, rowsQuery.refetch, refreshFacetCounts]);
|
|
203
|
-
// Infinite scroll: on every successful result append the rows and derive
|
|
204
|
-
// hasMore from nextCursor. Live updates (postgres NOTIFY) and initial loads
|
|
205
|
-
// both pass through here; the useEffect dependency array pins the dedup to
|
|
206
|
-
// the last processed data pointer.
|
|
207
|
-
const lastDataRef = useRef(null);
|
|
208
|
-
useEffect(() => {
|
|
209
|
-
if (!useInfinite)
|
|
210
|
-
return;
|
|
211
|
-
const data = rowsQuery.data;
|
|
212
|
-
if (data === null)
|
|
213
|
-
return;
|
|
214
|
-
if (data === lastDataRef.current)
|
|
215
|
-
return;
|
|
216
|
-
lastDataRef.current = data;
|
|
217
|
-
setAccumulated((prev) => {
|
|
218
|
-
// When cursor is undefined this is the first page after a sort/q change:
|
|
219
|
-
// replace everything instead of appending. Otherwise dedupe on id in case
|
|
220
|
-
// live updates bring in an entry on the next page that was already appended.
|
|
221
|
-
if (cursor === undefined)
|
|
222
|
-
return data.rows;
|
|
223
|
-
const seen = new Set(prev.map((r) => r["id"]));
|
|
224
|
-
const fresh = data.rows.filter((r) => !seen.has(r["id"]));
|
|
225
|
-
return [...prev, ...fresh];
|
|
226
|
-
});
|
|
227
|
-
setHasMore(data.nextCursor !== null);
|
|
228
|
-
}, [rowsQuery.data, useInfinite, cursor]);
|
|
229
|
-
const loadMore = useCallback(() => {
|
|
230
|
-
if (!useInfinite)
|
|
231
|
-
return;
|
|
232
|
-
if (rowsQuery.loading)
|
|
233
|
-
return;
|
|
234
|
-
const data = rowsQuery.data;
|
|
235
|
-
if (data?.nextCursor === undefined || data.nextCursor === null)
|
|
236
|
-
return;
|
|
237
|
-
setCursor(data.nextCursor);
|
|
238
|
-
}, [useInfinite, rowsQuery.loading, rowsQuery.data]);
|
|
239
|
-
// RowActions: schema form (handler QN + i18n key) -> resolved form
|
|
240
|
-
// (dispatcher call + translated strings). dispatcher.write knows the user
|
|
241
|
-
// internally (JWT cookie). The schema may contain raw strings as well as
|
|
242
|
-
// i18n keys; translate() returns the key when the bundle does not know it
|
|
243
|
-
// (convention everywhere in the renderer).
|
|
244
|
-
// Hook order: ALL hooks before the early return for loading/error,
|
|
245
|
-
// otherwise the hook slots collide between renders.
|
|
246
|
-
const t = useTranslation();
|
|
247
|
-
const effectiveTranslate = translate ?? t;
|
|
248
128
|
// Faceted filter: one dropdown per filterable select/boolean/reference field.
|
|
249
129
|
// Labels + select option labels use the same i18n convention as the column
|
|
250
130
|
// headers (fieldLabelKey / :option:<value>); reference fields load their
|
|
251
131
|
// options asynchronously through ReferenceFacetBridges.
|
|
252
132
|
const entityFacetSpecs = useMemo(() => resolveEntityFacetSpecs(entity.fields, featureName, screen.entity, effectiveTranslate), [entity.fields, featureName, screen.entity, effectiveTranslate]);
|
|
133
|
+
const facetFilterFields = useMemo(() => [...entityFacetSpecs.map((spec) => spec.field), ...range.rangeFields], [entityFacetSpecs, range.rangeFields]);
|
|
134
|
+
const listTable = useScreenListTable({
|
|
135
|
+
screen,
|
|
136
|
+
featureName,
|
|
137
|
+
payload: queryPayload,
|
|
138
|
+
filterFields: facetFilterFields,
|
|
139
|
+
queryType,
|
|
140
|
+
pageSize: limit,
|
|
141
|
+
paging: useInfinite ? "cursor" : "offset",
|
|
142
|
+
translate: effectiveTranslate,
|
|
143
|
+
});
|
|
144
|
+
const listRows = useScreenListRows({
|
|
145
|
+
queryType,
|
|
146
|
+
payload: queryPayload,
|
|
147
|
+
infinite: useInfinite,
|
|
148
|
+
aggregates: listTable.aggregates,
|
|
149
|
+
});
|
|
150
|
+
const { refreshAfterWrite: refreshListAfterWrite } = listRows;
|
|
151
|
+
const refreshRowsAfterWrite = useCallback(async () => {
|
|
152
|
+
refreshFacetCounts();
|
|
153
|
+
await refreshListAfterWrite();
|
|
154
|
+
}, [refreshFacetCounts, refreshListAfterWrite]);
|
|
253
155
|
const [entityReferenceFacetOptions, setEntityReferenceFacetOptions] = useState({});
|
|
254
156
|
const handleEntityFacetOptions = useCallback((field, options) => setEntityReferenceFacetOptions((prev) => prev[field] === options ? prev : { ...prev, [field]: options }), []);
|
|
255
157
|
const [facetCounts, setFacetCounts] = useState({});
|
|
256
158
|
const handleFacetCount = useCallback((key, count) => setFacetCounts((prev) => (prev[key] === count ? prev : { ...prev, [key]: count })), []);
|
|
257
159
|
const filterFacets = useMemo(() => buildEntityFilterFacets(mergeReferenceFacetOptions(entityFacetSpecs, entityReferenceFacetOptions), screen.facets, effectiveTranslate, facetCounts), [entityFacetSpecs, entityReferenceFacetOptions, screen.facets, effectiveTranslate, facetCounts]);
|
|
258
160
|
const facetCountQueries = useMemo(() => buildFacetCountRequests(entityFacetSpecs, screen.facets, effectiveTranslate).map((request) => {
|
|
259
|
-
const filters =
|
|
161
|
+
const filters = [
|
|
162
|
+
...buildFilterPayload({ ...urlState.filters, [request.field]: request.values }, (field) => entity.fields[field]?.type),
|
|
163
|
+
...range.rangeFilters,
|
|
164
|
+
];
|
|
260
165
|
return {
|
|
261
166
|
key: request.key,
|
|
262
167
|
payload: {
|
|
@@ -275,6 +180,7 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
275
180
|
urlState.filters,
|
|
276
181
|
urlState.q,
|
|
277
182
|
entity.fields,
|
|
183
|
+
range.rangeFilters,
|
|
278
184
|
]);
|
|
279
185
|
// Soft dispatcher: in tests that mount without a DispatcherProvider,
|
|
280
186
|
// rowActions stays undefined instead of crashing. Real apps have the
|
|
@@ -371,35 +277,7 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
371
277
|
}
|
|
372
278
|
if (dispatcher === undefined)
|
|
373
279
|
return null;
|
|
374
|
-
|
|
375
|
-
const writeActionVisible = writeAction.visible;
|
|
376
|
-
return {
|
|
377
|
-
id: writeAction.id,
|
|
378
|
-
label: effectiveTranslate(writeAction.label),
|
|
379
|
-
style: writeAction.style,
|
|
380
|
-
icon: resolveActionIcon(writeAction.id, writeAction.icon),
|
|
381
|
-
confirm: writeAction.confirm !== undefined ? effectiveTranslate(writeAction.confirm) : undefined,
|
|
382
|
-
confirmLabel: writeAction.confirmLabel !== undefined
|
|
383
|
-
? effectiveTranslate(writeAction.confirmLabel)
|
|
384
|
-
: undefined,
|
|
385
|
-
onTrigger: async (row) => {
|
|
386
|
-
const buildPayload = writeAction.payload;
|
|
387
|
-
const payload = buildPayload !== undefined
|
|
388
|
-
? evalRowExtractor(buildPayload, row.values)
|
|
389
|
-
: { id: row.values["id"] };
|
|
390
|
-
const result = await dispatcher.write(writeAction.handler, payload);
|
|
391
|
-
// write() does not throw: a failure result MUST become an error here,
|
|
392
|
-
// otherwise the confirm dialog closes silently and the user sees "nothing
|
|
393
|
-
// happened" (prod bug 2026-06-07).
|
|
394
|
-
if (!result.isSuccess) {
|
|
395
|
-
throw new WriteFailedError(result.error, dispatcherErrorText(result.error, effectiveTranslate));
|
|
396
|
-
}
|
|
397
|
-
await refreshRowsAfterWrite();
|
|
398
|
-
},
|
|
399
|
-
isVisible: writeActionVisible !== undefined
|
|
400
|
-
? (row) => evalFieldCondition(writeActionVisible, row.values)
|
|
401
|
-
: undefined,
|
|
402
|
-
};
|
|
280
|
+
return buildWriteHandlerRowAction(action, effectiveTranslate, refreshRowsAfterWrite, dispatcher);
|
|
403
281
|
})
|
|
404
282
|
.filter((a) => a !== null);
|
|
405
283
|
}, [
|
|
@@ -412,6 +290,13 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
412
290
|
refreshRowsAfterWrite,
|
|
413
291
|
openDrawer,
|
|
414
292
|
]);
|
|
293
|
+
const bulk = useListBulk({
|
|
294
|
+
bulkActions: screen.bulkActions,
|
|
295
|
+
rowActions: screen.rowActions,
|
|
296
|
+
translate: effectiveTranslate,
|
|
297
|
+
dispatcher,
|
|
298
|
+
reload: refreshRowsAfterWrite,
|
|
299
|
+
});
|
|
415
300
|
// ToolbarActions: Schema → Resolved-Form (analog rowActions), shared with
|
|
416
301
|
// projectionList and relatedList sections via buildProjectionToolbarActions.
|
|
417
302
|
const toolbarActions = useMemo(() => buildProjectionToolbarActions({
|
|
@@ -471,14 +356,14 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
471
356
|
refreshRowsAfterWrite,
|
|
472
357
|
invalidateExpansions,
|
|
473
358
|
]);
|
|
474
|
-
if (
|
|
359
|
+
if (listRows.firstLoad) {
|
|
475
360
|
return _jsx(QueryLoadingBanner, {});
|
|
476
361
|
}
|
|
477
|
-
if (
|
|
478
|
-
return (_jsx(QueryErrorBanner, { error:
|
|
362
|
+
if (listRows.error && !listRows.hasData) {
|
|
363
|
+
return (_jsx(QueryErrorBanner, { error: listRows.error, translate: effectiveTranslate, onRetry: listRows.retry }));
|
|
479
364
|
}
|
|
480
365
|
// A failed refetch keeps the last good data on screen.
|
|
481
|
-
const refetchErrorBanner =
|
|
366
|
+
const refetchErrorBanner = listRows.error ? (_jsx(QueryErrorBanner, { error: listRows.error, translate: effectiveTranslate, onRetry: listRows.retry })) : null;
|
|
482
367
|
// RenderList's onRowClick is a 1-arg callback; KumikoScreen's
|
|
483
368
|
// 2-arg shape (row, entityName) is the public surface — thread the
|
|
484
369
|
// screen's entity through here so callers don't have to re-derive
|
|
@@ -507,41 +392,24 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
507
392
|
// Assemble pager props only for pagination="pages". The server total
|
|
508
393
|
// arrives async; until it is there RenderList renders the table without a
|
|
509
394
|
// pager (the pager has its own total>0 guard).
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
? {
|
|
513
|
-
page: urlState.page,
|
|
514
|
-
limit,
|
|
515
|
-
total,
|
|
516
|
-
onPageChange: urlState.setPage,
|
|
517
|
-
pageSizeOptions: pageSizeOptionsFor(limit),
|
|
518
|
-
onPageSizeChange: urlState.setPageSize,
|
|
519
|
-
}
|
|
520
|
-
: undefined;
|
|
521
|
-
// In infinite mode rows come from accumulated (collected across several
|
|
522
|
-
// useQuery calls), with pages/false from the current result.
|
|
523
|
-
const renderRows = useInfinite ? accumulated : (rowsQuery.data?.rows ?? []);
|
|
524
|
-
return (_jsxs(_Fragment, { children: [refetchErrorBanner, _jsx(ReferenceFacetBridges, { specs: entityFacetSpecs, onOptions: handleEntityFacetOptions }), _jsx(FacetCountBridges, { queryType: queryType, queries: facetCountQueries, onCount: handleFacetCount, refreshNonce: facetCountRefreshNonce }), _jsx(RenderList, { screen: screen, entity: entity, rows: renderRows, featureName: featureName, searchable: searchable, narrowed: isListNarrowed(urlState.q, urlState.filters, defaultFilters), defaultFilterActive: isDefaultFilterActive(urlState.q, urlState.filters, defaultFilters), ...(screen.description !== undefined && {
|
|
395
|
+
const pager = listPager({ usePager, page: listRows.page, limit, urlState });
|
|
396
|
+
return (_jsxs(_Fragment, { children: [refetchErrorBanner, _jsx(ListGroupPageBridges, { ...listTable.aggregates.groupPages }), _jsx(ReferenceFacetBridges, { specs: entityFacetSpecs, onOptions: handleEntityFacetOptions }), _jsx(FacetCountBridges, { queryType: queryType, queries: facetCountQueries, onCount: handleFacetCount, refreshNonce: facetCountRefreshNonce }), _jsx(RenderList, { screen: screen, entity: entity, rows: listRows.rows, featureName: featureName, searchable: searchable, narrowed: isListNarrowed(urlState.q, urlState.filters, defaultFilters), defaultFilterActive: isDefaultFilterActive(urlState.q, urlState.filters, defaultFilters), ...(screen.description !== undefined && {
|
|
525
397
|
description: effectiveTranslate(screen.description),
|
|
526
398
|
}), ...(emptyContent !== undefined && { emptyContent }), searchValue: urlState.q, onSearchChange: urlState.setQ, sort: effectiveSort, onSortChange: urlState.setSort, ...(isEmbeddedScreen
|
|
527
399
|
? { screenPadding: false, chromeless: true }
|
|
528
|
-
: { screenPadding: true }), ...(screenFillsHeight(screen) && { scrollBody: true }), ...(pager !== undefined && { pager }), ...(rowActions !== undefined && { rowActions }), ...(screen.rowActionMode !== undefined && { rowActionMode: screen.rowActionMode }), ...(toolbarActions !== undefined && toolbarActions.length > 0 && { toolbarActions }), ...(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
}), ...(onCreate !== undefined && { onCreate }), ...(translate !== undefined && { translate }), ...(wrappedOnRowClick !== undefined && { onRowClick: wrappedOnRowClick }), ...(filterFacets.length > 0 && {
|
|
533
|
-
filterFacets,
|
|
400
|
+
: { screenPadding: true }), ...(screenFillsHeight(screen) && { scrollBody: true }), ...(pager !== undefined && { pager }), ...(rowActions !== undefined && { rowActions }), ...(screen.rowActionMode !== undefined && { rowActionMode: screen.rowActionMode }), ...(bulk !== undefined && { bulk }), ...(toolbarActions !== undefined && toolbarActions.length > 0 && { toolbarActions }), ...listRows.infinite, ...(onCreate !== undefined && { onCreate }), ...(translate !== undefined && { translate }), ...(wrappedOnRowClick !== undefined && { onRowClick: wrappedOnRowClick }), ...(filterFacets.length > 0 && { filterFacets, onFilterChange: urlState.setFilter }), ...(range.rangeFacets.length > 0 && {
|
|
401
|
+
rangeFacets: range.rangeFacets,
|
|
402
|
+
onRangeChange: range.onRangeChange,
|
|
403
|
+
}), ...((filterFacets.length > 0 || range.rangeFacets.length > 0) && {
|
|
534
404
|
filterValues: urlState.filters,
|
|
535
|
-
onFilterChange: urlState.setFilter,
|
|
536
405
|
onFilterReset: urlState.clearFilters,
|
|
537
|
-
}), ...(expandableSection !== undefined && {
|
|
406
|
+
}), ...listTable.props, ...(expandableSection !== undefined && {
|
|
538
407
|
expandedRowIds,
|
|
539
408
|
onToggleRowExpanded: toggleRowExpanded,
|
|
540
409
|
renderExpandedRow,
|
|
541
410
|
}) }), _jsx(DrawerHost, { schema: schema, drawerAction: drawerAction, drawerScreen: drawerScreen, ...(drawerInitialValues !== undefined && { drawerInitialValues }), userRoles: userRoles, ...(translate !== undefined && { translate }), onClose: closeDrawer, onSuccess: () => {
|
|
542
411
|
closeDrawer();
|
|
543
412
|
invalidateExpansions();
|
|
544
|
-
|
|
545
|
-
void rowsQuery.refetch();
|
|
413
|
+
void refreshRowsAfterWrite();
|
|
546
414
|
} })] }));
|
|
547
415
|
}
|