@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
- package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
- package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
- package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +1027 -0
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
- package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +101 -0
- package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +88 -0
- package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
- package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +122 -0
- package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
- package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +45 -0
- package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
- package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +408 -0
- package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs +4516 -0
- package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
- package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
- package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
- package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +416 -0
- package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +439 -0
- package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
- package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs +637 -0
- package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
- package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +251 -0
- package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
- package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
- package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
- package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
- package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
- package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
- package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
- package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +309 -0
- package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs +576 -0
- package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +161 -0
- package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +685 -0
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs +80 -0
- package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +296 -0
- package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
- package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
- package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
- package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
- package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
- package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
- package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
- package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
- package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +60 -0
- package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
- package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs +4738 -0
- package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
- package/package.json +15 -3
- package/types/tinya-code-gas-admin-ui.d.ts +3634 -0
- package/ng-package.json +0 -7
- package/src/lib/actions/action-registry.spec.ts +0 -52
- package/src/lib/actions/action-registry.ts +0 -126
- package/src/lib/actions/action-service.spec.ts +0 -215
- package/src/lib/actions/action-service.ts +0 -87
- package/src/lib/actions/descriptors.spec.ts +0 -155
- package/src/lib/actions/descriptors.ts +0 -154
- package/src/lib/columns/column-cell.ts +0 -33
- package/src/lib/columns/column-defaults.spec.ts +0 -99
- package/src/lib/columns/column-defaults.ts +0 -84
- package/src/lib/columns/column-format.spec.ts +0 -274
- package/src/lib/columns/descriptors.ts +0 -113
- package/src/lib/columns/format-badge.ts +0 -51
- package/src/lib/columns/format-boolean.ts +0 -58
- package/src/lib/columns/format-currency.ts +0 -30
- package/src/lib/columns/format-date.ts +0 -35
- package/src/lib/columns/format-number.ts +0 -32
- package/src/lib/columns/format-text.ts +0 -23
- package/src/lib/columns/format-thumbnail.ts +0 -63
- package/src/lib/core/adapters/firebase-auth.adapter.ts +0 -6
- package/src/lib/core/guards/auth.guard.spec.ts +0 -88
- package/src/lib/core/guards/auth.guard.ts +0 -48
- package/src/lib/core/guards/unsaved-changes.guard.ts +0 -16
- package/src/lib/core/interceptors/api-error.interceptor.spec.ts +0 -182
- package/src/lib/core/interceptors/api-error.interceptor.ts +0 -87
- package/src/lib/core/models/api.model.ts +0 -104
- package/src/lib/core/models/schema-descriptions.ts +0 -118
- package/src/lib/core/models/schema.model.ts +0 -1097
- package/src/lib/core/registry/composition-validator.spec.ts +0 -358
- package/src/lib/core/registry/composition-validator.ts +0 -270
- package/src/lib/core/registry/field-validators.spec.ts +0 -199
- package/src/lib/core/registry/field-validators.ts +0 -440
- package/src/lib/core/registry/render-host.spec.ts +0 -208
- package/src/lib/core/registry/render-host.ts +0 -646
- package/src/lib/core/registry/render-registry.spec.ts +0 -96
- package/src/lib/core/registry/render-registry.ts +0 -312
- package/src/lib/core/registry/schema-catalog.ts +0 -156
- package/src/lib/core/services/api.service.spec.ts +0 -1142
- package/src/lib/core/services/api.service.ts +0 -371
- package/src/lib/core/services/auth.service.spec.ts +0 -653
- package/src/lib/core/services/auth.service.ts +0 -503
- package/src/lib/core/services/config.service.spec.ts +0 -121
- package/src/lib/core/services/config.service.ts +0 -119
- package/src/lib/core/services/data-source.service.spec.ts +0 -179
- package/src/lib/core/services/data-source.service.ts +0 -142
- package/src/lib/core/services/error-mapper.service.spec.ts +0 -50
- package/src/lib/core/services/error-mapper.service.ts +0 -49
- package/src/lib/core/services/notification.service.ts +0 -73
- package/src/lib/core/services/relation-drawer.service.ts +0 -41
- package/src/lib/core/services/theme.service.spec.ts +0 -106
- package/src/lib/core/services/theme.service.ts +0 -86
- package/src/lib/core/services/transport.spec.ts +0 -198
- package/src/lib/core/services/transport.ts +0 -164
- package/src/lib/core/services/upload.service.ts +0 -81
- package/src/lib/core/testing/categories.schema.ts +0 -125
- package/src/lib/core/testing/orders.schema.ts +0 -372
- package/src/lib/core/testing/products.schema.ts +0 -258
- package/src/lib/core/testing/site.schema.ts +0 -195
- package/src/lib/core/testing/test-catalog.ts +0 -21
- package/src/lib/core/tokens.ts +0 -112
- package/src/lib/core/utils/clipboard.spec.ts +0 -55
- package/src/lib/core/utils/clipboard.ts +0 -90
- package/src/lib/core/utils/context-resolver.spec.ts +0 -95
- package/src/lib/core/utils/context-resolver.ts +0 -101
- package/src/lib/core/utils/response-unwrapper.spec.ts +0 -70
- package/src/lib/core/utils/response-unwrapper.ts +0 -103
- package/src/lib/core/utils/source-options.spec.ts +0 -96
- package/src/lib/core/utils/source-options.ts +0 -54
- package/src/lib/core/utils/template-interpolator.spec.ts +0 -59
- package/src/lib/core/utils/template-interpolator.ts +0 -56
- package/src/lib/core/view-navigation/view-navigation.service.spec.ts +0 -207
- package/src/lib/core/view-navigation/view-navigation.service.ts +0 -132
- package/src/lib/fields/boolean/boolean.descriptor.ts +0 -11
- package/src/lib/fields/boolean/boolean.ts +0 -40
- package/src/lib/fields/color/color.descriptor.ts +0 -12
- package/src/lib/fields/color/color.ts +0 -34
- package/src/lib/fields/currency/currency.descriptor.ts +0 -12
- package/src/lib/fields/currency/currency.ts +0 -67
- package/src/lib/fields/date/date.descriptor.ts +0 -12
- package/src/lib/fields/date/date.ts +0 -36
- package/src/lib/fields/descriptors.ts +0 -122
- package/src/lib/fields/display/display-badge.ts +0 -65
- package/src/lib/fields/display/display-date.ts +0 -39
- package/src/lib/fields/display/display-defaults.ts +0 -84
- package/src/lib/fields/display/display-file.ts +0 -41
- package/src/lib/fields/display/display-image.ts +0 -54
- package/src/lib/fields/display/display-list.ts +0 -107
- package/src/lib/fields/display/display-number.ts +0 -41
- package/src/lib/fields/display/display-text.ts +0 -42
- package/src/lib/fields/display/display.spec.ts +0 -242
- package/src/lib/fields/dropdown/dropdown.descriptor.ts +0 -12
- package/src/lib/fields/dropdown/dropdown.ts +0 -45
- package/src/lib/fields/email/email.descriptor.ts +0 -12
- package/src/lib/fields/email/email.ts +0 -28
- package/src/lib/fields/field-aria.ts +0 -60
- package/src/lib/fields/field-host/field-host.spec.ts +0 -118
- package/src/lib/fields/field-host/field-host.ts +0 -47
- package/src/lib/fields/field-node.ts +0 -88
- package/src/lib/fields/file/file.descriptor.ts +0 -14
- package/src/lib/fields/file/file.spec.ts +0 -134
- package/src/lib/fields/file/file.ts +0 -281
- package/src/lib/fields/group/group.descriptor.ts +0 -21
- package/src/lib/fields/group/group.ts +0 -110
- package/src/lib/fields/image/image.descriptor.ts +0 -12
- package/src/lib/fields/image/image.spec.ts +0 -117
- package/src/lib/fields/image/image.ts +0 -281
- package/src/lib/fields/key-value/key-value.descriptor.ts +0 -11
- package/src/lib/fields/key-value/key-value.ts +0 -283
- package/src/lib/fields/list/list.descriptor.ts +0 -21
- package/src/lib/fields/list/list.ts +0 -376
- package/src/lib/fields/multiselect/multiselect.descriptor.ts +0 -11
- package/src/lib/fields/multiselect/multiselect.spec.ts +0 -142
- package/src/lib/fields/multiselect/multiselect.ts +0 -152
- package/src/lib/fields/number/number.descriptor.ts +0 -12
- package/src/lib/fields/number/number.ts +0 -40
- package/src/lib/fields/phone/phone.descriptor.ts +0 -12
- package/src/lib/fields/phone/phone.ts +0 -46
- package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +0 -12
- package/src/lib/fields/readonly-text/readonly-text.ts +0 -58
- package/src/lib/fields/relation/relation.descriptor.ts +0 -12
- package/src/lib/fields/relation/relation.spec.ts +0 -193
- package/src/lib/fields/relation/relation.ts +0 -224
- package/src/lib/fields/rich-select/rich-select.descriptor.ts +0 -12
- package/src/lib/fields/rich-select/rich-select.ts +0 -175
- package/src/lib/fields/select/radio-mode.ts +0 -25
- package/src/lib/fields/select/select.descriptor.ts +0 -12
- package/src/lib/fields/select/select.spec.ts +0 -162
- package/src/lib/fields/select/select.ts +0 -210
- package/src/lib/fields/slug/slug.descriptor.ts +0 -19
- package/src/lib/fields/slug/slug.ts +0 -67
- package/src/lib/fields/string-list/string-list.descriptor.ts +0 -11
- package/src/lib/fields/string-list/string-list.ts +0 -222
- package/src/lib/fields/text/text.descriptor.ts +0 -12
- package/src/lib/fields/text/text.ts +0 -35
- package/src/lib/fields/textarea/textarea.descriptor.ts +0 -12
- package/src/lib/fields/textarea/textarea.spec.ts +0 -117
- package/src/lib/fields/textarea/textarea.ts +0 -126
- package/src/lib/fields/time/time.descriptor.ts +0 -12
- package/src/lib/fields/time/time.ts +0 -28
- package/src/lib/fields/unknown-render/unknown-render.ts +0 -49
- package/src/lib/fields/url/url.descriptor.ts +0 -12
- package/src/lib/fields/url/url.ts +0 -53
- package/src/lib/gas-admin-ui.spec.ts +0 -21
- package/src/lib/gas-admin-ui.ts +0 -9
- package/src/lib/layouts/descriptors.ts +0 -9
- package/src/lib/pages/dashboard/dashboard.ts +0 -167
- package/src/lib/pages/detail-view/detail-view.spec.ts +0 -333
- package/src/lib/pages/detail-view/detail-view.ts +0 -570
- package/src/lib/pages/drawer-form/drawer-form.ts +0 -228
- package/src/lib/pages/form-view/form-model.ts +0 -88
- package/src/lib/pages/form-view/form-schema.ts +0 -255
- package/src/lib/pages/form-view/form-view.ts +0 -1622
- package/src/lib/pages/list-view/list-view.formats.spec.ts +0 -214
- package/src/lib/pages/list-view/list-view.ts +0 -882
- package/src/lib/pages/login/login.spec.ts +0 -109
- package/src/lib/pages/login/login.ts +0 -227
- package/src/lib/pages/resource-page/resource-page.ts +0 -234
- package/src/lib/shared/components/badge/badge.ts +0 -35
- package/src/lib/shared/components/button/button.ts +0 -65
- package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +0 -48
- package/src/lib/shared/components/copy-button/copy-button.ts +0 -56
- package/src/lib/shared/components/copy-share/copy-share.spec.ts +0 -122
- package/src/lib/shared/components/copy-share/copy-share.ts +0 -107
- package/src/lib/shared/components/drawer/drawer.spec.ts +0 -127
- package/src/lib/shared/components/drawer/drawer.ts +0 -172
- package/src/lib/shared/components/empty-state/empty-state.ts +0 -30
- package/src/lib/shared/components/modal/modal.spec.ts +0 -149
- package/src/lib/shared/components/modal/modal.ts +0 -145
- package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +0 -165
- package/src/lib/shared/components/post-create-modal/post-create-modal.ts +0 -159
- package/src/lib/shared/components/skeleton/skeleton.ts +0 -31
- package/src/lib/shared/components/toast/toast.ts +0 -58
- package/src/lib/shared/utils/col-span.ts +0 -25
- package/src/lib/shared/utils/condition-evaluator.ts +0 -53
- package/src/lib/shared/utils/depends-on.ts +0 -48
- package/src/lib/shared/utils/dialog-focus.ts +0 -28
- package/src/lib/shared/utils/field-path.ts +0 -49
- package/src/lib/shared/utils/gap-sorting.ts +0 -144
- package/src/lib/shared/utils/seed.spec.ts +0 -64
- package/src/lib/shared/utils/seed.ts +0 -149
- package/src/lib/shared/utils/slugify.ts +0 -13
- package/src/lib/shared/utils/validators.ts +0 -41
- package/src/lib/shell/layout/layout.ts +0 -63
- package/src/lib/shell/shell.routes.spec.ts +0 -59
- package/src/lib/shell/shell.routes.ts +0 -122
- package/src/lib/shell/sidebar/sidebar.ts +0 -139
- package/src/lib/shell/theme-toggle/theme-toggle.ts +0 -74
- package/src/lib/views/calendar-view/calendar-model.ts +0 -426
- package/src/lib/views/calendar-view/calendar-view.spec.ts +0 -557
- package/src/lib/views/calendar-view/calendar-view.ts +0 -568
- package/src/lib/views/composer/composer-host.spec.ts +0 -301
- package/src/lib/views/composer/composer-host.ts +0 -248
- package/src/lib/views/composer/composer-imports.spec.ts +0 -54
- package/src/lib/views/composer/view-context.spec.ts +0 -117
- package/src/lib/views/composer/view-context.ts +0 -109
- package/src/lib/views/composer/view-slot.spec.ts +0 -130
- package/src/lib/views/composer/view-slot.ts +0 -178
- package/src/lib/views/descriptors.ts +0 -46
- package/src/lib/views/kanban-view/kanban-model.ts +0 -173
- package/src/lib/views/kanban-view/kanban-view.spec.ts +0 -540
- package/src/lib/views/kanban-view/kanban-view.ts +0 -327
- package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +0 -17
- package/src/lib/widgets/bar-chart/bar-chart.spec.ts +0 -66
- package/src/lib/widgets/bar-chart/bar-chart.ts +0 -76
- package/src/lib/widgets/chart-line/chart-line.descriptor.ts +0 -17
- package/src/lib/widgets/chart-line/chart-line.spec.ts +0 -113
- package/src/lib/widgets/chart-line/chart-line.ts +0 -219
- package/src/lib/widgets/descriptors.ts +0 -29
- package/src/lib/widgets/metric-card/metric-card.descriptor.ts +0 -41
- package/src/lib/widgets/metric-card/metric-card.spec.ts +0 -52
- package/src/lib/widgets/metric-card/metric-card.ts +0 -48
- package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +0 -13
- package/src/lib/widgets/quick-actions/quick-actions.spec.ts +0 -61
- package/src/lib/widgets/quick-actions/quick-actions.ts +0 -100
- package/src/lib/widgets/record-list/record-list.descriptor.ts +0 -16
- package/src/lib/widgets/record-list/record-list.spec.ts +0 -79
- package/src/lib/widgets/record-list/record-list.ts +0 -115
- package/src/lib/widgets/series.spec.ts +0 -42
- package/src/lib/widgets/series.ts +0 -56
- package/src/lib/widgets/status-progress/status-progress.descriptor.ts +0 -19
- package/src/lib/widgets/status-progress/status-progress.spec.ts +0 -63
- package/src/lib/widgets/status-progress/status-progress.ts +0 -104
- package/src/lib/widgets/widget-host/widget-host.spec.ts +0 -179
- package/src/lib/widgets/widget-host/widget-host.ts +0 -99
- package/src/public-api.ts +0 -104
- package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
- package/tsconfig.lib.json +0 -13
- package/tsconfig.lib.prod.json +0 -11
- package/tsconfig.spec.json +0 -10
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { RenderDescriptor, RenderExtras } from '../core/registry/render-registry';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Manifiesto de descriptores de formato de columna (R4.3 · `kind:
|
|
5
|
-
* 'column-format'`).
|
|
6
|
-
*
|
|
7
|
-
* Es el equivalente a `fields/descriptors.ts` y `widgets/descriptors.ts`:
|
|
8
|
-
* una línea por formato y ningún import de componente — cada `load()` guarda
|
|
9
|
-
* el cierre de un `import()` **con literal**, que es lo que permite al
|
|
10
|
-
* bundler partir el chunk; el registro los recoge al importar este módulo
|
|
11
|
-
* (`core/registry/render-registry.ts`).
|
|
12
|
-
*
|
|
13
|
-
* **Añadir un formato** ⇒ crear `format-<nombre>.ts` + una entrada acá.
|
|
14
|
-
* `list-view` no se toca: ése es el criterio de éxito de R4.3.
|
|
15
|
-
*
|
|
16
|
-
* Todos comparten el cableado: el descriptor sólo expone la celda, que la
|
|
17
|
-
* vista cuelga de `extras.data`.
|
|
18
|
-
*/
|
|
19
|
-
const inputs = (_config: unknown, extras: RenderExtras): Record<string, unknown> => ({
|
|
20
|
-
cell: extras.data,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const text: RenderDescriptor = {
|
|
24
|
-
kind: 'column-format',
|
|
25
|
-
type: 'text',
|
|
26
|
-
since: '1.0',
|
|
27
|
-
surfaces: ['list'],
|
|
28
|
-
load: () => import('./format-text').then((module) => module.ColumnFormatText),
|
|
29
|
-
inputs,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const badge: RenderDescriptor = {
|
|
33
|
-
kind: 'column-format',
|
|
34
|
-
type: 'badge',
|
|
35
|
-
since: '1.0',
|
|
36
|
-
surfaces: ['list'],
|
|
37
|
-
load: () => import('./format-badge').then((module) => module.ColumnFormatBadge),
|
|
38
|
-
inputs,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const thumbnail: RenderDescriptor = {
|
|
42
|
-
kind: 'column-format',
|
|
43
|
-
type: 'thumbnail',
|
|
44
|
-
since: '1.0',
|
|
45
|
-
surfaces: ['list'],
|
|
46
|
-
load: () => import('./format-thumbnail').then((module) => module.ColumnFormatThumbnail),
|
|
47
|
-
inputs,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const boolean: RenderDescriptor = {
|
|
51
|
-
kind: 'column-format',
|
|
52
|
-
type: 'boolean',
|
|
53
|
-
since: '1.0',
|
|
54
|
-
surfaces: ['list'],
|
|
55
|
-
load: () => import('./format-boolean').then((module) => module.ColumnFormatBoolean),
|
|
56
|
-
inputs,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const number: RenderDescriptor = {
|
|
60
|
-
kind: 'column-format',
|
|
61
|
-
type: 'number',
|
|
62
|
-
since: '1.0',
|
|
63
|
-
surfaces: ['list'],
|
|
64
|
-
load: () => import('./format-number').then((module) => module.ColumnFormatNumber),
|
|
65
|
-
inputs,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const currency: RenderDescriptor = {
|
|
69
|
-
kind: 'column-format',
|
|
70
|
-
type: 'currency',
|
|
71
|
-
since: '1.0',
|
|
72
|
-
surfaces: ['list'],
|
|
73
|
-
load: () => import('./format-currency').then((module) => module.ColumnFormatCurrency),
|
|
74
|
-
inputs,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const date: RenderDescriptor = {
|
|
78
|
-
kind: 'column-format',
|
|
79
|
-
type: 'date',
|
|
80
|
-
since: '1.0',
|
|
81
|
-
surfaces: ['list'],
|
|
82
|
-
load: () => import('./format-date').then((module) => module.ColumnFormatDate),
|
|
83
|
-
inputs,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/** Los 7 formatos del `@switch` que este registro reemplaza (R4.3). */
|
|
87
|
-
export const columnFormatDescriptors: readonly RenderDescriptor[] = [
|
|
88
|
-
text,
|
|
89
|
-
badge,
|
|
90
|
-
thumbnail,
|
|
91
|
-
boolean,
|
|
92
|
-
number,
|
|
93
|
-
currency,
|
|
94
|
-
date,
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Los 7 nombres, como dato.
|
|
99
|
-
*
|
|
100
|
-
* Va en paralelo a `ListColumnFormat` (unión de `schema.model`) y lo vigila
|
|
101
|
-
* `core/registry/contract.spec.ts`: la unión vive en tipos y el registro en
|
|
102
|
-
* runtime, y sólo un test reconcilia los dos — el mismo tripwire que ya
|
|
103
|
-
* existe para los 20 campos y los 6 widgets.
|
|
104
|
-
*/
|
|
105
|
-
export const COLUMN_FORMAT_TYPES = [
|
|
106
|
-
'text',
|
|
107
|
-
'badge',
|
|
108
|
-
'thumbnail',
|
|
109
|
-
'boolean',
|
|
110
|
-
'number',
|
|
111
|
-
'currency',
|
|
112
|
-
'date',
|
|
113
|
-
] as const;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { Badge, type BadgeKind } from '../shared/components/badge/badge';
|
|
4
|
-
import { resolveBadgeKind } from '../fields/display/display-badge';
|
|
5
|
-
import type { SelectField } from '../core/models/schema.model';
|
|
6
|
-
import { getValue } from '../shared/utils/field-path';
|
|
7
|
-
import type { ColumnCell } from './column-cell';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Formato `badge` (R4.3, afinado en R4.4).
|
|
11
|
-
*
|
|
12
|
-
* Un booleano usa `trueLabel`/`falseLabel` del campo (o «Sí»/«No») con
|
|
13
|
-
* `success`/`danger` — el vocabulario de la lista para el control que
|
|
14
|
-
* permite escribir. El vacío sigue siendo «Sin dato»/`danger`.
|
|
15
|
-
*
|
|
16
|
-
* El resto alinea el chip con el display del detalle (D41): un `select`
|
|
17
|
-
* pinta la **etiqueta** de la opción y los estados se clasifican con
|
|
18
|
-
* `resolveBadgeKind`, el mismo criterio que la cabecera de la ficha —
|
|
19
|
-
* antes, toda columna declarada `badge` salía verde sin mirar el valor.
|
|
20
|
-
*/
|
|
21
|
-
@Component({
|
|
22
|
-
selector: 'app-column-format-badge',
|
|
23
|
-
imports: [Badge],
|
|
24
|
-
template: `<app-badge [label]="badge().label" [kind]="badge().kind" />`,
|
|
25
|
-
})
|
|
26
|
-
export class ColumnFormatBadge {
|
|
27
|
-
readonly cell = input.required<ColumnCell>();
|
|
28
|
-
|
|
29
|
-
protected readonly badge = computed(() => badgeInfo(this.cell()));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function badgeInfo(cell: ColumnCell): { label: string; kind: BadgeKind } {
|
|
33
|
-
const value = getValue(cell.row, cell.column.key);
|
|
34
|
-
const field = cell.fields.find((candidate) => candidate.key === cell.column.key);
|
|
35
|
-
if (typeof value === 'boolean') {
|
|
36
|
-
const label =
|
|
37
|
-
value === true
|
|
38
|
-
? ((field?.type === 'boolean' ? field.trueLabel : undefined) ?? 'Sí')
|
|
39
|
-
: ((field?.type === 'boolean' ? field.falseLabel : undefined) ?? 'No');
|
|
40
|
-
return { label, kind: value ? 'success' : 'danger' };
|
|
41
|
-
}
|
|
42
|
-
const text = value == null ? '' : String(value);
|
|
43
|
-
if (text === '') {
|
|
44
|
-
return { label: 'Sin dato', kind: 'danger' };
|
|
45
|
-
}
|
|
46
|
-
const etiqueta =
|
|
47
|
-
field?.type === 'select'
|
|
48
|
-
? ((field as SelectField).options?.find((option) => option.value === text)?.label ?? text)
|
|
49
|
-
: text;
|
|
50
|
-
return { label: etiqueta, kind: resolveBadgeKind(text) };
|
|
51
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { Badge } from '../shared/components/badge/badge';
|
|
4
|
-
import { getValue } from '../shared/utils/field-path';
|
|
5
|
-
import type { ColumnCell } from './column-cell';
|
|
6
|
-
import { badgeInfo } from './format-badge';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Formato `boolean` (R4.3): interruptor o badge.
|
|
10
|
-
*
|
|
11
|
-
* Es la rama `@case ('boolean')` de `list-view`, con una sola diferencia de
|
|
12
|
-
* domicilio: hoy sólo monta este componente si el formato efectivo ya es
|
|
13
|
-
* `boolean`, así que la comprobación `column.format === 'boolean'` que hacía
|
|
14
|
-
* `isSwitchColumn` sobra. El criterio restante — `active` booleano y con
|
|
15
|
-
* permiso de edición (base.md §10) — vive acá, que es quien dibuja el control.
|
|
16
|
-
*/
|
|
17
|
-
@Component({
|
|
18
|
-
selector: 'app-column-format-boolean',
|
|
19
|
-
imports: [Badge],
|
|
20
|
-
template: `
|
|
21
|
-
@if (esInterruptor()) {
|
|
22
|
-
<input
|
|
23
|
-
type="checkbox"
|
|
24
|
-
class="size-5 cursor-pointer accent-primary"
|
|
25
|
-
[checked]="valor()"
|
|
26
|
-
[disabled]="cell().saving"
|
|
27
|
-
[attr.aria-label]="cell().column.label + ': ' + cell().title"
|
|
28
|
-
(click)="$event.stopPropagation()"
|
|
29
|
-
(change)="alternar($event)"
|
|
30
|
-
/>
|
|
31
|
-
} @else {
|
|
32
|
-
<app-badge [label]="badge().label" [kind]="badge().kind" />
|
|
33
|
-
}
|
|
34
|
-
`,
|
|
35
|
-
})
|
|
36
|
-
export class ColumnFormatBoolean {
|
|
37
|
-
readonly cell = input.required<ColumnCell>();
|
|
38
|
-
|
|
39
|
-
protected readonly badge = computed(() => badgeInfo(this.cell()));
|
|
40
|
-
|
|
41
|
-
protected readonly valor = computed(() => {
|
|
42
|
-
const value = getValue(this.cell().row, this.cell().column.key);
|
|
43
|
-
return value === true || value === 'true';
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/** `active` declarado como boolean en el schema → interruptor (base.md §10). */
|
|
47
|
-
protected readonly esInterruptor = computed(() => {
|
|
48
|
-
const cell = this.cell();
|
|
49
|
-
if (cell.column.key !== 'active' || !cell.canUpdate) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
return cell.fields.some((field) => field.type === 'boolean' && field.key === 'active');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
protected alternar(event: Event): void {
|
|
56
|
-
this.cell().toggle?.((event.target as HTMLInputElement).checked);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { getValue } from '../shared/utils/field-path';
|
|
4
|
-
import type { ColumnCell } from './column-cell';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Formato `currency` (R4.3). Igual que el helper de `list-view`: `es-PE`,
|
|
8
|
-
* moneda tomada del schema (se pasaba desde la vista porque sólo ella la
|
|
9
|
-
* conoce) y texto crudo si el valor no es número.
|
|
10
|
-
*/
|
|
11
|
-
@Component({
|
|
12
|
-
selector: 'app-column-format-currency',
|
|
13
|
-
template: `{{ precio() }}`,
|
|
14
|
-
})
|
|
15
|
-
export class ColumnFormatCurrency {
|
|
16
|
-
readonly cell = input.required<ColumnCell>();
|
|
17
|
-
|
|
18
|
-
protected readonly precio = computed(() => {
|
|
19
|
-
const cell = this.cell();
|
|
20
|
-
const value = getValue(cell.row, cell.column.key);
|
|
21
|
-
const number = Number(value);
|
|
22
|
-
if (!Number.isFinite(number)) {
|
|
23
|
-
return value == null ? '' : String(value);
|
|
24
|
-
}
|
|
25
|
-
return new Intl.NumberFormat('es-PE', {
|
|
26
|
-
style: 'currency',
|
|
27
|
-
currency: cell.currency,
|
|
28
|
-
}).format(number);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { getValue } from '../shared/utils/field-path';
|
|
4
|
-
import type { ColumnCell } from './column-cell';
|
|
5
|
-
|
|
6
|
-
function formatDate(value: unknown): string {
|
|
7
|
-
if (typeof value !== 'string' || value === '') {
|
|
8
|
-
return value == null ? '' : String(value);
|
|
9
|
-
}
|
|
10
|
-
const date = new Date(value);
|
|
11
|
-
if (Number.isNaN(date.getTime())) {
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
// Fechas `YYYY-MM-DD`: forzar UTC para no desfasar un día.
|
|
15
|
-
return date.toLocaleDateString('es-PE', { timeZone: 'UTC' });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Formato `date` (R4.3). Corto (`toLocaleDateString`), a diferencia del
|
|
20
|
-
* display de la ficha, que va con `dateStyle: 'medium'`: cada superficie
|
|
21
|
-
* con su formato, pero ambos desde su propio componente.
|
|
22
|
-
*/
|
|
23
|
-
@Component({
|
|
24
|
-
selector: 'app-column-format-date',
|
|
25
|
-
template: `{{ fecha() }}`,
|
|
26
|
-
})
|
|
27
|
-
export class ColumnFormatDate {
|
|
28
|
-
readonly cell = input.required<ColumnCell>();
|
|
29
|
-
|
|
30
|
-
protected readonly fecha = computed(() => formatDate(this.valor()));
|
|
31
|
-
|
|
32
|
-
private valor(): unknown {
|
|
33
|
-
return getValue(this.cell().row, this.cell().column.key);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { getValue } from '../shared/utils/field-path';
|
|
4
|
-
import type { ColumnCell } from './column-cell';
|
|
5
|
-
|
|
6
|
-
const NUMBER_FORMAT = new Intl.NumberFormat('es-PE');
|
|
7
|
-
|
|
8
|
-
function formatNumber(value: unknown): string {
|
|
9
|
-
const number = Number(value);
|
|
10
|
-
if (!Number.isFinite(number)) {
|
|
11
|
-
return value == null ? '' : String(value);
|
|
12
|
-
}
|
|
13
|
-
return NUMBER_FORMAT.format(number);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Formato `number` (R4.3). Misma fórmula que el helper de `list-view`:
|
|
18
|
-
* miles con separador `es-PE` y texto crudo si el valor no es número.
|
|
19
|
-
*/
|
|
20
|
-
@Component({
|
|
21
|
-
selector: 'app-column-format-number',
|
|
22
|
-
template: `{{ numero() }}`,
|
|
23
|
-
})
|
|
24
|
-
export class ColumnFormatNumber {
|
|
25
|
-
readonly cell = input.required<ColumnCell>();
|
|
26
|
-
|
|
27
|
-
protected readonly numero = computed(() => formatNumber(this.valor()));
|
|
28
|
-
|
|
29
|
-
private valor(): unknown {
|
|
30
|
-
return getValue(this.cell().row, this.cell().column.key);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { getValue } from '../shared/utils/field-path';
|
|
4
|
-
import type { ColumnCell } from './column-cell';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Formato `text` (R4.3 · el `@default` del `@switch` viejo).
|
|
8
|
-
*
|
|
9
|
-
* `cellText` de `list-view`: `null`/`undefined` se pintan vacíos y el resto
|
|
10
|
-
* pasa por `String()` — un objeto sale `[object Object]`, igual que antes.
|
|
11
|
-
*/
|
|
12
|
-
@Component({
|
|
13
|
-
selector: 'app-column-format-text',
|
|
14
|
-
template: `{{ texto() }}`,
|
|
15
|
-
})
|
|
16
|
-
export class ColumnFormatText {
|
|
17
|
-
readonly cell = input.required<ColumnCell>();
|
|
18
|
-
|
|
19
|
-
protected readonly texto = computed(() => {
|
|
20
|
-
const value = getValue(this.cell().row, this.cell().column.key);
|
|
21
|
-
return value == null ? '' : String(value);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Component, computed, input } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
import { getValue } from '../shared/utils/field-path';
|
|
4
|
-
import type { ColumnCell } from './column-cell';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Formato `thumbnail` (R4.3): miniatura de la fila.
|
|
8
|
-
*
|
|
9
|
-
* Tanto `thumbnailSrc` como `thumbnailAlt` se mudan desde `list-view`: la
|
|
10
|
-
* columna puede apuntar a `image_url`, al primer elemento de `images[]` o a
|
|
11
|
-
* un objeto con `image_url`, y el texto alternativo sale del item o de la
|
|
12
|
-
* fila. Sin URL se pinta el `—` de siempre.
|
|
13
|
-
*/
|
|
14
|
-
@Component({
|
|
15
|
-
selector: 'app-column-format-thumbnail',
|
|
16
|
-
template: `
|
|
17
|
-
@if (src(); as url) {
|
|
18
|
-
<img [src]="url" [alt]="alt()" class="size-9 rounded-md object-cover" loading="lazy" />
|
|
19
|
-
} @else {
|
|
20
|
-
<span class="text-neutral" aria-hidden="true">—</span>
|
|
21
|
-
}
|
|
22
|
-
`,
|
|
23
|
-
})
|
|
24
|
-
export class ColumnFormatThumbnail {
|
|
25
|
-
readonly cell = input.required<ColumnCell>();
|
|
26
|
-
|
|
27
|
-
protected readonly src = computed(() => {
|
|
28
|
-
const value = this.valor();
|
|
29
|
-
if (typeof value === 'string') {
|
|
30
|
-
return value !== '' ? value : null;
|
|
31
|
-
}
|
|
32
|
-
if (Array.isArray(value)) {
|
|
33
|
-
const first = value[0];
|
|
34
|
-
const url = typeof first === 'string' ? first : getValue(first, 'image_url');
|
|
35
|
-
return typeof url === 'string' && url !== '' ? url : null;
|
|
36
|
-
}
|
|
37
|
-
if (value && typeof value === 'object') {
|
|
38
|
-
const url = getValue(value, 'image_url');
|
|
39
|
-
return typeof url === 'string' && url !== '' ? url : null;
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
protected readonly alt = computed(() => {
|
|
45
|
-
const value = this.valor();
|
|
46
|
-
let item: unknown = this.cell().row;
|
|
47
|
-
if (Array.isArray(value)) {
|
|
48
|
-
item = value[0] ?? null;
|
|
49
|
-
} else if (value && typeof value === 'object') {
|
|
50
|
-
item = value;
|
|
51
|
-
}
|
|
52
|
-
const alt = item == null ? null : getValue(item, 'image_alt');
|
|
53
|
-
if (typeof alt === 'string' && alt !== '') {
|
|
54
|
-
return alt;
|
|
55
|
-
}
|
|
56
|
-
const rootAlt = this.cell().row['image_alt'];
|
|
57
|
-
return typeof rootAlt === 'string' ? rootAlt : '';
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
private valor(): unknown {
|
|
61
|
-
return getValue(this.cell().row, this.cell().column.key);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Re-exporta `FirebaseAuthAdapter` desde `tokens.ts` (única fuente de verdad).
|
|
3
|
-
* Mantiene este archivo como punto de importación estable para consumidores
|
|
4
|
-
* que ya referencian esta ruta, sin duplicar la definición de la interfaz.
|
|
5
|
-
*/
|
|
6
|
-
export type { FirebaseAuthAdapter } from '../tokens';
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
2
|
-
import { TestBed } from '@angular/core/testing';
|
|
3
|
-
import { ActivatedRouteSnapshot, Router, UrlTree, provideRouter } from '@angular/router';
|
|
4
|
-
|
|
5
|
-
import { API_URL } from '../tokens';
|
|
6
|
-
import { SESSION_TOKEN_KEY, SESSION_USER_KEY } from '../services/auth.service';
|
|
7
|
-
import { authGuard, roleGuard } from './auth.guard';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* R2.10 — guards de sesión (auth.md §5.3).
|
|
11
|
-
*
|
|
12
|
-
* No son una barrera (el back re-verifica desde R2.6): son el filtro de
|
|
13
|
-
* pantalla. Por eso aquí sólo se comprueba HACIA DÓNDE mandan, no qué
|
|
14
|
-
* protegen.
|
|
15
|
-
*/
|
|
16
|
-
describe('authGuard / roleGuard — filtro de pantalla (R2.10)', () => {
|
|
17
|
-
afterEach(() => sessionStorage.clear());
|
|
18
|
-
|
|
19
|
-
/** `role === null` ⇒ sin sesión: no se siembra nada en el storage. */
|
|
20
|
-
function setup(role: string | null = 'admin') {
|
|
21
|
-
sessionStorage.clear();
|
|
22
|
-
if (role !== null) {
|
|
23
|
-
sessionStorage.setItem(SESSION_TOKEN_KEY, 'tok');
|
|
24
|
-
sessionStorage.setItem(SESSION_USER_KEY, JSON.stringify({ id: 'u_1', role }));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
TestBed.configureTestingModule({
|
|
28
|
-
providers: [provideHttpClient(), provideRouter([]), { provide: API_URL, useValue: '/api' }],
|
|
29
|
-
});
|
|
30
|
-
return { authGuard, roleGuard, router: TestBed.inject(Router) };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** `route` mínimo con un solo parámetro de ruta. */
|
|
34
|
-
function routeWithId(id: string | null): ActivatedRouteSnapshot {
|
|
35
|
-
return {
|
|
36
|
-
paramMap: {
|
|
37
|
-
get: (key: string) => (key === 'id' ? id : null),
|
|
38
|
-
},
|
|
39
|
-
} as unknown as ActivatedRouteSnapshot;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const isUrlTree = (r: unknown): r is UrlTree => r instanceof UrlTree;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* El router invoca un guard DENTRO de un contexto de inyección; una llamada
|
|
46
|
-
* directa desde el spec no lo tiene, y `inject(AuthService)` revienta.
|
|
47
|
-
* `runInInjectionContext` reproducía el contexto real del router.
|
|
48
|
-
*/
|
|
49
|
-
function run(guard: typeof authGuard, route: ActivatedRouteSnapshot): boolean | UrlTree {
|
|
50
|
-
const result = TestBed.runInInjectionContext(() => guard(route, {} as never));
|
|
51
|
-
// Los dos guards son síncronos: `MaybeAsync` sólo es ruido de tipos acá.
|
|
52
|
-
return result as boolean | UrlTree;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
it('con sesión deja pasar', () => {
|
|
56
|
-
const { authGuard: guard } = setup();
|
|
57
|
-
expect(run(guard, {} as ActivatedRouteSnapshot)).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('sin sesión manda a /login', () => {
|
|
61
|
-
const { authGuard: guard, router } = setup(null);
|
|
62
|
-
const result = run(guard, {} as ActivatedRouteSnapshot);
|
|
63
|
-
expect(isUrlTree(result)).toBe(true);
|
|
64
|
-
expect(router.serializeUrl(result as UrlTree)).toBe('/login');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('sin sesión, un `:id` también manda a /login (redundancia barata)', () => {
|
|
68
|
-
const { roleGuard: guard, router } = setup(null);
|
|
69
|
-
const result = run(guard, routeWithId('orders'));
|
|
70
|
-
expect(isUrlTree(result)).toBe(true);
|
|
71
|
-
expect(router.serializeUrl(result as UrlTree)).toBe('/login');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('un `:id` desconocido deja que responda el back (no inventamos política)', () => {
|
|
75
|
-
const { roleGuard: guard } = setup();
|
|
76
|
-
expect(run(guard, routeWithId('no-existe'))).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('una ruta sin `:id` no decide nada', () => {
|
|
80
|
-
const { roleGuard: guard } = setup();
|
|
81
|
-
expect(run(guard, routeWithId(null))).toBe(true);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('un recurso sin `access` declarado se ve con sesión', () => {
|
|
85
|
-
const { roleGuard: guard } = setup('staff');
|
|
86
|
-
expect(run(guard, routeWithId('dashboard'))).toBe(true);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { inject } from '@angular/core';
|
|
2
|
-
import type { CanActivateFn } from '@angular/router';
|
|
3
|
-
import { Router } from '@angular/router';
|
|
4
|
-
|
|
5
|
-
import { getSchema } from '../registry/schema-catalog';
|
|
6
|
-
import { AuthService, LOGIN_PATH } from '../services/auth.service';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Guards de sesión (auth.md §5.3).
|
|
10
|
-
*
|
|
11
|
-
* Dos puertas y ninguna es una barrera de seguridad: el back re-verifica
|
|
12
|
-
* `accessLevel` en **cada** petición desde R2.6. Éstas sólo evitan pintar
|
|
13
|
-
* una pantalla que no le toca al usuario — enseñarle un formulario que va
|
|
14
|
-
* a recibir 403 es mala UX, no un agujero.
|
|
15
|
-
*
|
|
16
|
-
* `authGuard` va en la ruta madre (todo el shell); `roleGuard` en cada
|
|
17
|
-
* `:id`, que es donde aparece el recurso que puede tener `access`.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/** Sin sesión → login. Corre ANTES que cualquier ruta del shell. */
|
|
21
|
-
export const authGuard: CanActivateFn = () => {
|
|
22
|
-
const auth = inject(AuthService);
|
|
23
|
-
if (auth.isAuthenticated()) return true;
|
|
24
|
-
return inject(Router).createUrlTree([LOGIN_PATH]);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* El recurso declara `access` y esta sesión no lo cumple → se cancela la
|
|
29
|
-
* navegación. No hay pantalla de 403 (tampoco la pide §5.3) y el menú ya
|
|
30
|
-
* oculta la entrada, así que queda sólo el caso de alguien tecleando la URL.
|
|
31
|
-
*/
|
|
32
|
-
export const roleGuard: CanActivateFn = (route) => {
|
|
33
|
-
const auth = inject(AuthService);
|
|
34
|
-
const router = inject(Router);
|
|
35
|
-
|
|
36
|
-
// Redundante con `authGuard` (la madre ya filtra) pero barato: un hijo
|
|
37
|
-
// nunca debe dejar una sesión muerta navegando sola.
|
|
38
|
-
if (!auth.isAuthenticated()) return router.createUrlTree([LOGIN_PATH]);
|
|
39
|
-
|
|
40
|
-
const id = route.data?.['resourceId'] ?? route.paramMap.get('id');
|
|
41
|
-
// Ruta sin recurso declarado, o id que no existe en el registry → que
|
|
42
|
-
// responda el back (404). No inventar una política sobre datos ajenos.
|
|
43
|
-
if (id === null) return true;
|
|
44
|
-
const schema = getSchema(String(id));
|
|
45
|
-
if (schema === undefined) return true;
|
|
46
|
-
|
|
47
|
-
return auth.canAccess(schema.access);
|
|
48
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { CanDeactivateFn } from '@angular/router';
|
|
2
|
-
|
|
3
|
-
/** Componente que expone si se puede salir (base.md §13.9: cambios sin guardar). */
|
|
4
|
-
export interface CanLeaveWhenDirty {
|
|
5
|
-
canDeactivate(): boolean | Promise<boolean>;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Avisa antes de salir con cambios sin guardar. El componente decide:
|
|
10
|
-
* `canDeactivate()` devuelve `true` para salir limpio o una `Promise` que
|
|
11
|
-
* resuelve según la respuesta del usuario (vía `NotificationService.confirm`).
|
|
12
|
-
*/
|
|
13
|
-
export const unsavedChangesGuard: CanDeactivateFn<unknown> = (component) => {
|
|
14
|
-
const candidate = component as Partial<CanLeaveWhenDirty> | null | undefined;
|
|
15
|
-
return candidate?.canDeactivate?.() ?? true;
|
|
16
|
-
};
|