@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.17
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/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +1027 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +101 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +88 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +122 -0
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +45 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +408 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs +4516 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +416 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +439 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs +637 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +251 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +309 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs +576 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +161 -0
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +685 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs +80 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +296 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +60 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs +4738 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
- package/package.json +15 -3
- package/types/tinya-code-gas-admin-ui.d.ts +3634 -0
- package/ng-package.json +0 -7
- package/src/lib/actions/action-registry.spec.ts +0 -52
- package/src/lib/actions/action-registry.ts +0 -126
- package/src/lib/actions/action-service.spec.ts +0 -215
- package/src/lib/actions/action-service.ts +0 -87
- package/src/lib/actions/descriptors.spec.ts +0 -155
- package/src/lib/actions/descriptors.ts +0 -154
- package/src/lib/columns/column-cell.ts +0 -33
- package/src/lib/columns/column-defaults.spec.ts +0 -99
- package/src/lib/columns/column-defaults.ts +0 -84
- package/src/lib/columns/column-format.spec.ts +0 -274
- package/src/lib/columns/descriptors.ts +0 -113
- package/src/lib/columns/format-badge.ts +0 -51
- package/src/lib/columns/format-boolean.ts +0 -58
- package/src/lib/columns/format-currency.ts +0 -30
- package/src/lib/columns/format-date.ts +0 -35
- package/src/lib/columns/format-number.ts +0 -32
- package/src/lib/columns/format-text.ts +0 -23
- package/src/lib/columns/format-thumbnail.ts +0 -63
- package/src/lib/core/adapters/firebase-auth.adapter.ts +0 -6
- package/src/lib/core/guards/auth.guard.spec.ts +0 -88
- package/src/lib/core/guards/auth.guard.ts +0 -48
- package/src/lib/core/guards/unsaved-changes.guard.ts +0 -16
- package/src/lib/core/interceptors/api-error.interceptor.spec.ts +0 -182
- package/src/lib/core/interceptors/api-error.interceptor.ts +0 -87
- package/src/lib/core/models/api.model.ts +0 -104
- package/src/lib/core/models/schema-descriptions.ts +0 -118
- package/src/lib/core/models/schema.model.ts +0 -1097
- package/src/lib/core/registry/composition-validator.spec.ts +0 -358
- package/src/lib/core/registry/composition-validator.ts +0 -270
- package/src/lib/core/registry/field-validators.spec.ts +0 -199
- package/src/lib/core/registry/field-validators.ts +0 -440
- package/src/lib/core/registry/render-host.spec.ts +0 -208
- package/src/lib/core/registry/render-host.ts +0 -646
- package/src/lib/core/registry/render-registry.spec.ts +0 -96
- package/src/lib/core/registry/render-registry.ts +0 -312
- package/src/lib/core/registry/schema-catalog.ts +0 -156
- package/src/lib/core/services/api.service.spec.ts +0 -1142
- package/src/lib/core/services/api.service.ts +0 -371
- package/src/lib/core/services/auth.service.spec.ts +0 -653
- package/src/lib/core/services/auth.service.ts +0 -503
- package/src/lib/core/services/config.service.spec.ts +0 -121
- package/src/lib/core/services/config.service.ts +0 -119
- package/src/lib/core/services/data-source.service.spec.ts +0 -179
- package/src/lib/core/services/data-source.service.ts +0 -142
- package/src/lib/core/services/error-mapper.service.spec.ts +0 -50
- package/src/lib/core/services/error-mapper.service.ts +0 -49
- package/src/lib/core/services/notification.service.ts +0 -73
- package/src/lib/core/services/relation-drawer.service.ts +0 -41
- package/src/lib/core/services/theme.service.spec.ts +0 -106
- package/src/lib/core/services/theme.service.ts +0 -86
- package/src/lib/core/services/transport.spec.ts +0 -198
- package/src/lib/core/services/transport.ts +0 -164
- package/src/lib/core/services/upload.service.ts +0 -81
- package/src/lib/core/testing/categories.schema.ts +0 -125
- package/src/lib/core/testing/orders.schema.ts +0 -372
- package/src/lib/core/testing/products.schema.ts +0 -258
- package/src/lib/core/testing/site.schema.ts +0 -195
- package/src/lib/core/testing/test-catalog.ts +0 -21
- package/src/lib/core/tokens.ts +0 -112
- package/src/lib/core/utils/clipboard.spec.ts +0 -55
- package/src/lib/core/utils/clipboard.ts +0 -90
- package/src/lib/core/utils/context-resolver.spec.ts +0 -95
- package/src/lib/core/utils/context-resolver.ts +0 -101
- package/src/lib/core/utils/response-unwrapper.spec.ts +0 -70
- package/src/lib/core/utils/response-unwrapper.ts +0 -103
- package/src/lib/core/utils/source-options.spec.ts +0 -96
- package/src/lib/core/utils/source-options.ts +0 -54
- package/src/lib/core/utils/template-interpolator.spec.ts +0 -59
- package/src/lib/core/utils/template-interpolator.ts +0 -56
- package/src/lib/core/view-navigation/view-navigation.service.spec.ts +0 -207
- package/src/lib/core/view-navigation/view-navigation.service.ts +0 -132
- package/src/lib/fields/boolean/boolean.descriptor.ts +0 -11
- package/src/lib/fields/boolean/boolean.ts +0 -40
- package/src/lib/fields/color/color.descriptor.ts +0 -12
- package/src/lib/fields/color/color.ts +0 -34
- package/src/lib/fields/currency/currency.descriptor.ts +0 -12
- package/src/lib/fields/currency/currency.ts +0 -67
- package/src/lib/fields/date/date.descriptor.ts +0 -12
- package/src/lib/fields/date/date.ts +0 -36
- package/src/lib/fields/descriptors.ts +0 -122
- package/src/lib/fields/display/display-badge.ts +0 -65
- package/src/lib/fields/display/display-date.ts +0 -39
- package/src/lib/fields/display/display-defaults.ts +0 -84
- package/src/lib/fields/display/display-file.ts +0 -41
- package/src/lib/fields/display/display-image.ts +0 -54
- package/src/lib/fields/display/display-list.ts +0 -107
- package/src/lib/fields/display/display-number.ts +0 -41
- package/src/lib/fields/display/display-text.ts +0 -42
- package/src/lib/fields/display/display.spec.ts +0 -242
- package/src/lib/fields/dropdown/dropdown.descriptor.ts +0 -12
- package/src/lib/fields/dropdown/dropdown.ts +0 -45
- package/src/lib/fields/email/email.descriptor.ts +0 -12
- package/src/lib/fields/email/email.ts +0 -28
- package/src/lib/fields/field-aria.ts +0 -60
- package/src/lib/fields/field-host/field-host.spec.ts +0 -118
- package/src/lib/fields/field-host/field-host.ts +0 -47
- package/src/lib/fields/field-node.ts +0 -88
- package/src/lib/fields/file/file.descriptor.ts +0 -14
- package/src/lib/fields/file/file.spec.ts +0 -134
- package/src/lib/fields/file/file.ts +0 -281
- package/src/lib/fields/group/group.descriptor.ts +0 -21
- package/src/lib/fields/group/group.ts +0 -110
- package/src/lib/fields/image/image.descriptor.ts +0 -12
- package/src/lib/fields/image/image.spec.ts +0 -117
- package/src/lib/fields/image/image.ts +0 -281
- package/src/lib/fields/key-value/key-value.descriptor.ts +0 -11
- package/src/lib/fields/key-value/key-value.ts +0 -283
- package/src/lib/fields/list/list.descriptor.ts +0 -21
- package/src/lib/fields/list/list.ts +0 -376
- package/src/lib/fields/multiselect/multiselect.descriptor.ts +0 -11
- package/src/lib/fields/multiselect/multiselect.spec.ts +0 -142
- package/src/lib/fields/multiselect/multiselect.ts +0 -152
- package/src/lib/fields/number/number.descriptor.ts +0 -12
- package/src/lib/fields/number/number.ts +0 -40
- package/src/lib/fields/phone/phone.descriptor.ts +0 -12
- package/src/lib/fields/phone/phone.ts +0 -46
- package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +0 -12
- package/src/lib/fields/readonly-text/readonly-text.ts +0 -58
- package/src/lib/fields/relation/relation.descriptor.ts +0 -12
- package/src/lib/fields/relation/relation.spec.ts +0 -193
- package/src/lib/fields/relation/relation.ts +0 -224
- package/src/lib/fields/rich-select/rich-select.descriptor.ts +0 -12
- package/src/lib/fields/rich-select/rich-select.ts +0 -175
- package/src/lib/fields/select/radio-mode.ts +0 -25
- package/src/lib/fields/select/select.descriptor.ts +0 -12
- package/src/lib/fields/select/select.spec.ts +0 -162
- package/src/lib/fields/select/select.ts +0 -210
- package/src/lib/fields/slug/slug.descriptor.ts +0 -19
- package/src/lib/fields/slug/slug.ts +0 -67
- package/src/lib/fields/string-list/string-list.descriptor.ts +0 -11
- package/src/lib/fields/string-list/string-list.ts +0 -222
- package/src/lib/fields/text/text.descriptor.ts +0 -12
- package/src/lib/fields/text/text.ts +0 -35
- package/src/lib/fields/textarea/textarea.descriptor.ts +0 -12
- package/src/lib/fields/textarea/textarea.spec.ts +0 -117
- package/src/lib/fields/textarea/textarea.ts +0 -126
- package/src/lib/fields/time/time.descriptor.ts +0 -12
- package/src/lib/fields/time/time.ts +0 -28
- package/src/lib/fields/unknown-render/unknown-render.ts +0 -49
- package/src/lib/fields/url/url.descriptor.ts +0 -12
- package/src/lib/fields/url/url.ts +0 -53
- package/src/lib/gas-admin-ui.spec.ts +0 -21
- package/src/lib/gas-admin-ui.ts +0 -9
- package/src/lib/layouts/descriptors.ts +0 -9
- package/src/lib/pages/dashboard/dashboard.ts +0 -167
- package/src/lib/pages/detail-view/detail-view.spec.ts +0 -333
- package/src/lib/pages/detail-view/detail-view.ts +0 -570
- package/src/lib/pages/drawer-form/drawer-form.ts +0 -228
- package/src/lib/pages/form-view/form-model.ts +0 -88
- package/src/lib/pages/form-view/form-schema.ts +0 -255
- package/src/lib/pages/form-view/form-view.ts +0 -1622
- package/src/lib/pages/list-view/list-view.formats.spec.ts +0 -214
- package/src/lib/pages/list-view/list-view.ts +0 -882
- package/src/lib/pages/login/login.spec.ts +0 -109
- package/src/lib/pages/login/login.ts +0 -227
- package/src/lib/pages/resource-page/resource-page.ts +0 -234
- package/src/lib/shared/components/badge/badge.ts +0 -35
- package/src/lib/shared/components/button/button.ts +0 -65
- package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +0 -48
- package/src/lib/shared/components/copy-button/copy-button.ts +0 -56
- package/src/lib/shared/components/copy-share/copy-share.spec.ts +0 -122
- package/src/lib/shared/components/copy-share/copy-share.ts +0 -107
- package/src/lib/shared/components/drawer/drawer.spec.ts +0 -127
- package/src/lib/shared/components/drawer/drawer.ts +0 -172
- package/src/lib/shared/components/empty-state/empty-state.ts +0 -30
- package/src/lib/shared/components/modal/modal.spec.ts +0 -149
- package/src/lib/shared/components/modal/modal.ts +0 -145
- package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +0 -165
- package/src/lib/shared/components/post-create-modal/post-create-modal.ts +0 -159
- package/src/lib/shared/components/skeleton/skeleton.ts +0 -31
- package/src/lib/shared/components/toast/toast.ts +0 -58
- package/src/lib/shared/utils/col-span.ts +0 -25
- package/src/lib/shared/utils/condition-evaluator.ts +0 -53
- package/src/lib/shared/utils/depends-on.ts +0 -48
- package/src/lib/shared/utils/dialog-focus.ts +0 -28
- package/src/lib/shared/utils/field-path.ts +0 -49
- package/src/lib/shared/utils/gap-sorting.ts +0 -144
- package/src/lib/shared/utils/seed.spec.ts +0 -64
- package/src/lib/shared/utils/seed.ts +0 -149
- package/src/lib/shared/utils/slugify.ts +0 -13
- package/src/lib/shared/utils/validators.ts +0 -41
- package/src/lib/shell/layout/layout.ts +0 -63
- package/src/lib/shell/shell.routes.spec.ts +0 -59
- package/src/lib/shell/shell.routes.ts +0 -122
- package/src/lib/shell/sidebar/sidebar.ts +0 -139
- package/src/lib/shell/theme-toggle/theme-toggle.ts +0 -74
- package/src/lib/views/calendar-view/calendar-model.ts +0 -426
- package/src/lib/views/calendar-view/calendar-view.spec.ts +0 -557
- package/src/lib/views/calendar-view/calendar-view.ts +0 -568
- package/src/lib/views/composer/composer-host.spec.ts +0 -301
- package/src/lib/views/composer/composer-host.ts +0 -248
- package/src/lib/views/composer/composer-imports.spec.ts +0 -54
- package/src/lib/views/composer/view-context.spec.ts +0 -117
- package/src/lib/views/composer/view-context.ts +0 -109
- package/src/lib/views/composer/view-slot.spec.ts +0 -130
- package/src/lib/views/composer/view-slot.ts +0 -178
- package/src/lib/views/descriptors.ts +0 -46
- package/src/lib/views/kanban-view/kanban-model.ts +0 -173
- package/src/lib/views/kanban-view/kanban-view.spec.ts +0 -540
- package/src/lib/views/kanban-view/kanban-view.ts +0 -327
- package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +0 -17
- package/src/lib/widgets/bar-chart/bar-chart.spec.ts +0 -66
- package/src/lib/widgets/bar-chart/bar-chart.ts +0 -76
- package/src/lib/widgets/chart-line/chart-line.descriptor.ts +0 -17
- package/src/lib/widgets/chart-line/chart-line.spec.ts +0 -113
- package/src/lib/widgets/chart-line/chart-line.ts +0 -219
- package/src/lib/widgets/descriptors.ts +0 -29
- package/src/lib/widgets/metric-card/metric-card.descriptor.ts +0 -41
- package/src/lib/widgets/metric-card/metric-card.spec.ts +0 -52
- package/src/lib/widgets/metric-card/metric-card.ts +0 -48
- package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +0 -13
- package/src/lib/widgets/quick-actions/quick-actions.spec.ts +0 -61
- package/src/lib/widgets/quick-actions/quick-actions.ts +0 -100
- package/src/lib/widgets/record-list/record-list.descriptor.ts +0 -16
- package/src/lib/widgets/record-list/record-list.spec.ts +0 -79
- package/src/lib/widgets/record-list/record-list.ts +0 -115
- package/src/lib/widgets/series.spec.ts +0 -42
- package/src/lib/widgets/series.ts +0 -56
- package/src/lib/widgets/status-progress/status-progress.descriptor.ts +0 -19
- package/src/lib/widgets/status-progress/status-progress.spec.ts +0 -63
- package/src/lib/widgets/status-progress/status-progress.ts +0 -104
- package/src/lib/widgets/widget-host/widget-host.spec.ts +0 -179
- package/src/lib/widgets/widget-host/widget-host.ts +0 -99
- package/src/public-api.ts +0 -104
- package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
- package/tsconfig.lib.json +0 -13
- package/tsconfig.lib.prod.json +0 -11
- package/tsconfig.spec.json +0 -10
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
-
import { GasAdminUi } from './gas-admin-ui';
|
|
3
|
-
|
|
4
|
-
describe('GasAdminUi', () => {
|
|
5
|
-
let component: GasAdminUi;
|
|
6
|
-
let fixture: ComponentFixture<GasAdminUi>;
|
|
7
|
-
|
|
8
|
-
beforeEach(async () => {
|
|
9
|
-
await TestBed.configureTestingModule({
|
|
10
|
-
imports: [GasAdminUi],
|
|
11
|
-
}).compileComponents();
|
|
12
|
-
|
|
13
|
-
fixture = TestBed.createComponent(GasAdminUi);
|
|
14
|
-
component = fixture.componentInstance;
|
|
15
|
-
await fixture.whenStable();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should create', () => {
|
|
19
|
-
expect(component).toBeTruthy();
|
|
20
|
-
});
|
|
21
|
-
});
|
package/src/lib/gas-admin-ui.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { LayoutDescriptor } from '../core/registry/render-registry';
|
|
2
|
-
|
|
3
|
-
export const layoutDescriptors: readonly LayoutDescriptor[] = [
|
|
4
|
-
{ kind: 'layout', type: 'grid', since: '9.2' },
|
|
5
|
-
{ kind: 'layout', type: 'tabs', since: '9.2' },
|
|
6
|
-
{ kind: 'layout', type: 'sections', since: '9.2' },
|
|
7
|
-
{ kind: 'layout', type: 'steps', since: '9.2' },
|
|
8
|
-
{ kind: 'layout', type: 'columns', since: '9.2' },
|
|
9
|
-
];
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { Component, computed, inject, input, resource } from '@angular/core';
|
|
2
|
-
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
|
|
3
|
-
import { catchError, of, switchMap } from 'rxjs';
|
|
4
|
-
|
|
5
|
-
import type { DataSource, ResourceSchema, WidgetSchema } from '../../core/models/schema.model';
|
|
6
|
-
import { ApiService } from '../../core/services/api.service';
|
|
7
|
-
import { DataSourceService, type SourceRow } from '../../core/services/data-source.service';
|
|
8
|
-
import { EmptyState } from '../../shared/components/empty-state/empty-state';
|
|
9
|
-
import { WidgetHost } from '../../widgets/widget-host/widget-host';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Panel de métricas — tercer `kind` del registry (refactormotor.md F4).
|
|
13
|
-
*
|
|
14
|
-
* Sólo lectura: no hay CRUD y los datos llegan de un endpoint declarativo
|
|
15
|
-
* (Etapa 2, S4). Los widgets se declaran en `widgets` del schema — no en
|
|
16
|
-
* `fields`, porque un KPI no es un campo (ver `ResourceSchema.widgets`).
|
|
17
|
-
*
|
|
18
|
-
* Dos formas de dato, la que declare cada widget (F8 · R6.5):
|
|
19
|
-
*
|
|
20
|
-
* - **payload**: el `key` del widget es su clave en la respuesta del
|
|
21
|
-
* endpoint; `source: { kind: 'payload' }` lee la respuesta entera.
|
|
22
|
-
* - **fuente declarada** (`source: { resource, view?, params? }`): el widget
|
|
23
|
-
* pide sus filas al `DataSourceService` y deja de depender de que un
|
|
24
|
-
* handler haya armado `data[key]`. Acá se piden TODAS juntas, así que un
|
|
25
|
-
* panel con seis fuentes iguales hace una vuelta, no seis (la caché del
|
|
26
|
-
* servicio es compartida con relations y selects).
|
|
27
|
-
*/
|
|
28
|
-
@Component({
|
|
29
|
-
selector: 'app-dashboard',
|
|
30
|
-
imports: [EmptyState, WidgetHost],
|
|
31
|
-
template: `
|
|
32
|
-
<header class="mb-6">
|
|
33
|
-
<h1 class="font-display text-2xl font-semibold">{{ schema().labelPlural }}</h1>
|
|
34
|
-
<p class="text-sm text-neutral">Dashboard · {{ widgets().length }} widgets</p>
|
|
35
|
-
</header>
|
|
36
|
-
|
|
37
|
-
@if (falloFuentes()) {
|
|
38
|
-
<!-- Degradación visible (F9): sin este aviso el fallo de una fuente
|
|
39
|
-
se confundiría con «el panel no tiene datos». -->
|
|
40
|
-
<p class="mb-4 text-sm text-danger" role="alert">
|
|
41
|
-
No se pudieron cargar los datos de algunos widgets.
|
|
42
|
-
</p>
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@if (widgets().length === 0) {
|
|
46
|
-
<app-empty-state
|
|
47
|
-
title="Sin widgets declarados"
|
|
48
|
-
message="Los widgets se declaran en la propiedad widgets del schema del dashboard."
|
|
49
|
-
/>
|
|
50
|
-
} @else {
|
|
51
|
-
<div class="grid grid-cols-12 gap-4">
|
|
52
|
-
@for (widget of widgets(); track widget.key) {
|
|
53
|
-
<app-widget-host [widget]="widget" [data]="datum(widget)" [loading]="cargando()" />
|
|
54
|
-
}
|
|
55
|
-
</div>
|
|
56
|
-
}
|
|
57
|
-
`,
|
|
58
|
-
})
|
|
59
|
-
export class Dashboard {
|
|
60
|
-
private readonly api = inject(ApiService, { optional: true });
|
|
61
|
-
private readonly ds = inject(DataSourceService);
|
|
62
|
-
|
|
63
|
-
/** Descriptor del dashboard (lo resuelve `ResourcePage` contra el registry). */
|
|
64
|
-
readonly schema = input.required<ResourceSchema>();
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Respuesta del endpoint de métricas indexada por `key` de widget.
|
|
68
|
-
* Si se pasa explícitamente (como en tests con fixtures), se usa directamente;
|
|
69
|
-
* de lo contrario se obtienen los datos de forma reactiva desde el endpoint `get`.
|
|
70
|
-
*/
|
|
71
|
-
readonly data = input<Record<string, unknown> | null>(null);
|
|
72
|
-
|
|
73
|
-
private readonly fetchedData = toSignal(
|
|
74
|
-
toObservable(this.schema).pipe(
|
|
75
|
-
switchMap((schema) => {
|
|
76
|
-
const getEndpoint = schema.endpoint?.get;
|
|
77
|
-
// `of({})` = SIN get contratado: ya hay respuesta (vacía). El
|
|
78
|
-
// `null` inicial del signal en cambio marca «todavía viaja».
|
|
79
|
-
if (!getEndpoint || !this.api) return of<Record<string, unknown>>({});
|
|
80
|
-
return this.api
|
|
81
|
-
.request<Record<string, unknown>>('GET', getEndpoint)
|
|
82
|
-
.pipe(catchError(() => of<Record<string, unknown>>({})));
|
|
83
|
-
}),
|
|
84
|
-
),
|
|
85
|
-
{ initialValue: null },
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
protected readonly effectiveData = computed<Record<string, unknown>>(() => {
|
|
89
|
-
const override = this.data();
|
|
90
|
-
if (override !== null && override !== undefined) return override;
|
|
91
|
-
return this.fetchedData() ?? {};
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
protected readonly widgets = computed(() => this.schema().widgets ?? []);
|
|
95
|
-
|
|
96
|
-
// ── Fuentes declaradas (F8 · R6.5) ──────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Claves de los widgets con fuente declarada, en una cadena: es el
|
|
100
|
-
* `params` del `resource` y sólo cambia cuando cambia el panel. `''`
|
|
101
|
-
* (ninguna fuente) ⇒ `undefined` ⇒ el resource queda idle y no pide nada.
|
|
102
|
-
*/
|
|
103
|
-
private readonly clavesFuente = computed(() =>
|
|
104
|
-
this.widgets()
|
|
105
|
-
.map((widget) => (esFuente(widget.source) ? widget.key : ''))
|
|
106
|
-
.filter((key) => key !== '')
|
|
107
|
-
.join('|'),
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Filas de todos los widgets con `source`, pedidas de una sola vez.
|
|
112
|
-
*
|
|
113
|
-
* Cada fila queda bajo `widget.key`, que es el mismo contrato de lectura
|
|
114
|
-
* que tiene el payload: `datum()` devuelve filas cuando hay fuente y la
|
|
115
|
-
* clave de siempre cuando no, y el descriptor del widget traduce la forma
|
|
116
|
-
* que necesita.
|
|
117
|
-
*/
|
|
118
|
-
private readonly fuentes = resource({
|
|
119
|
-
params: () => (this.clavesFuente() === '' ? undefined : this.clavesFuente()),
|
|
120
|
-
loader: async () => {
|
|
121
|
-
const filas: Record<string, SourceRow[]> = {};
|
|
122
|
-
for (const widget of this.widgets()) {
|
|
123
|
-
if (!esFuente(widget.source)) continue;
|
|
124
|
-
filas[widget.key] = await this.ds.rows(widget.source);
|
|
125
|
-
}
|
|
126
|
-
return filas;
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
/** ¿Alguna fuente del panel falló? (`status()` no tira; `value()` sí.) */
|
|
131
|
-
protected readonly falloFuentes = computed(() => this.fuentes.status() === 'error');
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Estado de carga del panel — mientras dure, cada tarjeta reserva su
|
|
135
|
-
* espacio con skeleton (`cargar ≠ vacío`, doc/ux-ui-mobile.md §estados).
|
|
136
|
-
* Cubre LOS dos caminos de dato: el payload (`null` inicial = sin
|
|
137
|
-
* respuesta todavía) y las fuentes declaradas (`resource` en loading;
|
|
138
|
-
* con params vacíos queda idle, que NO es carga).
|
|
139
|
-
*/
|
|
140
|
-
protected readonly cargando = computed(() => {
|
|
141
|
-
const payloadViaja = this.data() === null && this.fetchedData() === null;
|
|
142
|
-
const fuentesViajan = this.fuentes.status() === 'loading';
|
|
143
|
-
return payloadViaja || fuentesViajan;
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
/** `null` explícito cuando la clave no vino: el widget muestra su vacío. */
|
|
147
|
-
protected datum(widget: WidgetSchema): unknown {
|
|
148
|
-
// Fuente declarada: el dato son SUS filas, no una clave del payload.
|
|
149
|
-
if (esFuente(widget.source)) {
|
|
150
|
-
// `value()` del resource TIRA en estado error (contract de Angular):
|
|
151
|
-
// se mira el estado antes de leerlo. En carga devuelve `null` igual
|
|
152
|
-
// que el camino de payload, que también arranca vacío.
|
|
153
|
-
return this.fuentes.status() === 'error'
|
|
154
|
-
? null
|
|
155
|
-
: (this.fuentes.value()?.[widget.key] ?? null);
|
|
156
|
-
}
|
|
157
|
-
const allData = this.effectiveData();
|
|
158
|
-
// `source` lo declara el schema: el orquestador no sabe qué tipo es
|
|
159
|
-
// ni qué claves compone cada widget.
|
|
160
|
-
return widget.source?.kind === 'payload' ? allData : (allData[widget.key] ?? null);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** ¿Este widget declara una fuente (`{ resource, … }`) y no el payload? */
|
|
165
|
-
function esFuente(source: WidgetSchema['source']): source is DataSource {
|
|
166
|
-
return source !== undefined && source !== null && 'resource' in source;
|
|
167
|
-
}
|
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
-
import { provideRouter, Router } from '@angular/router';
|
|
3
|
-
import { NEVER, of, throwError } from 'rxjs';
|
|
4
|
-
import { describe, expect, it, beforeEach, vi } from 'vitest';
|
|
5
|
-
|
|
6
|
-
import type { ResourceSchema } from '../../core/models/schema.model';
|
|
7
|
-
import { ActionService } from '../../actions/action-service';
|
|
8
|
-
import { ApiService } from '../../core/services/api.service';
|
|
9
|
-
import { API_URL } from '../../core/tokens';
|
|
10
|
-
import { DetailView } from './detail-view';
|
|
11
|
-
|
|
12
|
-
describe('DetailView', () => {
|
|
13
|
-
let fixture: ComponentFixture<DetailView>;
|
|
14
|
-
|
|
15
|
-
const mockSchema: ResourceSchema = {
|
|
16
|
-
id: 'orders',
|
|
17
|
-
label: 'Pedido',
|
|
18
|
-
labelPlural: 'Pedidos',
|
|
19
|
-
kind: 'collection',
|
|
20
|
-
endpoint: { list: '/admin/orders', get: '/admin/orders/{key}' },
|
|
21
|
-
keyField: 'ref',
|
|
22
|
-
titleField: 'customer_name',
|
|
23
|
-
listColumns: [],
|
|
24
|
-
fields: [
|
|
25
|
-
{ key: 'ref', label: 'Referencia', type: 'text' },
|
|
26
|
-
{ key: 'customer_name', label: 'Cliente', type: 'text' },
|
|
27
|
-
{ key: 'pickup_date', label: 'Fecha Retiro', type: 'date' },
|
|
28
|
-
{
|
|
29
|
-
key: 'status',
|
|
30
|
-
label: 'Estado',
|
|
31
|
-
type: 'select',
|
|
32
|
-
options: [
|
|
33
|
-
{ value: 'PENDIENTE', label: 'Pendiente' },
|
|
34
|
-
{ value: 'ENTREGADO', label: 'Entregado' },
|
|
35
|
-
],
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
detail: {
|
|
39
|
-
enabled: true,
|
|
40
|
-
headerFields: ['ref', 'status'],
|
|
41
|
-
allowEdit: true,
|
|
42
|
-
allowDelete: false,
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const mockRecord = {
|
|
47
|
-
ref: 'ORD-42',
|
|
48
|
-
customer_name: 'Ana García',
|
|
49
|
-
pickup_date: '2026-10-10',
|
|
50
|
-
status: 'PENDIENTE',
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const getSpy = vi.fn();
|
|
54
|
-
|
|
55
|
-
beforeEach(async () => {
|
|
56
|
-
getSpy.mockReset();
|
|
57
|
-
getSpy.mockImplementation(() => of(null));
|
|
58
|
-
await TestBed.configureTestingModule({
|
|
59
|
-
imports: [DetailView],
|
|
60
|
-
providers: [
|
|
61
|
-
{
|
|
62
|
-
provide: ApiService,
|
|
63
|
-
useValue: {
|
|
64
|
-
get: getSpy,
|
|
65
|
-
request: () => of(null),
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
// `AuthService` pide `API_URL` (convención de specs, R7.5)
|
|
69
|
-
{ provide: API_URL, useValue: '/api' },
|
|
70
|
-
// R8.8: `DetailView` inyecta `Router` (trigger → confirmación +
|
|
71
|
-
// ruta) — convención de list-view.quick-edit.spec.
|
|
72
|
-
provideRouter([]),
|
|
73
|
-
],
|
|
74
|
-
}).compileComponents();
|
|
75
|
-
fixture = TestBed.createComponent(DetailView);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Monta la vista y espera los display del registro.
|
|
80
|
-
*
|
|
81
|
-
* `fixture.whenStable()` no basta: el `load()` de cada descriptor es un
|
|
82
|
-
* `import()` ajeno al rastreo de Angular. Se espera acotadamente mientras
|
|
83
|
-
* quede algún `<app-skeleton>`; si un componente nunca monta, la espera se
|
|
84
|
-
* agota y falla la aserción del test (acotación, no espera infinita).
|
|
85
|
-
*/
|
|
86
|
-
async function montar(fixture: ComponentFixture<DetailView>): Promise<void> {
|
|
87
|
-
fixture.detectChanges();
|
|
88
|
-
await fixture.whenStable();
|
|
89
|
-
for (
|
|
90
|
-
let intento = 0;
|
|
91
|
-
intento < 100 && fixture.nativeElement.querySelector('app-skeleton');
|
|
92
|
-
intento++
|
|
93
|
-
) {
|
|
94
|
-
fixture.detectChanges();
|
|
95
|
-
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
96
|
-
}
|
|
97
|
-
fixture.detectChanges();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
it('1. renderiza la cabecera con el título del registro y los badges de headerFields', async () => {
|
|
101
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
102
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
103
|
-
await montar(fixture);
|
|
104
|
-
|
|
105
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
106
|
-
expect(root.querySelector('h1')?.textContent?.trim()).toBe('Ana García');
|
|
107
|
-
// badge de ref y status en la cabecera
|
|
108
|
-
expect(root.textContent).toContain('ORD-42');
|
|
109
|
-
expect(root.textContent).toContain('Pendiente');
|
|
110
|
-
// Los headerFields salen como chips (R4.2): `ref` en neutral y
|
|
111
|
-
// `status` en la clase de estado que ya usaba la ficha.
|
|
112
|
-
const cabeceras = root.querySelectorAll('header app-badge');
|
|
113
|
-
expect(cabeceras.length, 'deben ser 2 los chips de la cabecera').toBe(2);
|
|
114
|
-
expect(cabeceras[0].className).toContain('bg-neutral');
|
|
115
|
-
expect(cabeceras[1].className).toContain('bg-accent/20');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('2. renderiza las secciones de campos con sus valores', async () => {
|
|
119
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
120
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
121
|
-
await montar(fixture);
|
|
122
|
-
|
|
123
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
124
|
-
expect(root.textContent).toContain('Ana García');
|
|
125
|
-
expect(root.textContent).toContain('2026');
|
|
126
|
-
// label del campo
|
|
127
|
-
expect(root.textContent).toContain('Referencia');
|
|
128
|
-
expect(root.textContent).toContain('Cliente');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('3. emite el evento edit al hacer clic en el botón Editar', () => {
|
|
132
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
133
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
134
|
-
fixture.detectChanges();
|
|
135
|
-
|
|
136
|
-
let emitted: Record<string, unknown> | null = null;
|
|
137
|
-
fixture.componentInstance.edit.subscribe((rec) => {
|
|
138
|
-
emitted = rec as Record<string, unknown>;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
142
|
-
const editBtn = Array.from(root.querySelectorAll<HTMLButtonElement>('button[app-button]')).find(
|
|
143
|
-
(b) => b.textContent?.trim().includes('Editar'),
|
|
144
|
-
);
|
|
145
|
-
expect(editBtn, 'debe existir el botón Editar').toBeDefined();
|
|
146
|
-
editBtn!.click();
|
|
147
|
-
fixture.detectChanges();
|
|
148
|
-
|
|
149
|
-
expect(emitted).toEqual(mockRecord);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('4. emite el evento back al hacer clic en el botón Volver', () => {
|
|
153
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
154
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
155
|
-
fixture.detectChanges();
|
|
156
|
-
|
|
157
|
-
let emitted = false;
|
|
158
|
-
fixture.componentInstance.back.subscribe(() => {
|
|
159
|
-
emitted = true;
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
163
|
-
const backBtn = Array.from(root.querySelectorAll<HTMLButtonElement>('button[app-button]')).find(
|
|
164
|
-
(b) => b.textContent?.trim().includes('Volver'),
|
|
165
|
-
);
|
|
166
|
-
expect(backBtn, 'debe existir el botón Volver').toBeDefined();
|
|
167
|
-
backBtn!.click();
|
|
168
|
-
fixture.detectChanges();
|
|
169
|
-
|
|
170
|
-
expect(emitted).toBe(true);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('5. renderiza secciones de historial (tipo list) cuando existen', async () => {
|
|
174
|
-
const listSchema: ResourceSchema = {
|
|
175
|
-
...mockSchema,
|
|
176
|
-
fields: [
|
|
177
|
-
...mockSchema.fields,
|
|
178
|
-
{
|
|
179
|
-
key: 'history',
|
|
180
|
-
label: 'Historial',
|
|
181
|
-
type: 'list',
|
|
182
|
-
itemFields: [
|
|
183
|
-
{ key: 'action', label: 'Acción', type: 'text' },
|
|
184
|
-
{ key: 'detail', label: 'Detalle', type: 'text' },
|
|
185
|
-
],
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
};
|
|
189
|
-
const recordWithHistory = {
|
|
190
|
-
...mockRecord,
|
|
191
|
-
history: [{ action: 'PEDIDO_CREADO', detail: 'Pedido registrado' }],
|
|
192
|
-
};
|
|
193
|
-
fixture.componentRef.setInput('schema', listSchema);
|
|
194
|
-
fixture.componentRef.setInput('record', recordWithHistory);
|
|
195
|
-
await montar(fixture);
|
|
196
|
-
|
|
197
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
198
|
-
expect(root.textContent).toContain('Pedido registrado');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('6. R8.8: renderiza el botón de un trigger y lo dispara vía actionService', async () => {
|
|
202
|
-
const triggerSchema: ResourceSchema = {
|
|
203
|
-
...mockSchema,
|
|
204
|
-
actions: [
|
|
205
|
-
{
|
|
206
|
-
id: 'regenerate_pin',
|
|
207
|
-
type: 'trigger',
|
|
208
|
-
name: 'regenerate-pin',
|
|
209
|
-
label: 'Regenerar PIN',
|
|
210
|
-
},
|
|
211
|
-
],
|
|
212
|
-
};
|
|
213
|
-
fixture.componentRef.setInput('schema', triggerSchema);
|
|
214
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
215
|
-
await montar(fixture);
|
|
216
|
-
|
|
217
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
218
|
-
const triggerBtn = Array.from(
|
|
219
|
-
root.querySelectorAll<HTMLButtonElement>('button[app-button]'),
|
|
220
|
-
).find((b) => b.textContent?.trim() === 'Regenerar PIN');
|
|
221
|
-
expect(triggerBtn, 'debe existir el botón Regenerar PIN').toBeDefined();
|
|
222
|
-
|
|
223
|
-
// El clic delega en actionService.run (la confirmación y la ruta son
|
|
224
|
-
// cosa del descriptor, no de la vista — R3.11).
|
|
225
|
-
const runSpy = vi
|
|
226
|
-
.spyOn(TestBed.inject(ActionService), 'run')
|
|
227
|
-
.mockResolvedValue({ ok: true, reload: true });
|
|
228
|
-
triggerBtn!.click();
|
|
229
|
-
fixture.detectChanges();
|
|
230
|
-
await fixture.whenStable();
|
|
231
|
-
|
|
232
|
-
expect(runSpy).toHaveBeenCalledTimes(1);
|
|
233
|
-
const [action, request] = runSpy.mock.calls[0];
|
|
234
|
-
expect(action).toMatchObject({ id: 'regenerate_pin', name: 'regenerate-pin' });
|
|
235
|
-
expect(request.resource).toBe('orders');
|
|
236
|
-
expect(request.keyField).toBe('ref');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('7. mientras viaja el get, reserva el espacio con skeleton (cargar ≠ vacío)', () => {
|
|
240
|
-
// Regresión del «renderizado completo pero vacío»: con el get lento
|
|
241
|
-
// (Apps Script ~1s) el detalle pintaba la fila parcial con los campos
|
|
242
|
-
// pesados en `—`. Ahora la región de secciones queda en busy con
|
|
243
|
-
// skeletons con la forma de las tarjetas.
|
|
244
|
-
getSpy.mockImplementation(() => NEVER);
|
|
245
|
-
|
|
246
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
247
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
248
|
-
fixture.detectChanges();
|
|
249
|
-
|
|
250
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
251
|
-
expect(root.querySelector('[aria-busy="true"] app-skeleton'), 'skeleton visible').toBeTruthy();
|
|
252
|
-
// Las etiquetas de las secciones NO se pintan hasta que llegue el registro.
|
|
253
|
-
expect(root.textContent).not.toContain('Fecha Retiro');
|
|
254
|
-
// La cabecera sí: son datos reales de la fila de la lista.
|
|
255
|
-
expect(root.textContent).toContain('ORD-42');
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('8. estado de error: ofrece reintento y al reintentar pinta el registro', async () => {
|
|
259
|
-
getSpy.mockImplementationOnce(() => throwError(() => new Error('500')));
|
|
260
|
-
getSpy.mockImplementationOnce(() => of({ ...mockRecord, pickup_date: '2026-10-12' }));
|
|
261
|
-
|
|
262
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
263
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
264
|
-
await montar(fixture);
|
|
265
|
-
|
|
266
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
267
|
-
expect(root.textContent).toContain('No se pudo cargar el registro');
|
|
268
|
-
|
|
269
|
-
const retryBtn = Array.from(
|
|
270
|
-
root.querySelectorAll<HTMLButtonElement>('button[app-button]'),
|
|
271
|
-
).find((b) => b.textContent?.trim().includes('Reintentar'));
|
|
272
|
-
expect(retryBtn, 'debe existir el botón Reintentar').toBeDefined();
|
|
273
|
-
retryBtn!.click();
|
|
274
|
-
await montar(fixture);
|
|
275
|
-
|
|
276
|
-
// El date se pinta formateado por render-host, no en crudo.
|
|
277
|
-
expect(root.textContent).toContain('12 oct. 2026');
|
|
278
|
-
expect(root.textContent).not.toContain('No se pudo cargar el registro');
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// ── R9.9 · D4 — target load error recovery ──
|
|
282
|
-
|
|
283
|
-
it('9. D4: el estado de error ofrece «Volver» junto a «Reintentar» y navega de vuelta', async () => {
|
|
284
|
-
getSpy.mockImplementationOnce(() => throwError(() => new Error('boom')));
|
|
285
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
286
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
287
|
-
await montar(fixture);
|
|
288
|
-
|
|
289
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
290
|
-
expect(root.textContent).toContain('No se pudo cargar el registro');
|
|
291
|
-
// El estado de error es un `app-empty-state` con ambas salidas DENTRO
|
|
292
|
-
// (el header también tiene «Volver», así que se busca dentro del slot).
|
|
293
|
-
const volver = Array.from(
|
|
294
|
-
root.querySelectorAll<HTMLButtonElement>('app-empty-state button[app-button]'),
|
|
295
|
-
).find((b) => b.textContent?.trim().includes('Volver'));
|
|
296
|
-
expect(volver, 'debe existir el botón Volver en el estado de error').toBeDefined();
|
|
297
|
-
|
|
298
|
-
const router = TestBed.inject(Router);
|
|
299
|
-
const navegar = vi.spyOn(router, 'navigate');
|
|
300
|
-
volver!.click();
|
|
301
|
-
await fixture.whenStable();
|
|
302
|
-
expect(navegar).toHaveBeenCalled();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it('10. D4: la cabecera oculta Editar/Eliminar mientras el registro está en error', async () => {
|
|
306
|
-
getSpy.mockImplementationOnce(() => throwError(() => new Error('boom')));
|
|
307
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
308
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
309
|
-
await montar(fixture);
|
|
310
|
-
|
|
311
|
-
const root = fixture.nativeElement as HTMLElement;
|
|
312
|
-
expect(root.textContent).toContain('No se pudo cargar el registro');
|
|
313
|
-
expect(root.textContent).not.toContain('Editar');
|
|
314
|
-
// Reintentar ⇒ éxito ⇒ la acción vuelve a existir
|
|
315
|
-
getSpy.mockImplementationOnce(() => of({ ...mockRecord }));
|
|
316
|
-
Array.from(root.querySelectorAll<HTMLButtonElement>('button[app-button]'))
|
|
317
|
-
.find((b) => b.textContent?.trim().includes('Reintentar'))!
|
|
318
|
-
.click();
|
|
319
|
-
await montar(fixture);
|
|
320
|
-
expect((fixture.nativeElement as HTMLElement).textContent).toContain('Editar');
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('11. D4: el error original queda retenido con identidad intacta (diagnóstico)', async () => {
|
|
324
|
-
const fallo = new Error('boom de red');
|
|
325
|
-
getSpy.mockImplementationOnce(() => throwError(() => fallo));
|
|
326
|
-
fixture.componentRef.setInput('schema', mockSchema);
|
|
327
|
-
fixture.componentRef.setInput('record', mockRecord);
|
|
328
|
-
await montar(fixture);
|
|
329
|
-
|
|
330
|
-
// Identity assert: el MISMO objeto, no una copia ni un string mapeado.
|
|
331
|
-
expect(fixture.componentInstance.errorDeCarga()).toBe(fallo);
|
|
332
|
-
});
|
|
333
|
-
});
|