@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.18
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
package/ng-package.json
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
actionType,
|
|
5
|
-
actionsFor,
|
|
6
|
-
getAction,
|
|
7
|
-
registerAction,
|
|
8
|
-
type ActionDescriptor,
|
|
9
|
-
} from './action-registry';
|
|
10
|
-
|
|
11
|
-
function descriptor(
|
|
12
|
-
type: string,
|
|
13
|
-
surfaces: ActionDescriptor['surfaces'] = ['row'],
|
|
14
|
-
): ActionDescriptor {
|
|
15
|
-
return { type, surfaces, run: async () => ({ ok: true }) };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('action-registry', () => {
|
|
19
|
-
it('registra un descriptor y lo devuelve por su tipo', () => {
|
|
20
|
-
registerAction(descriptor('compartir'));
|
|
21
|
-
expect(getAction('compartir')?.type).toBe('compartir');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('devuelve undefined para un tipo sin registrar', () => {
|
|
25
|
-
expect(getAction('sin-registrar')).toBeUndefined();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('al re-registrar un tipo reemplaza el descriptor anterior', () => {
|
|
29
|
-
registerAction(descriptor('navegar', ['detail']));
|
|
30
|
-
registerAction(descriptor('navegar', ['row', 'detail']));
|
|
31
|
-
expect(getAction('navegar')?.surfaces).toEqual(['row', 'detail']);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('lista sólo los descriptores cuya superficie coincide', () => {
|
|
35
|
-
registerAction(descriptor('cabecera', ['header']));
|
|
36
|
-
expect(actionsFor('header').map((d) => d.type)).toEqual(['cabecera']);
|
|
37
|
-
expect(actionsFor('bulk')).toEqual([]);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('actionType', () => {
|
|
42
|
-
it('usa el tipo declarado', () => {
|
|
43
|
-
expect(actionType({ id: 'x', label: 'X', type: 'trigger' })).toBe('trigger');
|
|
44
|
-
expect(actionType({ id: 'x', label: 'X', type: 'copy-share', urlTemplate: '/p/{ref}' })).toBe(
|
|
45
|
-
'copy-share',
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('una acción sin type es una navegación (NavigateAction.type es opcional)', () => {
|
|
50
|
-
expect(actionType({ id: 'x', label: 'X', urlTemplate: '/p/{ref}' })).toBe('navigate');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import type { Router } from '@angular/router';
|
|
2
|
-
|
|
3
|
-
import type { LucideIcon } from '@lucide/angular';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
actionDescriptors,
|
|
7
|
-
isShareAction,
|
|
8
|
-
isTriggerAction,
|
|
9
|
-
resolveShare,
|
|
10
|
-
type ResolvedShare,
|
|
11
|
-
} from './descriptors';
|
|
12
|
-
import type { ResourceAction } from '../core/models/schema.model';
|
|
13
|
-
import type { SessionUser } from '../core/services/auth.service';
|
|
14
|
-
import type { ApiService } from '../core/services/api.service';
|
|
15
|
-
import type { NotificationService } from '../core/services/notification.service';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Registro único de acciones (R3.9 · `refactormotor.md`).
|
|
19
|
-
*
|
|
20
|
-
* Es el gemelo del registro de render (`core/registry/render-registry.ts`):
|
|
21
|
-
* en lugar de «qué componente pinta un tipo de campo», responde «qué
|
|
22
|
-
* comportamiento ejecuta un tipo de acción» y permite **migrar el dispatch
|
|
23
|
-
* if/copiado-pegado de las vistas (R3.11) a datos + un solo `run`**.
|
|
24
|
-
*
|
|
25
|
-
* Como los descriptores son objetos planos de módulo (no los inyecta Angular),
|
|
26
|
-
* todo lo que necesiten llegar por el `ActionContext`: los puertos (`api`,
|
|
27
|
-
* `router`, `toast`) y los datos (`record`, `resource`, `vars`).
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/** Superficies donde una acción puede aparecer. */
|
|
31
|
-
export type ActionSurface = 'row' | 'detail' | 'header' | 'bulk' | 'post-create';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Lo que aporta el llamador al ejecutar una acción: el registro sobre el que
|
|
35
|
-
* corre y los puertos que el descriptor usará para actuar.
|
|
36
|
-
*
|
|
37
|
-
* `record` es `null` en las superficies sin fila (`header`, `bulk`), para que
|
|
38
|
-
* un descriptor pueda distinguir «sin registro» de «registro vacío».
|
|
39
|
-
*/
|
|
40
|
-
export interface ActionRequest {
|
|
41
|
-
record: Record<string, unknown> | null;
|
|
42
|
-
/** Id del recurso (schema) dueño de la acción. */
|
|
43
|
-
resource: string;
|
|
44
|
-
api: ApiService;
|
|
45
|
-
router: Router;
|
|
46
|
-
toast: NotificationService;
|
|
47
|
-
user: SessionUser | null;
|
|
48
|
-
/**
|
|
49
|
-
* `keyField` del schema. **R3.12 (desviación nº 3 del contrato):** con
|
|
50
|
-
* `record` forma la clave que necesita la ruta lógica de `trigger`
|
|
51
|
-
* (`/admin/<recurso>/<key>/actions/<name>`). Lo aporta la vista, que es
|
|
52
|
-
* quien tiene el schema.
|
|
53
|
-
*/
|
|
54
|
-
keyField: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Contexto que recibe el descriptor: la petición del llamador más el contexto
|
|
59
|
-
* de interpolación ya resuelto. `ActionService.run` lo arma, así que ninguna
|
|
60
|
-
* vista repite `buildInterpolationContext(record)`.
|
|
61
|
-
*/
|
|
62
|
-
export interface ActionContext extends ActionRequest {
|
|
63
|
-
/** `{...configGlobal, ...record, public_base_url}` — listo para las plantillas. */
|
|
64
|
-
vars: Record<string, unknown>;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Resultado que la vista puede leer para saber si debe recargar. */
|
|
68
|
-
export interface ActionResult {
|
|
69
|
-
/** `false` cuando la acción no llegó a ejecutarse; el error ya se notificó. */
|
|
70
|
-
ok: boolean;
|
|
71
|
-
/** `true` cuando tocó datos y la vista debe recargar su listado/detalle. */
|
|
72
|
-
reload?: boolean;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface ActionDescriptor {
|
|
76
|
-
/** Clave del dispatch: el `type` del schema (`'navigate'` no lo declara). */
|
|
77
|
-
type: string;
|
|
78
|
-
/** Superficies donde esta acción puede aparecer. */
|
|
79
|
-
surfaces: ActionSurface[];
|
|
80
|
-
run: (ctx: ActionContext, action: ResourceAction) => Promise<ActionResult>;
|
|
81
|
-
/** `true` si el descriptor exige confirmación antes de ejecutar. */
|
|
82
|
-
confirm?: boolean;
|
|
83
|
-
/**
|
|
84
|
-
* Icono lucide que representa la acción donde el espacio es reducido
|
|
85
|
-
* (la fila del listado). Sin él, la vista muestra `action.label`.
|
|
86
|
-
*/
|
|
87
|
-
icon?: LucideIcon;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export { isShareAction, isTriggerAction, resolveShare, type ResolvedShare };
|
|
91
|
-
|
|
92
|
-
const ACCIONES = new Map<string, ActionDescriptor>();
|
|
93
|
-
|
|
94
|
-
/** Registra (o reemplaza) un descriptor de acción. */
|
|
95
|
-
export function registerAction(descriptor: ActionDescriptor): void {
|
|
96
|
-
ACCIONES.set(descriptor.type, descriptor);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function getAction(type: string): ActionDescriptor | undefined {
|
|
100
|
-
return ACCIONES.get(type);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Descriptores disponibles en una superficie. */
|
|
104
|
-
export function actionsFor(surface: ActionSurface): ActionDescriptor[] {
|
|
105
|
-
return [...ACCIONES.values()].filter((descriptor) => descriptor.surfaces.includes(surface));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Clave de dispatch de una acción. `NavigateAction.type` es **opcional**
|
|
110
|
-
* (schema.model.ts), así que una acción sin `type` es una navegación.
|
|
111
|
-
*/
|
|
112
|
-
export function actionType(action: ResourceAction): string {
|
|
113
|
-
return action.type ?? 'navigate';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Tipos registrados. Sólo para comprobaciones y tests. */
|
|
117
|
-
export function actionTypes(): string[] {
|
|
118
|
-
return [...ACCIONES.keys()];
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Catálogo a scope de módulo: se registra al importar, sin esperar a DI,
|
|
122
|
-
// igual que el registro de render (mismo motivo: `buildFormSchema()` es una
|
|
123
|
-
// función pura que consulta sin inyectar nada).
|
|
124
|
-
for (const descriptor of actionDescriptors) {
|
|
125
|
-
registerAction(descriptor);
|
|
126
|
-
}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { ActionService } from './action-service';
|
|
5
|
-
import { registerAction, type ActionContext, type ActionDescriptor } from './action-registry';
|
|
6
|
-
import { actionDescriptors } from './descriptors';
|
|
7
|
-
import type { ResourceAction } from '../core/models/schema.model';
|
|
8
|
-
import type { ApiService } from '../core/services/api.service';
|
|
9
|
-
import { ConfigService } from '../core/services/config.service';
|
|
10
|
-
import type { NotificationService } from '../core/services/notification.service';
|
|
11
|
-
import type { Router } from '@angular/router';
|
|
12
|
-
|
|
13
|
-
/** Notificador falso: sólo el contrato que `ActionService` usa. */
|
|
14
|
-
function fakeToast(): NotificationService & { confirm: ReturnType<typeof vi.fn> } {
|
|
15
|
-
return {
|
|
16
|
-
confirm: vi.fn().mockResolvedValue(true),
|
|
17
|
-
error: vi.fn(),
|
|
18
|
-
success: vi.fn(),
|
|
19
|
-
info: vi.fn(),
|
|
20
|
-
dismiss: vi.fn(),
|
|
21
|
-
} as unknown as NotificationService & { confirm: ReturnType<typeof vi.fn> };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function fakeRequest(toast: NotificationService) {
|
|
25
|
-
return {
|
|
26
|
-
record: { slug: 'tecla', ref: 'p1' },
|
|
27
|
-
resource: 'productos',
|
|
28
|
-
api: {} as ApiService,
|
|
29
|
-
router: { navigate: async () => true } as unknown as Router,
|
|
30
|
-
toast,
|
|
31
|
-
user: null,
|
|
32
|
-
keyField: 'ref',
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const COMPARTIR: ResourceAction = {
|
|
37
|
-
id: 'compartir',
|
|
38
|
-
label: 'Compartir',
|
|
39
|
-
type: 'copy-share',
|
|
40
|
-
urlTemplate: 'https://demo/p/{ref}',
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
describe('ActionService', () => {
|
|
44
|
-
let service: ActionService;
|
|
45
|
-
let toast: ReturnType<typeof fakeToast>;
|
|
46
|
-
const ensureLoaded = vi.fn<() => Promise<void>>().mockResolvedValue(undefined);
|
|
47
|
-
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
toast = fakeToast();
|
|
50
|
-
ensureLoaded.mockClear();
|
|
51
|
-
ensureLoaded.mockResolvedValue(undefined);
|
|
52
|
-
TestBed.configureTestingModule({
|
|
53
|
-
providers: [
|
|
54
|
-
// ConfigService real pediría HttpClient/API_URL; sólo aporta `vars`
|
|
55
|
-
// y el reintento de config que `copy-share` dispara.
|
|
56
|
-
{
|
|
57
|
-
provide: ConfigService,
|
|
58
|
-
useValue: {
|
|
59
|
-
ensureLoaded,
|
|
60
|
-
buildInterpolationContext: (record: Record<string, unknown>) => ({
|
|
61
|
-
...record,
|
|
62
|
-
public_base_url: 'https://demo',
|
|
63
|
-
}),
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
});
|
|
68
|
-
service = TestBed.inject(ActionService);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// El `Map` del registro es estado de módulo **compartido entre ficheros**
|
|
72
|
-
// cuando vitest los ejecuta en el mismo worker: varios tests de éste
|
|
73
|
-
// sobrescriben `copy-share` / `navigate` / `trigger` con dobles.
|
|
74
|
-
// Sin restaurar aquí, `contract.spec` y `descriptors.spec` leen esos dobles
|
|
75
|
-
// y la suite se pone flaka **según el orden de ficheros** (falló 4 tests de
|
|
76
|
-
// `descriptors.spec` en una corrida y 0 en la siguiente, sin tocar código).
|
|
77
|
-
// Quien ensucia es quien limpia: el estado por defecto es el catálogo real.
|
|
78
|
-
afterEach(() => {
|
|
79
|
-
for (const descriptor of actionDescriptors) registerAction(descriptor);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('ejecuta el descriptor y le entrega la petición + vars de interpolación', async () => {
|
|
83
|
-
const vistos: ActionContext[] = [];
|
|
84
|
-
registerAction({
|
|
85
|
-
type: 'copy-share',
|
|
86
|
-
surfaces: ['row', 'post-create'],
|
|
87
|
-
run: async (ctx) => {
|
|
88
|
-
vistos.push(ctx);
|
|
89
|
-
return { ok: true, reload: true };
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const resultado = await service.run(COMPARTIR, fakeRequest(toast));
|
|
94
|
-
|
|
95
|
-
expect(resultado).toEqual({ ok: true, reload: true });
|
|
96
|
-
expect(vistos).toHaveLength(1);
|
|
97
|
-
expect(vistos[0].record).toEqual({ slug: 'tecla', ref: 'p1' });
|
|
98
|
-
expect(vistos[0].resource).toBe('productos');
|
|
99
|
-
expect(vistos[0].vars).toEqual({ slug: 'tecla', ref: 'p1', public_base_url: 'https://demo' });
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('copy-share reintenta la config global ANTES de resolver vars', async () => {
|
|
103
|
-
// Regresión del «mensaje = sólo la URL»: si el load del bootstrap falló,
|
|
104
|
-
// el descriptor debe ver la config ya recargada, no el snapshot vacío.
|
|
105
|
-
let ensureHecho = false;
|
|
106
|
-
ensureLoaded.mockImplementation(async () => {
|
|
107
|
-
ensureHecho = true;
|
|
108
|
-
});
|
|
109
|
-
const varsAlEjecutar: Record<string, unknown>[] = [];
|
|
110
|
-
registerAction({
|
|
111
|
-
type: 'copy-share',
|
|
112
|
-
surfaces: ['row'],
|
|
113
|
-
run: async (ctx) => {
|
|
114
|
-
expect(ensureHecho).toBe(true);
|
|
115
|
-
varsAlEjecutar.push(ctx.vars);
|
|
116
|
-
return { ok: true };
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
await service.run(COMPARTIR, fakeRequest(toast));
|
|
121
|
-
|
|
122
|
-
expect(ensureLoaded).toHaveBeenCalledOnce();
|
|
123
|
-
expect(varsAlEjecutar[0]).toEqual({
|
|
124
|
-
slug: 'tecla',
|
|
125
|
-
ref: 'p1',
|
|
126
|
-
public_base_url: 'https://demo',
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('acciones que no son copy-share no tocan la config', async () => {
|
|
131
|
-
const run = vi.fn<NonNullable<ActionDescriptor['run']>>().mockResolvedValue({ ok: true });
|
|
132
|
-
registerAction({ type: 'navigate', surfaces: ['row'], run });
|
|
133
|
-
|
|
134
|
-
await service.run({ id: 'ver', label: 'Ver', urlTemplate: '/p/{ref}' }, fakeRequest(toast));
|
|
135
|
-
|
|
136
|
-
expect(ensureLoaded).not.toHaveBeenCalled();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('una acción sin type resuelve el descriptor navigate', async () => {
|
|
140
|
-
const run = vi.fn<NonNullable<ActionDescriptor['run']>>();
|
|
141
|
-
registerAction({ type: 'navigate', surfaces: ['row', 'detail'], run });
|
|
142
|
-
|
|
143
|
-
await service.run({ id: 'ver', label: 'Ver', urlTemplate: '/p/{ref}' }, fakeRequest(toast));
|
|
144
|
-
|
|
145
|
-
expect(run).toHaveBeenCalledOnce();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('sin descriptor registrado rompe en lugar de ignorarse', async () => {
|
|
149
|
-
// `ResourceAction` es una unión cerrada y el registro es estado de
|
|
150
|
-
// módulo compartido entre tests: se fuerza un type que nadie registra
|
|
151
|
-
// (el cast a `unknown` sólo salva al compilador, no cambia el código).
|
|
152
|
-
const desconocida = { id: 'x', label: 'X', type: 'nadie' } as unknown as ResourceAction;
|
|
153
|
-
await expect(service.run(desconocida, fakeRequest(toast))).rejects.toThrow(
|
|
154
|
-
'no tiene descriptor registrado',
|
|
155
|
-
);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('con confirmación rechazada no ejecuta y devuelve ok false', async () => {
|
|
159
|
-
toast.confirm.mockResolvedValue(false);
|
|
160
|
-
const run = vi.fn<NonNullable<ActionDescriptor['run']>>();
|
|
161
|
-
registerAction({
|
|
162
|
-
type: 'trigger',
|
|
163
|
-
surfaces: ['row'],
|
|
164
|
-
confirm: true,
|
|
165
|
-
run,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const resultado = await service.run(
|
|
169
|
-
{
|
|
170
|
-
id: 'publicar',
|
|
171
|
-
label: 'Publicar',
|
|
172
|
-
type: 'trigger',
|
|
173
|
-
confirmMessage: 'Se publicará para todos.',
|
|
174
|
-
},
|
|
175
|
-
fakeRequest(toast),
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
expect(toast.confirm).toHaveBeenCalledWith({
|
|
179
|
-
title: 'Publicar',
|
|
180
|
-
message: 'Se publicará para todos.',
|
|
181
|
-
confirmLabel: 'Confirmar',
|
|
182
|
-
cancelLabel: 'Cancelar',
|
|
183
|
-
});
|
|
184
|
-
expect(run).not.toHaveBeenCalled();
|
|
185
|
-
expect(resultado).toEqual({ ok: false });
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('con confirmación aceptada ejecuta el descriptor', async () => {
|
|
189
|
-
const run = vi.fn<NonNullable<ActionDescriptor['run']>>().mockResolvedValue({ ok: true });
|
|
190
|
-
registerAction({ type: 'trigger', surfaces: ['row'], confirm: true, run });
|
|
191
|
-
|
|
192
|
-
const resultado = await service.run(
|
|
193
|
-
{ id: 'duplicar', label: 'Duplicar', type: 'trigger' },
|
|
194
|
-
fakeRequest(toast),
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
expect(run).toHaveBeenCalledOnce();
|
|
198
|
-
expect(resultado).toEqual({ ok: true });
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('un error del descriptor se notifica y no se devuelve como éxito', async () => {
|
|
202
|
-
registerAction({
|
|
203
|
-
type: 'copy-share',
|
|
204
|
-
surfaces: ['row'],
|
|
205
|
-
run: async () => {
|
|
206
|
-
throw new Error('El backend respondió 500');
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
const resultado = await service.run(COMPARTIR, fakeRequest(toast));
|
|
211
|
-
|
|
212
|
-
expect(toast.error).toHaveBeenCalledWith('El backend respondió 500');
|
|
213
|
-
expect(resultado).toEqual({ ok: false });
|
|
214
|
-
});
|
|
215
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { Service, inject } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
actionType,
|
|
5
|
-
getAction,
|
|
6
|
-
type ActionContext,
|
|
7
|
-
type ActionRequest,
|
|
8
|
-
type ActionResult,
|
|
9
|
-
} from './action-registry';
|
|
10
|
-
import type { ResourceAction } from '../core/models/schema.model';
|
|
11
|
-
import { ConfigService } from '../core/services/config.service';
|
|
12
|
-
import { ErrorMapperService } from '../core/services/error-mapper.service';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Ejecuta una acción declarada en el schema (R3.9 · `refactormotor.md`).
|
|
16
|
-
*
|
|
17
|
-
* Sustituye el dispatch por tipo que hoy vive en `list-view` y en las
|
|
18
|
-
* copias de `detail-view` y `post-create-modal` (R3.11). El camino siempre
|
|
19
|
-
* es el mismo:
|
|
20
|
-
*
|
|
21
|
-
* 1. resolver el descriptor (si no existe, **rompe** — nada de «disponible
|
|
22
|
-
* próximamente», que hoy oculta esquemas mal declarados);
|
|
23
|
-
* 2. pedir confirmación si el descriptor la exige;
|
|
24
|
-
* 3. montar el `ActionContext` (petición + `vars` de interpolación);
|
|
25
|
-
* 4. ejecutar y, si el descriptor lanza, notificar el error y devolver
|
|
26
|
-
* `{ ok: false }` para que la vista no trate el fallo como éxito.
|
|
27
|
-
*/
|
|
28
|
-
@Service()
|
|
29
|
-
export class ActionService {
|
|
30
|
-
private readonly config = inject(ConfigService);
|
|
31
|
-
private readonly errores = inject(ErrorMapperService);
|
|
32
|
-
|
|
33
|
-
async run(action: ResourceAction, request: ActionRequest): Promise<ActionResult> {
|
|
34
|
-
const type = actionType(action);
|
|
35
|
-
const descriptor = getAction(type);
|
|
36
|
-
if (!descriptor) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`[actions] «${action.label}» no tiene descriptor registrado (type "${type}").`,
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (descriptor.confirm) {
|
|
43
|
-
const aceptado = await request.toast.confirm({
|
|
44
|
-
title: action.label,
|
|
45
|
-
message: confirmMessage(action),
|
|
46
|
-
confirmLabel: 'Confirmar',
|
|
47
|
-
cancelLabel: 'Cancelar',
|
|
48
|
-
});
|
|
49
|
-
if (!aceptado) {
|
|
50
|
-
return { ok: false };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// `copy-share` (R8.7) resuelve su mensaje contra la config global
|
|
55
|
-
// (`share_message_template`). Si el load del bootstrap no llegó (arranque
|
|
56
|
-
// sin sesión o red lenta), lo pedimos ahora —con la sesión ya iniciada—
|
|
57
|
-
// ANTES de congelar `vars`: si no, el mensaje copiado degradaría a
|
|
58
|
-
// «sólo la URL» hasta el próximo F5.
|
|
59
|
-
if (descriptor.type === 'copy-share') {
|
|
60
|
-
await this.config.ensureLoaded();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const ctx: ActionContext = { ...request, vars: this.vars(request.record) };
|
|
64
|
-
try {
|
|
65
|
-
return await descriptor.run(ctx, action);
|
|
66
|
-
} catch (err) {
|
|
67
|
-
request.toast.error(this.errores.messageOf(err));
|
|
68
|
-
return { ok: false };
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Config global + registro. Sin registro (`header`, `bulk`) el contexto de
|
|
74
|
-
* interpolación queda vacío: el descriptor no tiene nada que interpolar.
|
|
75
|
-
*
|
|
76
|
-
* Público porque `detail-view` sólo **presenta** una acción (pinta
|
|
77
|
-
* `<app-copy-share>`) en vez de ejecutarla, y aun así necesita el mismo
|
|
78
|
-
* contexto: R3.11 acabó con la tercera copia de esta lógica.
|
|
79
|
-
*/
|
|
80
|
-
vars(record: Record<string, unknown> | null): Record<string, unknown> {
|
|
81
|
-
return record ? this.config.buildInterpolationContext(record) : {};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function confirmMessage(action: ResourceAction): string {
|
|
86
|
-
return 'confirmMessage' in action && action.confirmMessage ? action.confirmMessage : action.label;
|
|
87
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi, type MockInstance } from 'vitest';
|
|
2
|
-
import { of } from 'rxjs';
|
|
3
|
-
|
|
4
|
-
import { getAction, type ActionContext } from './action-registry';
|
|
5
|
-
import { resolveShare } from './descriptors';
|
|
6
|
-
import type { CopyShareAction, NavigateAction, TriggerAction } from '../core/models/schema.model';
|
|
7
|
-
import type { ApiService } from '../core/services/api.service';
|
|
8
|
-
import type { NotificationService } from '../core/services/notification.service';
|
|
9
|
-
import type { Router } from '@angular/router';
|
|
10
|
-
|
|
11
|
-
const VARS = { public_base_url: 'https://demo', ref: 'p1', customer_name: 'Ana' };
|
|
12
|
-
|
|
13
|
-
const COMPARTIR: CopyShareAction = {
|
|
14
|
-
id: 'share',
|
|
15
|
-
label: 'Compartir',
|
|
16
|
-
type: 'copy-share',
|
|
17
|
-
urlTemplate: '{public_base_url}/p/{ref}',
|
|
18
|
-
shareTextTemplate: 'Hola {customer_name}, tu pedido {ref}',
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function contexto(): ActionContext {
|
|
22
|
-
return {
|
|
23
|
-
record: { ref: 'p1' },
|
|
24
|
-
resource: 'orders',
|
|
25
|
-
api: { request: vi.fn().mockReturnValue(of({ ok: true })) } as unknown as ApiService,
|
|
26
|
-
router: { navigateByUrl: vi.fn().mockResolvedValue(true) } as unknown as Router,
|
|
27
|
-
toast: {
|
|
28
|
-
success: vi.fn(),
|
|
29
|
-
error: vi.fn(),
|
|
30
|
-
info: vi.fn(),
|
|
31
|
-
confirm: vi.fn(),
|
|
32
|
-
dismiss: vi.fn(),
|
|
33
|
-
} as unknown as NotificationService,
|
|
34
|
-
user: null,
|
|
35
|
-
keyField: 'ref',
|
|
36
|
-
vars: VARS,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** El `run` de un tipo registrado; lanza si no existe (estado incoherente). */
|
|
41
|
-
function ejecutar(type: string, action: CopyShareAction | NavigateAction | TriggerAction) {
|
|
42
|
-
const descriptor = getAction(type);
|
|
43
|
-
if (!descriptor) throw new Error(`sin descriptor «${type}»`);
|
|
44
|
-
return descriptor.run;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
describe('resolveShare', () => {
|
|
48
|
-
it('interpola enlace y mensaje con el contexto del registro', () => {
|
|
49
|
-
expect(resolveShare(COMPARTIR, VARS)).toEqual({
|
|
50
|
-
url: 'https://demo/p/p1',
|
|
51
|
-
shareText: 'Hola Ana, tu pedido p1',
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('sin shareTextTemplate cae a share_message_template (config global)', () => {
|
|
56
|
-
const action: CopyShareAction = { ...COMPARTIR, shareTextTemplate: undefined };
|
|
57
|
-
expect(resolveShare(action, { ...VARS, share_message_template: 'Hola {ref}' })).toEqual({
|
|
58
|
-
url: 'https://demo/p/p1',
|
|
59
|
-
shareText: 'Hola p1',
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('sin plantilla ninguna el mensaje queda vacío', () => {
|
|
64
|
-
const action: CopyShareAction = { ...COMPARTIR, shareTextTemplate: undefined };
|
|
65
|
-
expect(resolveShare(action, VARS).shareText).toBe('');
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('descriptores de acción', () => {
|
|
70
|
-
const escritor = vi.fn().mockResolvedValue(undefined);
|
|
71
|
-
let abrir: MockInstance;
|
|
72
|
-
|
|
73
|
-
beforeEach(() => {
|
|
74
|
-
escritor.mockClear();
|
|
75
|
-
Object.defineProperty(window.navigator, 'clipboard', {
|
|
76
|
-
value: { writeText: escritor },
|
|
77
|
-
configurable: true,
|
|
78
|
-
});
|
|
79
|
-
abrir = vi.spyOn(window, 'open').mockReturnValue(null);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
afterEach(() => {
|
|
83
|
-
vi.restoreAllMocks();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('copy-share copia el mensaje completo y lo anuncia', async () => {
|
|
87
|
-
const ctx = contexto();
|
|
88
|
-
const resultado = await ejecutar('copy-share', COMPARTIR)(ctx, COMPARTIR);
|
|
89
|
-
|
|
90
|
-
expect(escritor).toHaveBeenCalledWith('Hola Ana, tu pedido p1 https://demo/p/p1');
|
|
91
|
-
expect(ctx.toast.success).toHaveBeenCalledWith('Mensaje copiado al portapapeles.');
|
|
92
|
-
expect(resultado).toEqual({ ok: true });
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('navigate abre una URL absoluta en otra pestaña', async () => {
|
|
96
|
-
const action: NavigateAction = {
|
|
97
|
-
id: 'ver',
|
|
98
|
-
label: 'Ver público',
|
|
99
|
-
urlTemplate: '{public_base_url}/p/{ref}',
|
|
100
|
-
};
|
|
101
|
-
const ctx = contexto();
|
|
102
|
-
|
|
103
|
-
await ejecutar('navigate', action)(ctx, action);
|
|
104
|
-
|
|
105
|
-
expect(abrir).toHaveBeenCalledWith('https://demo/p/p1', '_blank', 'noopener');
|
|
106
|
-
expect(ctx.router.navigateByUrl).not.toHaveBeenCalled();
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('navigate entrega una ruta interna al router', async () => {
|
|
110
|
-
const action: NavigateAction = { id: 'editar', label: 'Editar', urlTemplate: '/orders/p1' };
|
|
111
|
-
const ctx = contexto();
|
|
112
|
-
|
|
113
|
-
await ejecutar('navigate', action)(ctx, action);
|
|
114
|
-
|
|
115
|
-
expect(ctx.router.navigateByUrl).toHaveBeenCalledWith('/orders/p1');
|
|
116
|
-
expect(abrir).not.toHaveBeenCalled();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('trigger arma la ruta lógica de la acción declarada y pide recarga', async () => {
|
|
120
|
-
const action: TriggerAction = {
|
|
121
|
-
id: 'markDelivered',
|
|
122
|
-
label: 'Marcar entregado',
|
|
123
|
-
type: 'trigger',
|
|
124
|
-
};
|
|
125
|
-
const ctx = contexto();
|
|
126
|
-
|
|
127
|
-
const resultado = await ejecutar('trigger', action)(ctx, action);
|
|
128
|
-
|
|
129
|
-
expect(ctx.api.request).toHaveBeenCalledWith('POST', '/admin/orders/p1/actions/markDelivered');
|
|
130
|
-
expect(resultado).toEqual({ ok: true, reload: true });
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('trigger usa `name` cuando en el back se llama distinto que el `id`', async () => {
|
|
134
|
-
const action: TriggerAction = {
|
|
135
|
-
id: 'reenviar',
|
|
136
|
-
label: 'Reenviar pin',
|
|
137
|
-
type: 'trigger',
|
|
138
|
-
name: 'resendPin',
|
|
139
|
-
};
|
|
140
|
-
const ctx = contexto();
|
|
141
|
-
|
|
142
|
-
await ejecutar('trigger', action)(ctx, action);
|
|
143
|
-
|
|
144
|
-
expect(ctx.api.request).toHaveBeenCalledWith('POST', '/admin/orders/p1/actions/resendPin');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('sin clave de registro no dispara nada y lo dice (fail-loud)', async () => {
|
|
148
|
-
const action: TriggerAction = { id: 'markDelivered', label: 'Marcar', type: 'trigger' };
|
|
149
|
-
const ctx = contexto();
|
|
150
|
-
ctx.record = null;
|
|
151
|
-
|
|
152
|
-
await expect(ejecutar('trigger', action)(ctx, action)).rejects.toThrow('necesita la clave ref');
|
|
153
|
-
expect(ctx.api.request).not.toHaveBeenCalled();
|
|
154
|
-
});
|
|
155
|
-
});
|