@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
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Component,
|
|
3
|
-
DestroyRef,
|
|
4
|
-
Injector,
|
|
5
|
-
OnInit,
|
|
6
|
-
computed,
|
|
7
|
-
inject,
|
|
8
|
-
input,
|
|
9
|
-
output,
|
|
10
|
-
signal,
|
|
11
|
-
} from '@angular/core';
|
|
12
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
13
|
-
import { form, submit } from '@angular/forms/signals';
|
|
14
|
-
import { firstValueFrom } from 'rxjs';
|
|
15
|
-
|
|
16
|
-
import type { FieldSchema, ResourceSchema } from '../../core/models/schema.model';
|
|
17
|
-
import { ApiService } from '../../core/services/api.service';
|
|
18
|
-
import { ErrorMapperService } from '../../core/services/error-mapper.service';
|
|
19
|
-
import { NotificationService } from '../../core/services/notification.service';
|
|
20
|
-
import { FieldHost } from '../../fields/field-host/field-host';
|
|
21
|
-
import { childTree, type RootTree } from '../../fields/field-node';
|
|
22
|
-
import { Button } from '../../shared/components/button/button';
|
|
23
|
-
import { Drawer, type DrawerSize } from '../../shared/components/drawer/drawer';
|
|
24
|
-
import { Skeleton } from '../../shared/components/skeleton/skeleton';
|
|
25
|
-
import { buildFormSchema } from '../form-view/form-schema';
|
|
26
|
-
import { buildPayload, seedModel } from '../form-view/form-model';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Formulario dentro de un drawer (plan 6.4/6.5, guía §5).
|
|
30
|
-
*
|
|
31
|
-
* Es deliberadamente más chico que `form-view`: sin pestañas, sin secciones,
|
|
32
|
-
* sin borrador y sin resumen de errores. Sirve para abrir 1–3 campos sin
|
|
33
|
-
* perder el contexto de la pantalla de la que vino el usuario, y para crear
|
|
34
|
-
* un registro desde el dropdown de una relación.
|
|
35
|
-
*
|
|
36
|
-
* Componente controlado: `open` entra por `input()`, y el padre cierra con
|
|
37
|
-
* `close`/`saved`. Nada navega por su cuenta.
|
|
38
|
-
*/
|
|
39
|
-
@Component({
|
|
40
|
-
selector: 'app-drawer-form',
|
|
41
|
-
imports: [Button, Drawer, FieldHost, Skeleton],
|
|
42
|
-
template: `
|
|
43
|
-
<app-drawer [open]="open()" [title]="drawerTitle()" [size]="size()" (close)="close.emit()">
|
|
44
|
-
@if (status() === 'loading') {
|
|
45
|
-
<app-skeleton [lines]="4" />
|
|
46
|
-
} @else if (status() === 'error') {
|
|
47
|
-
<p role="alert" class="rounded-lg bg-danger/10 px-3 py-2 text-sm text-danger">
|
|
48
|
-
{{ loadError() }}
|
|
49
|
-
</p>
|
|
50
|
-
} @else if (tree(); as formTree) {
|
|
51
|
-
@if (generalError()) {
|
|
52
|
-
<p
|
|
53
|
-
role="alert"
|
|
54
|
-
class="mb-4 rounded-lg bg-danger/10 px-3 py-2 text-sm text-danger"
|
|
55
|
-
data-drawer-error
|
|
56
|
-
>
|
|
57
|
-
{{ generalError() }}
|
|
58
|
-
</p>
|
|
59
|
-
}
|
|
60
|
-
@for (field of visibleFields(); track field.key) {
|
|
61
|
-
<div class="mb-4">
|
|
62
|
-
<app-field-host
|
|
63
|
-
[field]="field"
|
|
64
|
-
[tree]="formTree"
|
|
65
|
-
[exists]="mode() === 'edit'"
|
|
66
|
-
[serverErrors]="fieldErrors()"
|
|
67
|
-
[resource]="schema().id"
|
|
68
|
-
/>
|
|
69
|
-
</div>
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
<div drawer-actions class="flex justify-end gap-2">
|
|
74
|
-
<button app-button variant="outline" type="button" (click)="close.emit()">Cancelar</button>
|
|
75
|
-
<button app-button type="button" [loading]="saving()" (click)="save()">Guardar</button>
|
|
76
|
-
</div>
|
|
77
|
-
</app-drawer>
|
|
78
|
-
`,
|
|
79
|
-
})
|
|
80
|
-
export class DrawerForm implements OnInit {
|
|
81
|
-
readonly open = input(false);
|
|
82
|
-
readonly schema = input.required<ResourceSchema>();
|
|
83
|
-
/** Subconjunto de campos a mostrar. Por defecto, todos los del schema. */
|
|
84
|
-
readonly fields = input<readonly FieldSchema[] | undefined>(undefined);
|
|
85
|
-
readonly mode = input<'create' | 'edit'>('create');
|
|
86
|
-
readonly recordKey = input<string | null>(null);
|
|
87
|
-
readonly title = input<string | null>(null);
|
|
88
|
-
readonly size = input<DrawerSize>('md');
|
|
89
|
-
|
|
90
|
-
/** Registro creado o actualizado, listo para que el padre refresque. */
|
|
91
|
-
readonly saved = output<Record<string, unknown>>();
|
|
92
|
-
readonly close = output<void>();
|
|
93
|
-
|
|
94
|
-
private readonly api = inject(ApiService);
|
|
95
|
-
private readonly notifications = inject(NotificationService);
|
|
96
|
-
private readonly errorMapper = inject(ErrorMapperService);
|
|
97
|
-
private readonly injector = inject(Injector);
|
|
98
|
-
private readonly destroyRef = inject(DestroyRef);
|
|
99
|
-
|
|
100
|
-
private readonly tree = signal<RootTree | null>(null);
|
|
101
|
-
private readonly status = signal<'idle' | 'loading' | 'ready' | 'error'>('idle');
|
|
102
|
-
private readonly saving = signal(false);
|
|
103
|
-
private readonly generalError = signal('');
|
|
104
|
-
private readonly fieldErrors = signal<Record<string, string>>({});
|
|
105
|
-
private readonly loadError = signal('');
|
|
106
|
-
|
|
107
|
-
readonly visibleFields = computed<readonly FieldSchema[]>(
|
|
108
|
-
() => this.fields() ?? this.schema().fields,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
readonly drawerTitle = computed(() => {
|
|
112
|
-
if (this.title() !== null) {
|
|
113
|
-
return this.title() as string;
|
|
114
|
-
}
|
|
115
|
-
const label = this.schema().label;
|
|
116
|
-
return this.mode() === 'create' ? `Crear ${label}` : `Editar ${label}`;
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
ngOnInit(): void {
|
|
120
|
-
// Se construye al montar, NO en un `effect`: `form()` crea un effect
|
|
121
|
-
// interno y no puede correr dentro de otro (NG0602). Los padres montan
|
|
122
|
-
// este componente bajo un `@if` y fijan los inputs, así que no hace
|
|
123
|
-
// falta reaccionar a cambios posteriores.
|
|
124
|
-
this.build();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private build(): void {
|
|
128
|
-
const schema = this.schema();
|
|
129
|
-
const recordKey = this.recordKey();
|
|
130
|
-
const schemaFn = buildFormSchema(schema, this.api, recordKey ?? undefined);
|
|
131
|
-
const tree = form(signal(seedModel(schema)), schemaFn, { injector: this.injector });
|
|
132
|
-
|
|
133
|
-
if (this.mode() === 'create' || recordKey === null) {
|
|
134
|
-
this.tree.set(tree);
|
|
135
|
-
this.status.set('ready');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Edición: el valor se pisa con el registro, dejando los defaults de
|
|
140
|
-
// los campos que el backend no devuelve.
|
|
141
|
-
this.status.set('loading');
|
|
142
|
-
this.api
|
|
143
|
-
.get<Record<string, unknown>>(schema.endpoint, recordKey)
|
|
144
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
145
|
-
.subscribe({
|
|
146
|
-
next: (record) => {
|
|
147
|
-
tree().value.set({ ...seedModel(schema), ...record });
|
|
148
|
-
this.tree.set(tree);
|
|
149
|
-
this.status.set('ready');
|
|
150
|
-
},
|
|
151
|
-
error: (error: unknown) => {
|
|
152
|
-
this.loadError.set(this.errorMapper.messageOf(error));
|
|
153
|
-
this.status.set('error');
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async save(): Promise<void> {
|
|
159
|
-
const tree = this.tree();
|
|
160
|
-
const schema = this.schema();
|
|
161
|
-
if (tree === null || this.saving()) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
this.saving.set(true);
|
|
165
|
-
this.generalError.set('');
|
|
166
|
-
this.fieldErrors.set({});
|
|
167
|
-
try {
|
|
168
|
-
const ok = await submit(tree, {
|
|
169
|
-
// `null` = sin errores propios: los del backend se pintan aparte.
|
|
170
|
-
action: async () => {
|
|
171
|
-
await this.persist(tree, schema);
|
|
172
|
-
return null;
|
|
173
|
-
},
|
|
174
|
-
onInvalid: () => this.markTouched(tree),
|
|
175
|
-
});
|
|
176
|
-
if (!ok || Object.keys(this.fieldErrors()).length > 0 || this.generalError() !== '') {
|
|
177
|
-
this.markTouched(tree);
|
|
178
|
-
}
|
|
179
|
-
} finally {
|
|
180
|
-
this.saving.set(false);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Marca como tocado lo que se está mostrando. Se recorre por campo y no
|
|
186
|
-
* desde la raíz: `FieldTree<Record<string, unknown>>` se indexa con una
|
|
187
|
-
* clave dinámica y `markAsTouched` no compila ahí (`childTree` centraliza
|
|
188
|
-
* ese cast). Baja a todos los descendientes, así un `group` queda cubierto.
|
|
189
|
-
*/
|
|
190
|
-
private markTouched(tree: RootTree): void {
|
|
191
|
-
for (const field of this.visibleFields()) {
|
|
192
|
-
childTree<unknown>(tree, field.key)().markAsTouched();
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** create/update; nunca lanza (los errores quedan en las señales). */
|
|
197
|
-
private async persist(tree: RootTree, schema: ResourceSchema): Promise<void> {
|
|
198
|
-
const payload = buildPayload(schema, tree);
|
|
199
|
-
try {
|
|
200
|
-
if (this.mode() === 'create') {
|
|
201
|
-
const created = await firstValueFrom(
|
|
202
|
-
this.api.create<Record<string, unknown>>(schema.endpoint, payload),
|
|
203
|
-
);
|
|
204
|
-
this.notifications.success('Registro creado.');
|
|
205
|
-
this.saved.emit(created ?? {});
|
|
206
|
-
this.close.emit();
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
const updated = await firstValueFrom(
|
|
210
|
-
this.api.update<Record<string, unknown>>(
|
|
211
|
-
schema.endpoint,
|
|
212
|
-
this.recordKey() ?? undefined,
|
|
213
|
-
payload,
|
|
214
|
-
),
|
|
215
|
-
);
|
|
216
|
-
this.notifications.success('Registro guardado.');
|
|
217
|
-
this.saved.emit(updated ?? {});
|
|
218
|
-
this.close.emit();
|
|
219
|
-
} catch (error: unknown) {
|
|
220
|
-
const mapped = this.errorMapper.map(error);
|
|
221
|
-
this.fieldErrors.set(mapped.fields);
|
|
222
|
-
const withoutFields = Object.keys(mapped.fields).length === 0;
|
|
223
|
-
this.generalError.set(
|
|
224
|
-
mapped.general ?? (withoutFields ? this.errorMapper.messageOf(error) : ''),
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { FieldSchema, ResourceSchema } from '../../core/models/schema.model';
|
|
2
|
-
import { childTree, itemTree, listTree, type RootTree } from '../../fields/field-node';
|
|
3
|
-
import { seedFields } from '../../shared/utils/seed';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Modelo y payload del formulario genérico (Fase 10, ampliado en Fase 11).
|
|
7
|
-
*
|
|
8
|
-
* - `seedModel` siembra un valor inicial para CADA campo declarado en el
|
|
9
|
-
* schema antes de crear el formulario: el árbol de Signal Forms replica la
|
|
10
|
-
* forma del modelo, así que un campo ausente no tendría estado (ni valor
|
|
11
|
-
* que enviar). La siembra vive en `shared/utils/seed.ts`.
|
|
12
|
-
* - `buildPayload` decide qué viaja al backend (base.md §10): solo las claves
|
|
13
|
-
* declaradas en el schema, sin los ocultos y sin `positionField` raíz.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/** Valores por defecto del schema, en el mismo orden/shape que el JSON. */
|
|
17
|
-
export function seedModel(schema: ResourceSchema): Record<string, unknown> {
|
|
18
|
-
return seedFields(schema.fields);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Payload del guardado: whitelist de `schema.fields`.
|
|
23
|
-
*
|
|
24
|
-
* - Los campos ocultos (`visibleWhen` falso) no se muestran ni se envían
|
|
25
|
-
* (base.md §10): usar `hidden()` garantiza que no aparezcan acá aunque
|
|
26
|
-
* tengan valor sembrado — también dentro de `group` y de los ítems de una
|
|
27
|
-
* `list` (recursivo).
|
|
28
|
-
* - `positionField` del recurso se excluye aunque esté declarado: el orden
|
|
29
|
-
* del listado lo gestiona el backend (api.md R3, nunca se expone). El
|
|
30
|
-
* `positionField` de los ÍTEMS de una lista sí viaja: el orden local lo
|
|
31
|
-
* calcula el front (base.md §8).
|
|
32
|
-
* - Los tipos que la UI todavía no edita SÍ viajan: sus valores llegan del
|
|
33
|
-
* registro leído, así que reenviarlos evita pisarlos.
|
|
34
|
-
*/
|
|
35
|
-
export function buildPayload(schema: ResourceSchema, root: RootTree): Record<string, unknown> {
|
|
36
|
-
const payload: Record<string, unknown> = {};
|
|
37
|
-
collectPayload(root, schema.fields, payload, schema.positionField);
|
|
38
|
-
return payload;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function collectPayload(
|
|
42
|
-
tree: RootTree,
|
|
43
|
-
fields: readonly FieldSchema[],
|
|
44
|
-
payload: Record<string, unknown>,
|
|
45
|
-
excludedKey: string | undefined,
|
|
46
|
-
): void {
|
|
47
|
-
for (const field of fields) {
|
|
48
|
-
if (excludedKey !== undefined && field.key === excludedKey) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const state = childTree<unknown>(tree, field.key)();
|
|
52
|
-
if (state.hidden()) {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (field.type === 'group') {
|
|
56
|
-
const nested: Record<string, unknown> = {};
|
|
57
|
-
collectPayload(
|
|
58
|
-
childTree<Record<string, unknown>>(tree, field.key),
|
|
59
|
-
field.fields,
|
|
60
|
-
nested,
|
|
61
|
-
undefined,
|
|
62
|
-
);
|
|
63
|
-
payload[field.key] = nested;
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (field.type === 'list') {
|
|
67
|
-
const items = listTree(tree, field.key);
|
|
68
|
-
const raw = (state.value() as Record<string, unknown>[] | null) ?? [];
|
|
69
|
-
const list: unknown[] = [];
|
|
70
|
-
for (let index = 0; index < raw.length; index++) {
|
|
71
|
-
const nested: Record<string, unknown> = {};
|
|
72
|
-
collectPayload(itemTree(items, index), field.itemFields, nested, undefined);
|
|
73
|
-
// El orden de los ítems viaja con el registro padre (base.md §8): el
|
|
74
|
-
// `positionField` no es un campo editable, por eso no está en
|
|
75
|
-
// `itemFields` y hay que leerlo del modelo crudo.
|
|
76
|
-
const positionKey = field.positionField;
|
|
77
|
-
const position = positionKey !== undefined ? raw[index]?.[positionKey] : undefined;
|
|
78
|
-
if (positionKey !== undefined && position !== undefined) {
|
|
79
|
-
nested[positionKey] = position;
|
|
80
|
-
}
|
|
81
|
-
list.push(nested);
|
|
82
|
-
}
|
|
83
|
-
payload[field.key] = list;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
payload[field.key] = state.value();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
applyEach,
|
|
3
|
-
disabled,
|
|
4
|
-
hidden,
|
|
5
|
-
readonly as readonlyRule,
|
|
6
|
-
type SchemaFn,
|
|
7
|
-
type SchemaPathTree,
|
|
8
|
-
} from '@angular/forms/signals';
|
|
9
|
-
|
|
10
|
-
import type { FieldSchema, ResourceSchema } from '../../core/models/schema.model';
|
|
11
|
-
import type { ApiService } from '../../core/services/api.service';
|
|
12
|
-
import {
|
|
13
|
-
FIELD_VALIDATORS,
|
|
14
|
-
registerEmailRule,
|
|
15
|
-
registerUrlRule,
|
|
16
|
-
type FieldPath,
|
|
17
|
-
type ValidatorContext,
|
|
18
|
-
} from '../../core/registry/field-validators';
|
|
19
|
-
import { isSupported } from '../../core/registry/render-registry';
|
|
20
|
-
import { evaluateCondition } from '../../shared/utils/condition-evaluator';
|
|
21
|
-
|
|
22
|
-
/** Ruta de un hijo bajo un path (raíz, grupo o ítem). */
|
|
23
|
-
type ChildPath<V> = FieldPath<V>;
|
|
24
|
-
/** Ruta raíz del formulario. */
|
|
25
|
-
type RootPath = SchemaPathTree<Record<string, unknown>>;
|
|
26
|
-
/** Ruta de un campo lista (para `applyEach`). */
|
|
27
|
-
type ListPath<V> = FieldPath<V>;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Reglas del formulario desde el schema (base.md §4, §6, §9, §10).
|
|
31
|
-
*
|
|
32
|
-
* Hay DOS clases de reglas y viven en sitios distintos:
|
|
33
|
-
*
|
|
34
|
-
* 1. **Ciclo de vida** — `visibleWhen`, `readonlyOn`, `hiddenOn`, `dependsOn`:
|
|
35
|
-
* decides si el campo se toca, se ve o se manda. Vive acá, con la
|
|
36
|
-
* estructura del formulario.
|
|
37
|
-
* 2. **Validadores** — obligatoriedad, longitud, patrón, rangos, únicos…:
|
|
38
|
-
* vive en `core/registry/field-validators.ts` (F7 + B11), con los MISMOS
|
|
39
|
-
* nombres que el back. Este módulo sólo RECORRE ese registro por cada
|
|
40
|
-
* campo: añadir un validador es una entrada allá, no un `case` acá.
|
|
41
|
-
*
|
|
42
|
-
* El schema de Signal Forms recibe el path RAÍZ; las reglas se atan a la ruta
|
|
43
|
-
* dinámica de cada campo. El barrido es **recursivo** — un `group` registra
|
|
44
|
-
* las reglas de sus hijos bajo su propia ruta y un `list` registra las de
|
|
45
|
-
* cada ítem con `applyEach`, de modo que las reglas corran también para los
|
|
46
|
-
* ítems que se agregan después.
|
|
47
|
-
*
|
|
48
|
-
* Solo se generan reglas para los tipos que la UI sabe editar (`isSupported('field', …)`):
|
|
49
|
-
* un campo invisible con `required` bloquearía el guardado para siempre.
|
|
50
|
-
*
|
|
51
|
-
* `api` y `excludeKey` alimentan la validación `unique`: se consulta el
|
|
52
|
-
* listado del recurso y se descarta el propio registro (la clave del registro
|
|
53
|
-
* en edición, tomada de la ruta).
|
|
54
|
-
*/
|
|
55
|
-
export function buildFormSchema(
|
|
56
|
-
schema: ResourceSchema,
|
|
57
|
-
api: ApiService,
|
|
58
|
-
excludeKey?: string,
|
|
59
|
-
): SchemaFn<Record<string, unknown>> {
|
|
60
|
-
return (root) => {
|
|
61
|
-
applyRulesToFields(
|
|
62
|
-
{ schema, api, excludeKey, root, container: root, siblings: schema.fields },
|
|
63
|
-
schema.fields,
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Ámbito de registro de reglas.
|
|
70
|
-
*
|
|
71
|
-
* - `root` es siempre la raíz del formulario (referencia para condiciones que
|
|
72
|
-
* nombran un campo de la raíz, base.md §4: «mismo nivel o registro raíz»).
|
|
73
|
-
* - `container` es el nodo del que cuelgan las rutas hijas: la raíz, un
|
|
74
|
-
* `group` o un ítem de un `list`.
|
|
75
|
-
* - `siblings` son los campos declarados en `container`: si una condición
|
|
76
|
-
* nombra a uno de ellos se evalúa contra el contenedor, si no, contra la
|
|
77
|
-
* raíz.
|
|
78
|
-
*/
|
|
79
|
-
interface RuleScope {
|
|
80
|
-
schema: ResourceSchema;
|
|
81
|
-
api: ApiService;
|
|
82
|
-
excludeKey: string | undefined;
|
|
83
|
-
root: RootPath;
|
|
84
|
-
container: object;
|
|
85
|
-
siblings: readonly FieldSchema[];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function applyRulesToFields(scope: RuleScope, fields: readonly FieldSchema[]): void {
|
|
89
|
-
for (const field of fields) {
|
|
90
|
-
if (!isSupported('field', field.type)) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
applyRulesToField(scope, field, pathAt<unknown>(scope.container, field.key));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function applyRulesToField(scope: RuleScope, field: FieldSchema, path: ChildPath<unknown>): void {
|
|
98
|
-
applyLifecycleRules(scope, field, path);
|
|
99
|
-
|
|
100
|
-
// Validadores: el registro manda. Cada entrada decide si el campo la pide
|
|
101
|
-
// y ata su regla a ESTA ruta (F7: sin `if` por regla en este módulo).
|
|
102
|
-
const ctx: ValidatorContext = {
|
|
103
|
-
path,
|
|
104
|
-
field,
|
|
105
|
-
schema: scope.schema,
|
|
106
|
-
api: scope.api,
|
|
107
|
-
excludeKey: scope.excludeKey,
|
|
108
|
-
};
|
|
109
|
-
for (const entry of FIELD_VALIDATORS) {
|
|
110
|
-
if (entry.declares(ctx)) {
|
|
111
|
-
entry.register(ctx);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Estructura (no es validador): los HIJOS se registran bajo su propia
|
|
116
|
-
// ruta, recursivamente, para que las reglas corran también en los ítems
|
|
117
|
-
// que el usuario agrega después.
|
|
118
|
-
switch (field.type) {
|
|
119
|
-
case 'group': {
|
|
120
|
-
applyRulesToFields({ ...scope, container: path, siblings: field.fields }, field.fields);
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
case 'list': {
|
|
124
|
-
applyEach(path as unknown as ListPath<Record<string, unknown>[]>, (item) =>
|
|
125
|
-
applyRulesToFields(
|
|
126
|
-
{ ...scope, container: item as object, siblings: field.itemFields },
|
|
127
|
-
field.itemFields,
|
|
128
|
-
),
|
|
129
|
-
);
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
case 'string-list': {
|
|
133
|
-
applyEach(path as unknown as ListPath<string[]>, (item) =>
|
|
134
|
-
applyStringItemRules(item as ChildPath<string>, field.itemType),
|
|
135
|
-
);
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
default:
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* ¿Aplica `mode` en ESTE contexto de formulario?
|
|
145
|
-
*
|
|
146
|
-
* Lo comparten `readonlyOn` y `hiddenOn`: `always` vale en todos los modos,
|
|
147
|
-
* `create` sólo en alta y `update` sólo en edición. El modo se detecta por
|
|
148
|
-
* `scope.excludeKey !== undefined`, que es la señal que ya usaba `readonlyOn`
|
|
149
|
-
* (form-view define `mode` a partir de la misma condición).
|
|
150
|
-
*/
|
|
151
|
-
function modeAppliesTo(mode: 'create' | 'update' | 'always', isEdit: boolean): boolean {
|
|
152
|
-
return mode === 'always' || (mode === 'update' && isEdit) || (mode === 'create' && !isEdit);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Ciclo de vida del campo: visibilidad, edición y dependencias (base.md §4).
|
|
157
|
-
*
|
|
158
|
-
* Aquí NO hay validadores — la obligatoriedad vive en el registro.
|
|
159
|
-
* `hidden` además excluye el campo de `dirty`, `invalid` y del payload
|
|
160
|
-
* (base.md §10 «Campos ocultos»), y `disabled` lo deja fuera de la
|
|
161
|
-
* validación, así un `required` en el hijo no bloquea el guardado mientras
|
|
162
|
-
* no haya nada que elegir.
|
|
163
|
-
*/
|
|
164
|
-
function applyLifecycleRules(scope: RuleScope, field: FieldSchema, path: ChildPath<unknown>): void {
|
|
165
|
-
if (field.visibleWhen) {
|
|
166
|
-
const condition = field.visibleWhen;
|
|
167
|
-
hidden(path, {
|
|
168
|
-
when: (ctx) =>
|
|
169
|
-
!evaluateCondition(condition, ctx.valueOf(conditionPath(scope, condition.field))),
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
// Selección dependiente (guía §1, plan 6.6): el hijo no se puede tocar
|
|
173
|
-
// hasta que el padre tenga valor.
|
|
174
|
-
//
|
|
175
|
-
// Acá NO sirve `conditionPath`: eso devuelve el contenedor entero porque
|
|
176
|
-
// `evaluateCondition` recibe el objeto de hermanos. Acá se necesita el
|
|
177
|
-
// valor concreto del padre.
|
|
178
|
-
if (field.dependsOn) {
|
|
179
|
-
const parentKey = field.dependsOn;
|
|
180
|
-
const isSibling = scope.siblings.some((candidate) => candidate.key === parentKey);
|
|
181
|
-
const parent = isSibling ? scope.container : scope.root;
|
|
182
|
-
const parentPath = pathAt<unknown>(parent, parentKey);
|
|
183
|
-
disabled(path, ({ valueOf }) => isEmptyValue(valueOf(parentPath)));
|
|
184
|
-
}
|
|
185
|
-
if (field.readonly) {
|
|
186
|
-
readonlyRule(path, { when: () => true });
|
|
187
|
-
}
|
|
188
|
-
if (field.readonlyOn && modeAppliesTo(field.readonlyOn, scope.excludeKey !== undefined)) {
|
|
189
|
-
readonlyRule(path, { when: () => true });
|
|
190
|
-
}
|
|
191
|
-
// Ciclo de vida de la visibilidad — simétrico a `readonlyOn` de arriba.
|
|
192
|
-
// `hidden()` deja el campo fuera de la validación y del payload, así que en
|
|
193
|
-
// alta un campo que LLENA EL BACK no ocupa la sección ni exige nada: sin
|
|
194
|
-
// esto, `ref` y `pin` aparecían vacíos con un "se genera solo al guardar".
|
|
195
|
-
if (field.hiddenOn && modeAppliesTo(field.hiddenOn, scope.excludeKey !== undefined)) {
|
|
196
|
-
hidden(path, { when: () => true });
|
|
197
|
-
}
|
|
198
|
-
if (field.readonlyWhen) {
|
|
199
|
-
const condition = field.readonlyWhen;
|
|
200
|
-
readonlyRule(path, {
|
|
201
|
-
when: (ctx) =>
|
|
202
|
-
evaluateCondition(condition, ctx.valueOf(conditionPath(scope, condition.field))),
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Vacío para el propósito de «el padre todavía no eligió nada». */
|
|
208
|
-
function isEmptyValue(value: unknown): boolean {
|
|
209
|
-
if (value === undefined || value === null || value === '') {
|
|
210
|
-
return true;
|
|
211
|
-
}
|
|
212
|
-
return Array.isArray(value) && value.length === 0;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Path contra el que se evalúa una condición: el contenedor si nombra a un
|
|
217
|
-
* campo hermano, la raíz si no (base.md §4: «otro campo del mismo nivel o
|
|
218
|
-
* del registro raíz»).
|
|
219
|
-
*/
|
|
220
|
-
function conditionPath(scope: RuleScope, key: string): RootPath {
|
|
221
|
-
const isSibling = scope.siblings.some((field) => field.key === key);
|
|
222
|
-
const target = isSibling ? scope.container : scope.root;
|
|
223
|
-
return target as RootPath;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/** Ítems de `string-list`: validan según el tipo declarado (§9: text/url/email). */
|
|
227
|
-
function applyStringItemRules(
|
|
228
|
-
path: ChildPath<string>,
|
|
229
|
-
itemType: 'text' | 'url' | 'email' | undefined,
|
|
230
|
-
): void {
|
|
231
|
-
if (itemType === 'email') {
|
|
232
|
-
registerEmailRule(path);
|
|
233
|
-
}
|
|
234
|
-
if (itemType === 'url') {
|
|
235
|
-
registerUrlRule(path);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Navegación dinámica sobre el árbol de paths.
|
|
241
|
-
*
|
|
242
|
-
* Indexar `SchemaPathTree<Record<string, unknown>>` con una clave dinámica
|
|
243
|
-
* devuelve `SchemaPath<unknown, …> | undefined`: el `| undefined` es solo una
|
|
244
|
-
* consecuencia del index signature, y las reglas con valor concreto (`min`,
|
|
245
|
-
* `minLength`, `email`…) exigen afinar el tipo. Los casts de este módulo
|
|
246
|
-
* viven acá; los del registro, en `field-validators.ts` (solución reportada
|
|
247
|
-
* en plan.md, Fase 10).
|
|
248
|
-
*/
|
|
249
|
-
function pathAt<V>(parent: object, key: string): ChildPath<V> {
|
|
250
|
-
const path = (parent as unknown as Record<string, unknown>)[key];
|
|
251
|
-
if (path === undefined) {
|
|
252
|
-
throw new Error(`El formulario no contiene la ruta "${key}".`);
|
|
253
|
-
}
|
|
254
|
-
return path as ChildPath<V>;
|
|
255
|
-
}
|