@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
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { n as parseNavigationUrl, t as interpolateTemplate } from "./tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs";
|
|
2
|
+
import { t as EmptyState } from "./tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs";
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import { Component, computed, inject, input } from "@angular/core";
|
|
5
|
+
import { Router, RouterLink } from "@angular/router";
|
|
6
|
+
var RecordList = class RecordList {
|
|
7
|
+
router = inject(Router, { optional: true });
|
|
8
|
+
widget = input.required(...ngDevMode ? [{ debugName: "widget" }] : /* istanbul ignore next */ []);
|
|
9
|
+
data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
|
|
10
|
+
rows = computed(() => {
|
|
11
|
+
const val = this.data();
|
|
12
|
+
if (!Array.isArray(val)) return [];
|
|
13
|
+
return val.filter((item) => typeof item === "object" && item !== null);
|
|
14
|
+
}, ...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
|
|
15
|
+
formatHeader(key) {
|
|
16
|
+
return key.replace(/_/g, " ");
|
|
17
|
+
}
|
|
18
|
+
formatCell(value) {
|
|
19
|
+
if (value === null || value === void 0 || value === "") return "—";
|
|
20
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
21
|
+
return String(value);
|
|
22
|
+
}
|
|
23
|
+
trackRow(row, index) {
|
|
24
|
+
return row["id"] || row["ref"] || row["key"] || index;
|
|
25
|
+
}
|
|
26
|
+
resolveRoute(row) {
|
|
27
|
+
const template = this.widget().action?.routeTemplate;
|
|
28
|
+
if (!template) return {
|
|
29
|
+
path: "",
|
|
30
|
+
queryParams: {}
|
|
31
|
+
};
|
|
32
|
+
return parseNavigationUrl(interpolateTemplate(template, row));
|
|
33
|
+
}
|
|
34
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
35
|
+
minVersion: "12.0.0",
|
|
36
|
+
version: "22.2.3",
|
|
37
|
+
ngImport: i0,
|
|
38
|
+
type: RecordList,
|
|
39
|
+
deps: [],
|
|
40
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
41
|
+
});
|
|
42
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
43
|
+
minVersion: "17.0.0",
|
|
44
|
+
version: "22.2.3",
|
|
45
|
+
type: RecordList,
|
|
46
|
+
isStandalone: true,
|
|
47
|
+
selector: "app-record-list",
|
|
48
|
+
inputs: {
|
|
49
|
+
widget: {
|
|
50
|
+
classPropertyName: "widget",
|
|
51
|
+
publicName: "widget",
|
|
52
|
+
isSignal: true,
|
|
53
|
+
isRequired: true,
|
|
54
|
+
transformFunction: null
|
|
55
|
+
},
|
|
56
|
+
data: {
|
|
57
|
+
classPropertyName: "data",
|
|
58
|
+
publicName: "data",
|
|
59
|
+
isSignal: true,
|
|
60
|
+
isRequired: false,
|
|
61
|
+
transformFunction: null
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
ngImport: i0,
|
|
65
|
+
template: `
|
|
66
|
+
<article class="flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4">
|
|
67
|
+
<header class="mb-3 flex items-center justify-between">
|
|
68
|
+
<div class="flex items-center gap-2">
|
|
69
|
+
<h2 class="text-sm font-semibold text-neutral-light">{{ widget().label }}</h2>
|
|
70
|
+
@if (rows().length > 0) {
|
|
71
|
+
<span
|
|
72
|
+
class="inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary"
|
|
73
|
+
>
|
|
74
|
+
{{ rows().length }}
|
|
75
|
+
</span>
|
|
76
|
+
}
|
|
77
|
+
</div>
|
|
78
|
+
</header>
|
|
79
|
+
|
|
80
|
+
@if (rows().length === 0) {
|
|
81
|
+
<div class="flex flex-1 items-center justify-center py-6">
|
|
82
|
+
<app-empty-state
|
|
83
|
+
title="Sin registros pendientes"
|
|
84
|
+
message="No hay registros que requieran atención en este momento."
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
} @else {
|
|
88
|
+
<div class="flex-1 overflow-x-auto">
|
|
89
|
+
<table class="w-full text-left text-sm" role="table">
|
|
90
|
+
<thead>
|
|
91
|
+
<tr class="border-b border-neutral/10 text-xs text-neutral">
|
|
92
|
+
@for (col of widget().columns; track col) {
|
|
93
|
+
<th scope="col" class="pb-2 font-medium capitalize">{{ formatHeader(col) }}</th>
|
|
94
|
+
}
|
|
95
|
+
@if (widget().action) {
|
|
96
|
+
<th scope="col" class="pb-2 text-right font-medium">Acción</th>
|
|
97
|
+
}
|
|
98
|
+
</tr>
|
|
99
|
+
</thead>
|
|
100
|
+
<tbody class="divide-y divide-neutral/10">
|
|
101
|
+
@for (row of rows(); track trackRow(row, $index)) {
|
|
102
|
+
<tr class="transition-colors hover:bg-neutral/5">
|
|
103
|
+
@for (col of widget().columns; track col) {
|
|
104
|
+
<td class="py-2.5 pr-3 text-neutral-light">
|
|
105
|
+
<span class="line-clamp-1">{{ formatCell(row[col]) }}</span>
|
|
106
|
+
</td>
|
|
107
|
+
}
|
|
108
|
+
@if (widget().action) {
|
|
109
|
+
<td class="py-2.5 text-right">
|
|
110
|
+
<a
|
|
111
|
+
[routerLink]="resolveRoute(row).path"
|
|
112
|
+
[queryParams]="resolveRoute(row).queryParams"
|
|
113
|
+
class="inline-flex items-center rounded-lg border border-neutral/30 bg-surface px-2.5 py-1 text-xs font-medium text-neutral-light transition-colors hover:bg-neutral/10"
|
|
114
|
+
>
|
|
115
|
+
{{ widget().action?.label || 'Ver' }}
|
|
116
|
+
</a>
|
|
117
|
+
</td>
|
|
118
|
+
}
|
|
119
|
+
</tr>
|
|
120
|
+
}
|
|
121
|
+
</tbody>
|
|
122
|
+
</table>
|
|
123
|
+
</div>
|
|
124
|
+
}
|
|
125
|
+
</article>
|
|
126
|
+
`,
|
|
127
|
+
isInline: true,
|
|
128
|
+
dependencies: [{
|
|
129
|
+
kind: "component",
|
|
130
|
+
type: EmptyState,
|
|
131
|
+
selector: "app-empty-state",
|
|
132
|
+
inputs: ["title", "message"]
|
|
133
|
+
}, {
|
|
134
|
+
kind: "directive",
|
|
135
|
+
type: RouterLink,
|
|
136
|
+
selector: "[routerLink]",
|
|
137
|
+
inputs: [
|
|
138
|
+
"target",
|
|
139
|
+
"queryParams",
|
|
140
|
+
"fragment",
|
|
141
|
+
"queryParamsHandling",
|
|
142
|
+
"state",
|
|
143
|
+
"info",
|
|
144
|
+
"relativeTo",
|
|
145
|
+
"preserveFragment",
|
|
146
|
+
"skipLocationChange",
|
|
147
|
+
"replaceUrl",
|
|
148
|
+
"browserUrl",
|
|
149
|
+
"routerLink"
|
|
150
|
+
]
|
|
151
|
+
}]
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
155
|
+
minVersion: "12.0.0",
|
|
156
|
+
version: "22.2.3",
|
|
157
|
+
ngImport: i0,
|
|
158
|
+
type: RecordList,
|
|
159
|
+
decorators: [{
|
|
160
|
+
type: Component,
|
|
161
|
+
args: [{
|
|
162
|
+
selector: "app-record-list",
|
|
163
|
+
imports: [EmptyState, RouterLink],
|
|
164
|
+
template: `
|
|
165
|
+
<article class="flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4">
|
|
166
|
+
<header class="mb-3 flex items-center justify-between">
|
|
167
|
+
<div class="flex items-center gap-2">
|
|
168
|
+
<h2 class="text-sm font-semibold text-neutral-light">{{ widget().label }}</h2>
|
|
169
|
+
@if (rows().length > 0) {
|
|
170
|
+
<span
|
|
171
|
+
class="inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary"
|
|
172
|
+
>
|
|
173
|
+
{{ rows().length }}
|
|
174
|
+
</span>
|
|
175
|
+
}
|
|
176
|
+
</div>
|
|
177
|
+
</header>
|
|
178
|
+
|
|
179
|
+
@if (rows().length === 0) {
|
|
180
|
+
<div class="flex flex-1 items-center justify-center py-6">
|
|
181
|
+
<app-empty-state
|
|
182
|
+
title="Sin registros pendientes"
|
|
183
|
+
message="No hay registros que requieran atención en este momento."
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
} @else {
|
|
187
|
+
<div class="flex-1 overflow-x-auto">
|
|
188
|
+
<table class="w-full text-left text-sm" role="table">
|
|
189
|
+
<thead>
|
|
190
|
+
<tr class="border-b border-neutral/10 text-xs text-neutral">
|
|
191
|
+
@for (col of widget().columns; track col) {
|
|
192
|
+
<th scope="col" class="pb-2 font-medium capitalize">{{ formatHeader(col) }}</th>
|
|
193
|
+
}
|
|
194
|
+
@if (widget().action) {
|
|
195
|
+
<th scope="col" class="pb-2 text-right font-medium">Acción</th>
|
|
196
|
+
}
|
|
197
|
+
</tr>
|
|
198
|
+
</thead>
|
|
199
|
+
<tbody class="divide-y divide-neutral/10">
|
|
200
|
+
@for (row of rows(); track trackRow(row, $index)) {
|
|
201
|
+
<tr class="transition-colors hover:bg-neutral/5">
|
|
202
|
+
@for (col of widget().columns; track col) {
|
|
203
|
+
<td class="py-2.5 pr-3 text-neutral-light">
|
|
204
|
+
<span class="line-clamp-1">{{ formatCell(row[col]) }}</span>
|
|
205
|
+
</td>
|
|
206
|
+
}
|
|
207
|
+
@if (widget().action) {
|
|
208
|
+
<td class="py-2.5 text-right">
|
|
209
|
+
<a
|
|
210
|
+
[routerLink]="resolveRoute(row).path"
|
|
211
|
+
[queryParams]="resolveRoute(row).queryParams"
|
|
212
|
+
class="inline-flex items-center rounded-lg border border-neutral/30 bg-surface px-2.5 py-1 text-xs font-medium text-neutral-light transition-colors hover:bg-neutral/10"
|
|
213
|
+
>
|
|
214
|
+
{{ widget().action?.label || 'Ver' }}
|
|
215
|
+
</a>
|
|
216
|
+
</td>
|
|
217
|
+
}
|
|
218
|
+
</tr>
|
|
219
|
+
}
|
|
220
|
+
</tbody>
|
|
221
|
+
</table>
|
|
222
|
+
</div>
|
|
223
|
+
}
|
|
224
|
+
</article>
|
|
225
|
+
`
|
|
226
|
+
}]
|
|
227
|
+
}],
|
|
228
|
+
propDecorators: {
|
|
229
|
+
widget: [{
|
|
230
|
+
type: i0.Input,
|
|
231
|
+
args: [{
|
|
232
|
+
isSignal: true,
|
|
233
|
+
alias: "widget",
|
|
234
|
+
required: true
|
|
235
|
+
}]
|
|
236
|
+
}],
|
|
237
|
+
data: [{
|
|
238
|
+
type: i0.Input,
|
|
239
|
+
args: [{
|
|
240
|
+
isSignal: true,
|
|
241
|
+
alias: "data",
|
|
242
|
+
required: false
|
|
243
|
+
}]
|
|
244
|
+
}]
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
export { RecordList };
|
|
248
|
+
|
|
249
|
+
//# sourceMappingURL=tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/widgets/record-list/record-list.ts"],"sourcesContent":["import { Component, computed, inject, input } from '@angular/core';\nimport { Router, RouterLink } from '@angular/router';\n\nimport type { RecordListWidget } from '../../core/models/schema.model';\nimport { interpolateTemplate, parseNavigationUrl } from '../../core/utils/template-interpolator';\nimport { EmptyState } from '../../shared/components/empty-state/empty-state';\n\n/**\n * Tabla embebida de registros operativos para el Dashboard.\n * Permite visualizar filas clave (ej. pedidos que requieren atención)\n * con enlace de acción por fila hacia su ficha de detalle.\n */\n@Component({\n selector: 'app-record-list',\n imports: [EmptyState, RouterLink],\n template: `\n <article class=\"flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4\">\n <header class=\"mb-3 flex items-center justify-between\">\n <div class=\"flex items-center gap-2\">\n <h2 class=\"text-sm font-semibold text-neutral-light\">{{ widget().label }}</h2>\n @if (rows().length > 0) {\n <span\n class=\"inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ rows().length }}\n </span>\n }\n </div>\n </header>\n\n @if (rows().length === 0) {\n <div class=\"flex flex-1 items-center justify-center py-6\">\n <app-empty-state\n title=\"Sin registros pendientes\"\n message=\"No hay registros que requieran atención en este momento.\"\n />\n </div>\n } @else {\n <div class=\"flex-1 overflow-x-auto\">\n <table class=\"w-full text-left text-sm\" role=\"table\">\n <thead>\n <tr class=\"border-b border-neutral/10 text-xs text-neutral\">\n @for (col of widget().columns; track col) {\n <th scope=\"col\" class=\"pb-2 font-medium capitalize\">{{ formatHeader(col) }}</th>\n }\n @if (widget().action) {\n <th scope=\"col\" class=\"pb-2 text-right font-medium\">Acción</th>\n }\n </tr>\n </thead>\n <tbody class=\"divide-y divide-neutral/10\">\n @for (row of rows(); track trackRow(row, $index)) {\n <tr class=\"transition-colors hover:bg-neutral/5\">\n @for (col of widget().columns; track col) {\n <td class=\"py-2.5 pr-3 text-neutral-light\">\n <span class=\"line-clamp-1\">{{ formatCell(row[col]) }}</span>\n </td>\n }\n @if (widget().action) {\n <td class=\"py-2.5 text-right\">\n <a\n [routerLink]=\"resolveRoute(row).path\"\n [queryParams]=\"resolveRoute(row).queryParams\"\n class=\"inline-flex items-center rounded-lg border border-neutral/30 bg-surface px-2.5 py-1 text-xs font-medium text-neutral-light transition-colors hover:bg-neutral/10\"\n >\n {{ widget().action?.label || 'Ver' }}\n </a>\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </article>\n `,\n})\nexport class RecordList {\n protected readonly router = inject(Router, { optional: true });\n\n readonly widget = input.required<RecordListWidget>();\n readonly data = input<Record<string, unknown>[] | null>(null);\n\n protected readonly rows = computed<Record<string, unknown>[]>(() => {\n const val = this.data();\n if (!Array.isArray(val)) return [];\n return val.filter(\n (item): item is Record<string, unknown> => typeof item === 'object' && item !== null,\n );\n });\n\n protected formatHeader(key: string): string {\n return key.replace(/_/g, ' ');\n }\n\n protected formatCell(value: unknown): string {\n if (value === null || value === undefined || value === '') return '—';\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n }\n\n protected trackRow(row: Record<string, unknown>, index: number): string | number {\n return (row['id'] as string) || (row['ref'] as string) || (row['key'] as string) || index;\n }\n\n protected resolveRoute(row: Record<string, unknown>): {\n path: string;\n queryParams: Record<string, string>;\n } {\n const template = this.widget().action?.routeTemplate;\n if (!template) return { path: '', queryParams: {} };\n return parseNavigationUrl(interpolateTemplate(template, row));\n }\n}\n"],"mappings":";;;;;AA8EA,IAAa,aAAb,MAAa,WAAU;CACF,SAAS,OAAO,QAAQ,EAAE,UAAU,KAAI,CAAE;CAEpD,SAAS,MAAM,SAA4B,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAC3C,OAAO,MAAwC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAE1C,OAAO,eAAyC;EACjE,MAAM,MAAM,KAAK,KAAI;EACrB,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAA;EAChC,OAAO,IAAI,QACR,SAA0C,OAAO,SAAS,YAAY,SAAS,IAAI;CAExF,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAEQ,aAAa,KAAW;EAChC,OAAO,IAAI,QAAQ,MAAM,GAAG;CAC9B;CAEU,WAAW,OAAc;EACjC,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,IAAI,OAAO;EAClE,IAAI,OAAO,UAAU,UAAU,OAAO,KAAK,UAAU,KAAK;EAC1D,OAAO,OAAO,KAAK;CACrB;CAEU,SAAS,KAA8B,OAAa;EAC5D,OAAQ,IAAI,SAAqB,IAAI,UAAsB,IAAI,UAAqB;CACtF;CAEU,aAAa,KAA4B;EAIjD,MAAM,WAAW,KAAK,OAAM,CAAE,CAAC,QAAQ;EACvC,IAAI,CAAC,UAAU,OAAO;GAAE,MAAM;GAAI,aAAa,CAAA;EAAE;EACjD,OAAO,mBAAmB,oBAAoB,UAAU,GAAG,CAAC;CAC9D;CAnCW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAU,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAV,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAU,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UA/DX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6DT,UAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MA9DS;GAAU,UAAA;GAAA,QAAA,CAAA,SAAA,SAAA;EAAA,GAAA;GAAA,MAAA;GAAA,MAAE;GAAU,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;EAAA,CAAA;CAAA,CAAA;;AAgErB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAU,YAAA,CAAA;EAlEtB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS,CAAC,YAAY,UAAU;GAChC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8DX,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { Service, signal } from "@angular/core";
|
|
3
|
+
var RelationDrawerService = class RelationDrawerService {
|
|
4
|
+
pending = signal(null, ...ngDevMode ? [{ debugName: "pending" }] : /* istanbul ignore next */ []);
|
|
5
|
+
request = this.pending.asReadonly();
|
|
6
|
+
open(resource, onCreated) {
|
|
7
|
+
this.pending.set({
|
|
8
|
+
resource,
|
|
9
|
+
onCreated
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
clear() {
|
|
13
|
+
this.pending.set(null);
|
|
14
|
+
}
|
|
15
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
16
|
+
minVersion: "12.0.0",
|
|
17
|
+
version: "22.2.3",
|
|
18
|
+
ngImport: i0,
|
|
19
|
+
type: RelationDrawerService,
|
|
20
|
+
deps: [],
|
|
21
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
22
|
+
});
|
|
23
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
24
|
+
minVersion: "22.0.0",
|
|
25
|
+
version: "22.2.3",
|
|
26
|
+
ngImport: i0,
|
|
27
|
+
type: RelationDrawerService
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
31
|
+
minVersion: "12.0.0",
|
|
32
|
+
version: "22.2.3",
|
|
33
|
+
ngImport: i0,
|
|
34
|
+
type: RelationDrawerService,
|
|
35
|
+
decorators: [{ type: Service }]
|
|
36
|
+
});
|
|
37
|
+
export { RelationDrawerService as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/core/services/relation-drawer.service.ts"],"sourcesContent":["import { Service, signal } from '@angular/core';\n\n/** Pedido de «Crear nuevo» lanzado desde el dropdown de una relación. */\nexport interface RelationCreateRequest {\n /** Recurso a crear (el `source.resource` de la relación). */\n resource: string;\n /**\n * Se invoca con la clave recién creada. Vive en la relación porque es ella\n * la que tiene que recargar sus opciones y preseleccionar el valor.\n */\n onCreated: (key: string) => void;\n}\n\n/**\n * Puente entre el control `relation` y el drawer que abre el formulario.\n *\n * Existe como señal inyectable y NO como un `output()` encadenado porque el\n * camino directo — `relation → DrawerForm → FieldHost → relation` — arma un\n * ciclo de imports de módulos: `field-host` se decoraría con\n * `FieldRelation === undefined` y Angular tiraría `Cannot read properties of\n * undefined (reading 'ɵcmp')`. El campo no puede importar un componente que,\n * a su vez, lo importa a él.\n *\n * Sólo hay un drawer a la vez, así que una única señal alcanza: quien lo\n * abre lo cierra con `clear()` al recibir `close`/`saved`.\n */\n@Service()\nexport class RelationDrawerService {\n private readonly pending = signal<RelationCreateRequest | null>(null);\n\n /** Pedido en curso; `null` cuando no hay panel abierto. */\n readonly request = this.pending.asReadonly();\n\n open(resource: string, onCreated: (key: string) => void): void {\n this.pending.set({ resource, onCreated });\n }\n\n clear(): void {\n this.pending.set(null);\n }\n}\n"],"mappings":";;AA2BA,IAAa,wBAAb,MAAa,sBAAqB;CACf,UAAU,OAAqC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAG5D,UAAU,KAAK,QAAQ,WAAU;CAE1C,KAAK,UAAkB,WAAgC;EACrD,KAAK,QAAQ,IAAI;GAAE;GAAU;EAAS,CAAE;CAC1C;CAEA,QAAK;EACH,KAAK,QAAQ,IAAI,IAAI;CACvB;CAZW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAqB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAArB,OAAA,QAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;CAAqB,CAAA;;AAArB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAqB,YAAA,CAAA,EADjC,MAAA,QAAA,CAAA"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { i as getSchema } from "./tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs";
|
|
2
|
+
import { t as Button } from "./tinya-code-gas-admin-ui-button-BQjNW8KB.mjs";
|
|
3
|
+
import { n as dataSourceKey, t as DataSourceService } from "./tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs";
|
|
4
|
+
import { n as FieldAria } from "./tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs";
|
|
5
|
+
import { t as childTree } from "./tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs";
|
|
6
|
+
import { t as optionsFromRows } from "./tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs";
|
|
7
|
+
import { t as Skeleton } from "./tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs";
|
|
8
|
+
import { t as RelationDrawerService } from "./tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs";
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
import { Component, computed, inject, input, resource, signal } from "@angular/core";
|
|
11
|
+
import { LucidePlus } from "@lucide/angular";
|
|
12
|
+
import { FormField } from "@angular/forms/signals";
|
|
13
|
+
var FieldRelation = class FieldRelation {
|
|
14
|
+
field = input.required(...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
|
|
15
|
+
tree = input.required(...ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []);
|
|
16
|
+
ds = inject(DataSourceService);
|
|
17
|
+
drawer = inject(RelationDrawerService);
|
|
18
|
+
node = computed(() => childTree(this.tree(), this.field().key), ...ngDevMode ? [{ debugName: "node" }] : /* istanbul ignore next */ []);
|
|
19
|
+
state = computed(() => this.node()(), ...ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []);
|
|
20
|
+
query = signal("", ...ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []);
|
|
21
|
+
targetSchema = computed(() => getSchema(this.field().source.resource), ...ngDevMode ? [{ debugName: "targetSchema" }] : /* istanbul ignore next */ []);
|
|
22
|
+
canCreate = computed(() => this.targetSchema()?.permissions?.create !== false, ...ngDevMode ? [{ debugName: "canCreate" }] : /* istanbul ignore next */ []);
|
|
23
|
+
useSearch = computed(() => this.options().length > 7, ...ngDevMode ? [{ debugName: "useSearch" }] : /* istanbul ignore next */ []);
|
|
24
|
+
onQuery(event) {
|
|
25
|
+
this.query.set(event.target.value);
|
|
26
|
+
}
|
|
27
|
+
matches = computed(() => {
|
|
28
|
+
const all = this.options();
|
|
29
|
+
const term = this.query().trim().toLowerCase();
|
|
30
|
+
if (term === "") return all;
|
|
31
|
+
return all.filter((option) => option.label.toLowerCase().includes(term));
|
|
32
|
+
}, ...ngDevMode ? [{ debugName: "matches" }] : /* istanbul ignore next */ []);
|
|
33
|
+
noMatches = computed(() => this.useSearch() && this.query().trim() !== "" && this.matches().length === 0, ...ngDevMode ? [{ debugName: "noMatches" }] : /* istanbul ignore next */ []);
|
|
34
|
+
visibleOptions = computed(() => {
|
|
35
|
+
const filtered = this.matches();
|
|
36
|
+
if (this.query().trim() === "") return filtered;
|
|
37
|
+
const selected = String(this.state().value() ?? "");
|
|
38
|
+
if (filtered.some((option) => option.value === selected)) return filtered;
|
|
39
|
+
const kept = this.options().find((option) => option.value === selected);
|
|
40
|
+
return kept === void 0 ? filtered : [...filtered, kept];
|
|
41
|
+
}, ...ngDevMode ? [{ debugName: "visibleOptions" }] : /* istanbul ignore next */ []);
|
|
42
|
+
requestCreate() {
|
|
43
|
+
const resource = this.field().source.resource;
|
|
44
|
+
this.drawer.open(resource, (key) => {
|
|
45
|
+
this.ds.invalidate(resource);
|
|
46
|
+
this.optionsResource.reload();
|
|
47
|
+
this.node()().value.set(key);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
registro = computed(() => this.field().source.params === void 0 ? void 0 : this.tree()().value(), ...ngDevMode ? [{ debugName: "registro" }] : /* istanbul ignore next */ []);
|
|
51
|
+
claveFuente = computed(() => dataSourceKey(this.field().source, this.registro()), ...ngDevMode ? [{ debugName: "claveFuente" }] : /* istanbul ignore next */ []);
|
|
52
|
+
optionsResource = resource({
|
|
53
|
+
...ngDevMode ? { debugName: "optionsResource" } : /* istanbul ignore next */ {},
|
|
54
|
+
params: () => this.claveFuente(),
|
|
55
|
+
loader: async () => this.ds.rows(this.field().source, this.registro())
|
|
56
|
+
});
|
|
57
|
+
options = computed(() => this.optionsResource.status() === "error" ? [] : optionsFromRows(this.optionsResource.value() ?? [], {
|
|
58
|
+
source: this.field().source,
|
|
59
|
+
target: this.targetSchema(),
|
|
60
|
+
onlyActive: this.field().onlyActive,
|
|
61
|
+
secondaryField: this.field().secondaryField
|
|
62
|
+
}), ...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
|
|
63
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
64
|
+
minVersion: "12.0.0",
|
|
65
|
+
version: "22.2.3",
|
|
66
|
+
ngImport: i0,
|
|
67
|
+
type: FieldRelation,
|
|
68
|
+
deps: [],
|
|
69
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
70
|
+
});
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
72
|
+
minVersion: "17.0.0",
|
|
73
|
+
version: "22.2.3",
|
|
74
|
+
type: FieldRelation,
|
|
75
|
+
isStandalone: true,
|
|
76
|
+
selector: "app-field-relation",
|
|
77
|
+
inputs: {
|
|
78
|
+
field: {
|
|
79
|
+
classPropertyName: "field",
|
|
80
|
+
publicName: "field",
|
|
81
|
+
isSignal: true,
|
|
82
|
+
isRequired: true,
|
|
83
|
+
transformFunction: null
|
|
84
|
+
},
|
|
85
|
+
tree: {
|
|
86
|
+
classPropertyName: "tree",
|
|
87
|
+
publicName: "tree",
|
|
88
|
+
isSignal: true,
|
|
89
|
+
isRequired: true,
|
|
90
|
+
transformFunction: null
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
ngImport: i0,
|
|
94
|
+
template: `
|
|
95
|
+
@switch (optionsResource.status()) {
|
|
96
|
+
@case ('loading') {
|
|
97
|
+
<!-- El output es labelable: el for del label del host sigue teniendo
|
|
98
|
+
ancla, y como ya es live region anuncia la carga. El skeleton
|
|
99
|
+
reemplaza al texto con animate-pulse (plan 6.7). -->
|
|
100
|
+
<output class="block" [id]="state().name()" aria-busy="true">
|
|
101
|
+
<app-skeleton [lines]="1" [height]="40" />
|
|
102
|
+
<span class="sr-only">Cargando opciones…</span>
|
|
103
|
+
</output>
|
|
104
|
+
}
|
|
105
|
+
@case ('error') {
|
|
106
|
+
<!-- Output en vez de un párrafo: es labelable (el label del host
|
|
107
|
+
tiene ancla) y ya es live region, así que con role=alert el
|
|
108
|
+
fallo de carga se anuncia sin repetir el texto en otro nodo. -->
|
|
109
|
+
<output class="field-input block text-danger" [id]="state().name()" role="alert">
|
|
110
|
+
No se pudieron cargar las opciones.
|
|
111
|
+
</output>
|
|
112
|
+
}
|
|
113
|
+
@default {
|
|
114
|
+
@if (useSearch()) {
|
|
115
|
+
<!-- Guía §1: más de 7 opciones → dropdown con búsqueda. El filtro
|
|
116
|
+
no reemplaza al select, lo acota; así el teclado y el valor
|
|
117
|
+
elegido siguen funcionando igual. -->
|
|
118
|
+
<input
|
|
119
|
+
type="search"
|
|
120
|
+
class="mb-1 w-full rounded-lg border border-neutral/30 bg-surface px-2 py-1 text-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
|
|
121
|
+
placeholder="Buscar…"
|
|
122
|
+
aria-label="Buscar entre las opciones"
|
|
123
|
+
[attr.aria-controls]="state().name()"
|
|
124
|
+
[value]="query()"
|
|
125
|
+
(input)="onQuery($event)"
|
|
126
|
+
/>
|
|
127
|
+
}
|
|
128
|
+
<select class="field-input" [id]="state().name()" [formField]="node()">
|
|
129
|
+
@if (!field().required) {
|
|
130
|
+
<option value="">{{ field().placeholder ?? '— Seleccionar —' }}</option>
|
|
131
|
+
}
|
|
132
|
+
@for (option of visibleOptions(); track option.value) {
|
|
133
|
+
<option [value]="option.value">{{ option.label }}</option>
|
|
134
|
+
}
|
|
135
|
+
</select>
|
|
136
|
+
@if (noMatches()) {
|
|
137
|
+
<p class="mt-1 text-xs text-neutral" role="status">
|
|
138
|
+
Sin resultados para «{{ query() }}».
|
|
139
|
+
</p>
|
|
140
|
+
} @else if (options().length === 0) {
|
|
141
|
+
<p class="mt-1 text-xs text-neutral">Sin opciones disponibles.</p>
|
|
142
|
+
}
|
|
143
|
+
@if (targetSchema() !== undefined && canCreate()) {
|
|
144
|
+
<!-- Un <option> no puede contener un botón: la acción va justo
|
|
145
|
+
debajo del control, pegada al dropdown. -->
|
|
146
|
+
<button
|
|
147
|
+
app-button
|
|
148
|
+
variant="ghost"
|
|
149
|
+
type="button"
|
|
150
|
+
class="mt-1 -ml-2"
|
|
151
|
+
(click)="requestCreate()"
|
|
152
|
+
>
|
|
153
|
+
<svg lucidePlus size="16" />
|
|
154
|
+
Crear nuevo
|
|
155
|
+
</button>
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
`,
|
|
160
|
+
isInline: true,
|
|
161
|
+
dependencies: [
|
|
162
|
+
{
|
|
163
|
+
kind: "component",
|
|
164
|
+
type: Button,
|
|
165
|
+
selector: "button[app-button]",
|
|
166
|
+
inputs: [
|
|
167
|
+
"variant",
|
|
168
|
+
"size",
|
|
169
|
+
"type",
|
|
170
|
+
"disabled",
|
|
171
|
+
"loading"
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
kind: "directive",
|
|
176
|
+
type: FieldAria,
|
|
177
|
+
selector: "input[id], select[id], textarea[id], output[id]"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
kind: "directive",
|
|
181
|
+
type: FormField,
|
|
182
|
+
selector: "[formField]",
|
|
183
|
+
inputs: ["formField"],
|
|
184
|
+
exportAs: ["formField"]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
kind: "component",
|
|
188
|
+
type: LucidePlus,
|
|
189
|
+
selector: "svg[lucidePlus]"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
kind: "component",
|
|
193
|
+
type: Skeleton,
|
|
194
|
+
selector: "app-skeleton",
|
|
195
|
+
inputs: [
|
|
196
|
+
"lines",
|
|
197
|
+
"height",
|
|
198
|
+
"width"
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
205
|
+
minVersion: "12.0.0",
|
|
206
|
+
version: "22.2.3",
|
|
207
|
+
ngImport: i0,
|
|
208
|
+
type: FieldRelation,
|
|
209
|
+
decorators: [{
|
|
210
|
+
type: Component,
|
|
211
|
+
args: [{
|
|
212
|
+
selector: "app-field-relation",
|
|
213
|
+
imports: [
|
|
214
|
+
Button,
|
|
215
|
+
FieldAria,
|
|
216
|
+
FormField,
|
|
217
|
+
LucidePlus,
|
|
218
|
+
Skeleton
|
|
219
|
+
],
|
|
220
|
+
template: `
|
|
221
|
+
@switch (optionsResource.status()) {
|
|
222
|
+
@case ('loading') {
|
|
223
|
+
<!-- El output es labelable: el for del label del host sigue teniendo
|
|
224
|
+
ancla, y como ya es live region anuncia la carga. El skeleton
|
|
225
|
+
reemplaza al texto con animate-pulse (plan 6.7). -->
|
|
226
|
+
<output class="block" [id]="state().name()" aria-busy="true">
|
|
227
|
+
<app-skeleton [lines]="1" [height]="40" />
|
|
228
|
+
<span class="sr-only">Cargando opciones…</span>
|
|
229
|
+
</output>
|
|
230
|
+
}
|
|
231
|
+
@case ('error') {
|
|
232
|
+
<!-- Output en vez de un párrafo: es labelable (el label del host
|
|
233
|
+
tiene ancla) y ya es live region, así que con role=alert el
|
|
234
|
+
fallo de carga se anuncia sin repetir el texto en otro nodo. -->
|
|
235
|
+
<output class="field-input block text-danger" [id]="state().name()" role="alert">
|
|
236
|
+
No se pudieron cargar las opciones.
|
|
237
|
+
</output>
|
|
238
|
+
}
|
|
239
|
+
@default {
|
|
240
|
+
@if (useSearch()) {
|
|
241
|
+
<!-- Guía §1: más de 7 opciones → dropdown con búsqueda. El filtro
|
|
242
|
+
no reemplaza al select, lo acota; así el teclado y el valor
|
|
243
|
+
elegido siguen funcionando igual. -->
|
|
244
|
+
<input
|
|
245
|
+
type="search"
|
|
246
|
+
class="mb-1 w-full rounded-lg border border-neutral/30 bg-surface px-2 py-1 text-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
|
|
247
|
+
placeholder="Buscar…"
|
|
248
|
+
aria-label="Buscar entre las opciones"
|
|
249
|
+
[attr.aria-controls]="state().name()"
|
|
250
|
+
[value]="query()"
|
|
251
|
+
(input)="onQuery($event)"
|
|
252
|
+
/>
|
|
253
|
+
}
|
|
254
|
+
<select class="field-input" [id]="state().name()" [formField]="node()">
|
|
255
|
+
@if (!field().required) {
|
|
256
|
+
<option value="">{{ field().placeholder ?? '— Seleccionar —' }}</option>
|
|
257
|
+
}
|
|
258
|
+
@for (option of visibleOptions(); track option.value) {
|
|
259
|
+
<option [value]="option.value">{{ option.label }}</option>
|
|
260
|
+
}
|
|
261
|
+
</select>
|
|
262
|
+
@if (noMatches()) {
|
|
263
|
+
<p class="mt-1 text-xs text-neutral" role="status">
|
|
264
|
+
Sin resultados para «{{ query() }}».
|
|
265
|
+
</p>
|
|
266
|
+
} @else if (options().length === 0) {
|
|
267
|
+
<p class="mt-1 text-xs text-neutral">Sin opciones disponibles.</p>
|
|
268
|
+
}
|
|
269
|
+
@if (targetSchema() !== undefined && canCreate()) {
|
|
270
|
+
<!-- Un <option> no puede contener un botón: la acción va justo
|
|
271
|
+
debajo del control, pegada al dropdown. -->
|
|
272
|
+
<button
|
|
273
|
+
app-button
|
|
274
|
+
variant="ghost"
|
|
275
|
+
type="button"
|
|
276
|
+
class="mt-1 -ml-2"
|
|
277
|
+
(click)="requestCreate()"
|
|
278
|
+
>
|
|
279
|
+
<svg lucidePlus size="16" />
|
|
280
|
+
Crear nuevo
|
|
281
|
+
</button>
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
`
|
|
286
|
+
}]
|
|
287
|
+
}],
|
|
288
|
+
propDecorators: {
|
|
289
|
+
field: [{
|
|
290
|
+
type: i0.Input,
|
|
291
|
+
args: [{
|
|
292
|
+
isSignal: true,
|
|
293
|
+
alias: "field",
|
|
294
|
+
required: true
|
|
295
|
+
}]
|
|
296
|
+
}],
|
|
297
|
+
tree: [{
|
|
298
|
+
type: i0.Input,
|
|
299
|
+
args: [{
|
|
300
|
+
isSignal: true,
|
|
301
|
+
alias: "tree",
|
|
302
|
+
required: true
|
|
303
|
+
}]
|
|
304
|
+
}]
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
export { FieldRelation };
|
|
308
|
+
|
|
309
|
+
//# sourceMappingURL=tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/fields/relation/relation.ts"],"sourcesContent":["import { Component, computed, inject, input, resource, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\n\nimport { LucidePlus } from '@lucide/angular';\n\nimport type { RelationField, SelectOption } from '../../core/models/schema.model';\nimport { DataSourceService, dataSourceKey } from '../../core/services/data-source.service';\nimport { RelationDrawerService } from '../../core/services/relation-drawer.service';\nimport { optionsFromRows } from '../../core/utils/source-options';\nimport { Button } from '../../shared/components/button/button';\nimport { getSchema } from '../../core/registry/schema-catalog';\nimport { Skeleton } from '../../shared/components/skeleton/skeleton';\nimport { FieldAria } from '../field-aria';\nimport { childTree, type RootTree } from '../field-node';\n\n/**\n * Referencia a otro recurso (base.md §5.2): `<select>` con opciones del\n * listado del recurso destino, cargadas desde `field.source` (F8 · R6.5).\n *\n * La vuelta no la arma este componente: pasa por `DataSourceService`, que\n * centraliza la caché por `resource+view+params`. El `resource()` de Angular\n * de acá sólo aporta el estado (loading/error/recarga), y su `params` es la\n * clave de la fuente ya interpolada — así una relación con `params`\n * dependientes del formulario se recarga cuando cambia el dato, y una sin\n * `params` no se entera de las teclas.\n *\n * Más de 7 opciones → búsqueda encima del select (plan 6.1, guía §1). Se\n * filtra un `<select>` nativo y no se construye un combobox propio: conserva\n * la navegación con teclado del navegador, el valor seleccionado visible y\n * la lista de opciones accesible sin gestionar `aria-activedescendant`.\n */\n@Component({\n selector: 'app-field-relation',\n imports: [Button, FieldAria, FormField, LucidePlus, Skeleton],\n template: `\n @switch (optionsResource.status()) {\n @case ('loading') {\n <!-- El output es labelable: el for del label del host sigue teniendo\n ancla, y como ya es live region anuncia la carga. El skeleton\n reemplaza al texto con animate-pulse (plan 6.7). -->\n <output class=\"block\" [id]=\"state().name()\" aria-busy=\"true\">\n <app-skeleton [lines]=\"1\" [height]=\"40\" />\n <span class=\"sr-only\">Cargando opciones…</span>\n </output>\n }\n @case ('error') {\n <!-- Output en vez de un párrafo: es labelable (el label del host\n tiene ancla) y ya es live region, así que con role=alert el\n fallo de carga se anuncia sin repetir el texto en otro nodo. -->\n <output class=\"field-input block text-danger\" [id]=\"state().name()\" role=\"alert\">\n No se pudieron cargar las opciones.\n </output>\n }\n @default {\n @if (useSearch()) {\n <!-- Guía §1: más de 7 opciones → dropdown con búsqueda. El filtro\n no reemplaza al select, lo acota; así el teclado y el valor\n elegido siguen funcionando igual. -->\n <input\n type=\"search\"\n class=\"mb-1 w-full rounded-lg border border-neutral/30 bg-surface px-2 py-1 text-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n placeholder=\"Buscar…\"\n aria-label=\"Buscar entre las opciones\"\n [attr.aria-controls]=\"state().name()\"\n [value]=\"query()\"\n (input)=\"onQuery($event)\"\n />\n }\n <select class=\"field-input\" [id]=\"state().name()\" [formField]=\"node()\">\n @if (!field().required) {\n <option value=\"\">{{ field().placeholder ?? '— Seleccionar —' }}</option>\n }\n @for (option of visibleOptions(); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n @if (noMatches()) {\n <p class=\"mt-1 text-xs text-neutral\" role=\"status\">\n Sin resultados para «{{ query() }}».\n </p>\n } @else if (options().length === 0) {\n <p class=\"mt-1 text-xs text-neutral\">Sin opciones disponibles.</p>\n }\n @if (targetSchema() !== undefined && canCreate()) {\n <!-- Un <option> no puede contener un botón: la acción va justo\n debajo del control, pegada al dropdown. -->\n <button\n app-button\n variant=\"ghost\"\n type=\"button\"\n class=\"mt-1 -ml-2\"\n (click)=\"requestCreate()\"\n >\n <svg lucidePlus size=\"16\" />\n Crear nuevo\n </button>\n }\n }\n }\n `,\n})\nexport class FieldRelation {\n readonly field = input.required<RelationField>();\n readonly tree = input.required<RootTree>();\n\n private readonly ds = inject(DataSourceService);\n private readonly drawer = inject(RelationDrawerService);\n\n protected readonly node = computed(() => childTree<string>(this.tree(), this.field().key));\n protected readonly state = computed(() => this.node()());\n\n /** Texto escrito en el buscador (sólo se usa si supera el umbral). */\n protected readonly query = signal('');\n\n protected readonly targetSchema = computed(() => getSchema(this.field().source.resource));\n\n protected readonly canCreate = computed(() => this.targetSchema()?.permissions?.create !== false);\n\n /** Umbral de la guía §1: 5–7 opciones dropdown simple, más de 7 con búsqueda. */\n protected readonly useSearch = computed(() => this.options().length > 7);\n\n protected onQuery(event: Event): void {\n this.query.set((event.target as HTMLInputElement).value);\n }\n\n /**\n * Opciones que coinciden con el término de búsqueda, SIN conservar la\n * elegida. Es la base del mensaje «Sin resultados».\n */\n protected readonly matches = computed<SelectOption[]>(() => {\n const all = this.options();\n const term = this.query().trim().toLowerCase();\n if (term === '') {\n return all;\n }\n return all.filter((option) => option.label.toLowerCase().includes(term));\n });\n\n /** El buscador está activo y no encontró nada nuevo (el elegido no cuenta). */\n protected readonly noMatches = computed(\n () => this.useSearch() && this.query().trim() !== '' && this.matches().length === 0,\n );\n\n /**\n * Opciones que se dibujan. Con búsqueda activa se acotan por etiqueta,\n * PERO la opción elegida se conserva siempre: si desapareciera del DOM el\n * select dejaría de mostrar el valor actual (guía §1: «valor seleccionado\n * siempre visible»). Por eso no se dibuja a partir de `matches`.\n */\n protected readonly visibleOptions = computed<SelectOption[]>(() => {\n const filtered = this.matches();\n if (this.query().trim() === '') {\n return filtered;\n }\n const selected = String(this.state().value() ?? '');\n if (filtered.some((option) => option.value === selected)) {\n return filtered;\n }\n const kept = this.options().find((option) => option.value === selected);\n return kept === undefined ? filtered : [...filtered, kept];\n });\n\n /**\n * Pide el panel de «Crear nuevo». El servicio guarda el callback que, al\n * confirmarse la creación, recarga las opciones y preselecciona la clave.\n */\n protected requestCreate(): void {\n const resource = this.field().source.resource;\n this.drawer.open(resource, (key) => {\n // La fila nueva todavía no está en la caché compartida: sin este\n // `invalidate` la recarga devolvería la lista vieja (F8 · R6.5).\n this.ds.invalidate(resource);\n this.optionsResource.reload();\n // Se setea DESPUÉS de pedir la recarga: si la opción todavía no está\n // en el DOM el select mostraría vacío, y al llegar se reengancha sola\n // (visibleOptions conserva la elegida aunque el filtro la oculte).\n this.node()().value.set(key);\n });\n }\n\n /**\n * Registro del formulario, sólo para resolver `{campo}` en `source.params`.\n *\n * Si la fuente no declara parámetros el registro NO se lee: la relación\n * no depende del formulario y no se recalcula con cada tecla.\n */\n private readonly registro = computed<Record<string, unknown> | undefined>(() =>\n this.field().source.params === undefined ? undefined : this.tree()().value(),\n );\n\n /** Clave de la fuente ya interpolada: es lo que `resource` compara. */\n private readonly claveFuente = computed(() =>\n dataSourceKey(this.field().source, this.registro()),\n );\n\n /**\n * Carga de las opciones. `resource()` sólo aporta estado (loading/error/\n * recarga): la vuelta y la caché son del `DataSourceService`, que así\n * comparte filas con el resto de consumidores de la misma fuente.\n */\n private readonly optionsResource = resource({\n params: () => this.claveFuente(),\n loader: async () => this.ds.rows(this.field().source, this.registro()),\n });\n\n /**\n * Opciones (F8): filas de la fuente declarada → `SelectOption`.\n *\n * El `@switch` del template sólo entra en `default` cuando no hubo fallo,\n * pero el estado se mira acá también: `value()` del resource TIRA en\n * estado error (contract de Angular) y un computed que se evalúe por otra\n * vía tiraría el render entero.\n */\n protected readonly options = computed<SelectOption[]>(() =>\n this.optionsResource.status() === 'error'\n ? []\n : optionsFromRows(this.optionsResource.value() ?? [], {\n source: this.field().source,\n target: this.targetSchema(),\n onlyActive: this.field().onlyActive,\n secondaryField: this.field().secondaryField,\n }),\n );\n}\n"],"mappings":"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"}
|