@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,96 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
get,
|
|
5
|
+
isSupported,
|
|
6
|
+
register,
|
|
7
|
+
resolve,
|
|
8
|
+
unregister,
|
|
9
|
+
type RenderDescriptor,
|
|
10
|
+
} from './render-registry';
|
|
11
|
+
|
|
12
|
+
/** Los 21 tipos de campo que la UI sabe dibujar (R3.3). */
|
|
13
|
+
const CAMPOS = [
|
|
14
|
+
'text',
|
|
15
|
+
'textarea',
|
|
16
|
+
'slug',
|
|
17
|
+
'number',
|
|
18
|
+
'currency',
|
|
19
|
+
'boolean',
|
|
20
|
+
'select',
|
|
21
|
+
'multiselect',
|
|
22
|
+
'url',
|
|
23
|
+
'email',
|
|
24
|
+
'phone',
|
|
25
|
+
'date',
|
|
26
|
+
'time',
|
|
27
|
+
'readonly-text',
|
|
28
|
+
'group',
|
|
29
|
+
'list',
|
|
30
|
+
'string-list',
|
|
31
|
+
'key-value',
|
|
32
|
+
'relation',
|
|
33
|
+
'image',
|
|
34
|
+
'file',
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
/** Componente que sólo puede salir si el registro no resuelve. */
|
|
38
|
+
class SinRenderizador {}
|
|
39
|
+
|
|
40
|
+
describe('render-registry', () => {
|
|
41
|
+
it('registra y devuelve el descriptor por (kind, type)', () => {
|
|
42
|
+
const descriptor: RenderDescriptor = {
|
|
43
|
+
kind: 'view',
|
|
44
|
+
type: 'ficha-de-prueba',
|
|
45
|
+
since: '9.9',
|
|
46
|
+
load: async () => SinRenderizador,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
register('view', descriptor);
|
|
50
|
+
try {
|
|
51
|
+
expect(get('view', 'ficha-de-prueba')).toBe(descriptor);
|
|
52
|
+
expect(get('field', 'ficha-de-prueba')).toBeUndefined();
|
|
53
|
+
} finally {
|
|
54
|
+
// El catálogo es GLOBAL: sin retirarla, la entrada de prueba contamina
|
|
55
|
+
// `renderKinds()` y el tripwire de contract.spec.ts flashea según el
|
|
56
|
+
// orden de ejecución (R7.6).
|
|
57
|
+
unregister('view', 'ficha-de-prueba');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('isSupported sólo mira dentro de su kind', () => {
|
|
62
|
+
expect(isSupported('field', 'texto-que-no-existe')).toBe(false);
|
|
63
|
+
expect(isSupported('widget', 'text')).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('los 21 tipos de campo están en el catálogo', () => {
|
|
67
|
+
for (const type of CAMPOS) {
|
|
68
|
+
expect(isSupported('field', type), `falta el descriptor de "${type}"`).toBe(true);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Son 21 imports dinámicos de componentes reales: con el suite completo
|
|
73
|
+
// compitiendo por el hilo, el default de 10 s se queda corto y el gate se
|
|
74
|
+
// pone rojo por reloj, no por código.
|
|
75
|
+
it('los 21 tipos de campo resuelven su componente real', async () => {
|
|
76
|
+
for (const type of CAMPOS) {
|
|
77
|
+
const component = await resolve('field', type, SinRenderizador);
|
|
78
|
+
expect(component, `"${type}" resolvió el fallback`).not.toBe(SinRenderizador);
|
|
79
|
+
}
|
|
80
|
+
}, 30_000);
|
|
81
|
+
|
|
82
|
+
it('devuelve el fallback cuando el tipo no está registrado', async () => {
|
|
83
|
+
await expect(resolve('field', 'no-existe', SinRenderizador)).resolves.toBe(SinRenderizador);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('el descriptor declara kind, since y carga perezosa', () => {
|
|
87
|
+
for (const type of CAMPOS) {
|
|
88
|
+
const descriptor = get('field', type)!;
|
|
89
|
+
expect(descriptor.kind, type).toBe('field');
|
|
90
|
+
expect(descriptor.type, type).toBe(type);
|
|
91
|
+
expect(descriptor.since, type).toBeTruthy();
|
|
92
|
+
expect(typeof descriptor.load, type).toBe('function');
|
|
93
|
+
expect(descriptor.surfaces, type).toContain('form');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDevMode,
|
|
3
|
+
makeEnvironmentProviders,
|
|
4
|
+
provideAppInitializer,
|
|
5
|
+
type EnvironmentProviders,
|
|
6
|
+
type TemplateRef,
|
|
7
|
+
type Type,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
|
|
10
|
+
import type { RootTree } from '../../fields/field-node';
|
|
11
|
+
import type { SeedKind } from '../../shared/utils/seed';
|
|
12
|
+
import { columnFormatDescriptors } from '../../columns/descriptors';
|
|
13
|
+
import { fieldDescriptors } from '../../fields/descriptors';
|
|
14
|
+
import { layoutDescriptors } from '../../layouts/descriptors';
|
|
15
|
+
import { widgetDescriptors } from '../../widgets/descriptors';
|
|
16
|
+
import { viewDescriptors } from '../../views/descriptors';
|
|
17
|
+
import type { FieldSchema, LayoutMode, ListColumn, WidgetSchema } from '../models/schema.model';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Registro único de render (R3.1 · `doc/plan-refactor-motor.md` §3.1).
|
|
21
|
+
*
|
|
22
|
+
* Un solo sitio declara qué componentes sabe dibujar la UI: cada tipo de
|
|
23
|
+
* campo, widget, acción o vista aporta un `RenderDescriptor` y el registro
|
|
24
|
+
* lo resuelve por `(kind, type)`. Los hosts dejan de mantener `Set`s de tipos
|
|
25
|
+
* e imports a mano — **en runtime el registro es la única fuente de verdad**.
|
|
26
|
+
*
|
|
27
|
+
* Se carga a scope de módulo y no desde DI: `buildFormSchema()` es una
|
|
28
|
+
* función pura que consulta el registro sin inyectar nada, así que un
|
|
29
|
+
* registro llenado únicamente por un provider dejaría esa consulta correr
|
|
30
|
+
* contra un catálogo vacío. `provideRenderDescriptors()` existe igualmente
|
|
31
|
+
* como punto de entrada explícito para `app.config.ts` (R3.2).
|
|
32
|
+
*
|
|
33
|
+
* Autodescubrimiento (D9-1): se opta por **registro manual** — un manifiesto
|
|
34
|
+
* con una línea por descriptor — porque `import.meta.glob` no está
|
|
35
|
+
* implementada por el bundler de producción (`@angular/build:application`
|
|
36
|
+
* usa esbuild) y la llamada cruda sobreviviría en `dist/`, rompiendo el
|
|
37
|
+
* arranque. Con Vite sólo en el dev-server y en el runner de tests, además,
|
|
38
|
+
* el comportamiento habría diferido entre `npm test` y `npm run build`.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** Qué clase de cosa se está resolviendo. Identificador único dentro de su `kind`. */
|
|
42
|
+
export type RenderKind = 'field' | 'column-format' | 'widget' | 'action' | 'view' | 'layout';
|
|
43
|
+
export type ComponentRenderKind = Exclude<RenderKind, 'layout'>;
|
|
44
|
+
|
|
45
|
+
/** Superficies en las que un descriptor puede aparecer. */
|
|
46
|
+
export type RenderSurface = 'form' | 'display' | 'list' | 'filter';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Qué puede describir un `RenderDescriptor`: un campo del formulario, un
|
|
50
|
+
* widget del dashboard o una columna de listado (R4.3).
|
|
51
|
+
*
|
|
52
|
+
* Es el tipo del input `config` del host. Los descriptores sólo comparten
|
|
53
|
+
* `key` y `label`; lo demás lo decide cada `kind`, y quien necesita el resto
|
|
54
|
+
* lo castea con su propia mirada (`cfgCampo()`, que es lo que el host ya
|
|
55
|
+
* hacía antes de que existieran las columnas).
|
|
56
|
+
*/
|
|
57
|
+
export type RenderConfig = FieldSchema | WidgetSchema | ListColumn;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Contexto de render que el host expone por DI (R3.4 · `doc/plan-refactor-motor.md` §3.4).
|
|
61
|
+
*
|
|
62
|
+
* Los controles viven en un componente distinto por cada tipo, así que en vez
|
|
63
|
+
* de repetir cinco inputs en los 20 el host lo provee una sola vez y cada
|
|
64
|
+
* control lo inyecta si lo necesita — el mismo criterio que ya usaba
|
|
65
|
+
* `FIELD_ARIA`.
|
|
66
|
+
*
|
|
67
|
+
* `tree` viaja en el contexto y no como input suelto porque es **por
|
|
68
|
+
* instancia**: los hijos de un `group` o de un `list` navegan su subárbol, no
|
|
69
|
+
* el del padre.
|
|
70
|
+
*
|
|
71
|
+
* Vive acá y no en `render-host.ts` porque el contrato de los descriptores
|
|
72
|
+
* (`RenderExtras`) necesita nombrarlo: el descriptor de un campo compuesto
|
|
73
|
+
* decide qué se le pasa al componente y eso sólo es escribible conociendo el
|
|
74
|
+
* tipo. `render-host.ts` lo re-exporta para no mover a sus consumidores.
|
|
75
|
+
*/
|
|
76
|
+
export interface RenderContext {
|
|
77
|
+
/** Árbol del formulario del nivel de este campo. */
|
|
78
|
+
tree: RootTree;
|
|
79
|
+
/** Errores del backend por ruta (`address.street`, `faq[2].answer`). */
|
|
80
|
+
serverErrors: Record<string, string>;
|
|
81
|
+
/** Prefijo de ruta de este campo en el registro raíz (`address.`). */
|
|
82
|
+
pathPrefix: string;
|
|
83
|
+
/** Si el registro ya existe (lo consume `slug` con `lockAfterCreate`). */
|
|
84
|
+
exists: boolean;
|
|
85
|
+
/** Recurso dueño del formulario (lo consume `image` para la firma, §11.2). */
|
|
86
|
+
resource: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Contexto vacío con el que arranca `RenderHost.ctx`.
|
|
91
|
+
*
|
|
92
|
+
* Sólo lo alcanza quien renderiza sin contexto — los widgets, que no forman
|
|
93
|
+
* parte de un formulario. Un campo montado sin `ctx` es un error de
|
|
94
|
+
* programación y `childTree` lo dice con su propio mensaje, igual que lo
|
|
95
|
+
* decía el `input.required` anterior.
|
|
96
|
+
*/
|
|
97
|
+
export const RENDER_CONTEXT_VACIO: RenderContext = {
|
|
98
|
+
tree: undefined as unknown as RootTree,
|
|
99
|
+
serverErrors: {},
|
|
100
|
+
pathPrefix: '',
|
|
101
|
+
exists: false,
|
|
102
|
+
resource: '',
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Segundo argumento de `RenderDescriptor.inputs`.
|
|
107
|
+
*
|
|
108
|
+
* Aporta lo que el host conoce y el descriptor no: el contexto de formulario
|
|
109
|
+
* (sólo para campos), el payload del dato (sólo para widgets) y los dos
|
|
110
|
+
* templates con los que se componen `group` y `list`.
|
|
111
|
+
*/
|
|
112
|
+
export interface RenderExtras {
|
|
113
|
+
/** Contexto del nivel; `RENDER_CONTEXT_VACIO` cuando no hay formulario. */
|
|
114
|
+
ctx: RenderContext;
|
|
115
|
+
/** Payload del widget (`<app-widget-host [data]>`); `null` en campos. */
|
|
116
|
+
data: unknown;
|
|
117
|
+
/** Template del contenido de un `group`. */
|
|
118
|
+
groupContent?: TemplateRef<unknown>;
|
|
119
|
+
/** Template de los hijos de un `list`. */
|
|
120
|
+
childTemplate?: TemplateRef<unknown>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Declaración de un componente renderizable.
|
|
125
|
+
*
|
|
126
|
+
* No lleva `configSchema`: esa cláusula de `refactormotor.md` no existe en
|
|
127
|
+
* el código y el plan la descartó (D17).
|
|
128
|
+
*/
|
|
129
|
+
export interface RenderDescriptor<C = unknown> {
|
|
130
|
+
/** Clase de cosa. */
|
|
131
|
+
kind: ComponentRenderKind;
|
|
132
|
+
/** Identificador `kebab-case`, único dentro de `kind`. */
|
|
133
|
+
type: string;
|
|
134
|
+
/** Versión del contrato en que apareció (`doc/refactormotor.md`). */
|
|
135
|
+
since: string;
|
|
136
|
+
/**
|
|
137
|
+
* Carga perezosa del componente. El registro se resuelve sin arrastrar el
|
|
138
|
+
* bundle: los descriptores sólo guardan el cierre, no la clase.
|
|
139
|
+
*/
|
|
140
|
+
load: () => Promise<Type<any>>;
|
|
141
|
+
/** Superficies en las que se usa. Sólo lo que se pueda evidenciar en el código. */
|
|
142
|
+
surfaces?: RenderSurface[];
|
|
143
|
+
/** Valores por defecto de la configuración del descriptor. */
|
|
144
|
+
defaults?: Partial<C>;
|
|
145
|
+
/**
|
|
146
|
+
* Forma del valor inicial que siembra este campo en el modelo del
|
|
147
|
+
* formulario (D32 · R3.8).
|
|
148
|
+
*
|
|
149
|
+
* **Dato, no función**: un nombre resuelto por `shared/utils/seed.ts`, no
|
|
150
|
+
* una clausura. Así el descriptor sigue siendo puro —`kind`, `type`,
|
|
151
|
+
* `load`, `surfaces`, `seed`— y `seed.ts` es el único dueño de recorrer
|
|
152
|
+
* un árbol de campos. La alternativa (`seed: (cfg) => …`) obligaría a que
|
|
153
|
+
* `group` importara `seedFields`, lo que cerraría un ciclo
|
|
154
|
+
* registro → manifiesto → descriptor → `seed` → registro.
|
|
155
|
+
*
|
|
156
|
+
* Sólo los campos lo declaran. **Obligatorio para `kind: 'field'`** — lo
|
|
157
|
+
* vigila `core/registry/contract.spec.ts`, porque la exhaustividad de una
|
|
158
|
+
* unión de strings no puede imponerse en tiempo de compilación.
|
|
159
|
+
*/
|
|
160
|
+
seed?: SeedKind;
|
|
161
|
+
/**
|
|
162
|
+
* Cableado del componente: qué inputs recibe y con qué valor.
|
|
163
|
+
*
|
|
164
|
+
* Es **la** pieza que mantiene el host genérico: sin esto el motor tendría
|
|
165
|
+
* que saber que `metric-card` recibe `label/value/hint` y que `group`
|
|
166
|
+
* necesita además el template de sus hijos, y «añadir un tipo» volvería a
|
|
167
|
+
* tocar `render-host.ts` (R3.8). Cada descriptor declara el suyo y el host
|
|
168
|
+
* sólo hace `ngComponentOutletInputs = descriptor.inputs(config, extras)`.
|
|
169
|
+
*
|
|
170
|
+
* No es obligatorio: el 80 % de los tipos comparten la forma estándar de su
|
|
171
|
+
* `kind` — `{field, tree}` en campos, `{widget, data}` en widgets — y para
|
|
172
|
+
* ellos el host aplica esa forma por defecto. Se declara sólo cuando el
|
|
173
|
+
* componente se desvía de ella.
|
|
174
|
+
*/
|
|
175
|
+
inputs?: (config: C, extras: RenderExtras) => Record<string, unknown>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Declaración de un layout manejado por el host de formularios. */
|
|
179
|
+
export interface LayoutDescriptor {
|
|
180
|
+
kind: 'layout';
|
|
181
|
+
type: LayoutMode;
|
|
182
|
+
since: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Catálogo en memoria: `kind:type` → descriptor. */
|
|
186
|
+
const RENDERERS = new Map<string, RenderDescriptor>();
|
|
187
|
+
const LAYOUTS = new Map<string, LayoutDescriptor>();
|
|
188
|
+
|
|
189
|
+
function keyOf(kind: RenderKind, type: string): string {
|
|
190
|
+
return `${kind}:${type}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Registra un descriptor. Idempotente por clave: volver a registrar el mismo
|
|
195
|
+
* `(kind, type)` lo sobrescribe, lo que permite que un módulo se recargue en
|
|
196
|
+
* desarrollo sin duplicar entradas.
|
|
197
|
+
*/
|
|
198
|
+
export function register(kind: 'layout', descriptor: LayoutDescriptor): void;
|
|
199
|
+
export function register(kind: ComponentRenderKind, descriptor: RenderDescriptor): void;
|
|
200
|
+
export function register(kind: RenderKind, descriptor: RenderDescriptor | LayoutDescriptor): void {
|
|
201
|
+
if (kind === 'layout') {
|
|
202
|
+
if (!('kind' in descriptor) || descriptor.kind !== 'layout') {
|
|
203
|
+
throw new Error(`El descriptor de layout "${descriptor.type}" no declara kind: "layout".`);
|
|
204
|
+
}
|
|
205
|
+
LAYOUTS.set(descriptor.type, descriptor);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (descriptor.kind === 'layout') {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`El descriptor de layout "${descriptor.type}" no puede registrarse como ${kind}.`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
RENDERERS.set(keyOf(kind, descriptor.type), descriptor);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Quita un descriptor (R7.6). Simétrico a `register`: los specs que
|
|
218
|
+
* registran entradas de prueba deben retirarlas, o el catálogo global queda
|
|
219
|
+
* contaminado para cualquier otro spec que lea `renderKinds()` (flaky por
|
|
220
|
+
* orden de ejecución).
|
|
221
|
+
*/
|
|
222
|
+
export function unregister(kind: RenderKind, type: string): void {
|
|
223
|
+
if (kind === 'layout') {
|
|
224
|
+
LAYOUTS.delete(type);
|
|
225
|
+
} else {
|
|
226
|
+
RENDERERS.delete(keyOf(kind, type));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Descriptor declarado para `(kind, type)`, o `undefined` si nadie lo registró. */
|
|
231
|
+
export function get(kind: ComponentRenderKind, type: string): RenderDescriptor | undefined {
|
|
232
|
+
return RENDERERS.get(keyOf(kind, type));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** ¿La UI sabe dibujar este `(kind, type)`? Reemplaza a los `Set`s de los hosts. */
|
|
236
|
+
export function isSupported(kind: RenderKind, type: string): boolean {
|
|
237
|
+
return kind === 'layout' ? LAYOUTS.has(type) : RENDERERS.has(keyOf(kind, type));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Componente para `(kind, type)`, o `fallback` si el tipo no está en el
|
|
242
|
+
* catálogo.
|
|
243
|
+
*
|
|
244
|
+
* Es **asíncrona** porque `load()` importa el componente bajo demanda; el
|
|
245
|
+
* `fallback` es síncrono y sólo se usa cuando no hay descriptor. Un fallo de
|
|
246
|
+
* `load()` NO se traga: propagarlo es lo que hace visible un descriptor mal
|
|
247
|
+
* escrito, y la política «nunca pantalla rota» la resuelve el llamante con el
|
|
248
|
+
* `fallback` que ya recibe.
|
|
249
|
+
*/
|
|
250
|
+
export async function resolve<C = unknown>(
|
|
251
|
+
kind: ComponentRenderKind,
|
|
252
|
+
type: string,
|
|
253
|
+
fallback: Type<C>,
|
|
254
|
+
): Promise<Type<C>> {
|
|
255
|
+
const descriptor = get(kind, type);
|
|
256
|
+
if (!descriptor) return fallback;
|
|
257
|
+
return (await descriptor.load()) as Type<C>;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Catálogo a scope de módulo: se registra al importar, sin esperar a DI.
|
|
261
|
+
for (const descriptor of [
|
|
262
|
+
...fieldDescriptors,
|
|
263
|
+
...widgetDescriptors,
|
|
264
|
+
...columnFormatDescriptors,
|
|
265
|
+
...viewDescriptors,
|
|
266
|
+
...layoutDescriptors,
|
|
267
|
+
]) {
|
|
268
|
+
if (descriptor.kind === 'layout') {
|
|
269
|
+
register('layout', descriptor);
|
|
270
|
+
} else {
|
|
271
|
+
register(descriptor.kind, descriptor);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Punto de entrada para `app.config.ts` (R3.2).
|
|
277
|
+
*
|
|
278
|
+
* El catálogo ya quedó cargado al importar este módulo; el provider sirve
|
|
279
|
+
* para que el arranque sea explícito y para avisar en desarrollo si el
|
|
280
|
+
* manifiesto vino vacío — que es exactamente lo que pasaría si alguien
|
|
281
|
+
* borra una línea del manifiesto sin reemplazarla.
|
|
282
|
+
*/
|
|
283
|
+
export function provideRenderDescriptors(): EnvironmentProviders {
|
|
284
|
+
return makeEnvironmentProviders([
|
|
285
|
+
provideAppInitializer(() => {
|
|
286
|
+
if (isDevMode() && RENDERERS.size === 0 && LAYOUTS.size === 0) {
|
|
287
|
+
console.warn('[render-registry] el catálogo de descriptores vino vacío');
|
|
288
|
+
}
|
|
289
|
+
}),
|
|
290
|
+
]);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Cuántos descriptores hay registrados. Sólo para comprobaciones y tests. */
|
|
294
|
+
export function renderDescriptorCount(): number {
|
|
295
|
+
return RENDERERS.size + LAYOUTS.size;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* `kind`s que hoy tienen al menos un descriptor.
|
|
300
|
+
*
|
|
301
|
+
* Existe para el test de exhaustividad (R3.7): él recorre los schemas de los
|
|
302
|
+
* `kind`s que tienen registro y **falla** si aparece un `kind` con descriptor
|
|
303
|
+
* que nadie recorre — de lo contrario «tener registro» y «estar cubierto»
|
|
304
|
+
* serían dos afirmaciones distintas que nadie reconcilia.
|
|
305
|
+
*/
|
|
306
|
+
export function renderKinds(): RenderKind[] {
|
|
307
|
+
const kinds = new Set<RenderKind>([...RENDERERS.values()].map((descriptor) => descriptor.kind));
|
|
308
|
+
if (LAYOUTS.size > 0) {
|
|
309
|
+
kinds.add('layout');
|
|
310
|
+
}
|
|
311
|
+
return [...kinds];
|
|
312
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EnvironmentProviders,
|
|
3
|
+
InjectionToken,
|
|
4
|
+
Provider,
|
|
5
|
+
inject,
|
|
6
|
+
provideAppInitializer,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
9
|
+
|
|
10
|
+
import { apiErrorInterceptor } from '../interceptors/api-error.interceptor';
|
|
11
|
+
import { AuthService } from '../services/auth.service';
|
|
12
|
+
import { ConfigService } from '../services/config.service';
|
|
13
|
+
import type { AuthSchema, ResourceSchema, ResponseUnwrap } from '../models/schema.model';
|
|
14
|
+
import type { FirebaseAuthAdapter } from '../adapters/firebase-auth.adapter';
|
|
15
|
+
import { API_DRIVER, DEFAULT_RESPONSE_UNWRAP, FIREBASE_AUTH_ADAPTER, VALUE_SOURCES } from '../tokens';
|
|
16
|
+
import type { ValueSources } from '../tokens';
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Catálogo de schemas del consumidor (F1 · G-F2).
|
|
21
|
+
*
|
|
22
|
+
* Antes de la extracción el motor importaba `getSchema` del
|
|
23
|
+
* `schemas/registry.ts` de la app. Ese acoplamiento se rompe con un
|
|
24
|
+
* catálogo a nivel módulo: el consumidor llama
|
|
25
|
+
* `provideGasAdmin({ schemas, auth })` en su `app.config.ts` y el motor
|
|
26
|
+
* resuelve en runtime con la MISMA semántica que antes (un solo catálogo
|
|
27
|
+
* por aplicación, seteado una vez en el bootstrap).
|
|
28
|
+
*
|
|
29
|
+
* `provideGasAdmin` se ejecuta al evaluarse el `app.config` (módulo), y
|
|
30
|
+
* todo uso del catálogo (guards, componentes, rutas dinámicas) ocurre en
|
|
31
|
+
* runtime posterior al bootstrap — el orden es determinístico.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
let catalog: readonly ResourceSchema[] = [];
|
|
35
|
+
let authCatalog: AuthSchema | undefined;
|
|
36
|
+
|
|
37
|
+
/** Fija el catálogo (uso interno de `provideGasAdmin`; testable directo). */
|
|
38
|
+
export function setSchemaCatalog(
|
|
39
|
+
schemas: readonly ResourceSchema[],
|
|
40
|
+
auth?: AuthSchema,
|
|
41
|
+
): void {
|
|
42
|
+
catalog = schemas;
|
|
43
|
+
authCatalog = auth;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Busca un schema por `id`; `undefined` si no existe. */
|
|
47
|
+
export function getSchema(id: string): ResourceSchema | undefined {
|
|
48
|
+
return catalog.find((schema) => schema.id === id);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Catálogo completo en orden (menú lateral). */
|
|
52
|
+
export function allSchemas(): readonly ResourceSchema[] {
|
|
53
|
+
return catalog;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Declaración de la pantalla de login; `undefined` sin `auth` en config. */
|
|
57
|
+
export function getAuth(): AuthSchema | undefined {
|
|
58
|
+
return authCatalog;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Token DI del catálogo (para inyectarlo donde un `inject()` es posible). */
|
|
62
|
+
export const GAS_SCHEMAS = new InjectionToken<readonly ResourceSchema[]>(
|
|
63
|
+
'gas.admin.schemas',
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/** Configuración del motor. */
|
|
67
|
+
export interface GasAdminConfig {
|
|
68
|
+
/** Catálogo ordenado de recursos (menú + rutas + resolución `getSchema`). */
|
|
69
|
+
schemas: readonly ResourceSchema[];
|
|
70
|
+
/** Declaración de la pantalla de login (opcional: sin ella, sin `/login`). */
|
|
71
|
+
auth?: AuthSchema;
|
|
72
|
+
/**
|
|
73
|
+
* Driver de transporte HTTP.
|
|
74
|
+
*
|
|
75
|
+
* - `'gas'` (default): tunnel `POST text/plain` con envelope Apps Script.
|
|
76
|
+
* - `'rest'`: verbos HTTP reales con `Authorization: Bearer` en cabeceras.
|
|
77
|
+
*
|
|
78
|
+
* Sin declaración el motor usa `'gas'` — cero impacto en consumidores existentes.
|
|
79
|
+
*/
|
|
80
|
+
driver?: 'gas' | 'rest';
|
|
81
|
+
/**
|
|
82
|
+
* Fuentes de contexto que el consumidor aporta para marcadores en paths de
|
|
83
|
+
* endpoints: `{ <fuente> }` / `{ <fuente>.<ruta> }` se resuelven en el
|
|
84
|
+
* momento de la petición contra este registro más las fuentes construidas
|
|
85
|
+
* `auth` (sesión) y `config` (config global).
|
|
86
|
+
*
|
|
87
|
+
* Opcional: sin él, sólo existen `auth` y `config`. Declararlo no cambia
|
|
88
|
+
* ningún path que no lleve marcadores — cero impacto en schemas existentes.
|
|
89
|
+
*/
|
|
90
|
+
valueSources?: ValueSources;
|
|
91
|
+
/**
|
|
92
|
+
* Unwrap de respuesta global por defecto. Se fusiona con la declaración
|
|
93
|
+
* `endpoint.responseUnwrap` de cada recurso (la del recurso tiene prioridad
|
|
94
|
+
* en claves declaradas). Opcional: sin él, sólo aplica lo declarado por
|
|
95
|
+
* recurso — cero impacto en schemas existentes (R2).
|
|
96
|
+
*/
|
|
97
|
+
defaultResponseUnwrap?: ResponseUnwrap;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Wiring completo del motor: catálogo + HTTP con el interceptor de
|
|
102
|
+
* errores del envelope + loaders de config y sesión en el bootstrap
|
|
103
|
+
* (antes en el `app.config` del consumidor).
|
|
104
|
+
*
|
|
105
|
+
* El consumidor conserva `provideRouter` y `{ provide: API_URL, ... }`
|
|
106
|
+
* (su environment decide la URL del Web App).
|
|
107
|
+
*/
|
|
108
|
+
export function provideGasAdmin(
|
|
109
|
+
config: GasAdminConfig,
|
|
110
|
+
): (Provider | EnvironmentProviders)[] {
|
|
111
|
+
setSchemaCatalog(config.schemas, config.auth);
|
|
112
|
+
// Singletons de configuración: los declara el catálogo, no el servicio.
|
|
113
|
+
// Un singleton nuevo con `endpoint.get` se carga solo.
|
|
114
|
+
const configEndpoints = () =>
|
|
115
|
+
config.schemas.flatMap((schema) =>
|
|
116
|
+
schema.kind === 'singleton' && schema.endpoint?.get
|
|
117
|
+
? [{ get: schema.endpoint.get }]
|
|
118
|
+
: [],
|
|
119
|
+
);
|
|
120
|
+
return [
|
|
121
|
+
{ provide: GAS_SCHEMAS, useValue: config.schemas },
|
|
122
|
+
// Driver de transporte: 'gas' por defecto para cero breaking changes.
|
|
123
|
+
{ provide: API_DRIVER, useValue: config.driver ?? 'gas' },
|
|
124
|
+
// Fuentes de contexto del consumidor: vacío por defecto ⇒ sólo `auth` y
|
|
125
|
+
// `config`, que el motor arma por su cuenta en cada petición.
|
|
126
|
+
{ provide: VALUE_SOURCES, useValue: config.valueSources ?? {} },
|
|
127
|
+
// Unwrap global por defecto: undefined si no se declara ⇒ sólo aplica lo
|
|
128
|
+
// declarado por recurso (R2, cero impacto en schemas existentes).
|
|
129
|
+
{ provide: DEFAULT_RESPONSE_UNWRAP, useValue: config.defaultResponseUnwrap },
|
|
130
|
+
// Sin `authInterceptor` en modo GAS: el token viaja en el cuerpo del envelope
|
|
131
|
+
// (baseapi §2.3, criterio 11: ninguna cabecera custom).
|
|
132
|
+
// En modo REST el token viaja como cabecera `Authorization` dentro de ApiService.
|
|
133
|
+
provideHttpClient(withInterceptors([apiErrorInterceptor])),
|
|
134
|
+
// Carga de config en bootstrap (fuera del constructor del servicio):
|
|
135
|
+
// un singleton que falle no rompe el arranque.
|
|
136
|
+
provideAppInitializer(() => inject(ConfigService).load(configEndpoints())),
|
|
137
|
+
// Sesión (R2.12): revalida contra `/auth/me` el token que restauró el
|
|
138
|
+
// AuthService de `sessionStorage`. Corre ANTES del primer guard.
|
|
139
|
+
provideAppInitializer(() => inject(AuthService).restore()),
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Registra una implementación concreta de FirebaseAuthAdapter en el árbol de DI.
|
|
145
|
+
* Usar junto con provideGasAdmin() en app.config.ts al configurar proveedores federados
|
|
146
|
+
* (como 'google') o autenticación por Firebase.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* // app.config.ts
|
|
150
|
+
* provideGasAdmin({ schemas, auth }),
|
|
151
|
+
* provideFirebaseAdapter(new MyFirebaseAuthAdapter(getAuth(firebaseApp))),
|
|
152
|
+
*/
|
|
153
|
+
export function provideFirebaseAdapter(adapter: FirebaseAuthAdapter): Provider {
|
|
154
|
+
return { provide: FIREBASE_AUTH_ADAPTER, useValue: adapter };
|
|
155
|
+
}
|
|
156
|
+
|