@tinya-code/gas-admin-ui 0.2.0-alpha.12 → 0.2.0-alpha.15
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/README.md +222 -0
- package/ng-package.json +7 -0
- package/package.json +3 -15
- package/src/lib/actions/action-registry.spec.ts +52 -0
- package/src/lib/actions/action-registry.ts +126 -0
- package/src/lib/actions/action-service.spec.ts +215 -0
- package/src/lib/actions/action-service.ts +87 -0
- package/src/lib/actions/descriptors.spec.ts +155 -0
- package/src/lib/actions/descriptors.ts +154 -0
- package/src/lib/columns/column-cell.ts +33 -0
- package/src/lib/columns/column-defaults.spec.ts +99 -0
- package/src/lib/columns/column-defaults.ts +84 -0
- package/src/lib/columns/column-format.spec.ts +274 -0
- package/src/lib/columns/descriptors.ts +113 -0
- package/src/lib/columns/format-badge.ts +51 -0
- package/src/lib/columns/format-boolean.ts +58 -0
- package/src/lib/columns/format-currency.ts +30 -0
- package/src/lib/columns/format-date.ts +35 -0
- package/src/lib/columns/format-number.ts +32 -0
- package/src/lib/columns/format-text.ts +23 -0
- package/src/lib/columns/format-thumbnail.ts +63 -0
- package/src/lib/core/adapters/firebase-auth.adapter.ts +6 -0
- package/src/lib/core/guards/auth.guard.spec.ts +88 -0
- package/src/lib/core/guards/auth.guard.ts +48 -0
- package/src/lib/core/guards/unsaved-changes.guard.ts +16 -0
- package/src/lib/core/interceptors/api-error.interceptor.spec.ts +182 -0
- package/src/lib/core/interceptors/api-error.interceptor.ts +87 -0
- package/src/lib/core/models/api.model.ts +104 -0
- package/src/lib/core/models/schema-descriptions.ts +118 -0
- package/src/lib/core/models/schema.model.ts +1097 -0
- package/src/lib/core/registry/composition-validator.spec.ts +358 -0
- package/src/lib/core/registry/composition-validator.ts +270 -0
- package/src/lib/core/registry/field-validators.spec.ts +199 -0
- package/src/lib/core/registry/field-validators.ts +440 -0
- package/src/lib/core/registry/render-host.spec.ts +208 -0
- package/src/lib/core/registry/render-host.ts +646 -0
- package/src/lib/core/registry/render-registry.spec.ts +96 -0
- package/src/lib/core/registry/render-registry.ts +312 -0
- package/src/lib/core/registry/schema-catalog.ts +156 -0
- package/src/lib/core/services/api.service.spec.ts +1142 -0
- package/src/lib/core/services/api.service.ts +371 -0
- package/src/lib/core/services/auth.service.spec.ts +653 -0
- package/src/lib/core/services/auth.service.ts +503 -0
- package/src/lib/core/services/config.service.spec.ts +121 -0
- package/src/lib/core/services/config.service.ts +119 -0
- package/src/lib/core/services/data-source.service.spec.ts +179 -0
- package/src/lib/core/services/data-source.service.ts +142 -0
- package/src/lib/core/services/error-mapper.service.spec.ts +50 -0
- package/src/lib/core/services/error-mapper.service.ts +49 -0
- package/src/lib/core/services/notification.service.ts +73 -0
- package/src/lib/core/services/relation-drawer.service.ts +41 -0
- package/src/lib/core/services/theme.service.spec.ts +106 -0
- package/src/lib/core/services/theme.service.ts +86 -0
- package/src/lib/core/services/transport.spec.ts +198 -0
- package/src/lib/core/services/transport.ts +164 -0
- package/src/lib/core/services/upload.service.ts +81 -0
- package/src/lib/core/testing/categories.schema.ts +125 -0
- package/src/lib/core/testing/orders.schema.ts +372 -0
- package/src/lib/core/testing/products.schema.ts +258 -0
- package/src/lib/core/testing/site.schema.ts +195 -0
- package/src/lib/core/testing/test-catalog.ts +21 -0
- package/src/lib/core/tokens.ts +112 -0
- package/src/lib/core/utils/clipboard.spec.ts +55 -0
- package/src/lib/core/utils/clipboard.ts +90 -0
- package/src/lib/core/utils/context-resolver.spec.ts +95 -0
- package/src/lib/core/utils/context-resolver.ts +101 -0
- package/src/lib/core/utils/response-unwrapper.spec.ts +70 -0
- package/src/lib/core/utils/response-unwrapper.ts +103 -0
- package/src/lib/core/utils/source-options.spec.ts +96 -0
- package/src/lib/core/utils/source-options.ts +54 -0
- package/src/lib/core/utils/template-interpolator.spec.ts +59 -0
- package/src/lib/core/utils/template-interpolator.ts +56 -0
- package/src/lib/core/view-navigation/view-navigation.service.spec.ts +207 -0
- package/src/lib/core/view-navigation/view-navigation.service.ts +132 -0
- package/src/lib/fields/boolean/boolean.descriptor.ts +11 -0
- package/src/lib/fields/boolean/boolean.ts +40 -0
- package/src/lib/fields/color/color.descriptor.ts +12 -0
- package/src/lib/fields/color/color.ts +34 -0
- package/src/lib/fields/currency/currency.descriptor.ts +12 -0
- package/src/lib/fields/currency/currency.ts +67 -0
- package/src/lib/fields/date/date.descriptor.ts +12 -0
- package/src/lib/fields/date/date.ts +36 -0
- package/src/lib/fields/descriptors.ts +122 -0
- package/src/lib/fields/display/display-badge.ts +65 -0
- package/src/lib/fields/display/display-date.ts +39 -0
- package/src/lib/fields/display/display-defaults.ts +84 -0
- package/src/lib/fields/display/display-file.ts +41 -0
- package/src/lib/fields/display/display-image.ts +54 -0
- package/src/lib/fields/display/display-list.ts +107 -0
- package/src/lib/fields/display/display-number.ts +41 -0
- package/src/lib/fields/display/display-text.ts +42 -0
- package/src/lib/fields/display/display.spec.ts +242 -0
- package/src/lib/fields/dropdown/dropdown.descriptor.ts +12 -0
- package/src/lib/fields/dropdown/dropdown.ts +45 -0
- package/src/lib/fields/email/email.descriptor.ts +12 -0
- package/src/lib/fields/email/email.ts +28 -0
- package/src/lib/fields/field-aria.ts +60 -0
- package/src/lib/fields/field-host/field-host.spec.ts +118 -0
- package/src/lib/fields/field-host/field-host.ts +47 -0
- package/src/lib/fields/field-node.ts +88 -0
- package/src/lib/fields/file/file.descriptor.ts +14 -0
- package/src/lib/fields/file/file.spec.ts +134 -0
- package/src/lib/fields/file/file.ts +281 -0
- package/src/lib/fields/group/group.descriptor.ts +21 -0
- package/src/lib/fields/group/group.ts +110 -0
- package/src/lib/fields/image/image.descriptor.ts +12 -0
- package/src/lib/fields/image/image.spec.ts +117 -0
- package/src/lib/fields/image/image.ts +281 -0
- package/src/lib/fields/key-value/key-value.descriptor.ts +11 -0
- package/src/lib/fields/key-value/key-value.ts +283 -0
- package/src/lib/fields/list/list.descriptor.ts +21 -0
- package/src/lib/fields/list/list.ts +376 -0
- package/src/lib/fields/multiselect/multiselect.descriptor.ts +11 -0
- package/src/lib/fields/multiselect/multiselect.spec.ts +142 -0
- package/src/lib/fields/multiselect/multiselect.ts +152 -0
- package/src/lib/fields/number/number.descriptor.ts +12 -0
- package/src/lib/fields/number/number.ts +40 -0
- package/src/lib/fields/phone/phone.descriptor.ts +12 -0
- package/src/lib/fields/phone/phone.ts +46 -0
- package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +12 -0
- package/src/lib/fields/readonly-text/readonly-text.ts +58 -0
- package/src/lib/fields/relation/relation.descriptor.ts +12 -0
- package/src/lib/fields/relation/relation.spec.ts +193 -0
- package/src/lib/fields/relation/relation.ts +224 -0
- package/src/lib/fields/rich-select/rich-select.descriptor.ts +12 -0
- package/src/lib/fields/rich-select/rich-select.ts +175 -0
- package/src/lib/fields/select/radio-mode.ts +25 -0
- package/src/lib/fields/select/select.descriptor.ts +12 -0
- package/src/lib/fields/select/select.spec.ts +162 -0
- package/src/lib/fields/select/select.ts +210 -0
- package/src/lib/fields/slug/slug.descriptor.ts +19 -0
- package/src/lib/fields/slug/slug.ts +67 -0
- package/src/lib/fields/string-list/string-list.descriptor.ts +11 -0
- package/src/lib/fields/string-list/string-list.ts +222 -0
- package/src/lib/fields/text/text.descriptor.ts +12 -0
- package/src/lib/fields/text/text.ts +35 -0
- package/src/lib/fields/textarea/textarea.descriptor.ts +12 -0
- package/src/lib/fields/textarea/textarea.spec.ts +117 -0
- package/src/lib/fields/textarea/textarea.ts +126 -0
- package/src/lib/fields/time/time.descriptor.ts +12 -0
- package/src/lib/fields/time/time.ts +28 -0
- package/src/lib/fields/unknown-render/unknown-render.ts +49 -0
- package/src/lib/fields/url/url.descriptor.ts +12 -0
- package/src/lib/fields/url/url.ts +53 -0
- package/src/lib/gas-admin-ui.spec.ts +21 -0
- package/src/lib/gas-admin-ui.ts +9 -0
- package/src/lib/layouts/descriptors.ts +9 -0
- package/src/lib/pages/dashboard/dashboard.ts +167 -0
- package/src/lib/pages/detail-view/detail-view.spec.ts +333 -0
- package/src/lib/pages/detail-view/detail-view.ts +570 -0
- package/src/lib/pages/drawer-form/drawer-form.ts +228 -0
- package/src/lib/pages/form-view/form-model.ts +88 -0
- package/src/lib/pages/form-view/form-schema.ts +255 -0
- package/src/lib/pages/form-view/form-view.ts +1622 -0
- package/src/lib/pages/list-view/list-view.formats.spec.ts +214 -0
- package/src/lib/pages/list-view/list-view.ts +882 -0
- package/src/lib/pages/login/login.spec.ts +109 -0
- package/src/lib/pages/login/login.ts +227 -0
- package/src/lib/pages/resource-page/resource-page.ts +234 -0
- package/src/lib/shared/components/badge/badge.ts +35 -0
- package/src/lib/shared/components/button/button.ts +65 -0
- package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +48 -0
- package/src/lib/shared/components/copy-button/copy-button.ts +56 -0
- package/src/lib/shared/components/copy-share/copy-share.spec.ts +122 -0
- package/src/lib/shared/components/copy-share/copy-share.ts +107 -0
- package/src/lib/shared/components/drawer/drawer.spec.ts +127 -0
- package/src/lib/shared/components/drawer/drawer.ts +172 -0
- package/src/lib/shared/components/empty-state/empty-state.ts +30 -0
- package/src/lib/shared/components/modal/modal.spec.ts +149 -0
- package/src/lib/shared/components/modal/modal.ts +145 -0
- package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +165 -0
- package/src/lib/shared/components/post-create-modal/post-create-modal.ts +159 -0
- package/src/lib/shared/components/skeleton/skeleton.ts +31 -0
- package/src/lib/shared/components/toast/toast.ts +58 -0
- package/src/lib/shared/utils/col-span.ts +25 -0
- package/src/lib/shared/utils/condition-evaluator.ts +53 -0
- package/src/lib/shared/utils/depends-on.ts +48 -0
- package/src/lib/shared/utils/dialog-focus.ts +28 -0
- package/src/lib/shared/utils/field-path.ts +49 -0
- package/src/lib/shared/utils/gap-sorting.ts +144 -0
- package/src/lib/shared/utils/seed.spec.ts +64 -0
- package/src/lib/shared/utils/seed.ts +149 -0
- package/src/lib/shared/utils/slugify.ts +13 -0
- package/src/lib/shared/utils/validators.ts +41 -0
- package/src/lib/shell/layout/layout.ts +63 -0
- package/src/lib/shell/shell.routes.spec.ts +59 -0
- package/src/lib/shell/shell.routes.ts +122 -0
- package/src/lib/shell/sidebar/sidebar.ts +139 -0
- package/src/lib/shell/theme-toggle/theme-toggle.ts +74 -0
- package/src/lib/views/calendar-view/calendar-model.ts +426 -0
- package/src/lib/views/calendar-view/calendar-view.spec.ts +557 -0
- package/src/lib/views/calendar-view/calendar-view.ts +568 -0
- package/src/lib/views/composer/composer-host.spec.ts +301 -0
- package/src/lib/views/composer/composer-host.ts +248 -0
- package/src/lib/views/composer/composer-imports.spec.ts +54 -0
- package/src/lib/views/composer/view-context.spec.ts +117 -0
- package/src/lib/views/composer/view-context.ts +109 -0
- package/src/lib/views/composer/view-slot.spec.ts +130 -0
- package/src/lib/views/composer/view-slot.ts +178 -0
- package/src/lib/views/descriptors.ts +46 -0
- package/src/lib/views/kanban-view/kanban-model.ts +173 -0
- package/src/lib/views/kanban-view/kanban-view.spec.ts +540 -0
- package/src/lib/views/kanban-view/kanban-view.ts +327 -0
- package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +17 -0
- package/src/lib/widgets/bar-chart/bar-chart.spec.ts +66 -0
- package/src/lib/widgets/bar-chart/bar-chart.ts +76 -0
- package/src/lib/widgets/chart-line/chart-line.descriptor.ts +17 -0
- package/src/lib/widgets/chart-line/chart-line.spec.ts +113 -0
- package/src/lib/widgets/chart-line/chart-line.ts +219 -0
- package/src/lib/widgets/descriptors.ts +29 -0
- package/src/lib/widgets/metric-card/metric-card.descriptor.ts +41 -0
- package/src/lib/widgets/metric-card/metric-card.spec.ts +52 -0
- package/src/lib/widgets/metric-card/metric-card.ts +48 -0
- package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +13 -0
- package/src/lib/widgets/quick-actions/quick-actions.spec.ts +61 -0
- package/src/lib/widgets/quick-actions/quick-actions.ts +100 -0
- package/src/lib/widgets/record-list/record-list.descriptor.ts +16 -0
- package/src/lib/widgets/record-list/record-list.spec.ts +79 -0
- package/src/lib/widgets/record-list/record-list.ts +115 -0
- package/src/lib/widgets/series.spec.ts +42 -0
- package/src/lib/widgets/series.ts +56 -0
- package/src/lib/widgets/status-progress/status-progress.descriptor.ts +19 -0
- package/src/lib/widgets/status-progress/status-progress.spec.ts +63 -0
- package/src/lib/widgets/status-progress/status-progress.ts +104 -0
- package/src/lib/widgets/widget-host/widget-host.spec.ts +179 -0
- package/src/lib/widgets/widget-host/widget-host.ts +99 -0
- package/src/public-api.ts +104 -0
- package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
- package/tsconfig.lib.json +13 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +10 -0
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +0 -84
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +0 -140
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +0 -113
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +0 -163
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +0 -1027
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +0 -278
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +0 -107
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +0 -101
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +0 -141
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +0 -88
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +0 -107
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +0 -140
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +0 -119
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +0 -125
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +0 -152
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +0 -211
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +0 -116
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +0 -111
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +0 -122
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +0 -107
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +0 -109
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +0 -45
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +0 -50
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +0 -24
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +0 -27
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +0 -408
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs +0 -4516
- package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +0 -82
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +0 -105
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +0 -65
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +0 -65
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +0 -65
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +0 -59
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +0 -94
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +0 -72
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +0 -238
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +0 -416
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +0 -439
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +0 -513
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs +0 -637
- package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +0 -127
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +0 -251
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +0 -66
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +0 -114
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +0 -116
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +0 -235
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +0 -8
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +0 -124
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +0 -249
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +0 -39
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +0 -309
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs +0 -576
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +0 -161
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +0 -11
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +0 -685
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs +0 -80
- package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +0 -296
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +0 -119
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +0 -158
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +0 -26
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +0 -205
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +0 -432
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +0 -36
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +0 -107
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +0 -223
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +0 -107
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +0 -60
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +0 -141
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui.mjs +0 -4599
- package/fesm2022/tinya-code-gas-admin-ui.mjs.map +0 -1
- package/types/tinya-code-gas-admin-ui.d.ts +0 -3632
|
@@ -0,0 +1,1097 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modelos del schema de recursos — única fuente de verdad de la UI.
|
|
3
|
+
* Especificación: doc/base.md §3–§7 y §9.
|
|
4
|
+
*
|
|
5
|
+
* Contrato de imágenes (decisión api.md §1): `image_url` en todo el JSON.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Anchos de columna dentro de una fila del layout (base.md §4: 1–12). */
|
|
9
|
+
export type GridWidth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
10
|
+
|
|
11
|
+
/** Operadores de `visibleWhen` / `readonlyWhen` (base.md §4). */
|
|
12
|
+
export type ConditionOperator = 'eq' | 'ne' | 'empty' | 'contains';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Condición simple sobre otro campo del mismo nivel o del registro raíz.
|
|
16
|
+
* Ej.: `{ field: 'availability', operator: 'eq', value: 'PreOrder' }`.
|
|
17
|
+
*/
|
|
18
|
+
export interface FieldCondition {
|
|
19
|
+
field: string;
|
|
20
|
+
operator: ConditionOperator;
|
|
21
|
+
/** Valor de comparación; no aplica para `empty`. */
|
|
22
|
+
value?: string | number | boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Reglas de validación comunes (base.md §4).
|
|
27
|
+
* Nota: algunas se solapan con opciones propias del tipo (§5); el motor de
|
|
28
|
+
* validación (Fase 10) los fusiona y `validators` tiene prioridad.
|
|
29
|
+
*/
|
|
30
|
+
export interface FieldValidators {
|
|
31
|
+
minLength?: number;
|
|
32
|
+
maxLength?: number;
|
|
33
|
+
pattern?: string;
|
|
34
|
+
min?: number;
|
|
35
|
+
max?: number;
|
|
36
|
+
minWords?: number;
|
|
37
|
+
maxWords?: number;
|
|
38
|
+
/** El valor debe ser único en el recurso (validación asíncrona). */
|
|
39
|
+
unique?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Propiedades comunes a todo campo (base.md §4). */
|
|
43
|
+
export interface FieldBase<T> {
|
|
44
|
+
/** Nombre de la propiedad en el JSON que envía/recibe el back. */
|
|
45
|
+
key: string;
|
|
46
|
+
/** Rótulo visible para el usuario en el formulario y la ficha. */
|
|
47
|
+
label: string;
|
|
48
|
+
/** Texto corto de ayuda que se muestra debajo del campo. */
|
|
49
|
+
help?: string;
|
|
50
|
+
/** Texto sugerente que se muestra dentro del input cuando está vacío. */
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
/** Si es obligatorio. El back también lo valida (R7.4). */
|
|
53
|
+
required?: boolean;
|
|
54
|
+
/** Valor por defecto si el registro no trae este campo (ej. `default: 'none'` en un `select`/`dropdown`). */
|
|
55
|
+
default?: T;
|
|
56
|
+
/** Si el campo es solo lectura (no editable en el formulario). */
|
|
57
|
+
readonly?: boolean;
|
|
58
|
+
/** Bloquea el campo solo en creación, solo en edición o siempre. */
|
|
59
|
+
readonlyOn?: 'create' | 'update' | 'always';
|
|
60
|
+
/** Condición bajo la cual el campo es solo lectura (expresión sobre otros campos). */
|
|
61
|
+
readonlyWhen?: FieldCondition;
|
|
62
|
+
/** Condición bajo la cual el campo se muestra u oculta. */
|
|
63
|
+
visibleWhen?: FieldCondition;
|
|
64
|
+
/**
|
|
65
|
+
* Ciclo de vida de la VISIBILIDAD: oculta el campo en creación, en edición
|
|
66
|
+
* o siempre. Símétrico a `readonlyOn`, pero NO lo mismo que `visibleWhen`,
|
|
67
|
+
* que expresa una condición sobre el valor de otro campo.
|
|
68
|
+
*
|
|
69
|
+
* Vale para los campos que LLENA EL BACK (`ref`, `pin`): en alta no existen
|
|
70
|
+
* aún, así que mostrarlos vacíos y solo-lectura con un `help` que dice "se
|
|
71
|
+
* genera solo al guardar" es ruido ocupando la sección. `hidden()` de Signal
|
|
72
|
+
* Forms además los deja FUERA de la validación y del payload
|
|
73
|
+
* (field-host:311 no los dibuja, form-model:52 los salta).
|
|
74
|
+
*/
|
|
75
|
+
hiddenOn?: 'create' | 'update' | 'always';
|
|
76
|
+
/**
|
|
77
|
+
* Selección dependiente (guía §1: país → ciudad). Clave del campo padre
|
|
78
|
+
* del MISMO nivel: mientras el padre esté vacío este campo queda
|
|
79
|
+
* `disabled`, y si el padre cambia el hijo se reinicia a su valor por
|
|
80
|
+
* defecto (plan 6.6).
|
|
81
|
+
*/
|
|
82
|
+
dependsOn?: string;
|
|
83
|
+
/** Reglas de validación (mínimo, máximo, patrón, unicidad, etc.). */
|
|
84
|
+
validators?: FieldValidators;
|
|
85
|
+
/** Ancho en la grilla del formulario (1–12), igual que un widget del dashboard. */
|
|
86
|
+
width?: GridWidth;
|
|
87
|
+
/** Id de la sección/pestaña del layout a la que pertenece (base.md §4). */
|
|
88
|
+
section?: string;
|
|
89
|
+
/**
|
|
90
|
+
* R7.5: acceso por campo (B8 · R7.4b) — sólo UX; el back vuelve a
|
|
91
|
+
* verificar en cada petición.
|
|
92
|
+
*/
|
|
93
|
+
access?: {
|
|
94
|
+
/** Código de nivel de acceso requerido para leer el campo. */
|
|
95
|
+
read?: string;
|
|
96
|
+
/** Código de nivel de acceso requerido para escribir el campo. */
|
|
97
|
+
write?: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Descripción corta de para qué sirve este campo. Se muestra como tooltip
|
|
101
|
+
* al pasar el cursor sobre el rótulo en el formulario y la ficha.
|
|
102
|
+
*/
|
|
103
|
+
description?: string;
|
|
104
|
+
/** URL de documentación externa para este campo (se abre al hacer clic en el tooltip). */
|
|
105
|
+
docLink?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ─────────────────────────────────────────────────────────────
|
|
109
|
+
// §5.1 Campos simples (valor escalar)
|
|
110
|
+
// ─────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
export interface SelectOption {
|
|
113
|
+
value: string;
|
|
114
|
+
label: string;
|
|
115
|
+
disabled?: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface TextField extends FieldBase<string> {
|
|
119
|
+
type: 'text';
|
|
120
|
+
maxLength?: number;
|
|
121
|
+
pattern?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface ColorField extends FieldBase<string> {
|
|
125
|
+
type: 'color';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface TextareaField extends FieldBase<string> {
|
|
129
|
+
type: 'textarea';
|
|
130
|
+
rows?: number;
|
|
131
|
+
minWords?: number;
|
|
132
|
+
maxWords?: number;
|
|
133
|
+
/**
|
|
134
|
+
* Marcadores insertables como chips bajo el área (plantillas de mensaje).
|
|
135
|
+
* Cada chip escribe `{key}` en la posición del cursor, no al final: el
|
|
136
|
+
* operador escribe, apreta, sigue escribiendo. El motor back no se entera —
|
|
137
|
+
* recibe el string final y lo interpola (`interpolateTemplate`).
|
|
138
|
+
*
|
|
139
|
+
* `label` es el rótulo humano del botón ("PIN"); `key` es la clave que se
|
|
140
|
+
* inserta y que el back resuelve contra `config + registro`.
|
|
141
|
+
*/
|
|
142
|
+
tokens?: readonly TemplateToken[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Chip insertable en un `textarea` de plantilla. */
|
|
146
|
+
export interface TemplateToken {
|
|
147
|
+
/** Clave insertada como `{key}` y resuelta por el motor. */
|
|
148
|
+
key: string;
|
|
149
|
+
/** Rótulo visible en el chip (el token va como tooltip). */
|
|
150
|
+
label: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface SlugField extends FieldBase<string> {
|
|
154
|
+
type: 'slug';
|
|
155
|
+
/** Campo del que se autogenera el slug (ej. `name`). */
|
|
156
|
+
from: string;
|
|
157
|
+
/** Bloquea el campo una vez creado el registro (por defecto: sí). */
|
|
158
|
+
lockAfterCreate?: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface NumberField extends FieldBase<number> {
|
|
162
|
+
type: 'number';
|
|
163
|
+
min?: number;
|
|
164
|
+
max?: number;
|
|
165
|
+
step?: number;
|
|
166
|
+
decimals?: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface CurrencyField extends FieldBase<number> {
|
|
170
|
+
type: 'currency';
|
|
171
|
+
/** Campo del registro del que se toma la moneda (ej. `currency`). */
|
|
172
|
+
currencyFrom?: string;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface BooleanField extends FieldBase<boolean> {
|
|
176
|
+
type: 'boolean';
|
|
177
|
+
trueLabel?: string;
|
|
178
|
+
falseLabel?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* De dónde salen las opciones de un desplegable: **exactamente una** de las
|
|
183
|
+
* dos formas (XOR en el tipo, D62).
|
|
184
|
+
*
|
|
185
|
+
* - `options` — estáticas en el schema (el caso de las enums: `status`).
|
|
186
|
+
* - `source` — pedidas al fetcher declarado (F8 · R6.5) para listados que
|
|
187
|
+
* viven en otro recurso.
|
|
188
|
+
*
|
|
189
|
+
* Ninguna ⇒ un desplegable mudo; las dos ⇒ dos verdades para el mismo campo.
|
|
190
|
+
* Ambas reglas viven en este tipo, no en un chequeo en runtime.
|
|
191
|
+
*/
|
|
192
|
+
type SelectData =
|
|
193
|
+
{ options: SelectOption[]; source?: never } | { options?: never; source: DataSource };
|
|
194
|
+
|
|
195
|
+
export type SelectField = FieldBase<string> & { type: 'select' } & SelectData;
|
|
196
|
+
|
|
197
|
+
export type MultiselectField = FieldBase<string[]> & { type: 'multiselect' } & SelectData;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Desplegable nativo (`<select>`) que SIEMPRE se renderiza como lista
|
|
201
|
+
* desplegable, independientemente de cuántas opciones tenga.
|
|
202
|
+
*
|
|
203
|
+
* A diferencia de `select` (que usa radio buttons para 2–4 opciones
|
|
204
|
+
* estáticas por la guía de control §1), este tipo nunca muta a radios.
|
|
205
|
+
* Úsalo cuando necesites un dropdown verdadero aunque tenga pocas opciones.
|
|
206
|
+
*/
|
|
207
|
+
export interface DropdownField extends FieldBase<string> {
|
|
208
|
+
type: 'dropdown';
|
|
209
|
+
options: SelectOption[];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Opción de un selector visual enriquecido (`rich-select`).
|
|
214
|
+
*
|
|
215
|
+
* Además de `value`/`label`, cada opción puede declarar una `preview` con
|
|
216
|
+
* HTML seguro que el motor renderiza como tarjeta visual (badge, chip con
|
|
217
|
+
* icono, color swatch, etc.). El HTML viaja en el schema y el motor lo
|
|
218
|
+
* pinta tal cual tras pasar por el sanitizador de Angular.
|
|
219
|
+
*/
|
|
220
|
+
export interface RichSelectOption {
|
|
221
|
+
value: string;
|
|
222
|
+
label: string;
|
|
223
|
+
disabled?: boolean;
|
|
224
|
+
/** HTML seguro para pintar como preview de la opción (ej. `<span class="chip">…</span>`). */
|
|
225
|
+
preview?: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Selector visual enriquecido: cada opción se renderiza como tarjeta con su
|
|
230
|
+
* `preview` HTML en vez de un `<select>` nativo o radio buttons planos.
|
|
231
|
+
* Sólo opciones estáticas (sin `source`).
|
|
232
|
+
*/
|
|
233
|
+
export interface RichSelectField extends FieldBase<string> {
|
|
234
|
+
type: 'rich-select';
|
|
235
|
+
options: RichSelectOption[];
|
|
236
|
+
/**
|
|
237
|
+
* Ancho de cada tarjeta de opción en la grilla (1–12), igual que `width`
|
|
238
|
+
* de un campo. Por defecto `4` (3 tarjetas por fila en escritorio).
|
|
239
|
+
* Úsalo para opciones con preview larga (menos tarjetas por fila) o
|
|
240
|
+
* preview corta (más tarjetas).
|
|
241
|
+
*/
|
|
242
|
+
cardWidth?: GridWidth;
|
|
243
|
+
/**
|
|
244
|
+
* Cuántas tarjetas mostrar por fila en el punto de ruptura `lg`.
|
|
245
|
+
* Sobrescribe el cálculo automático basado en `cardWidth`.
|
|
246
|
+
* Ejemplo: `2` obliga a 2 columnas grandes sin importar el ancho.
|
|
247
|
+
*/
|
|
248
|
+
cardCols?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface UrlField extends FieldBase<string> {
|
|
252
|
+
type: 'url';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface EmailField extends FieldBase<string> {
|
|
256
|
+
type: 'email';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface PhoneField extends FieldBase<string> {
|
|
260
|
+
type: 'phone';
|
|
261
|
+
/** Normalización del valor guardado. */
|
|
262
|
+
format?: 'e164' | 'digits';
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface DateField extends FieldBase<string> {
|
|
266
|
+
type: 'date';
|
|
267
|
+
/** Fecha ISO `YYYY-MM-DD` permitida. */
|
|
268
|
+
min?: string;
|
|
269
|
+
max?: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface TimeField extends FieldBase<string> {
|
|
273
|
+
type: 'time';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface ReadonlyTextField extends FieldBase<string> {
|
|
277
|
+
type: 'readonly-text';
|
|
278
|
+
/** Formato de presentación (texto, fecha, moneda…). */
|
|
279
|
+
format?: string;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ─────────────────────────────────────────────────────────────
|
|
283
|
+
// §5.2 Referencias
|
|
284
|
+
// ─────────────────────────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Fuente de datos declarada (F8 · R6.5): UN vocabulario para relations,
|
|
288
|
+
* selects y widgets en lugar de tres. El fetcher es único
|
|
289
|
+
* (`DataSourceService`) y la clave de su caché es `resource+view+params`.
|
|
290
|
+
*
|
|
291
|
+
* `params` son valores interpolados `{campo}` que el front resuelve contra su
|
|
292
|
+
* contexto (el registro del formulario o la fila del widget) y manda como
|
|
293
|
+
* `payload.params`; el back los inyecta en el ctx de las vistas, donde una
|
|
294
|
+
* condición los lee con el operando `param: '<nombre>'`. Una vista que no
|
|
295
|
+
* referencia ese parámetro no se ve afectada por él — sólo cambia la clave
|
|
296
|
+
* de caché.
|
|
297
|
+
*
|
|
298
|
+
* Los parámetros llegan del navegador, así que son ENTRADA: sólo filtran
|
|
299
|
+
* dentro del recurso que la ruta ya autoriza a leer (nunca ensanchan el
|
|
300
|
+
* acceso) y una vista que pide un parámetro ausente queda fail-closed.
|
|
301
|
+
*/
|
|
302
|
+
export interface DataSource {
|
|
303
|
+
/** Recurso declarado (`resource.id`): su listado es el de las opciones. */
|
|
304
|
+
resource: string;
|
|
305
|
+
/** Vista declarada en `resource.views` (opcional): filtra en el back. */
|
|
306
|
+
view?: string;
|
|
307
|
+
/** Valores interpolados para la vista (`{campo}` ← contexto). */
|
|
308
|
+
params?: Record<string, string>;
|
|
309
|
+
/** Etiqueta por defecto de las filas (si no, `titleField` del recurso). */
|
|
310
|
+
labelField?: string;
|
|
311
|
+
/** Valor por defecto de las filas (si no, `keyField` del recurso). */
|
|
312
|
+
valueField?: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface RelationField extends FieldBase<string> {
|
|
316
|
+
type: 'relation';
|
|
317
|
+
/**
|
|
318
|
+
* De dónde salen las opciones (F8 · R6.5): `{ resource, view?, params?, … }`.
|
|
319
|
+
* Antes eran tres claves planas (`resource`/`labelField`/`valueField`);
|
|
320
|
+
* D62 las unifica con el resto de consumidores.
|
|
321
|
+
*/
|
|
322
|
+
source: DataSource;
|
|
323
|
+
/**
|
|
324
|
+
* Segundo dato a mostrar junto a la etiqueta (guía §1: «Juan Pérez ·
|
|
325
|
+
* DNI 123»). Se concatena con « · » y forma parte de la opción, así que
|
|
326
|
+
* también se busca sobre él.
|
|
327
|
+
*/
|
|
328
|
+
secondaryField?: string;
|
|
329
|
+
/** Cargar solo registros activos (lo exige además la FK en el back). */
|
|
330
|
+
onlyActive?: boolean;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ─────────────────────────────────────────────────────────────
|
|
334
|
+
// §5.3 Imagen — el valor es SOLO la URL pública (`image_url`)
|
|
335
|
+
// ─────────────────────────────────────────────────────────────
|
|
336
|
+
|
|
337
|
+
export interface ImageField extends FieldBase<string> {
|
|
338
|
+
type: 'image';
|
|
339
|
+
/** Tipos aceptados (ej. `image/*`, `image/png,image/jpeg`). */
|
|
340
|
+
accept?: string;
|
|
341
|
+
maxSizeMB?: number;
|
|
342
|
+
/** Relación de aspecto de la vista previa (ej. `16/9`). */
|
|
343
|
+
aspectRatio?: string;
|
|
344
|
+
previewSize?: string;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ─────────────────────────────────────────────────────────────
|
|
348
|
+
// §5.3b Archivo — el valor es SOLO la URL pública (mismo contrato que `image`)
|
|
349
|
+
// ─────────────────────────────────────────────────────────────
|
|
350
|
+
// R9.5.3: como `image`, pero para CUALQUIER archivo (pdf, xlsx, zip…). La
|
|
351
|
+
// única diferencia semántica es que NO fuerza el prefijo `image/` en el
|
|
352
|
+
// cliente: el catálogo de formatos lo acota el backend por campo (`formats`
|
|
353
|
+
// declarado) o la lista global, y el motor guarda igualmente la URL.
|
|
354
|
+
export interface FileField extends FieldBase<string> {
|
|
355
|
+
type: 'file';
|
|
356
|
+
/** Formatos aceptados (ej. `image/*`, `pdf,docx`). Si falta, usa los del backend. */
|
|
357
|
+
accept?: string;
|
|
358
|
+
maxSizeMB?: number;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ─────────────────────────────────────────────────────────────
|
|
362
|
+
// §5.4 Campos compuestos (contienen otros campos)
|
|
363
|
+
// ─────────────────────────────────────────────────────────────
|
|
364
|
+
|
|
365
|
+
export interface GroupField extends FieldBase<Record<string, unknown>> {
|
|
366
|
+
type: 'group';
|
|
367
|
+
fields: FieldSchema[];
|
|
368
|
+
/** Presentación del grupo (base.md §5.4). */
|
|
369
|
+
display?: 'card' | 'collapsible' | 'inline';
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Propiedades comunes a las listas (base.md §6). */
|
|
373
|
+
export interface ListOptions {
|
|
374
|
+
min?: number;
|
|
375
|
+
max?: number;
|
|
376
|
+
/** Si se puede reordenar (por defecto: sí). */
|
|
377
|
+
sortable?: boolean;
|
|
378
|
+
/** Campo donde se guarda el orden dentro de cada item (`position`). */
|
|
379
|
+
positionField?: string;
|
|
380
|
+
addLabel?: string;
|
|
381
|
+
emptyText?: string;
|
|
382
|
+
itemDisplay?: 'card' | 'row' | 'accordion';
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export interface ListField extends FieldBase<Record<string, unknown>[]>, ListOptions {
|
|
386
|
+
type: 'list';
|
|
387
|
+
/** Campos de cada item (cualquier tipo, incluso `group` o `list`). */
|
|
388
|
+
itemFields: FieldSchema[];
|
|
389
|
+
/** Campo del item usado como título cuando está colapsado. */
|
|
390
|
+
itemTitle?: string;
|
|
391
|
+
/** El primer item tiene significado especial (ej. imagen principal). */
|
|
392
|
+
primaryFirst?: boolean;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export interface StringListField extends FieldBase<string[]>, ListOptions {
|
|
396
|
+
type: 'string-list';
|
|
397
|
+
/** Tipo permitido de cada item (base.md §9: solo text, url o email). */
|
|
398
|
+
itemType?: 'text' | 'url' | 'email';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface KeyValueItem {
|
|
402
|
+
key: string;
|
|
403
|
+
value: string;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export interface KeyValueField extends FieldBase<KeyValueItem[]>, ListOptions {
|
|
407
|
+
type: 'key-value';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ─────────────────────────────────────────────────────────────
|
|
411
|
+
// §5.6 Widgets de panel (sólo `kind: 'dashboard'` — refactormotor.md F4)
|
|
412
|
+
// ─────────────────────────────────────────────────────────────
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Base de un widget de panel. Se declara en `ResourceSchema.widgets` — no
|
|
416
|
+
* en `fields`, porque un KPI no es un campo: no se valida, no se envía y
|
|
417
|
+
* `field-host` no lo renderiza. Sólo un recurso `kind: 'dashboard'` los
|
|
418
|
+
* dibuja, y agregar un widget es tocar el schema, no el template.
|
|
419
|
+
*
|
|
420
|
+
* Su `key` es además la clave del dato en la respuesta del endpoint del
|
|
421
|
+
* dashboard (`{ key: 'pendientes' }` ↔ `{ pendientes: 3 }`), salvo que el
|
|
422
|
+
* widget declare otra fuente (F8 · R6.5).
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Fuente de datos de un widget: el mismo vocabulario declarado de F8 que usan
|
|
427
|
+
* relations y selects (D62), más el caso «payload del panel».
|
|
428
|
+
*
|
|
429
|
+
* - `DataSource` (`{ resource, view?, params? }`): el widget pide sus filas o
|
|
430
|
+
* su agregado al recurso declarado vía `DataSourceService`; deja de depender
|
|
431
|
+
* de que un handler haya armado `data[widget.key]`.
|
|
432
|
+
* - `{ kind: 'payload' }`: lee la respuesta COMPLETA del endpoint del
|
|
433
|
+
* dashboard (varias claves a la vez).
|
|
434
|
+
*/
|
|
435
|
+
export type WidgetSource = DataSource | { kind: 'payload' };
|
|
436
|
+
|
|
437
|
+
export interface WidgetBase {
|
|
438
|
+
key: string;
|
|
439
|
+
label: string;
|
|
440
|
+
help?: string;
|
|
441
|
+
/** Ancho en la grilla del panel (1–12), igual que un campo. */
|
|
442
|
+
width?: GridWidth;
|
|
443
|
+
/**
|
|
444
|
+
* Ancho en la grilla en mobile (1–12). Por defecto `12` (ancho completo,
|
|
445
|
+
* apilado). Declararlo permite controlar el layout responsive en pantallas
|
|
446
|
+
* chicas sin tocar el ancho de escritorio (`width`).
|
|
447
|
+
*/
|
|
448
|
+
mobileWidth?: GridWidth;
|
|
449
|
+
/**
|
|
450
|
+
* De dónde saca sus datos (F8 · R6.5).
|
|
451
|
+
*
|
|
452
|
+
* - **ausente** (por defecto): `data[widget.key]`. Es el contrato normal y
|
|
453
|
+
* el que usan los KPI (`{ key: 'pendientes' }` ↔ `{ pendientes: 3 }`).
|
|
454
|
+
* - **`{ kind: 'payload' }`**: la respuesta COMPLETA, para widgets que se
|
|
455
|
+
* componen de varias claves (`status-progress` leyendo `pendientes` +
|
|
456
|
+
* `entregados` + `cancelados`) sin que el orquestador tenga que saber
|
|
457
|
+
* qué tipo de widget es.
|
|
458
|
+
* - **`DataSource`**: las filas salen del recurso declarado (vista
|
|
459
|
+
* incluida), pedidas al fetcher común.
|
|
460
|
+
*/
|
|
461
|
+
source?: WidgetSource;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** KPI de una cifra suelta («3 pendientes»). */
|
|
465
|
+
export interface MetricCardWidget extends WidgetBase {
|
|
466
|
+
type: 'metric-card';
|
|
467
|
+
/** Texto secundario bajo la cifra (estático, va en el schema). */
|
|
468
|
+
hint?: string;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** Barras por categoría con CSS/SVG — sin librería. */
|
|
472
|
+
export interface BarChartWidget extends WidgetBase {
|
|
473
|
+
type: 'bar-chart';
|
|
474
|
+
/** Sufijo de las cifras del eje («unidades», «S/»). */
|
|
475
|
+
unit?: string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Serie temporal con Chart.js.
|
|
480
|
+
*
|
|
481
|
+
* La librería (61,4 K gz medidos) vive en el chunk que abre el descriptor
|
|
482
|
+
* (`import('./chart-line')`), así que **no entra en el bundle inicial**; el
|
|
483
|
+
* `@defer (on viewport)` que el propio componente dibuja tarda además la
|
|
484
|
+
* creación del lienzo hasta que el gráfico se ve. Ver
|
|
485
|
+
* `widgets/chart-line/chart-line.ts`.
|
|
486
|
+
*/
|
|
487
|
+
export interface ChartLineWidget extends WidgetBase {
|
|
488
|
+
type: 'chart-line';
|
|
489
|
+
/** Sufijo de las cifras del eje («unidades», «S/»). */
|
|
490
|
+
unit?: string;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** Tabla embebida de registros operativos (ej. pedidos que requieren atención). */
|
|
494
|
+
export interface RecordListWidget extends WidgetBase {
|
|
495
|
+
type: 'record-list';
|
|
496
|
+
/**
|
|
497
|
+
* Claves de columnas a mostrar en la tabla compacta.
|
|
498
|
+
*
|
|
499
|
+
* No lleva `resource`: si las filas vienen declaradas, ese recurso ya está
|
|
500
|
+
* en `source.resource` (D63 retira la clave duplicada — estaba declarada y
|
|
501
|
+
* nadie la leía).
|
|
502
|
+
*/
|
|
503
|
+
columns: string[];
|
|
504
|
+
/** Acción de navegación por fila. */
|
|
505
|
+
action?: {
|
|
506
|
+
label: string;
|
|
507
|
+
routeTemplate: string;
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Grid de botones de accesos directos operativos. */
|
|
512
|
+
export interface QuickActionsWidget extends WidgetBase {
|
|
513
|
+
type: 'quick-actions';
|
|
514
|
+
actions: {
|
|
515
|
+
label: string;
|
|
516
|
+
icon?: string;
|
|
517
|
+
navigateTo: string;
|
|
518
|
+
variant?: 'primary' | 'secondary' | 'outline';
|
|
519
|
+
}[];
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/** Barra de distribución porcentual de estados o categorías. */
|
|
523
|
+
export interface StatusProgressWidget extends WidgetBase {
|
|
524
|
+
type: 'status-progress';
|
|
525
|
+
segments: {
|
|
526
|
+
key: string;
|
|
527
|
+
label: string;
|
|
528
|
+
color: 'success' | 'warning' | 'danger' | 'neutral';
|
|
529
|
+
}[];
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export type WidgetSchema =
|
|
533
|
+
| MetricCardWidget
|
|
534
|
+
| BarChartWidget
|
|
535
|
+
| ChartLineWidget
|
|
536
|
+
| RecordListWidget
|
|
537
|
+
| QuickActionsWidget
|
|
538
|
+
| StatusProgressWidget;
|
|
539
|
+
|
|
540
|
+
export type WidgetType = WidgetSchema['type'];
|
|
541
|
+
|
|
542
|
+
// ─────────────────────────────────────────────────────────────
|
|
543
|
+
// Unión discriminada por `type` (21 tipos, base.md §5)
|
|
544
|
+
// ─────────────────────────────────────────────────────────────
|
|
545
|
+
|
|
546
|
+
export type FieldSchema =
|
|
547
|
+
| TextField
|
|
548
|
+
| TextareaField
|
|
549
|
+
| SlugField
|
|
550
|
+
| NumberField
|
|
551
|
+
| CurrencyField
|
|
552
|
+
| BooleanField
|
|
553
|
+
| SelectField
|
|
554
|
+
| MultiselectField
|
|
555
|
+
| RichSelectField
|
|
556
|
+
| DropdownField
|
|
557
|
+
| UrlField
|
|
558
|
+
| EmailField
|
|
559
|
+
| PhoneField
|
|
560
|
+
| DateField
|
|
561
|
+
| TimeField
|
|
562
|
+
| ReadonlyTextField
|
|
563
|
+
| RelationField
|
|
564
|
+
| ImageField
|
|
565
|
+
| FileField
|
|
566
|
+
| GroupField
|
|
567
|
+
| ListField
|
|
568
|
+
| StringListField
|
|
569
|
+
| KeyValueField
|
|
570
|
+
| ColorField;
|
|
571
|
+
|
|
572
|
+
export type FieldType = FieldSchema['type'];
|
|
573
|
+
|
|
574
|
+
// ─────────────────────────────────────────────────────────────
|
|
575
|
+
// Listado, layout y metadatos del recurso (base.md §3)
|
|
576
|
+
// ─────────────────────────────────────────────────────────────
|
|
577
|
+
|
|
578
|
+
export type ListColumnFormat =
|
|
579
|
+
'text' | 'badge' | 'thumbnail' | 'boolean' | 'number' | 'currency' | 'date';
|
|
580
|
+
|
|
581
|
+
export interface ListColumn {
|
|
582
|
+
key: string;
|
|
583
|
+
label: string;
|
|
584
|
+
/**
|
|
585
|
+
* Sólo para sobreescribir: sin él manda la tabla de
|
|
586
|
+
* `columns/column-defaults` (`FORMATO_POR_DEFECTO`) según el `type` del
|
|
587
|
+
* campo con esta `key` (R4.4).
|
|
588
|
+
*/
|
|
589
|
+
format?: ListColumnFormat;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export interface ListFilter {
|
|
593
|
+
key: string;
|
|
594
|
+
label: string;
|
|
595
|
+
type?: 'text' | 'select' | 'boolean';
|
|
596
|
+
options?: SelectOption[];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export interface LayoutSection {
|
|
600
|
+
/** Coincide con `field.section`. */
|
|
601
|
+
id: string;
|
|
602
|
+
label: string;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export type LayoutMode = 'grid' | 'tabs' | 'sections' | 'steps' | 'columns';
|
|
606
|
+
|
|
607
|
+
export interface ResourceLayout {
|
|
608
|
+
/** Presentación del formulario. */
|
|
609
|
+
mode?: LayoutMode;
|
|
610
|
+
sections?: LayoutSection[];
|
|
611
|
+
/** Número de columnas para `mode: 'columns'` (por defecto 2). */
|
|
612
|
+
columns?: 2 | 3;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
export interface ResourceActionBase {
|
|
616
|
+
id: string;
|
|
617
|
+
label: string;
|
|
618
|
+
icon?: string;
|
|
619
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'danger';
|
|
620
|
+
visibleWhen?: { field: string; op: 'eq' | 'neq' | 'in'; value: unknown }[];
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export interface CopyShareAction extends ResourceActionBase {
|
|
624
|
+
type: 'copy-share';
|
|
625
|
+
urlTemplate: string;
|
|
626
|
+
shareTextTemplate?: string;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
export interface NavigateAction extends ResourceActionBase {
|
|
630
|
+
type?: 'navigate';
|
|
631
|
+
/** Plantilla con marcadores, ej. `/products/{slug}` o `/admin/orders?id={ref}`. */
|
|
632
|
+
urlTemplate: string;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
export interface TriggerAction extends ResourceActionBase {
|
|
636
|
+
/**
|
|
637
|
+
* Acción de dominio **declarada en el back** (B3 `actions.<name>`,
|
|
638
|
+
* publicada como `POST /admin/<recurso>/:id/actions/<name>` — R5.4).
|
|
639
|
+
* El destino no se declara acá: la ruta lógica se deriva en R3.12.
|
|
640
|
+
*/
|
|
641
|
+
type: 'trigger';
|
|
642
|
+
/** Nombre de la acción en el back si difiere del `id` de esta declaración. */
|
|
643
|
+
name?: string;
|
|
644
|
+
confirmMessage?: string;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** Acciones extra de registro o listado (duplicar, compartir, navegar…). */
|
|
648
|
+
export type ResourceAction = CopyShareAction | NavigateAction | TriggerAction;
|
|
649
|
+
|
|
650
|
+
/** Configuración de diálogo/modal o acción tras crear un registro con éxito. */
|
|
651
|
+
export interface PostCreateSchema {
|
|
652
|
+
mode: 'modal' | 'toast' | 'redirect_detail' | 'stay';
|
|
653
|
+
title?: string;
|
|
654
|
+
description?: string;
|
|
655
|
+
summaryFields?: string[];
|
|
656
|
+
actions?: ResourceAction[];
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** Configuración de Ficha de Detalle (modo lectura estructurado). */
|
|
660
|
+
export interface DetailViewSchema {
|
|
661
|
+
enabled: boolean;
|
|
662
|
+
headerFields?: string[];
|
|
663
|
+
sections?: {
|
|
664
|
+
id: string;
|
|
665
|
+
label: string;
|
|
666
|
+
fields: string[];
|
|
667
|
+
}[];
|
|
668
|
+
actions?: ResourceAction[];
|
|
669
|
+
allowEdit?: boolean;
|
|
670
|
+
allowDelete?: boolean;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/** Operaciones permitidas (base.md §3). `undefined` = permitido. */
|
|
674
|
+
export interface ResourcePermissions {
|
|
675
|
+
create?: boolean;
|
|
676
|
+
update?: boolean;
|
|
677
|
+
remove?: boolean;
|
|
678
|
+
reorder?: boolean;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Rutas de la API relativas a `API_URL` (base.md §3, api.md §6 Opción A).
|
|
683
|
+
*
|
|
684
|
+
* Marcadores que un path acepta — se resuelven ANTES de despachar la petición
|
|
685
|
+
* (y para ambos drivers):
|
|
686
|
+
*
|
|
687
|
+
* - `{key}` — clave del registro actual; sólo aplica a las operaciones con
|
|
688
|
+
* clave (`get`, `update`, `remove`). Si llega sin resolver, es error.
|
|
689
|
+
* - `{<fuente>}` / `{<fuente>.<ruta.anidada>}` — valor de una fuente de
|
|
690
|
+
* contexto: las construidas `auth` (sesión) y `config` (config global), o
|
|
691
|
+
* cualquier fuente registrada en `provideGasAdmin({ valueSources })`.
|
|
692
|
+
*
|
|
693
|
+
* El valor se codifica como segmento de URL. Un marcador sin valor, o con una
|
|
694
|
+
* fuente no registrada, lanza un error que nombra el path y el marcador: nunca
|
|
695
|
+
* se envía un segmento vacío. Los singleton solo usan `get` / `update`.
|
|
696
|
+
*/
|
|
697
|
+
export interface ResourceEndpoints {
|
|
698
|
+
list?: string;
|
|
699
|
+
get?: string;
|
|
700
|
+
create?: string;
|
|
701
|
+
update?: string;
|
|
702
|
+
remove?: string;
|
|
703
|
+
/**
|
|
704
|
+
* Declaración opcional de cómo unwrappear la respuesta de esta operación.
|
|
705
|
+
* Cuando se declara, el motor extrae el contenido de `dataKey` antes de
|
|
706
|
+
* devolverlo al consumidor (ej.: `{ data: [...] }` → `[...]`).
|
|
707
|
+
* Si no se declara, el motor mantiene el comportamiento actual:
|
|
708
|
+
* respuesta pasada tal cual (array plano, `{ items }`, o objeto crudo).
|
|
709
|
+
* Esta declaración es por operación; si se desea un valor global, usarlo
|
|
710
|
+
* en cada operación o considerar un default a nivel de config en futuro.
|
|
711
|
+
*/
|
|
712
|
+
responseUnwrap?: ResponseUnwrap;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Cómo el motor debe desempaquetar la respuesta HTTP antes de entregarla.
|
|
717
|
+
* Opcional y opt-in: schemas sin este campo siguen el contrato actual.
|
|
718
|
+
*
|
|
719
|
+
* - `dataKey`: clave en el body que contiene el payload real (ej. `data`,
|
|
720
|
+
* `items`, `result`). Si el body no tiene esta clave, se devuelve `undefined`
|
|
721
|
+
* para lista / objeto vacío según corresponda, y se lanza error en modo
|
|
722
|
+
* estricto si se configura.
|
|
723
|
+
* - `metaKey`: clave con metadatos (paginación, total, etc.). Se ignora en
|
|
724
|
+
* el valor devuelto al consumidor pero puede leerse si el motor la expone
|
|
725
|
+
* en futuro.
|
|
726
|
+
* - `apply`: `'list' | 'get' | 'create' | 'update' | 'remove' | 'all'`.
|
|
727
|
+
* Qué operaciones aplican el unwrap. Por defecto `'all'` cuando se declara.
|
|
728
|
+
*/
|
|
729
|
+
export interface ResponseUnwrap {
|
|
730
|
+
dataKey: string;
|
|
731
|
+
metaKey?: string;
|
|
732
|
+
apply?: 'list' | 'get' | 'create' | 'update' | 'remove' | 'all';
|
|
733
|
+
/**
|
|
734
|
+
* Claves de metadata de paginación dentro del sobre. Usadas por
|
|
735
|
+
* `ApiService.listPage()` para armar `PageResult<T>`. Opcional: sin
|
|
736
|
+
* declaración, el motor intenta auto-detectar claves comunes
|
|
737
|
+
* (`nextCursor`, `total`, `hasMore`) y, si no hay, `hasMore = false`.
|
|
738
|
+
*/
|
|
739
|
+
pagination?: {
|
|
740
|
+
/** Clave del cursor siguiente dentro de `meta` (o del body si no hay `metaKey`). */
|
|
741
|
+
cursorKey?: string;
|
|
742
|
+
/** Clave del total de registros. */
|
|
743
|
+
totalKey?: string;
|
|
744
|
+
/** Clave del flag booleano "hay más páginas". */
|
|
745
|
+
hasMoreKey?: string;
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Método HTTP soportado por endpoints personalizados.
|
|
751
|
+
* Declarado aquí (y no en api.service.ts) para evitar ciclos de importación
|
|
752
|
+
* entre modelos y servicios.
|
|
753
|
+
*/
|
|
754
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Definición de un endpoint personalizado más allá de los cinco estándar
|
|
758
|
+
* (list/get/create/update/remove). Permite al consumidor declarar rutas con
|
|
759
|
+
* verbos arbitrarios, segmentos extra, payloads JSON o multipart, y unwrap de
|
|
760
|
+
* respuesta propio.
|
|
761
|
+
*
|
|
762
|
+
* Ejemplo:
|
|
763
|
+
* name: 'recalculate-ranks'
|
|
764
|
+
* method: 'POST'
|
|
765
|
+
* path: '/admin/businesses/{businessId}/ranks/recalculate'
|
|
766
|
+
* payloadMode: 'json'
|
|
767
|
+
*/
|
|
768
|
+
export interface CustomEndpointDefinition {
|
|
769
|
+
/** Nombre único del endpoint dentro del recurso. Se usa para invocarlo. */
|
|
770
|
+
name: string;
|
|
771
|
+
/** Método HTTP de la petición. */
|
|
772
|
+
method: HttpMethod;
|
|
773
|
+
/** Ruta relativa a `API_URL`. Puede incluir marcadores {key}, {auth.user.id}, etc. */
|
|
774
|
+
path: string;
|
|
775
|
+
/** Modo de payload: 'json' (default) o 'multipart' para FormData. */
|
|
776
|
+
payloadMode?: 'json' | 'multipart';
|
|
777
|
+
/** Unwrap de respuesta override para este endpoint. Si no se declara, se usa el del recurso. */
|
|
778
|
+
responseUnwrap?: ResponseUnwrap;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
export interface ResourceSchema {
|
|
782
|
+
/** Identificador interno (`categories`). */
|
|
783
|
+
id: string;
|
|
784
|
+
label: string;
|
|
785
|
+
labelPlural: string;
|
|
786
|
+
/**
|
|
787
|
+
* `collection` → listado, `singleton` → formulario directo,
|
|
788
|
+
* `dashboard` → panel de sólo lectura (refactormotor.md F4; sus datos llegan
|
|
789
|
+
* un endpoint declarativo, no de CRUD).
|
|
790
|
+
*/
|
|
791
|
+
kind: 'collection' | 'singleton' | 'dashboard';
|
|
792
|
+
endpoint: ResourceEndpoints;
|
|
793
|
+
/** Campo que identifica el registro (`slug`). */
|
|
794
|
+
keyField: string;
|
|
795
|
+
/** Campo que se muestra como nombre del registro. */
|
|
796
|
+
titleField: string;
|
|
797
|
+
/** Endpoints personalizados más allá de list/get/create/update/remove. */
|
|
798
|
+
customEndpoints?: Record<string, CustomEndpointDefinition>;
|
|
799
|
+
/** Si el listado se reordena (requiere `positionField`). */
|
|
800
|
+
sortable?: boolean;
|
|
801
|
+
positionField?: string;
|
|
802
|
+
listColumns: ListColumn[];
|
|
803
|
+
filters?: ListFilter[];
|
|
804
|
+
/** Campos buscables en el listado. */
|
|
805
|
+
search?: string[];
|
|
806
|
+
/** Árbol de campos del formulario (base.md §4–§6). */
|
|
807
|
+
fields: FieldSchema[];
|
|
808
|
+
/**
|
|
809
|
+
* Widgets del panel — sólo `kind: 'dashboard'` (refactormotor.md F4).
|
|
810
|
+
*
|
|
811
|
+
* Van aparte de `fields`: un KPI no es un campo y no comparte `FieldBase`
|
|
812
|
+
* (`required`/`visibleWhen`/`validators`…). Decisión tomada tras medir el
|
|
813
|
+
* ripple de unirlos a `FieldSchema`: 18+ errores de tipos en 4 ficheros.
|
|
814
|
+
* `contract-check` sólo recorre `fields`, así que esta propiedad no se
|
|
815
|
+
* compara back↔front — el widget es config de UI, no dato almacenado.
|
|
816
|
+
*/
|
|
817
|
+
widgets?: WidgetSchema[];
|
|
818
|
+
layout?: ResourceLayout;
|
|
819
|
+
actions?: ResourceAction[];
|
|
820
|
+
/** Configuración de Ficha de Detalle estructurada para el recurso. */
|
|
821
|
+
detail?: DetailViewSchema;
|
|
822
|
+
/** Configuración de diálogo/modal post-creación. */
|
|
823
|
+
postCreate?: PostCreateSchema;
|
|
824
|
+
permissions?: ResourcePermissions;
|
|
825
|
+
/**
|
|
826
|
+
* Acceso declarado por recurso (auth.md §5.3) — **sólo UX**: oculta
|
|
827
|
+
* ruta, entrada de menú y botones. Aunque el front se manipule, el back
|
|
828
|
+
* vuelve a verificar en cada petición: esto nunca es una barrera.
|
|
829
|
+
*
|
|
830
|
+
* No lo declara ningún schema mientras sólo exista el rol `admin`
|
|
831
|
+
* (§9.4): sin declaración el efecto es «sesión», que es lo correcto hoy.
|
|
832
|
+
* Aparece el día que haya un segundo rol.
|
|
833
|
+
*/
|
|
834
|
+
access?: ResourceAccess;
|
|
835
|
+
/**
|
|
836
|
+
* Claves de `fields` que el listado edita en un drawer sin navegar
|
|
837
|
+
* (plan 6.5, guía §5: «edición rápida de pocos campos, panel lateral en
|
|
838
|
+
* lugar de pantalla nueva»). 1–3 campos; si no se declara, no hay atajo.
|
|
839
|
+
*/
|
|
840
|
+
quickEdit?: string[];
|
|
841
|
+
|
|
842
|
+
// ── Metadatos públicos de `/admin/schema` (F7-1, PLAN-MEJORAS) ──
|
|
843
|
+
// Ausentes ⇒ sólo manda el schema local (merge local-driven preservado).
|
|
844
|
+
/** Rutas efectivas por operación, con la forma pública si la declara. */
|
|
845
|
+
operations?: ResourceOperations;
|
|
846
|
+
/** Vistas declaradas como metadatos (sin operandos internos). */
|
|
847
|
+
views?: Record<string, ViewDescriptor>;
|
|
848
|
+
/** Páginas y rutas del frontend; separado de `views` del backend. */
|
|
849
|
+
uiViews?: Record<string, UiViewDescriptor>;
|
|
850
|
+
/** Lo mínimo del backend para menú/acciones: `access` normalizado. */
|
|
851
|
+
policies?: ResourcePolicies;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// ─────────────────────────────────────────────────────────────
|
|
855
|
+
// Metadatos públicos de `/admin/schema` (F7-1)
|
|
856
|
+
// ─────────────────────────────────────────────────────────────
|
|
857
|
+
|
|
858
|
+
/** Forma pública de la respuesta de una operación (declaración `shape`). */
|
|
859
|
+
export interface OperationShape {
|
|
860
|
+
pick?: 'full' | 'list' | string[];
|
|
861
|
+
include?: string[];
|
|
862
|
+
rename?: Record<string, string>;
|
|
863
|
+
nest?: Record<string, string[]>;
|
|
864
|
+
envelope?: 'plain' | 'list';
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/** Ruta efectiva de una operación: método + path (con `{key}` si aplica). */
|
|
868
|
+
export interface OperationDescriptor {
|
|
869
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
870
|
+
path: string;
|
|
871
|
+
shape?: OperationShape;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/** Operaciones CRUD efectivas (derivadas de la misma ruta que el router). */
|
|
875
|
+
export interface ResourceOperations {
|
|
876
|
+
list?: OperationDescriptor;
|
|
877
|
+
get?: OperationDescriptor;
|
|
878
|
+
create?: OperationDescriptor;
|
|
879
|
+
update?: OperationDescriptor;
|
|
880
|
+
remove?: OperationDescriptor;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Condición de vista como metadato público: el literal `value` y el `ref`
|
|
885
|
+
* (metadato de relación) viajan; el operando interno `from: '$item.x'` no.
|
|
886
|
+
*/
|
|
887
|
+
export interface ViewCondition {
|
|
888
|
+
field: string;
|
|
889
|
+
op: string;
|
|
890
|
+
not?: boolean;
|
|
891
|
+
value?: unknown;
|
|
892
|
+
ref?: string;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/** Vista declarada publicada como metadato (F7-1). */
|
|
896
|
+
export interface ViewDescriptor {
|
|
897
|
+
where?: ViewCondition[];
|
|
898
|
+
sort?: { field: string; dir?: 'asc' | 'desc' }[];
|
|
899
|
+
limit?: number;
|
|
900
|
+
extends?: string;
|
|
901
|
+
/** Vista con handler propio (escape hatch): su existencia, nada más. */
|
|
902
|
+
custom?: boolean;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/** Config para una `uiView` de tipo `calendar`. */
|
|
906
|
+
export interface CalendarViewConfig {
|
|
907
|
+
/** Campo `date` (o `datetime` futuro): inicio del evento. Obligatorio. */
|
|
908
|
+
startField: string;
|
|
909
|
+
/** Campo `date`/`time`: fin. Ausente ⇒ evento de 1 día sobre `startField`. */
|
|
910
|
+
endField?: string;
|
|
911
|
+
/** Campo `text`/`relation`: rótulo del evento. Obligatorio. */
|
|
912
|
+
titleField: string;
|
|
913
|
+
/** Campo `select`/`text`: color/estado (token de paleta o valor crudo). */
|
|
914
|
+
colorField?: string;
|
|
915
|
+
/** Vista por defecto al abrir. Por defecto `month`. */
|
|
916
|
+
defaultView?: 'month' | 'week' | 'day' | 'agenda';
|
|
917
|
+
/** Origen de filas; ausente ⇒ la propia instancia del recurso (su listado). */
|
|
918
|
+
source?: DataSource;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/** Config para una `uiView` de tipo `kanban`. */
|
|
922
|
+
export interface KanbanViewConfig {
|
|
923
|
+
/** Campo `select`/`relation`: columna por valor. Obligatorio. */
|
|
924
|
+
groupField: string;
|
|
925
|
+
/** Orden estable de columnas. Valores no declarados ⇒ columna extra al final. */
|
|
926
|
+
columns: KanbanColumn[];
|
|
927
|
+
/** Rótulo de la tarjeta; ausente ⇒ `keyField` del recurso. */
|
|
928
|
+
titleField?: string;
|
|
929
|
+
/** Segundo renglón de la tarjeta (opcional). */
|
|
930
|
+
subtitleField?: string;
|
|
931
|
+
/** Origen de filas; ausente ⇒ la propia instancia del recurso. */
|
|
932
|
+
source?: DataSource;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/** Una columna del tablero Kanban. */
|
|
936
|
+
export interface KanbanColumn {
|
|
937
|
+
/** Valor del `groupField` que agrupa esta columna. */
|
|
938
|
+
value: string;
|
|
939
|
+
/** Etiqueta visible de la columna. */
|
|
940
|
+
label: string;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Evento que dispara un `select` declarado (R9.9.4): `open`, `select` o una
|
|
945
|
+
* acción con nombre (`open-detail`). El string libre cubre las acciones con
|
|
946
|
+
* nombre sin perder autocompletado para los dos literales fijos.
|
|
947
|
+
*/
|
|
948
|
+
export type SelectionTrigger = 'open' | 'select' | (string & {});
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Destino de navegación declarado (R9.9.4 · spec view-navigation): recurso +
|
|
952
|
+
* `uiView` declarada + params de ruta permitidos. Las URLs crudas o
|
|
953
|
+
* externas NO son destinos válidos — el validador las rechaza pre-render.
|
|
954
|
+
*/
|
|
955
|
+
export interface NavigationTarget {
|
|
956
|
+
/** Recurso declarado (`schema.id` del front). */
|
|
957
|
+
resource: string;
|
|
958
|
+
/** Clave de `uiViews` en ese recurso. */
|
|
959
|
+
view: string;
|
|
960
|
+
/** Nombres de params de la ruta del destino (`:key` ⇒ `['key']`). */
|
|
961
|
+
params?: string[];
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Vinculación selección ⇒ transición declarada en una `uiView` o en un hijo
|
|
966
|
+
* de composición (R9.9.4). `route` exige un `NavigationTarget` declarado;
|
|
967
|
+
* `inline` selecciona en local y `none` es un no-op explícito.
|
|
968
|
+
*/
|
|
969
|
+
export type SelectionBinding =
|
|
970
|
+
| { on: SelectionTrigger; mode: 'none' | 'inline' }
|
|
971
|
+
| { on: SelectionTrigger; mode: 'route'; target: NavigationTarget };
|
|
972
|
+
|
|
973
|
+
/** Base común de todo hijo de una composición embebida (R9.9.2). */
|
|
974
|
+
export interface ViewChildBase {
|
|
975
|
+
/** Identificador estable y único entre hermanos del mismo contenedor. */
|
|
976
|
+
id: string;
|
|
977
|
+
/** Etiqueta visible (rótulo de la pestaña). */
|
|
978
|
+
label: string;
|
|
979
|
+
/** Conserva el estado al cambiar de pestaña; ausente ⇒ destruir (R9.9.5). */
|
|
980
|
+
retain?: boolean;
|
|
981
|
+
/** Visibilidad declarativa (condiciones sobre campos del formulario). */
|
|
982
|
+
visibleWhen?: FieldCondition[];
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Hijo declarado inline (`type` + `config`) o por referencia a una `uiView`
|
|
987
|
+
* del mismo schema (`ref`). Los `ref` hacen posible que un contenedor
|
|
988
|
+
* contenga —directa o transitivamente— a sí mismo: por eso el
|
|
989
|
+
* `composition-validator` es obligatorio antes del render (D2).
|
|
990
|
+
*/
|
|
991
|
+
export type ViewChildNode = (ViewChildBase & UiViewDescriptor) | (ViewChildBase & { ref: string });
|
|
992
|
+
|
|
993
|
+
/** Config de una `uiView` contenedora `tabs` (R9.9.2). */
|
|
994
|
+
export interface TabsConfig {
|
|
995
|
+
/** Lista ordenada de hijos; el orden declarado es el orden de render. */
|
|
996
|
+
children: ViewChildNode[];
|
|
997
|
+
/** `id` del hijo seleccionado al montar; ausente ⇒ el primero. */
|
|
998
|
+
initial?: string;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/** Vista `tabs` declarada en el schema local del frontend. */
|
|
1002
|
+
export interface UiViewTabs extends UiViewBase {
|
|
1003
|
+
type: 'tabs';
|
|
1004
|
+
config: TabsConfig;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/** Base común de toda `uiView`: tipo + ruta relativa al recurso. */
|
|
1008
|
+
export interface UiViewBase {
|
|
1009
|
+
/** Tipo resuelto por `kind: 'view'` en el registro de render. */
|
|
1010
|
+
type: string;
|
|
1011
|
+
/** Ruta relativa al recurso; ausente o vacía significa la ruta raíz. */
|
|
1012
|
+
path?: string;
|
|
1013
|
+
/**
|
|
1014
|
+
* Binding de selección declarado (R9.9.4). Ausente ⇒ la hoja conserva su
|
|
1015
|
+
* comportamiento local y NO navega; una URL cruda nunca es un destino
|
|
1016
|
+
* válido (el `composition-validator` la rechaza antes del render, D2).
|
|
1017
|
+
*/
|
|
1018
|
+
select?: SelectionBinding;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/** Vista `calendar` declarada en el schema local del frontend. */
|
|
1022
|
+
export interface UiViewCalendar extends UiViewBase {
|
|
1023
|
+
type: 'calendar';
|
|
1024
|
+
config: CalendarViewConfig;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/** Vista `kanban` declarada en el schema local del frontend. */
|
|
1028
|
+
export interface UiViewKanban extends UiViewBase {
|
|
1029
|
+
type: 'kanban';
|
|
1030
|
+
config: KanbanViewConfig;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Una página/ruta declarada en el schema local del frontend, discriminada
|
|
1035
|
+
* por `type`. Los tipos base (`list`/`detail`/`form`/`dashboard`) conservan
|
|
1036
|
+
* la forma plana sin `config`; `calendar` y `kanban` llevan su config tipada.
|
|
1037
|
+
*/
|
|
1038
|
+
export type UiViewDescriptor = UiViewBase | UiViewCalendar | UiViewKanban | UiViewTabs;
|
|
1039
|
+
|
|
1040
|
+
/** Políticas públicas: sólo `access`, lo mínimo para menú/acciones. */
|
|
1041
|
+
export interface ResourcePolicies {
|
|
1042
|
+
access: {
|
|
1043
|
+
read: string;
|
|
1044
|
+
write: string;
|
|
1045
|
+
/** R7.5: override por operación (B8 · R7.4a) */
|
|
1046
|
+
operations?: Record<string, string>;
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/** §5.3 — `access` de un recurso. `requires` usa el vocabulario de §4.4. */
|
|
1051
|
+
export interface ResourceAccess {
|
|
1052
|
+
requires?: string;
|
|
1053
|
+
roles?: string[];
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
/** Un campo de la pantalla de login (auth.md §5.1). */
|
|
1057
|
+
export interface AuthFieldDeclaration {
|
|
1058
|
+
key: string;
|
|
1059
|
+
/** `email` | `password` — tipos primitivos; el registro de render los
|
|
1060
|
+
* absorberá en Fase 3 (R3.3), cuando exista el descriptor `password`. */
|
|
1061
|
+
type: string;
|
|
1062
|
+
required?: boolean;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/** Supported auth providers. Extensible without breaking existing schemas. */
|
|
1066
|
+
export type AuthProvider = 'password' | 'google' | (string & {});
|
|
1067
|
+
|
|
1068
|
+
/** Firebase config block — present only when at least one Firebase provider is listed. */
|
|
1069
|
+
export interface FirebaseAuthConfig {
|
|
1070
|
+
/**
|
|
1071
|
+
* The backend endpoint that exchanges a Firebase ID token for the app token.
|
|
1072
|
+
* Defaults to '/auth/firebase' when omitted.
|
|
1073
|
+
*/
|
|
1074
|
+
exchangeEndpoint?: string;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Pantalla de login declarada (auth.md §5.1): **vive sólo en el schema del
|
|
1079
|
+
* front** — el back no conoce estas etiquetas ni este layout, sólo declara
|
|
1080
|
+
* el `input` de `/auth/login`. El `contract-check` (R2.11) verifica que las
|
|
1081
|
+
* claves de `loginFields` existan en ese `input`.
|
|
1082
|
+
*/
|
|
1083
|
+
export interface AuthSchema {
|
|
1084
|
+
/** Proveedores disponibles: 'password' | 'google' u otros federados. */
|
|
1085
|
+
providers: AuthProvider[];
|
|
1086
|
+
loginFields: AuthFieldDeclaration[];
|
|
1087
|
+
redirectAfterLogin: string;
|
|
1088
|
+
/**
|
|
1089
|
+
* D10-3 → **`false` siempre.** La opción «recordarme» con `localStorage`
|
|
1090
|
+
* quedó denegada (§9.3): el token vive en `sessionStorage` y muere con la
|
|
1091
|
+
* pestaña. Declarar `true` prometería un storage que nadie usa.
|
|
1092
|
+
*/
|
|
1093
|
+
rememberMe: boolean;
|
|
1094
|
+
/** Configuración de Firebase cuando se usan proveedores federados o Firebase Auth. */
|
|
1095
|
+
firebase?: FirebaseAuthConfig;
|
|
1096
|
+
}
|
|
1097
|
+
|