@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
package/dist/primitives.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ConfigCascade, ConfigScope, ConfigValueSource } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import type { FieldIconKey, FormWidth, IconKey, NavIconKey, RowActionDisplay, SelectOptionTone } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
3
|
import { type ComponentType, type FormEvent, type KeyboardEvent, type ReactNode, type Ref } from "react";
|
|
4
|
+
import type { DataTableBulk } from "./data-table-bulk-types.ts";
|
|
5
|
+
import type { DataTableDateRangeFacet, DataTableFacet } from "./data-table-facet-types.ts";
|
|
6
|
+
import type { DataTableTableBlock } from "./data-table-view-types.ts";
|
|
4
7
|
import type { FieldIssue, ListColumnViewModel, ListRowViewModel, RuntimeRenderer } from "./headless/index.ts";
|
|
5
8
|
export type { RuntimeRenderer };
|
|
6
9
|
/** Escape hatch for `data-*` test hooks (e.g. an E2E selector) that don't
|
|
@@ -647,55 +650,11 @@ export type DataTableRowAction = {
|
|
|
647
650
|
export declare function shouldRenderActionsIconOnly(actions: readonly {
|
|
648
651
|
readonly icon?: IconKey;
|
|
649
652
|
}[]): boolean;
|
|
650
|
-
export type
|
|
651
|
-
|
|
652
|
-
readonly field: string;
|
|
653
|
-
/** Translated Button-Label ("Status", "Active"). */
|
|
654
|
-
readonly label: string;
|
|
655
|
-
/** Selectable values with display labels. `value` is the raw filter value
|
|
656
|
-
* (a select option or `"true"`/`"false"`), transported as a string. */
|
|
657
|
-
readonly options: readonly {
|
|
658
|
-
readonly value: string;
|
|
659
|
-
readonly label: string;
|
|
660
|
-
}[];
|
|
661
|
-
/** Present: render the facet as a row of single-choice toggle chips instead
|
|
662
|
-
* of a dropdown. A chip is pressed while the selection equals its values. */
|
|
663
|
-
readonly chips?: readonly DataTableFacetChip[];
|
|
664
|
-
/** Chips only: show each chip's `count` next to its label. */
|
|
665
|
-
readonly showCounts?: boolean;
|
|
666
|
-
/** Chips only: hide chips whose `count` is 0 (unless pressed). */
|
|
667
|
-
readonly hideEmpty?: boolean;
|
|
668
|
-
};
|
|
669
|
-
export type DataTableFacetChip = {
|
|
670
|
-
readonly id: string;
|
|
671
|
-
/** Translated chip label. */
|
|
672
|
-
readonly label: string;
|
|
673
|
-
/** Selection a click sets; `[]` clears the facet. */
|
|
674
|
-
readonly values: readonly string[];
|
|
675
|
-
/** Matching row count, undefined while unknown. */
|
|
676
|
-
readonly count?: number;
|
|
677
|
-
};
|
|
678
|
-
export type DataTableDateRangeFacet = {
|
|
679
|
-
/** The facet's namespace (its date field) — a key, not a filter value. */
|
|
680
|
-
readonly field: string;
|
|
681
|
-
/** Translated label ("When"). */
|
|
682
|
-
readonly label: string;
|
|
683
|
-
readonly from: string;
|
|
684
|
-
readonly to: string;
|
|
685
|
-
};
|
|
686
|
-
/** Splits rows into collapsible groups (order of first appearance). A
|
|
687
|
-
* renderer without grouping support shows the flat list. A group whose
|
|
688
|
-
* `headerLabel` is undefined shows its rows without a header and never
|
|
689
|
-
* collapses. */
|
|
690
|
-
export type DataTableRowGrouping = {
|
|
691
|
-
readonly keyOf: (row: ListRowViewModel) => string;
|
|
692
|
-
readonly headerLabel: (groupKey: string, rows: readonly ListRowViewModel[]) => string | undefined;
|
|
693
|
-
readonly startsCollapsed: (groupKey: string) => boolean;
|
|
694
|
-
};
|
|
653
|
+
export type { BulkRowOutcome, DataTableBulk, DataTableBulkAction, } from "./data-table-bulk-types.ts";
|
|
654
|
+
export type { DataTableDateRangeFacet, DataTableFacet, DataTableFacetChip, } from "./data-table-facet-types.ts";
|
|
695
655
|
export type DataTableProps = {
|
|
696
656
|
readonly columns: readonly ListColumnViewModel[];
|
|
697
657
|
readonly rows: readonly ListRowViewModel[];
|
|
698
|
-
readonly rowGrouping?: DataTableRowGrouping;
|
|
699
658
|
/** Tints a row. Renderers without row tinting ignore it. */
|
|
700
659
|
readonly rowTone?: (row: ListRowViewModel) => SelectOptionTone | undefined;
|
|
701
660
|
readonly onRowClick?: (row: ListRowViewModel) => void;
|
|
@@ -723,6 +682,8 @@ export type DataTableProps = {
|
|
|
723
682
|
* kebab). Actions then sit at the same x-position across all rows
|
|
724
683
|
* (no drifting with label width) and all lists in an app look alike. */
|
|
725
684
|
readonly rowActionMode?: DataTableRowActionMode;
|
|
685
|
+
/** Present: row checkboxes plus a selection bar that runs these actions once per selected row. */
|
|
686
|
+
readonly bulk?: DataTableBulk;
|
|
726
687
|
/** Custom empty-state content (e.g. Icon + Heading + CTA-Button).
|
|
727
688
|
* The default renderer wraps it in a dashed-border box. */
|
|
728
689
|
readonly emptyState?: ReactNode;
|
|
@@ -832,7 +793,8 @@ export type DataTableProps = {
|
|
|
832
793
|
/** Content of the area under an expanded row. Native renderers implement
|
|
833
794
|
* the same three props. */
|
|
834
795
|
readonly renderExpandedRow?: (row: ListRowViewModel) => ReactNode;
|
|
835
|
-
};
|
|
796
|
+
} & DataTableTableBlock;
|
|
797
|
+
export type DataTableTableBlockProps = Pick<DataTableProps, keyof DataTableTableBlock>;
|
|
836
798
|
/** Cell type for one column of an embedded-list field. Mirrors
|
|
837
799
|
* EmbeddedListCellViewModel["type"] from `@cosmicdrift/kumiko-renderer/headless`. */
|
|
838
800
|
export type EmbeddedListCellType = "text" | "number" | "boolean" | "date" | "money" | "decimal" | "select" | "reference" | "timestamp";
|
|
@@ -1403,6 +1365,8 @@ export type JsonViewProps = {
|
|
|
1403
1365
|
* PDFs, an inline preview. Used for `renderer: { format: "file" }` on a detail field. */
|
|
1404
1366
|
export type FileValueListProps = {
|
|
1405
1367
|
readonly fileIds: readonly string[];
|
|
1368
|
+
/** Starts the inline PDF preview of the newest file open; uploads append, so that is the last id. */
|
|
1369
|
+
readonly previewOpenByDefault?: boolean;
|
|
1406
1370
|
readonly testId?: string;
|
|
1407
1371
|
};
|
|
1408
1372
|
/** Band above the tabs of a record detail: optional subtitle line plus the
|
|
@@ -92,6 +92,11 @@ export type CreateKumikoAppOptions = {
|
|
|
92
92
|
readonly hasWorkspaces?: boolean;
|
|
93
93
|
readonly features?: readonly FeatureSchema[];
|
|
94
94
|
}) => NavApi;
|
|
95
|
+
/** URL prefix the app is mounted under (for example "/admin"). The default nav adapter reads
|
|
96
|
+
* and writes URLs relative to it, and the auth gates and pages, which sit outside the
|
|
97
|
+
* NavProvider, use it to match and build their paths. A custom `navAdapter` handles its own
|
|
98
|
+
* prefix. */
|
|
99
|
+
readonly basePath?: string;
|
|
95
100
|
/** App-wide default width for form/detail screens that don't set their
|
|
96
101
|
* own `layout.width`. Default "4xl" (unchanged behavior) — a
|
|
97
102
|
* consumer app that wants e.g. bundled-feature screens to match its own
|
|
@@ -3,7 +3,7 @@ import { isOpenToAllGranted } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
|
3
3
|
import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
4
4
|
import { createRoot } from "react-dom/client";
|
|
5
5
|
import { rendererError, rendererWarn } from "../../dev-console.js";
|
|
6
|
-
import { AppFeaturesProvider, ClientActionsProvider, ColumnRenderersProvider, ContentEditorsProvider, CustomScreensProvider, createSessionEndedSignal, DashboardBodyProvider, DispatcherProvider, DraftStorageProvider, ErrorBoundary, ExtensionSectionsProvider, hasDetailScreen, KumikoScreen, kumikoDefaultTranslations, LeaveGuardDialog, LiveEventsProvider, LocaleProvider, mergeTranslations, NavProvider, navigateWithReturnTo, PrimitivesProvider, qualifyScreenId, ScreenMissingState, SessionEndedSignalProvider, TokensProvider, toAppSchema, translationsByLocaleFromKeys, useNav, usePrimitives, useTranslation, withSessionEndedDetection, } from "../../index.js";
|
|
6
|
+
import { AppFeaturesProvider, BasePathProvider, ClientActionsProvider, ColumnRenderersProvider, ContentEditorsProvider, CustomScreensProvider, createSessionEndedSignal, DashboardBodyProvider, DispatcherProvider, DraftStorageProvider, ErrorBoundary, ExtensionSectionsProvider, hasDetailScreen, KumikoScreen, kumikoDefaultTranslations, LeaveGuardDialog, LiveEventsProvider, LocaleProvider, mergeTranslations, NavProvider, navigateWithReturnTo, PrimitivesProvider, qualifyScreenId, ScreenMissingState, SessionEndedSignalProvider, TokensProvider, toAppSchema, translationsByLocaleFromKeys, useNav, usePrimitives, useTranslation, withSessionEndedDetection, } from "../../index.js";
|
|
7
7
|
import { createLiveDispatcher } from "../../live/index.js";
|
|
8
8
|
import { lastSegment } from "../layout/nav-tree.js";
|
|
9
9
|
import { clearFileMetaCache } from "../primitives/file-thumbnail.js";
|
|
@@ -19,6 +19,7 @@ import { stackWrappers } from "./client-plugin.js";
|
|
|
19
19
|
import { WebDashboardBody } from "./dashboard-body.js";
|
|
20
20
|
import { DocumentLangSync } from "./document-lang-sync.js";
|
|
21
21
|
import { createBrowserDraftStorage } from "./draft-storage.js";
|
|
22
|
+
import { ListStateStoreBoot } from "./list-state-store-boot.js";
|
|
22
23
|
import { useBrowserNavApi } from "./nav.js";
|
|
23
24
|
import { NavProvidersProvider } from "./nav-providers-context.js";
|
|
24
25
|
import { ResolversProvider } from "./resolvers-context.js";
|
|
@@ -237,7 +238,7 @@ function KumikoAppRoot(props) {
|
|
|
237
238
|
warnMissingCustomScreens(loaded, props.customScreens);
|
|
238
239
|
setApp(loaded);
|
|
239
240
|
}, schemaIsRoleProjected: isFetchMode, ...(isFetchMode && { onUnmountResetSchema: () => setApp(undefined) }), ...(props.translate !== undefined && { translate: props.translate }), ...(props.onRowClick !== undefined && { onRowClick: props.onRowClick }), ...(props.shell !== undefined && { shell: props.shell }) }));
|
|
240
|
-
return (_jsx(TokensBoot, { children: _jsxs(LocaleProvider, { resolver: props.localeResolver, fallbackBundles: fallbackBundles, children: [_jsx(DocumentLangSync, { resolver: props.localeResolver }), _jsx(PrimitivesProvider, { value: props.primitives, children: _jsx(ScreenWidthProvider, { width: props.screenWidth, children: _jsx(AppFeaturesProvider, { features: app?.features ?? EMPTY_FEATURES, children: _jsx(DispatcherProvider, { dispatcher: props.dispatcher, children: _jsx(DraftStorageProvider, { value: props.draftStorage, children: _jsx(LiveEventsProvider, { value: props.liveEvents, children: _jsx(DashboardBodyProvider, { value: WebDashboardBody, children: _jsx(CustomScreensProvider, { value: props.customScreens, children: _jsx(ColumnRenderersProvider, { value: props.columnRenderers, children: _jsx(ContentEditorsProvider, { value: props.contentEditors, children: _jsx(ExtensionSectionsProvider, { value: props.extensionSectionComponents, children: _jsx(ClientActionsProvider, { value: props.clientActions, children: _jsx(NavProvidersProvider, { value: navProviders, entities: navEntities, children: _jsx(ResolversProvider, { resolvers: props.resolvers, children: _jsx(ToastProvider, { children: _jsxs(ToastActionNotifier, { children: [_jsx(UpdateChecker, {}), _jsx(LeaveGuardDialog, {}), _jsx(SessionEndedSignalProvider, { signal: props.sessionEndedSignal, children: stackWrappers(props.providers, stackWrappers(props.gates, screenNode)) })] }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })] }) }));
|
|
241
|
+
return (_jsx(TokensBoot, { children: _jsxs(LocaleProvider, { resolver: props.localeResolver, fallbackBundles: fallbackBundles, children: [_jsx(DocumentLangSync, { resolver: props.localeResolver }), _jsx(PrimitivesProvider, { value: props.primitives, children: _jsx(ScreenWidthProvider, { width: props.screenWidth, children: _jsx(AppFeaturesProvider, { features: app?.features ?? EMPTY_FEATURES, children: _jsx(DispatcherProvider, { dispatcher: props.dispatcher, children: _jsx(DraftStorageProvider, { value: props.draftStorage, children: _jsx(LiveEventsProvider, { value: props.liveEvents, children: _jsx(DashboardBodyProvider, { value: WebDashboardBody, children: _jsx(CustomScreensProvider, { value: props.customScreens, children: _jsx(ColumnRenderersProvider, { value: props.columnRenderers, children: _jsx(ContentEditorsProvider, { value: props.contentEditors, children: _jsx(ExtensionSectionsProvider, { value: props.extensionSectionComponents, children: _jsx(ClientActionsProvider, { value: props.clientActions, children: _jsx(NavProvidersProvider, { value: navProviders, entities: navEntities, children: _jsx(ResolversProvider, { resolvers: props.resolvers, children: _jsx(ToastProvider, { children: _jsxs(ToastActionNotifier, { children: [_jsx(UpdateChecker, {}), _jsx(LeaveGuardDialog, {}), _jsx(SessionEndedSignalProvider, { signal: props.sessionEndedSignal, children: stackWrappers(props.providers, stackWrappers(props.gates, _jsx(ListStateStoreBoot, { children: screenNode }))) })] }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })] }) }));
|
|
241
242
|
}
|
|
242
243
|
// Sits INSIDE the clientFeature gates (e.g. an auth gate) — a gate that
|
|
243
244
|
// renders a login placeholder instead of children keeps this component
|
|
@@ -340,7 +341,9 @@ export function createKumikoApp(options = {}) {
|
|
|
340
341
|
}
|
|
341
342
|
}
|
|
342
343
|
const localeResolver = options.locale ?? createBrowserLocaleResolver();
|
|
343
|
-
const
|
|
344
|
+
const { basePath } = options;
|
|
345
|
+
const useBrowserNavApiWithBasePath = (navOptions) => useBrowserNavApi({ ...navOptions, ...(basePath !== undefined && { basePath }) });
|
|
346
|
+
const navAdapter = options.navAdapter ?? useBrowserNavApiWithBasePath;
|
|
344
347
|
const reporter = options.reportClientErrors === false ? undefined : createClientErrorReporter();
|
|
345
348
|
reporter?.installGlobalHandlers();
|
|
346
349
|
const handleBoundaryError = (error, info, context) => {
|
|
@@ -353,7 +356,7 @@ export function createKumikoApp(options = {}) {
|
|
|
353
356
|
options.onError?.(error, info, context);
|
|
354
357
|
};
|
|
355
358
|
const root = createRoot(container);
|
|
356
|
-
root.render(_jsx(ErrorBoundary, { scope: "root", onError: handleBoundaryError, fallback: ({ errorId }) => _jsx(RootErrorFallback, { errorId: errorId }), children: _jsx(BoundaryErrorHandlerContext.Provider, { value: handleBoundaryError, children: _jsx(KumikoAppRoot, { initialApp: initialApp, screenQn: options.screenQn, ...(options.schemaUrl !== undefined && { schemaUrl: options.schemaUrl }), clientFeatures: clientFeatures, providers: providers, gates: gates, customScreens: customScreens, columnRenderers: columnRenderers, extensionSectionComponents: extensionSectionComponents, clientActions: clientActions, contentEditors: contentEditors, resolvers: resolvers, dispatcher: dispatcher, sessionEndedSignal: sessionEndedSignal, draftStorage: draftStorage, primitives: primitives, liveEvents: liveEvents, localeResolver: localeResolver, navAdapter: navAdapter, screenWidth: options.screenWidth, ...(options.translate !== undefined && { translate: options.translate }), ...(options.onRowClick !== undefined && { onRowClick: options.onRowClick }), ...(options.shell !== undefined && { shell: options.shell }) }) }) }));
|
|
359
|
+
root.render(_jsx(ErrorBoundary, { scope: "root", onError: handleBoundaryError, fallback: ({ errorId }) => _jsx(RootErrorFallback, { errorId: errorId }), children: _jsx(BoundaryErrorHandlerContext.Provider, { value: handleBoundaryError, children: _jsx(BasePathProvider, { basePath: basePath, children: _jsx(KumikoAppRoot, { initialApp: initialApp, screenQn: options.screenQn, ...(options.schemaUrl !== undefined && { schemaUrl: options.schemaUrl }), clientFeatures: clientFeatures, providers: providers, gates: gates, customScreens: customScreens, columnRenderers: columnRenderers, extensionSectionComponents: extensionSectionComponents, clientActions: clientActions, contentEditors: contentEditors, resolvers: resolvers, dispatcher: dispatcher, sessionEndedSignal: sessionEndedSignal, draftStorage: draftStorage, primitives: primitives, liveEvents: liveEvents, localeResolver: localeResolver, navAdapter: navAdapter, screenWidth: options.screenWidth, ...(options.translate !== undefined && { translate: options.translate }), ...(options.onRowClick !== undefined && { onRowClick: options.onRowClick }), ...(options.shell !== undefined && { shell: options.shell }) }) }) }) }));
|
|
357
360
|
return { root };
|
|
358
361
|
}
|
|
359
362
|
// TokensBoot uses the browser-backed TokensApi hook (class-based
|
|
@@ -1,55 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { ErrorReference } from "../../app/error-reference.js";
|
|
4
|
-
import { dispatcherErrorText, EmbeddedScreenProvider, evalVisibleWhen, HeaderActionsBar, KumikoScreen, useEmbeddedScreen, useLocale, useNav, usePageHeaderCompact, usePageHeaderSlotAvailable, usePrimitives, useQuery, useRecordActions, useTranslation, } from "../../index.js";
|
|
5
|
-
import { cn } from "../lib/cn.js";
|
|
6
|
-
import { EmbeddedFormProvider } from "../primitives/index.js";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useNav, usePageHeaderCompact, usePageHeaderSlotAvailable, usePrimitives, useTranslation, } from "../../index.js";
|
|
7
3
|
import { PageSection } from "../primitives/layout.js";
|
|
8
|
-
import {
|
|
9
|
-
import { SectionCard } from "../widgets/section-card.js";
|
|
10
|
-
import { StatusBadge } from "../widgets/status-badge.js";
|
|
4
|
+
import { buildScopeBadge, dashboardDescription, recordTitleText, renderActionErrorBanner, renderDescriptionAndNotice, renderHeaderActionsBar, renderPageHeaderSlot, renderRecordError, renderRecordMissing, renderTitleRow, } from "./dashboard-header.js";
|
|
11
5
|
import { ChartPanelBody, CustomPanelBody, FeedPanelBody, ListPanelBody, ProgressListPanelBody, StatGroupPanelBody, StatPanelBody, TextPanelBody, } from "./dashboard-panels.js";
|
|
12
|
-
import {
|
|
13
|
-
import { DashboardQueryContext, HALF_PANEL,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// `params` can deep-link onto this filter.
|
|
17
|
-
function useFilterParams(screen, enabled) {
|
|
18
|
-
const { Field, Input } = usePrimitives();
|
|
19
|
-
const t = useTranslation();
|
|
20
|
-
const nav = useNav();
|
|
21
|
-
const filter = screen.filter;
|
|
22
|
-
const value = filter !== undefined ? (nav.searchParams[filter.id] ?? "") : "";
|
|
23
|
-
const optionsQueryResult = useQuery(filter?.optionsQuery ?? "", {}, { enabled: enabled && filter?.optionsQuery !== undefined });
|
|
24
|
-
if (filter === undefined) {
|
|
25
|
-
return { params: {}, picker: null };
|
|
26
|
-
}
|
|
27
|
-
const dynamicOptions = filter.optionsQuery !== undefined
|
|
28
|
-
? (optionsQueryResult.data?.rows ?? [])
|
|
29
|
-
: (filter.options ?? []).map((o) => ({ value: o.value, label: t(o.label) }));
|
|
30
|
-
const allLabel = t(filter.allLabel ?? "kumiko.dashboard.filter.all");
|
|
31
|
-
const options = [{ value: "", label: allLabel }, ...dynamicOptions];
|
|
32
|
-
const picker = (_jsx("div", { className: "max-w-xs", children: _jsx(Field, { id: `dashboard-filter-${filter.id}`, label: t(filter.label), children: _jsx(Input, { kind: "combobox", id: `dashboard-filter-${filter.id}`, name: filter.id, options: options, value: value, onChange: (next) => nav.setSearchParams({ [filter.id]: next === "" ? null : next }), placeholder: filter.placeholder !== undefined ? t(filter.placeholder) : allLabel }) }) }));
|
|
33
|
-
const params = value === "" ? {} : { [filter.id]: value };
|
|
34
|
-
return { params, picker };
|
|
35
|
-
}
|
|
36
|
-
// An unknown/stale URL value falls back to the declared default.
|
|
37
|
-
function useTimeRange(screen, translate) {
|
|
38
|
-
const t = useTranslation();
|
|
39
|
-
const nav = useNav();
|
|
40
|
-
const resolver = useLocale();
|
|
41
|
-
const timeRange = screen.timeRange;
|
|
42
|
-
if (timeRange === undefined)
|
|
43
|
-
return { params: {}, control: null };
|
|
44
|
-
const fromUrl = nav.searchParams[timeRange.id];
|
|
45
|
-
const value = timeRange.options.find((o) => o.value === fromUrl)?.value ?? timeRange.default;
|
|
46
|
-
return {
|
|
47
|
-
// Metric buckets are cut server-side; without the user's zone they default
|
|
48
|
-
// to UTC while the axis labels are formatted in the user's zone.
|
|
49
|
-
params: { [timeRange.id]: value, timeZone: resolver.timeZone() },
|
|
50
|
-
control: (_jsx(ModeSwitch, { value: value, options: timeRange.options.map((o) => ({ value: o.value, label: translate(o.label) })), onChange: (next) => nav.setSearchParams({ [timeRange.id]: next }), ariaLabel: t("kumiko.dashboard.time-range"), testId: `dashboard-time-range-${timeRange.id}` })),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
6
|
+
import { ScreenPanelTile } from "./dashboard-screen-tiles.js";
|
|
7
|
+
import { DashboardQueryContext, HALF_PANEL, PanelLoadedContext, useDashboardFormats, WIDE_PANEL, } from "./dashboard-shared.js";
|
|
8
|
+
import { GatedGridCell, useDashboardVisibility, VisibilityGateQueries, VisibilityQueryContext, } from "./dashboard-visibility.js";
|
|
9
|
+
import { useDashboardHeaderActions, useDashboardRecord, useDashboardScreenParams, } from "./use-dashboard-screen-state.js";
|
|
53
10
|
function panelSpanClassName(panel) {
|
|
54
11
|
if (panel.kind === "stat")
|
|
55
12
|
return undefined;
|
|
@@ -88,212 +45,51 @@ function PanelBody({ panel, label, screenId, screenParams, translate, }) {
|
|
|
88
45
|
}
|
|
89
46
|
return (_jsx(ProgressListPanelBody, { panel: panel, label: text, screenParams: screenParams, translate: translate }));
|
|
90
47
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return { key: `${query}|${JSON.stringify(payload)}`, query, payload };
|
|
95
|
-
}
|
|
96
|
-
// Embedded screens carry no screen filter; in-grid panels pass the filter
|
|
97
|
-
// (unless ignoreScreenFilter, never for a stat-group) and the time range.
|
|
98
|
-
function panelVisibilityGate(panel, screenParams) {
|
|
99
|
-
if (panel.kind === "custom" || panel.visibleWhen === undefined)
|
|
100
|
-
return undefined;
|
|
101
|
-
if (panel.kind === "screen")
|
|
102
|
-
return visibilityGate(panel.visibleWhen.query, NO_GATE_PAYLOAD);
|
|
103
|
-
const dropsFilter = panel.kind !== "stat-group" && panel.kind !== "text" && panel.ignoreScreenFilter === true;
|
|
104
|
-
return visibilityGate(panel.visibleWhen.query, {
|
|
105
|
-
...(dropsFilter ? {} : screenParams.filterParams),
|
|
106
|
-
...screenParams.rangeParams,
|
|
107
|
-
...screenParams.recordParams,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
// One live query per distinct gate (query + payload), shared by every panel
|
|
111
|
-
// that gates on it — N panels on the same status query would otherwise each
|
|
112
|
-
// open their own request, SSE subscription and refetch per event. The queries
|
|
113
|
-
// run as keyed siblings of the grid so a changing gate count never changes the
|
|
114
|
-
// grid's position in the tree (which would remount every panel).
|
|
115
|
-
function VisibilityGateQuery({ gate, onResult, onForget, }) {
|
|
116
|
-
const { data, error, loading, refetch } = useDashboardQuery(gate.query, gate.payload);
|
|
117
|
-
const { key } = gate;
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
onResult(key, { data, error, loading, refetch });
|
|
120
|
-
}, [key, data, error, loading, refetch, onResult]);
|
|
121
|
-
useEffect(() => () => onForget(key), [key, onForget]);
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
function VisibilityGateQueries({ gates, onResult, onForget, }) {
|
|
125
|
-
return gates.map((gate) => (_jsx(VisibilityGateQuery, { gate: gate, onResult: onResult, onForget: onForget }, gate.key)));
|
|
126
|
-
}
|
|
127
|
-
function useVisibilityGateResults() {
|
|
128
|
-
const [results, setResults] = useState(new Map());
|
|
129
|
-
const report = useCallback((key, result) => {
|
|
130
|
-
setResults((prev) => new Map(prev).set(key, result));
|
|
131
|
-
}, []);
|
|
132
|
-
const forget = useCallback((key) => {
|
|
133
|
-
setResults((prev) => {
|
|
134
|
-
if (!prev.has(key))
|
|
135
|
-
return prev;
|
|
136
|
-
const next = new Map(prev);
|
|
137
|
-
next.delete(key);
|
|
138
|
-
return next;
|
|
139
|
-
});
|
|
140
|
-
}, []);
|
|
141
|
-
return { results, report, forget };
|
|
142
|
-
}
|
|
143
|
-
const NOOP_REFETCH = async () => { };
|
|
144
|
-
// A gate reports through an effect, so for its first commit (and after a payload change) no
|
|
145
|
-
// result exists yet; without a placeholder that reads as "hidden" and flashes the fallback.
|
|
146
|
-
function withPendingGates(results, gateKeys) {
|
|
147
|
-
if (gateKeys.every((key) => results.has(key)))
|
|
148
|
-
return results;
|
|
149
|
-
const merged = new Map(results);
|
|
150
|
-
for (const key of gateKeys) {
|
|
151
|
-
if (!merged.has(key)) {
|
|
152
|
-
merged.set(key, { data: null, error: null, loading: true, refetch: NOOP_REFETCH });
|
|
153
|
-
}
|
|
48
|
+
function renderDashboardPanel(panel, featureName, screenId, screenParams, translate) {
|
|
49
|
+
if (panel.kind === "screen") {
|
|
50
|
+
return (_jsx(ScreenPanelTile, { panel: panel, featureName: featureName, translate: translate }, panel.id));
|
|
154
51
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
function distinctVisibilityGates(panels, screenParams) {
|
|
158
|
-
const gates = new Map();
|
|
159
|
-
for (const panel of panels) {
|
|
160
|
-
const gate = panelVisibilityGate(panel, screenParams);
|
|
161
|
-
if (gate !== undefined)
|
|
162
|
-
gates.set(gate.key, gate);
|
|
163
|
-
}
|
|
164
|
-
return [...gates.values()];
|
|
165
|
-
}
|
|
166
|
-
function GatedGridCell({ panel, screenParams, label, className, children, }) {
|
|
167
|
-
const gate = panelVisibilityGate(panel, screenParams);
|
|
168
|
-
const visibility = useContext(VisibilityQueryContext).get(gate?.key ?? "");
|
|
169
|
-
const visibleWhen = panel.kind === "custom" ? undefined : panel.visibleWhen;
|
|
170
|
-
if (visibleWhen !== undefined) {
|
|
171
|
-
const verdict = evalVisibleWhen(visibleWhen, visibility);
|
|
172
|
-
if (verdict === "error" && visibility?.error) {
|
|
173
|
-
return (_jsx("div", { className: cn("min-w-0", className), "data-testid": `dashboard-panel-${panel.id}`, children: _jsx(PanelError, { label: label, error: visibility.error, onRetry: () => void visibility.refetch() }) }));
|
|
174
|
-
}
|
|
175
|
-
// Loading renders nothing too: a skeleton that then vanishes flickers.
|
|
176
|
-
if (verdict !== "visible")
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
return _jsx("div", { className: cn("min-w-0", className), children: children });
|
|
180
|
-
}
|
|
181
|
-
function EmbeddedScreenPanelTile({ panel, target, translate, }) {
|
|
182
|
-
const screenBody = _jsx(KumikoScreen, { schema: target.schema, qn: target.qn, translate: translate });
|
|
183
|
-
const embedded = panel.chromeless === true ? (_jsx(EmbeddedFormProvider, { children: _jsx(EmbeddedScreenProvider, { children: screenBody }) })) : (screenBody);
|
|
184
|
-
return (_jsx("div", { className: cn("min-w-0", WIDE_PANEL), "data-testid": `dashboard-panel-${panel.id}`, children: panel.label !== undefined && panel.chromeless !== true ? (_jsx(SectionCard, { title: translate(panel.label), children: embedded })) : (_jsxs(_Fragment, { children: [panel.label !== undefined && (_jsx("h3", { className: "mb-3 text-sm font-semibold text-foreground", children: translate(panel.label) })), embedded] })) }));
|
|
185
|
-
}
|
|
186
|
-
// Own component so the target lookup (a hook) only runs for panels that actually fall back.
|
|
187
|
-
function FallbackScreenPanelTile({ panel, fallback, featureName, translate, }) {
|
|
188
|
-
const target = useEmbeddedScreen(featureName, fallback);
|
|
189
|
-
if (target === undefined)
|
|
190
|
-
return null;
|
|
191
|
-
return _jsx(EmbeddedScreenPanelTile, { panel: panel, target: target, translate: translate });
|
|
192
|
-
}
|
|
193
|
-
function ScreenPanelTile({ panel, featureName, translate, }) {
|
|
194
|
-
const visibleWhen = panel.visibleWhen;
|
|
195
|
-
const visibility = useContext(VisibilityQueryContext).get(visibleWhen !== undefined ? visibilityGate(visibleWhen.query, NO_GATE_PAYLOAD).key : "");
|
|
196
|
-
const target = useEmbeddedScreen(featureName, panel.screen);
|
|
197
|
-
const verdict = visibleWhen === undefined ? "visible" : evalVisibleWhen(visibleWhen, visibility);
|
|
198
|
-
// Nothing while the gate loads: a fallback that flashes before the real panel flickers.
|
|
199
|
-
if (verdict === "loading")
|
|
200
|
-
return null;
|
|
201
|
-
if (verdict !== "visible" && panel.fallback !== undefined) {
|
|
202
|
-
return (_jsx(FallbackScreenPanelTile, { panel: panel, fallback: panel.fallback, featureName: featureName, translate: translate }));
|
|
203
|
-
}
|
|
204
|
-
if (target === undefined)
|
|
205
|
-
return null;
|
|
206
|
-
// A failed gate query must not silently drop the panel: on the
|
|
207
|
-
// account-security page that would hide every MFA enable/disable path.
|
|
208
|
-
if (verdict === "error" && visibility?.error) {
|
|
209
|
-
return (_jsx("div", { className: cn("min-w-0", WIDE_PANEL), "data-testid": `dashboard-panel-${panel.id}`, children: _jsx(PanelError, { label: panel.label !== undefined ? translate(panel.label) : panel.id, error: visibility.error, onRetry: () => void visibility.refetch() }) }));
|
|
210
|
-
}
|
|
211
|
-
if (verdict !== "visible")
|
|
212
|
-
return null;
|
|
213
|
-
return _jsx(EmbeddedScreenPanelTile, { panel: panel, target: target, translate: translate });
|
|
214
|
-
}
|
|
215
|
-
const NO_RECORD_ROW = {};
|
|
216
|
-
function recordTitleText(row, field) {
|
|
217
|
-
if (row === null || field === undefined)
|
|
218
|
-
return undefined;
|
|
219
|
-
const value = row[field];
|
|
220
|
-
if (typeof value !== "string" && typeof value !== "number")
|
|
221
|
-
return undefined;
|
|
222
|
-
return String(value) === "" ? undefined : String(value);
|
|
52
|
+
const label = panel.kind === "custom" || panel.label === undefined ? undefined : translate(panel.label);
|
|
53
|
+
return (_jsx(GatedGridCell, { panel: panel, screenParams: screenParams, label: label ?? panel.id, className: panelSpanClassName(panel), children: _jsx(PanelBody, { panel: panel, label: label, screenId: screenId, screenParams: screenParams, translate: translate }) }, panel.id));
|
|
223
54
|
}
|
|
224
55
|
export function WebDashboardBody({ featureName, screen, translate, }) {
|
|
225
56
|
const t = useTranslation();
|
|
226
57
|
const effectiveTranslate = translate ?? t;
|
|
227
|
-
const
|
|
58
|
+
const primitives = usePrimitives();
|
|
228
59
|
const nav = useNav();
|
|
229
60
|
const headerSlotAvailable = usePageHeaderSlotAvailable();
|
|
230
61
|
const headerCompactContext = usePageHeaderCompact();
|
|
231
62
|
const { formatDateTime } = useDashboardFormats();
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const visibilityGates = distinctVisibilityGates(screen.panels, screenParams);
|
|
243
|
-
const gateResults = useVisibilityGateResults();
|
|
244
|
-
const gateKeysSignature = visibilityGates.map((gate) => gate.key).join("\n");
|
|
245
|
-
const gateResultsWithPending = useMemo(() => withPendingGates(gateResults.results, gateKeysSignature === "" ? [] : gateKeysSignature.split("\n")), [gateResults.results, gateKeysSignature]);
|
|
246
|
-
// The record query is not a panel query: it needs the interval before the
|
|
247
|
-
// registry context below exists, and `refresh.field` reads from its own row.
|
|
248
|
-
const [refreshIntervalMs, setRefreshIntervalMs] = useState(() => resolveRefreshIntervalMs(screen.refresh, null));
|
|
249
|
-
const recordQuery = useQuery(recordQueryName ?? "", recordParams, {
|
|
250
|
-
enabled: recordQueryName !== undefined && !recordMissing,
|
|
251
|
-
live: true,
|
|
252
|
-
...(refreshIntervalMs !== undefined && { refetchIntervalMs: refreshIntervalMs }),
|
|
253
|
-
});
|
|
254
|
-
const { data: recordRow, refetch: refetchRecord } = recordQuery;
|
|
255
|
-
useEffect(() => {
|
|
256
|
-
setRefreshIntervalMs(resolveRefreshIntervalMs(screen.refresh, recordRow));
|
|
257
|
-
}, [screen.refresh, recordRow]);
|
|
258
|
-
const { register, refetchRegistered } = useRefetchRegistry();
|
|
259
|
-
const queryRuntime = useMemo(() => ({ refreshIntervalMs, register }), [refreshIntervalMs, register]);
|
|
260
|
-
const refetchAll = useCallback(async () => {
|
|
261
|
-
await Promise.all([
|
|
262
|
-
recordQueryName !== undefined ? refetchRecord() : Promise.resolve(),
|
|
263
|
-
refetchRegistered(),
|
|
264
|
-
]);
|
|
265
|
-
}, [recordQueryName, refetchRecord, refetchRegistered]);
|
|
266
|
-
const [actionError, setActionError] = useState(null);
|
|
267
|
-
const idOnlyRow = useMemo(() => (recordPayloadKey !== undefined ? { id: recordId, [recordPayloadKey]: recordId } : null), [recordId, recordPayloadKey]);
|
|
268
|
-
const actionRow = recordQueryName !== undefined ? recordRow : idOnlyRow;
|
|
269
|
-
const headerActions = useRecordActions({
|
|
270
|
-
actions: actionRow !== null && !recordMissing ? screen.actions : undefined,
|
|
271
|
-
record: actionRow ?? NO_RECORD_ROW,
|
|
272
|
-
recordId,
|
|
273
|
-
translate: effectiveTranslate,
|
|
274
|
-
onWriteSuccess: refetchAll,
|
|
275
|
-
});
|
|
276
|
-
const scope = screen.scope;
|
|
277
|
-
// A raw description is agent-facing prose; only an i18n key is user-facing copy.
|
|
278
|
-
const translatedDescription = screen.description !== undefined ? effectiveTranslate(screen.description) : undefined;
|
|
279
|
-
const description = translatedDescription !== screen.description ? translatedDescription : undefined;
|
|
280
|
-
const scopeBadge = scope !== undefined ? (_jsx(StatusBadge, { tone: "accent", testId: `dashboard-${screen.id}-scope`, children: effectiveTranslate(scope.badge) })) : null;
|
|
281
|
-
if (recordMissing) {
|
|
282
|
-
return (_jsx(PageSection, { className: "flex flex-col gap-4", testId: `dashboard-${screen.id}`, children: _jsx(Banner, { variant: "info", testId: `dashboard-${screen.id}-record-missing`, children: t("kumiko.dashboard.record.missing") }) }));
|
|
63
|
+
const params = useDashboardScreenParams(screen, effectiveTranslate, nav);
|
|
64
|
+
const { screenParams } = params;
|
|
65
|
+
const visibility = useDashboardVisibility(screen.panels, screenParams);
|
|
66
|
+
const record = useDashboardRecord(screen, params);
|
|
67
|
+
const { recordQuery, recordRow, refetchRecord } = record;
|
|
68
|
+
const { actionError, setActionError, headerActions } = useDashboardHeaderActions(screen, params, record, effectiveTranslate);
|
|
69
|
+
const description = dashboardDescription(screen, effectiveTranslate);
|
|
70
|
+
const scopeBadge = buildScopeBadge(screen, effectiveTranslate);
|
|
71
|
+
if (params.recordMissing) {
|
|
72
|
+
return (_jsx(PageSection, { className: "flex flex-col gap-4", testId: `dashboard-${screen.id}`, children: renderRecordMissing(primitives, t, screen.id) }));
|
|
283
73
|
}
|
|
284
|
-
const usesPageHeaderSlot = headerSlotAvailable && PageHeader !== undefined;
|
|
285
|
-
const
|
|
286
|
-
|
|
74
|
+
const usesPageHeaderSlot = headerSlotAvailable && primitives.PageHeader !== undefined;
|
|
75
|
+
const model = {
|
|
76
|
+
screen,
|
|
77
|
+
t,
|
|
78
|
+
translate: effectiveTranslate,
|
|
79
|
+
primitives,
|
|
80
|
+
headerActions,
|
|
81
|
+
setActionError,
|
|
82
|
+
headerCompactContext,
|
|
83
|
+
usesPageHeaderSlot,
|
|
84
|
+
recordTitle: recordTitleText(recordRow, params.recordBinding?.titleField),
|
|
85
|
+
scopeBadge,
|
|
86
|
+
picker: params.picker,
|
|
87
|
+
rangeControl: params.rangeControl,
|
|
88
|
+
loadedAtMs: params.loadedAtMs,
|
|
89
|
+
formatDateTime,
|
|
90
|
+
};
|
|
91
|
+
const headerActionsBar = renderHeaderActionsBar(model);
|
|
287
92
|
// The shell header owns the title; the badge and the actions sit in it there.
|
|
288
93
|
const badgeInHeader = scopeBadge !== null && usesPageHeaderSlot;
|
|
289
|
-
|
|
290
|
-
return (_jsx(PanelLoadedContext.Provider, { value: reportLoaded, children: _jsx(DashboardQueryContext.Provider, { value: queryRuntime, children: _jsxs(PageSection, { className: "flex flex-col gap-4", testId: `dashboard-${screen.id}`, children: [showPageHeader && (_jsx(PageHeader, { ...(recordTitle !== undefined && { title: recordTitle }), ...(badgeInHeader && { status: scopeBadge }), ...(headerActionsBar !== null && { actions: headerActionsBar }) })), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [!usesPageHeaderSlot && recordTitle !== undefined && (_jsx(Heading, { variant: "page", testId: `dashboard-${screen.id}-record-title`, children: recordTitle })), !badgeInHeader && scopeBadge, picker] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [!usesPageHeaderSlot && headerActionsBar, screen.showUpdatedAt !== false && (_jsx("span", { "data-testid": `dashboard-${screen.id}-updated-at`, className: "text-xs tabular-nums text-muted-foreground", children: t("kumiko.dashboard.updated-at", { time: formatDateTime(loadedAtMs) }) })), rangeControl] })] }), actionError !== null && (_jsxs(Banner, { variant: "error", testId: "render-edit-action-error", children: [actionError.message, _jsx(ErrorReference, { requestId: actionError.requestId })] })), recordQuery.error !== null && recordRow === null && (_jsxs("div", { role: "alert", "data-testid": `dashboard-${screen.id}-record-error`, className: "flex flex-col items-start gap-2 text-sm", children: [_jsx("span", { className: "text-status-bad", children: dispatcherErrorText(recordQuery.error, t) }), _jsx(Button, { variant: "secondary", onClick: () => void refetchRecord(), children: t("kumiko.dashboard.panel.error.retry") })] })), description !== undefined && (_jsx(Text, { variant: "muted", testId: `dashboard-${screen.id}-description`, children: description })), scope?.notice !== undefined && (_jsx(Banner, { variant: "info", testId: `dashboard-${screen.id}-scope-notice`, children: effectiveTranslate(scope.notice) })), _jsxs(VisibilityQueryContext.Provider, { value: gateResultsWithPending, children: [_jsx(VisibilityGateQueries, { gates: visibilityGates, onResult: gateResults.report, onForget: gateResults.forget }), _jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", children: screen.panels.map((panel) => {
|
|
291
|
-
if (panel.kind === "screen") {
|
|
292
|
-
return (_jsx(ScreenPanelTile, { panel: panel, featureName: featureName, translate: effectiveTranslate }, panel.id));
|
|
293
|
-
}
|
|
294
|
-
const label = panel.kind === "custom" || panel.label === undefined
|
|
295
|
-
? undefined
|
|
296
|
-
: effectiveTranslate(panel.label);
|
|
297
|
-
return (_jsx(GatedGridCell, { panel: panel, screenParams: screenParams, label: label ?? panel.id, className: panelSpanClassName(panel), children: _jsx(PanelBody, { panel: panel, label: label, screenId: screen.id, screenParams: screenParams, translate: effectiveTranslate }) }, panel.id));
|
|
298
|
-
}) })] })] }) }) }));
|
|
94
|
+
return (_jsx(PanelLoadedContext.Provider, { value: params.reportLoaded, children: _jsx(DashboardQueryContext.Provider, { value: record.queryRuntime, children: _jsxs(PageSection, { className: "flex flex-col gap-4", testId: `dashboard-${screen.id}`, children: [renderPageHeaderSlot(model, headerActionsBar, badgeInHeader), renderTitleRow(model, headerActionsBar, badgeInHeader), renderActionErrorBanner(primitives, actionError), renderRecordError(model, recordQuery.error, recordRow, refetchRecord), renderDescriptionAndNotice(model, description), _jsxs(VisibilityQueryContext.Provider, { value: visibility.gateResultsWithPending, children: [_jsx(VisibilityGateQueries, { gates: visibility.visibilityGates, onResult: visibility.gateResults.report, onForget: visibility.gateResults.forget }), _jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", children: screen.panels.map((panel) => renderDashboardPanel(panel, featureName, screen.id, screenParams, effectiveTranslate)) })] })] }) }) }));
|
|
299
95
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DashboardScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
import type { Dispatch, ReactNode, SetStateAction } from "react";
|
|
3
|
+
import { type ErrorNotice } from "../../app/error-reference.tsx";
|
|
4
|
+
import type { DispatcherError, Translate } from "../../headless/index.ts";
|
|
5
|
+
import { type usePrimitives, type useRecordActions } from "../../index.ts";
|
|
6
|
+
import type { useDashboardFormats, useLoadedAt } from "./dashboard-shared.tsx";
|
|
7
|
+
type Primitives = ReturnType<typeof usePrimitives>;
|
|
8
|
+
export type DashboardHeaderModel = {
|
|
9
|
+
readonly screen: DashboardScreenDefinition;
|
|
10
|
+
readonly t: Translate;
|
|
11
|
+
readonly translate: Translate;
|
|
12
|
+
readonly primitives: Primitives;
|
|
13
|
+
readonly headerActions: ReturnType<typeof useRecordActions>;
|
|
14
|
+
readonly setActionError: Dispatch<SetStateAction<ErrorNotice | null>>;
|
|
15
|
+
readonly headerCompactContext: boolean;
|
|
16
|
+
readonly usesPageHeaderSlot: boolean;
|
|
17
|
+
readonly recordTitle: string | undefined;
|
|
18
|
+
readonly scopeBadge: ReactNode;
|
|
19
|
+
readonly picker: ReactNode;
|
|
20
|
+
readonly rangeControl: ReactNode;
|
|
21
|
+
readonly loadedAtMs: ReturnType<typeof useLoadedAt>["loadedAtMs"];
|
|
22
|
+
readonly formatDateTime: ReturnType<typeof useDashboardFormats>["formatDateTime"];
|
|
23
|
+
};
|
|
24
|
+
export declare function recordTitleText(row: Readonly<Record<string, unknown>> | null, field: string | undefined): string | undefined;
|
|
25
|
+
export declare function buildScopeBadge(screen: DashboardScreenDefinition, translate: Translate): ReactNode;
|
|
26
|
+
export declare function dashboardDescription(screen: DashboardScreenDefinition, translate: Translate): string | undefined;
|
|
27
|
+
export declare function renderRecordMissing(primitives: Primitives, t: Translate, screenId: string): ReactNode;
|
|
28
|
+
export declare function renderHeaderActionsBar(model: DashboardHeaderModel): ReactNode;
|
|
29
|
+
export declare function renderPageHeaderSlot(model: DashboardHeaderModel, headerActionsBar: ReactNode, badgeInHeader: boolean): ReactNode;
|
|
30
|
+
export declare function renderTitleRow(model: DashboardHeaderModel, headerActionsBar: ReactNode, badgeInHeader: boolean): ReactNode;
|
|
31
|
+
export declare function renderActionErrorBanner(primitives: Primitives, actionError: ErrorNotice | null): ReactNode;
|
|
32
|
+
export declare function renderRecordError(model: DashboardHeaderModel, error: DispatcherError | null, recordRow: Readonly<Record<string, unknown>> | null, refetchRecord: () => Promise<void>): ReactNode;
|
|
33
|
+
export declare function renderDescriptionAndNotice(model: DashboardHeaderModel, description: string | undefined): ReactNode;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ErrorReference } from "../../app/error-reference.js";
|
|
3
|
+
import { dispatcherErrorText, HeaderActionsBar, } from "../../index.js";
|
|
4
|
+
import { StatusBadge } from "../widgets/status-badge.js";
|
|
5
|
+
export function recordTitleText(row, field) {
|
|
6
|
+
if (row === null || field === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
const value = row[field];
|
|
9
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
10
|
+
return undefined;
|
|
11
|
+
return String(value) === "" ? undefined : String(value);
|
|
12
|
+
}
|
|
13
|
+
export function buildScopeBadge(screen, translate) {
|
|
14
|
+
const scope = screen.scope;
|
|
15
|
+
return scope !== undefined ? (_jsx(StatusBadge, { tone: "accent", testId: `dashboard-${screen.id}-scope`, children: translate(scope.badge) })) : null;
|
|
16
|
+
}
|
|
17
|
+
export function dashboardDescription(screen, translate) {
|
|
18
|
+
// A raw description is agent-facing prose; only an i18n key is user-facing copy.
|
|
19
|
+
const translatedDescription = screen.description !== undefined ? translate(screen.description) : undefined;
|
|
20
|
+
return translatedDescription !== screen.description ? translatedDescription : undefined;
|
|
21
|
+
}
|
|
22
|
+
export function renderRecordMissing(primitives, t, screenId) {
|
|
23
|
+
const { Banner } = primitives;
|
|
24
|
+
return (_jsx(Banner, { variant: "info", testId: `dashboard-${screenId}-record-missing`, children: t("kumiko.dashboard.record.missing") }));
|
|
25
|
+
}
|
|
26
|
+
export function renderHeaderActionsBar(model) {
|
|
27
|
+
const { screen, headerActions, headerCompactContext, usesPageHeaderSlot, setActionError } = model;
|
|
28
|
+
const { Button, Dialog, ActionOverflowMenu, Grid, PageHeader } = model.primitives;
|
|
29
|
+
return headerActions !== undefined && headerActions.length > 0 ? (_jsx(Grid, { columns: "auto", testId: `dashboard-${screen.id}-actions`, children: _jsx(HeaderActionsBar, { actions: headerActions, Button: Button, Dialog: Dialog, ActionOverflowMenu: ActionOverflowMenu, onError: setActionError, collapseAfterPrimary: usesPageHeaderSlot, compact: headerCompactContext && usesPageHeaderSlot, PageHeader: PageHeader, overflowTestId: `dashboard-${screen.id}-actions-overflow` }) })) : null;
|
|
30
|
+
}
|
|
31
|
+
export function renderPageHeaderSlot(model, headerActionsBar, badgeInHeader) {
|
|
32
|
+
const { PageHeader } = model.primitives;
|
|
33
|
+
const { recordTitle, scopeBadge, usesPageHeaderSlot } = model;
|
|
34
|
+
const showPageHeader = usesPageHeaderSlot && (badgeInHeader || recordTitle !== undefined || headerActionsBar !== null);
|
|
35
|
+
return (showPageHeader &&
|
|
36
|
+
PageHeader !== undefined && (_jsx(PageHeader, { ...(recordTitle !== undefined && { title: recordTitle }), ...(badgeInHeader && { status: scopeBadge }), ...(headerActionsBar !== null && { actions: headerActionsBar }) })));
|
|
37
|
+
}
|
|
38
|
+
export function renderTitleRow(model, headerActionsBar, badgeInHeader) {
|
|
39
|
+
const { Heading } = model.primitives;
|
|
40
|
+
const { screen, usesPageHeaderSlot, recordTitle, scopeBadge, picker, rangeControl } = model;
|
|
41
|
+
return (_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [!usesPageHeaderSlot && recordTitle !== undefined && (_jsx(Heading, { variant: "page", testId: `dashboard-${screen.id}-record-title`, children: recordTitle })), !badgeInHeader && scopeBadge, picker] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [!usesPageHeaderSlot && headerActionsBar, screen.showUpdatedAt !== false && (_jsx("span", { "data-testid": `dashboard-${screen.id}-updated-at`, className: "text-xs tabular-nums text-muted-foreground", children: model.t("kumiko.dashboard.updated-at", {
|
|
42
|
+
time: model.formatDateTime(model.loadedAtMs),
|
|
43
|
+
}) })), rangeControl] })] }));
|
|
44
|
+
}
|
|
45
|
+
export function renderActionErrorBanner(primitives, actionError) {
|
|
46
|
+
const { Banner } = primitives;
|
|
47
|
+
return (actionError !== null && (_jsxs(Banner, { variant: "error", testId: "render-edit-action-error", children: [actionError.message, _jsx(ErrorReference, { requestId: actionError.requestId })] })));
|
|
48
|
+
}
|
|
49
|
+
export function renderRecordError(model, error, recordRow, refetchRecord) {
|
|
50
|
+
const { Button } = model.primitives;
|
|
51
|
+
return (error !== null &&
|
|
52
|
+
recordRow === null && (_jsxs("div", { role: "alert", "data-testid": `dashboard-${model.screen.id}-record-error`, className: "flex flex-col items-start gap-2 text-sm", children: [_jsx("span", { className: "text-status-bad", children: dispatcherErrorText(error, model.t) }), _jsx(Button, { variant: "secondary", onClick: () => void refetchRecord(), children: model.t("kumiko.dashboard.panel.error.retry") })] })));
|
|
53
|
+
}
|
|
54
|
+
export function renderDescriptionAndNotice(model, description) {
|
|
55
|
+
const { Text, Banner } = model.primitives;
|
|
56
|
+
const { screen } = model;
|
|
57
|
+
return (_jsxs(_Fragment, { children: [description !== undefined && (_jsx(Text, { variant: "muted", testId: `dashboard-${screen.id}-description`, children: description })), screen.scope?.notice !== undefined && (_jsx(Banner, { variant: "info", testId: `dashboard-${screen.id}-scope-notice`, children: model.translate(screen.scope.notice) }))] }));
|
|
58
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DashboardScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import type { Translate } from "../../headless/index.ts";
|
|
4
|
+
export declare function useFilterParams(screen: DashboardScreenDefinition, enabled: boolean): {
|
|
5
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
6
|
+
readonly picker: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export declare function useTimeRange(screen: DashboardScreenDefinition, translate: Translate): {
|
|
9
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
10
|
+
readonly control: ReactNode;
|
|
11
|
+
};
|