@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.
Files changed (368) hide show
  1. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
  2. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
  3. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
  4. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
  5. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
  6. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
  7. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
  8. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
  9. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +1027 -0
  10. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +1 -0
  11. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
  12. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
  13. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +107 -0
  14. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +1 -0
  15. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +101 -0
  16. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +1 -0
  17. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
  18. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
  19. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +88 -0
  20. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +1 -0
  21. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
  22. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
  23. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
  24. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
  25. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
  26. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
  27. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
  28. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
  29. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
  30. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
  31. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
  32. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
  33. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
  34. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
  35. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
  36. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
  37. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +122 -0
  38. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +1 -0
  39. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
  40. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
  41. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
  42. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
  43. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +45 -0
  44. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +1 -0
  45. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
  46. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
  47. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
  48. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
  49. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
  50. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
  51. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +408 -0
  52. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +1 -0
  53. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs +4516 -0
  54. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs.map +1 -0
  55. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
  56. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
  57. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
  58. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
  59. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
  60. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
  61. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
  62. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
  63. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
  64. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
  65. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
  66. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
  67. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
  68. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
  69. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
  70. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
  71. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
  72. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
  73. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +416 -0
  74. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +1 -0
  75. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +439 -0
  76. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +1 -0
  77. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
  78. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
  79. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs +637 -0
  80. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs.map +1 -0
  81. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
  82. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
  83. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +251 -0
  84. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +1 -0
  85. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
  86. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
  87. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
  88. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
  89. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
  90. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
  91. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
  92. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
  93. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
  94. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
  95. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
  96. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
  97. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
  98. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
  99. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
  100. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
  101. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +309 -0
  102. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +1 -0
  103. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs +576 -0
  104. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs.map +1 -0
  105. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +161 -0
  106. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +1 -0
  107. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
  108. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +685 -0
  109. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +1 -0
  110. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs +80 -0
  111. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs.map +1 -0
  112. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +296 -0
  113. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +1 -0
  114. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
  115. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
  116. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
  117. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
  118. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
  119. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
  120. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
  121. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
  122. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
  123. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
  124. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
  125. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
  126. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
  127. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
  128. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
  129. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
  130. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
  131. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
  132. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +60 -0
  133. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +1 -0
  134. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
  135. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
  136. package/fesm2022/tinya-code-gas-admin-ui.mjs +4738 -0
  137. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
  138. package/package.json +15 -3
  139. package/types/tinya-code-gas-admin-ui.d.ts +3634 -0
  140. package/ng-package.json +0 -7
  141. package/src/lib/actions/action-registry.spec.ts +0 -52
  142. package/src/lib/actions/action-registry.ts +0 -126
  143. package/src/lib/actions/action-service.spec.ts +0 -215
  144. package/src/lib/actions/action-service.ts +0 -87
  145. package/src/lib/actions/descriptors.spec.ts +0 -155
  146. package/src/lib/actions/descriptors.ts +0 -154
  147. package/src/lib/columns/column-cell.ts +0 -33
  148. package/src/lib/columns/column-defaults.spec.ts +0 -99
  149. package/src/lib/columns/column-defaults.ts +0 -84
  150. package/src/lib/columns/column-format.spec.ts +0 -274
  151. package/src/lib/columns/descriptors.ts +0 -113
  152. package/src/lib/columns/format-badge.ts +0 -51
  153. package/src/lib/columns/format-boolean.ts +0 -58
  154. package/src/lib/columns/format-currency.ts +0 -30
  155. package/src/lib/columns/format-date.ts +0 -35
  156. package/src/lib/columns/format-number.ts +0 -32
  157. package/src/lib/columns/format-text.ts +0 -23
  158. package/src/lib/columns/format-thumbnail.ts +0 -63
  159. package/src/lib/core/adapters/firebase-auth.adapter.ts +0 -6
  160. package/src/lib/core/guards/auth.guard.spec.ts +0 -88
  161. package/src/lib/core/guards/auth.guard.ts +0 -48
  162. package/src/lib/core/guards/unsaved-changes.guard.ts +0 -16
  163. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +0 -182
  164. package/src/lib/core/interceptors/api-error.interceptor.ts +0 -87
  165. package/src/lib/core/models/api.model.ts +0 -104
  166. package/src/lib/core/models/schema-descriptions.ts +0 -118
  167. package/src/lib/core/models/schema.model.ts +0 -1097
  168. package/src/lib/core/registry/composition-validator.spec.ts +0 -358
  169. package/src/lib/core/registry/composition-validator.ts +0 -270
  170. package/src/lib/core/registry/field-validators.spec.ts +0 -199
  171. package/src/lib/core/registry/field-validators.ts +0 -440
  172. package/src/lib/core/registry/render-host.spec.ts +0 -208
  173. package/src/lib/core/registry/render-host.ts +0 -646
  174. package/src/lib/core/registry/render-registry.spec.ts +0 -96
  175. package/src/lib/core/registry/render-registry.ts +0 -312
  176. package/src/lib/core/registry/schema-catalog.ts +0 -156
  177. package/src/lib/core/services/api.service.spec.ts +0 -1142
  178. package/src/lib/core/services/api.service.ts +0 -371
  179. package/src/lib/core/services/auth.service.spec.ts +0 -653
  180. package/src/lib/core/services/auth.service.ts +0 -503
  181. package/src/lib/core/services/config.service.spec.ts +0 -121
  182. package/src/lib/core/services/config.service.ts +0 -119
  183. package/src/lib/core/services/data-source.service.spec.ts +0 -179
  184. package/src/lib/core/services/data-source.service.ts +0 -142
  185. package/src/lib/core/services/error-mapper.service.spec.ts +0 -50
  186. package/src/lib/core/services/error-mapper.service.ts +0 -49
  187. package/src/lib/core/services/notification.service.ts +0 -73
  188. package/src/lib/core/services/relation-drawer.service.ts +0 -41
  189. package/src/lib/core/services/theme.service.spec.ts +0 -106
  190. package/src/lib/core/services/theme.service.ts +0 -86
  191. package/src/lib/core/services/transport.spec.ts +0 -198
  192. package/src/lib/core/services/transport.ts +0 -164
  193. package/src/lib/core/services/upload.service.ts +0 -81
  194. package/src/lib/core/testing/categories.schema.ts +0 -125
  195. package/src/lib/core/testing/orders.schema.ts +0 -372
  196. package/src/lib/core/testing/products.schema.ts +0 -258
  197. package/src/lib/core/testing/site.schema.ts +0 -195
  198. package/src/lib/core/testing/test-catalog.ts +0 -21
  199. package/src/lib/core/tokens.ts +0 -112
  200. package/src/lib/core/utils/clipboard.spec.ts +0 -55
  201. package/src/lib/core/utils/clipboard.ts +0 -90
  202. package/src/lib/core/utils/context-resolver.spec.ts +0 -95
  203. package/src/lib/core/utils/context-resolver.ts +0 -101
  204. package/src/lib/core/utils/response-unwrapper.spec.ts +0 -70
  205. package/src/lib/core/utils/response-unwrapper.ts +0 -103
  206. package/src/lib/core/utils/source-options.spec.ts +0 -96
  207. package/src/lib/core/utils/source-options.ts +0 -54
  208. package/src/lib/core/utils/template-interpolator.spec.ts +0 -59
  209. package/src/lib/core/utils/template-interpolator.ts +0 -56
  210. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +0 -207
  211. package/src/lib/core/view-navigation/view-navigation.service.ts +0 -132
  212. package/src/lib/fields/boolean/boolean.descriptor.ts +0 -11
  213. package/src/lib/fields/boolean/boolean.ts +0 -40
  214. package/src/lib/fields/color/color.descriptor.ts +0 -12
  215. package/src/lib/fields/color/color.ts +0 -34
  216. package/src/lib/fields/currency/currency.descriptor.ts +0 -12
  217. package/src/lib/fields/currency/currency.ts +0 -67
  218. package/src/lib/fields/date/date.descriptor.ts +0 -12
  219. package/src/lib/fields/date/date.ts +0 -36
  220. package/src/lib/fields/descriptors.ts +0 -122
  221. package/src/lib/fields/display/display-badge.ts +0 -65
  222. package/src/lib/fields/display/display-date.ts +0 -39
  223. package/src/lib/fields/display/display-defaults.ts +0 -84
  224. package/src/lib/fields/display/display-file.ts +0 -41
  225. package/src/lib/fields/display/display-image.ts +0 -54
  226. package/src/lib/fields/display/display-list.ts +0 -107
  227. package/src/lib/fields/display/display-number.ts +0 -41
  228. package/src/lib/fields/display/display-text.ts +0 -42
  229. package/src/lib/fields/display/display.spec.ts +0 -242
  230. package/src/lib/fields/dropdown/dropdown.descriptor.ts +0 -12
  231. package/src/lib/fields/dropdown/dropdown.ts +0 -45
  232. package/src/lib/fields/email/email.descriptor.ts +0 -12
  233. package/src/lib/fields/email/email.ts +0 -28
  234. package/src/lib/fields/field-aria.ts +0 -60
  235. package/src/lib/fields/field-host/field-host.spec.ts +0 -118
  236. package/src/lib/fields/field-host/field-host.ts +0 -47
  237. package/src/lib/fields/field-node.ts +0 -88
  238. package/src/lib/fields/file/file.descriptor.ts +0 -14
  239. package/src/lib/fields/file/file.spec.ts +0 -134
  240. package/src/lib/fields/file/file.ts +0 -281
  241. package/src/lib/fields/group/group.descriptor.ts +0 -21
  242. package/src/lib/fields/group/group.ts +0 -110
  243. package/src/lib/fields/image/image.descriptor.ts +0 -12
  244. package/src/lib/fields/image/image.spec.ts +0 -117
  245. package/src/lib/fields/image/image.ts +0 -281
  246. package/src/lib/fields/key-value/key-value.descriptor.ts +0 -11
  247. package/src/lib/fields/key-value/key-value.ts +0 -283
  248. package/src/lib/fields/list/list.descriptor.ts +0 -21
  249. package/src/lib/fields/list/list.ts +0 -376
  250. package/src/lib/fields/multiselect/multiselect.descriptor.ts +0 -11
  251. package/src/lib/fields/multiselect/multiselect.spec.ts +0 -142
  252. package/src/lib/fields/multiselect/multiselect.ts +0 -152
  253. package/src/lib/fields/number/number.descriptor.ts +0 -12
  254. package/src/lib/fields/number/number.ts +0 -40
  255. package/src/lib/fields/phone/phone.descriptor.ts +0 -12
  256. package/src/lib/fields/phone/phone.ts +0 -46
  257. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +0 -12
  258. package/src/lib/fields/readonly-text/readonly-text.ts +0 -58
  259. package/src/lib/fields/relation/relation.descriptor.ts +0 -12
  260. package/src/lib/fields/relation/relation.spec.ts +0 -193
  261. package/src/lib/fields/relation/relation.ts +0 -224
  262. package/src/lib/fields/rich-select/rich-select.descriptor.ts +0 -12
  263. package/src/lib/fields/rich-select/rich-select.ts +0 -175
  264. package/src/lib/fields/select/radio-mode.ts +0 -25
  265. package/src/lib/fields/select/select.descriptor.ts +0 -12
  266. package/src/lib/fields/select/select.spec.ts +0 -162
  267. package/src/lib/fields/select/select.ts +0 -210
  268. package/src/lib/fields/slug/slug.descriptor.ts +0 -19
  269. package/src/lib/fields/slug/slug.ts +0 -67
  270. package/src/lib/fields/string-list/string-list.descriptor.ts +0 -11
  271. package/src/lib/fields/string-list/string-list.ts +0 -222
  272. package/src/lib/fields/text/text.descriptor.ts +0 -12
  273. package/src/lib/fields/text/text.ts +0 -35
  274. package/src/lib/fields/textarea/textarea.descriptor.ts +0 -12
  275. package/src/lib/fields/textarea/textarea.spec.ts +0 -117
  276. package/src/lib/fields/textarea/textarea.ts +0 -126
  277. package/src/lib/fields/time/time.descriptor.ts +0 -12
  278. package/src/lib/fields/time/time.ts +0 -28
  279. package/src/lib/fields/unknown-render/unknown-render.ts +0 -49
  280. package/src/lib/fields/url/url.descriptor.ts +0 -12
  281. package/src/lib/fields/url/url.ts +0 -53
  282. package/src/lib/gas-admin-ui.spec.ts +0 -21
  283. package/src/lib/gas-admin-ui.ts +0 -9
  284. package/src/lib/layouts/descriptors.ts +0 -9
  285. package/src/lib/pages/dashboard/dashboard.ts +0 -167
  286. package/src/lib/pages/detail-view/detail-view.spec.ts +0 -333
  287. package/src/lib/pages/detail-view/detail-view.ts +0 -570
  288. package/src/lib/pages/drawer-form/drawer-form.ts +0 -228
  289. package/src/lib/pages/form-view/form-model.ts +0 -88
  290. package/src/lib/pages/form-view/form-schema.ts +0 -255
  291. package/src/lib/pages/form-view/form-view.ts +0 -1622
  292. package/src/lib/pages/list-view/list-view.formats.spec.ts +0 -214
  293. package/src/lib/pages/list-view/list-view.ts +0 -882
  294. package/src/lib/pages/login/login.spec.ts +0 -109
  295. package/src/lib/pages/login/login.ts +0 -227
  296. package/src/lib/pages/resource-page/resource-page.ts +0 -234
  297. package/src/lib/shared/components/badge/badge.ts +0 -35
  298. package/src/lib/shared/components/button/button.ts +0 -65
  299. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +0 -48
  300. package/src/lib/shared/components/copy-button/copy-button.ts +0 -56
  301. package/src/lib/shared/components/copy-share/copy-share.spec.ts +0 -122
  302. package/src/lib/shared/components/copy-share/copy-share.ts +0 -107
  303. package/src/lib/shared/components/drawer/drawer.spec.ts +0 -127
  304. package/src/lib/shared/components/drawer/drawer.ts +0 -172
  305. package/src/lib/shared/components/empty-state/empty-state.ts +0 -30
  306. package/src/lib/shared/components/modal/modal.spec.ts +0 -149
  307. package/src/lib/shared/components/modal/modal.ts +0 -145
  308. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +0 -165
  309. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +0 -159
  310. package/src/lib/shared/components/skeleton/skeleton.ts +0 -31
  311. package/src/lib/shared/components/toast/toast.ts +0 -58
  312. package/src/lib/shared/utils/col-span.ts +0 -25
  313. package/src/lib/shared/utils/condition-evaluator.ts +0 -53
  314. package/src/lib/shared/utils/depends-on.ts +0 -48
  315. package/src/lib/shared/utils/dialog-focus.ts +0 -28
  316. package/src/lib/shared/utils/field-path.ts +0 -49
  317. package/src/lib/shared/utils/gap-sorting.ts +0 -144
  318. package/src/lib/shared/utils/seed.spec.ts +0 -64
  319. package/src/lib/shared/utils/seed.ts +0 -149
  320. package/src/lib/shared/utils/slugify.ts +0 -13
  321. package/src/lib/shared/utils/validators.ts +0 -41
  322. package/src/lib/shell/layout/layout.ts +0 -63
  323. package/src/lib/shell/shell.routes.spec.ts +0 -59
  324. package/src/lib/shell/shell.routes.ts +0 -122
  325. package/src/lib/shell/sidebar/sidebar.ts +0 -139
  326. package/src/lib/shell/theme-toggle/theme-toggle.ts +0 -74
  327. package/src/lib/views/calendar-view/calendar-model.ts +0 -426
  328. package/src/lib/views/calendar-view/calendar-view.spec.ts +0 -557
  329. package/src/lib/views/calendar-view/calendar-view.ts +0 -568
  330. package/src/lib/views/composer/composer-host.spec.ts +0 -301
  331. package/src/lib/views/composer/composer-host.ts +0 -248
  332. package/src/lib/views/composer/composer-imports.spec.ts +0 -54
  333. package/src/lib/views/composer/view-context.spec.ts +0 -117
  334. package/src/lib/views/composer/view-context.ts +0 -109
  335. package/src/lib/views/composer/view-slot.spec.ts +0 -130
  336. package/src/lib/views/composer/view-slot.ts +0 -178
  337. package/src/lib/views/descriptors.ts +0 -46
  338. package/src/lib/views/kanban-view/kanban-model.ts +0 -173
  339. package/src/lib/views/kanban-view/kanban-view.spec.ts +0 -540
  340. package/src/lib/views/kanban-view/kanban-view.ts +0 -327
  341. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +0 -17
  342. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +0 -66
  343. package/src/lib/widgets/bar-chart/bar-chart.ts +0 -76
  344. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +0 -17
  345. package/src/lib/widgets/chart-line/chart-line.spec.ts +0 -113
  346. package/src/lib/widgets/chart-line/chart-line.ts +0 -219
  347. package/src/lib/widgets/descriptors.ts +0 -29
  348. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +0 -41
  349. package/src/lib/widgets/metric-card/metric-card.spec.ts +0 -52
  350. package/src/lib/widgets/metric-card/metric-card.ts +0 -48
  351. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +0 -13
  352. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +0 -61
  353. package/src/lib/widgets/quick-actions/quick-actions.ts +0 -100
  354. package/src/lib/widgets/record-list/record-list.descriptor.ts +0 -16
  355. package/src/lib/widgets/record-list/record-list.spec.ts +0 -79
  356. package/src/lib/widgets/record-list/record-list.ts +0 -115
  357. package/src/lib/widgets/series.spec.ts +0 -42
  358. package/src/lib/widgets/series.ts +0 -56
  359. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +0 -19
  360. package/src/lib/widgets/status-progress/status-progress.spec.ts +0 -63
  361. package/src/lib/widgets/status-progress/status-progress.ts +0 -104
  362. package/src/lib/widgets/widget-host/widget-host.spec.ts +0 -179
  363. package/src/lib/widgets/widget-host/widget-host.ts +0 -99
  364. package/src/public-api.ts +0 -104
  365. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  366. package/tsconfig.lib.json +0 -13
  367. package/tsconfig.lib.prod.json +0 -11
  368. package/tsconfig.spec.json +0 -10
@@ -1,154 +0,0 @@
1
- import { firstValueFrom } from 'rxjs';
2
- import { LucideShare2 } from '@lucide/angular';
3
-
4
- import type { ActionDescriptor } from './action-registry';
5
- import type {
6
- CopyShareAction,
7
- NavigateAction,
8
- ResourceAction,
9
- TriggerAction,
10
- } from '../core/models/schema.model';
11
- import { buildShareMessage, writeClipboard } from '../core/utils/clipboard';
12
- import { interpolateTemplate } from '../core/utils/template-interpolator';
13
-
14
- /**
15
- * Descriptores de las tres acciones que hoy declara el modelo
16
- * (R3.10 · `doc/plan-refactor-motor.md` §3.2).
17
- *
18
- * Éste es el fichero que **cierra la triplicación de `copy-share`**: la
19
- * resolución de enlace y de mensaje vivía en `list-view.runAction`,
20
- * `detail-view.resolveUrl/resolveShareText` y
21
- * `post-create-modal.resolvedShareUrl/resolvedShareText`. Aquí se resuelve
22
- * una sola vez (`resolveShare`) y las vistas consumen ese resultado en R3.11.
23
- *
24
- * Se registra al importar, desde `action-registry.ts`, con el mismo criterio
25
- * que el registro de render: sin esperar a DI, porque el registro es la única
26
- * fuente de verdad en runtime.
27
- */
28
-
29
- /** Enlace y mensaje ya interpolados, listos para copiar o compartir. */
30
- export interface ResolvedShare {
31
- url: string;
32
- shareText: string;
33
- }
34
-
35
- /**
36
- * `true` cuando la acción es de las que las vistas presentan como botón de
37
- * compartir (`detail-view`, `post-create-modal`).
38
- *
39
- * Vive acá y no en la vista porque es **el único sitio donde se puede nombrar
40
- * `'copy-share'`**: fuera de `descriptors.ts` ninguna vista decide por tipo
41
- * (criterio de R3.11).
42
- */
43
- export function isShareAction(action: ResourceAction): action is CopyShareAction {
44
- return action.type === 'copy-share';
45
- }
46
-
47
- /**
48
- * `true` cuando la acción es un `trigger` (acción de dominio del back).
49
- *
50
- * Mismo criterio que `isShareAction`: el único sitio que nombra el tipo,
51
- * para que las vistas no decidan por string literal (R3.11). `detail-view`
52
- * lo usa en R8.8 para renderizar «Regenerar PIN» junto a los botones de
53
- * compartir.
54
- */
55
- export function isTriggerAction(action: ResourceAction): action is TriggerAction {
56
- return action.type === 'trigger';
57
- }
58
-
59
- /**
60
- * Resuelve `urlTemplate` y el mensaje de compartir contra `vars`
61
- * (config global + registro).
62
- *
63
- * **Única implementación** de esta lógica en el admin. El fallback a
64
- * `share_message_template` (la plantilla que declara el singleton de
65
- * configuración) lo aplican los tres puntos por igual: hasta ahora la fila
66
- * del listado no lo honraba y se quedaba sin saludo.
67
- */
68
- export function resolveShare(
69
- action: CopyShareAction,
70
- vars: Record<string, unknown>,
71
- ): ResolvedShare {
72
- const template =
73
- action.shareTextTemplate || (vars['share_message_template'] as string | undefined);
74
- return {
75
- url: interpolateTemplate(action.urlTemplate, vars),
76
- shareText: template ? interpolateTemplate(template, vars) : '',
77
- };
78
- }
79
-
80
- /** `copy-share` — copia (o comparte) el mensaje completo del enlace público. */
81
- const copyShare: ActionDescriptor = {
82
- type: 'copy-share',
83
- surfaces: ['row', 'detail', 'post-create'],
84
- // Icono de la fila del listado: la vista sólo decide entre «icono» y
85
- // «rótulo», nunca por tipo. Se pasa la CLASE, no el nombre: sin
86
- // `provideLucideIcons` no hay riesgo de `Unable to resolve icon`.
87
- icon: LucideShare2,
88
- run: async (ctx, action) => {
89
- const { url, shareText } = resolveShare(action as CopyShareAction, ctx.vars);
90
- const message = buildShareMessage(url, shareText);
91
- const copied = await writeClipboard(message);
92
- if (copied) {
93
- ctx.toast.success('Mensaje copiado al portapapeles.');
94
- } else {
95
- ctx.toast.info(`Copiar manualmente: ${message}`);
96
- }
97
- return { ok: true };
98
- },
99
- };
100
-
101
- /**
102
- * `navigate` — abre la plantilla resuelta: URL absoluta en otra pestaña,
103
- * ruta interna en el router. `NavigateAction.type` es opcional, así que el
104
- * servicio llega acá también con una acción que no declara `type`.
105
- */
106
- const navigate: ActionDescriptor = {
107
- type: 'navigate',
108
- surfaces: ['row', 'detail'],
109
- run: async (ctx, action) => {
110
- const url = interpolateTemplate((action as NavigateAction).urlTemplate, ctx.vars);
111
- if (/^https?:\/\//.test(url)) {
112
- window.open(url, '_blank', 'noopener');
113
- } else {
114
- await ctx.router.navigateByUrl(url);
115
- }
116
- return { ok: true };
117
- },
118
- };
119
-
120
- /**
121
- * `trigger` — dispara una **acción de dominio declarada en el back** (B3).
122
- *
123
- * **R3.12:** el destino ya no lo declara el schema (`endpoint` y `method`
124
- * murieron en este cambio). Se deriva de `resource` + clave del registro +
125
- * `name` (o `id`), que es exactamente la ruta que el back publica solo en
126
- * R5.4: `POST /admin/<recurso>/:id/actions/<name>`.
127
- *
128
- * ⚠️ **O2:** la ruta lógica viaja en el `path` del envelope, no en la URL —
129
- * el HTTP sigue siendo el `POST API_URL` de siempre.
130
- *
131
- * Siempre pide confirmación: es la única acción de las tres que puede dejar
132
- * una cola de trabajo hecha.
133
- */
134
- const trigger: ActionDescriptor = {
135
- type: 'trigger',
136
- surfaces: ['row', 'detail'],
137
- confirm: true,
138
- run: async (ctx, action) => {
139
- const declared = action as TriggerAction;
140
- const rawKey = ctx.record?.[ctx.keyField];
141
- if (rawKey === null || rawKey === undefined || rawKey === '') {
142
- throw new Error(
143
- `La acción «${declared.label}» necesita la clave ${ctx.keyField} del registro.`,
144
- );
145
- }
146
- const name = declared.name ?? declared.id;
147
- const route = `/admin/${ctx.resource}/${String(rawKey)}/actions/${name}`;
148
- await firstValueFrom(ctx.api.request('POST', route));
149
- return { ok: true, reload: true };
150
- },
151
- };
152
-
153
- /** Catálogo — una línea por acción, en el orden en que se registran. */
154
- export const actionDescriptors: readonly ActionDescriptor[] = [copyShare, navigate, trigger];
@@ -1,33 +0,0 @@
1
- import type { FieldSchema, ListColumn } from '../core/models/schema.model';
2
-
3
- type Row = Record<string, unknown>;
4
-
5
- /**
6
- * Contexto de una celda de listado (R4.3 · `kind: 'column-format'`).
7
- *
8
- * Es lo que antes cada `@case` de `list-view` pedía a la vista como
9
- * `row`/`column` y lo que el descriptor cuelga de `extras.data`: el
10
- * componente de formato no conoce a la vista, sólo a su celda.
11
- *
12
- * `fields`, `canUpdate`, `saving`, `currency` y `toggle` viajan acá porque
13
- * son decisiones de la vista (permisos, moneda del schema, escritura de la
14
- * fila); un formato nuevo no necesita tocar `list-view` para leerlas.
15
- */
16
- export interface ColumnCell {
17
- /** Fila completa. */
18
- row: Row;
19
- /** Columna que se pinta (`key`, `label`, `format`). */
20
- column: ListColumn;
21
- /** Campos del recurso: de acá salen `trueLabel`/`falseLabel`. */
22
- fields: FieldSchema[];
23
- /** `titleField` de la fila, para el `aria-label` del interruptor. */
24
- title: string;
25
- /** ¿La fila admite escritura? (`ListView.canUpdate`) */
26
- canUpdate: boolean;
27
- /** ¿La fila está guardando? (`ListView.savingKey === keyOf(row)`) */
28
- saving: boolean;
29
- /** Moneda del schema, para el formato `currency`. */
30
- currency: string;
31
- /** Escribe el valor en la fila. Sólo lo usa el interruptor `active`. */
32
- toggle?: (checked: boolean) => void;
33
- }
@@ -1,99 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { SUPPORTED_FIELD_TYPE_LIST } from '../fields/descriptors';
4
- import type { FieldSchema, ListColumn } from '../core/models/schema.model';
5
- import { FORMATO_POR_DEFECTO, formatoDeColumna, formatoPorTipo } from './column-defaults';
6
-
7
- /**
8
- * R4.4 — «declarada, no implícita»: la tabla de formato por defecto.
9
- *
10
- * Dos promesas: que la tabla cubra **todos** los tipos del catálogo, y que
11
- * una columna sin `format` pinta lo que la tabla dice — no un `?? 'text'`
12
- * implícito que dependía de la memoria de quien escribía el schema.
13
- */
14
- describe('R4.4 — formato por defecto según field.type', () => {
15
- const columna = (parcial: Partial<ListColumn> & Pick<ListColumn, 'key'>): ListColumn => ({
16
- label: parcial.key,
17
- ...parcial,
18
- });
19
- const campo = (key: string, type: FieldSchema['type']): FieldSchema =>
20
- ({ key, label: key, type }) as FieldSchema;
21
-
22
- it('cubre exactamente el catálogo de tipos de campo', () => {
23
- // El `Record<FieldType, …>` ya lo exige en compilación; el test además
24
- // fija que ningún tipo se quede sin fila ni aparezca una fantasma.
25
- expect(Object.keys(FORMATO_POR_DEFECTO).sort()).toEqual([...SUPPORTED_FIELD_TYPE_LIST].sort());
26
- expect(SUPPORTED_FIELD_TYPE_LIST.length).toBe(24);
27
- });
28
-
29
- it('repasa la paridad tipo a tipo con el display del detalle', () => {
30
- const esperado: Record<string, string> = {
31
- text: 'text',
32
- textarea: 'text',
33
- slug: 'text',
34
- url: 'text',
35
- email: 'text',
36
- phone: 'text',
37
- 'readonly-text': 'text',
38
- relation: 'text',
39
- group: 'text',
40
- 'key-value': 'text',
41
- 'string-list': 'text',
42
- multiselect: 'text',
43
- time: 'text',
44
- list: 'text',
45
- date: 'date',
46
- number: 'number',
47
- currency: 'currency',
48
- boolean: 'boolean',
49
- select: 'badge',
50
- image: 'thumbnail',
51
- file: 'text',
52
- color: 'text',
53
- 'rich-select': 'badge',
54
- dropdown: 'badge',
55
- };
56
- expect(Object.keys(FORMATO_POR_DEFECTO).sort()).toEqual(Object.keys(esperado).sort());
57
- for (const [tipo, formato] of Object.entries(esperado)) {
58
- expect(formatoPorTipo(tipo), `tipo ${tipo}`).toBe(formato);
59
- }
60
- });
61
-
62
- it('la declaración del schema manda sobre la tabla', () => {
63
- expect(
64
- formatoDeColumna(columna({ key: 'status', format: 'text' }), [campo('status', 'select')]),
65
- ).toBe('text');
66
- expect(
67
- formatoDeColumna(columna({ key: 'price', format: 'badge' }), [campo('price', 'currency')]),
68
- ).toBe('badge');
69
- });
70
-
71
- it('sin formato declarado usa el tipo del campo', () => {
72
- const campos = [
73
- campo('status', 'select'),
74
- campo('pickup_date', 'date'),
75
- campo('active', 'boolean'),
76
- campo('photo', 'image'),
77
- campo('price', 'currency'),
78
- campo('name', 'slug'),
79
- ];
80
- expect(formatoDeColumna(columna({ key: 'status' }), campos)).toBe('badge');
81
- expect(formatoDeColumna(columna({ key: 'pickup_date' }), campos)).toBe('date');
82
- expect(formatoDeColumna(columna({ key: 'active' }), campos)).toBe('boolean');
83
- expect(formatoDeColumna(columna({ key: 'photo' }), campos)).toBe('thumbnail');
84
- expect(formatoDeColumna(columna({ key: 'price' }), campos)).toBe('currency');
85
- expect(formatoDeColumna(columna({ key: 'name' }), campos)).toBe('text');
86
- });
87
-
88
- it('una columna sin campo asociado o con tipo mal escrito degrada a text', () => {
89
- // El `@default` del `@switch` que R4.3 reemplazó: la degradación es la
90
- // misma y nunca lanza.
91
- expect(formatoDeColumna(columna({ key: 'inventada' }), [campo('otra', 'text')])).toBe('text');
92
- expect(formatoPorTipo('holograma')).toBeUndefined();
93
- expect(
94
- formatoDeColumna(columna({ key: 'raro' }), [
95
- campo('raro', 'holograma' as FieldSchema['type']),
96
- ]),
97
- ).toBe('text');
98
- });
99
- });
@@ -1,84 +0,0 @@
1
- import type {
2
- FieldSchema,
3
- FieldType,
4
- ListColumn,
5
- ListColumnFormat,
6
- } from '../core/models/schema.model';
7
-
8
- /**
9
- * **Tabla de formato de columna por defecto según `field.type`** (R4.4 del
10
- * plan): «declarada, no implícita» — `column.format` sólo sirve para
11
- * sobreescribirla.
12
- *
13
- * Es la hermana de `fields/display/display-defaults.ts` (R4.1): un solo
14
- * sitio decide qué pinta una columna cuando el schema no dice nada, en vez
15
- * de un `?? 'text'` repartido por la vista. El vocabulario se alinea con el
16
- * display del detalle — `select` es chip, `date` es fecha, `image` es
17
- * miniatura — con las dos concesiones que sólo el listado puede hacer:
18
- * `boolean` baja al interruptor (R4.3) en vez de al chip, y `list`, que en
19
- * la ficha es timeline, acá sigue siendo texto porque el registro de
20
- * formatos no tiene timeline (D41).
21
- *
22
- * `Record<FieldType, …>` es el **tripwire de exhaustividad en compilación**:
23
- * un tipo nuevo obliga a elegir su formato de lista antes de que el build
24
- * pase, y un tipo retirado obliga a limpiar la entrada.
25
- */
26
- export const FORMATO_POR_DEFECTO: Record<FieldType, ListColumnFormat> = {
27
- text: 'text',
28
- textarea: 'text',
29
- slug: 'text',
30
- url: 'text',
31
- email: 'text',
32
- phone: 'text',
33
- 'readonly-text': 'text',
34
- relation: 'text',
35
- group: 'text',
36
- 'key-value': 'text',
37
- 'string-list': 'text',
38
- multiselect: 'text',
39
- time: 'text',
40
- list: 'text',
41
- date: 'date',
42
- number: 'number',
43
- currency: 'currency',
44
- boolean: 'boolean',
45
- select: 'badge',
46
- image: 'thumbnail',
47
- // Un archivo no tiene miniatura: en la lista va como URL en crudo (R9.5.3).
48
- file: 'text',
49
- // Un color se pinta como texto (el hex #RRGGBB) en el listado.
50
- color: 'text',
51
- // Un rich-select se pinta como badge con el label de la opción.
52
- 'rich-select': 'badge',
53
- // Un dropdown se pinta como badge con el label de la opción.
54
- dropdown: 'badge',
55
- };
56
-
57
- /**
58
- * Formato por defecto para un `type`, o `undefined` si el schema lo escribió
59
- * mal (tipo fuera de la unión). La degradación — igual que `displayLoader()` —
60
- * es `text`, que era el `@default` del `@switch` que R4.3 reemplazó.
61
- */
62
- export function formatoPorTipo(type: string): ListColumnFormat | undefined {
63
- return Object.prototype.hasOwnProperty.call(FORMATO_POR_DEFECTO, type)
64
- ? FORMATO_POR_DEFECTO[type as FieldType]
65
- : undefined;
66
- }
67
-
68
- /**
69
- * Formato final de una columna: la declaración del schema si existe, si no,
70
- * la tabla de arriba según el `type` del campo con esa `key`, y si la columna
71
- * ni siquiera aparece en `fields` (columna derivada o key inventada), `text`.
72
- *
73
- * Es la única puerta por la que `list-view` decide qué pinta una celda.
74
- */
75
- export function formatoDeColumna(
76
- column: ListColumn,
77
- fields: readonly FieldSchema[],
78
- ): ListColumnFormat {
79
- if (column.format) {
80
- return column.format;
81
- }
82
- const field = fields.find((candidate) => candidate.key === column.key);
83
- return (field ? formatoPorTipo(field.type) : undefined) ?? 'text';
84
- }
@@ -1,274 +0,0 @@
1
- import { Component, input } from '@angular/core';
2
- import { TestBed } from '@angular/core/testing';
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
4
-
5
- import type { ListColumn } from '../core/models/schema.model';
6
- import { RenderHost } from '../core/registry/render-host';
7
- import { COLUMN_FORMAT_TYPES } from './descriptors';
8
- import type { ColumnCell } from './column-cell';
9
-
10
- /**
11
- * Los 7 formatos de columna (R4.3 · `kind: 'column-format'`).
12
- *
13
- * Cada caso es un `@case` del `@switch` que vivía en `list-view`: si el
14
- * formato pinta distinto de lo que pintaba allí, este test se pone rojo. Se
15
- * monta por `RenderHost` y no por el componente suelto para cubrir también
16
- * la resolución del registro (descriptor, `inputs`, degradación).
17
- */
18
- @Component({
19
- selector: 'spec-column-host',
20
- imports: [RenderHost],
21
- template: `
22
- <app-render-host kind="column-format" [type]="formato()" [config]="column()" [data]="cell()" />
23
- `,
24
- })
25
- class Host {
26
- readonly formato = input.required<string>();
27
- readonly column = input.required<ListColumn>();
28
- readonly cell = input.required<ColumnCell>();
29
- }
30
-
31
- describe('R4.3 — formatos de columna registrados', () => {
32
- beforeEach(async () => {
33
- await TestBed.configureTestingModule({ imports: [Host] }).compileComponents();
34
- });
35
-
36
- /**
37
- * Monta el host y espera el `load()` perezoso del formato.
38
- *
39
- * `whenStable()` no cubre el `import()` dinámico por sí solo, así que se
40
- * espera acotadamente mientras quede `<app-skeleton>`; si el formato nunca
41
- * monta, la espera se agota y falla la aserción del test.
42
- */
43
- async function pintar(column: ListColumn, cell: Partial<ColumnCell> = {}): Promise<HTMLElement> {
44
- const fixture = TestBed.createComponent(Host);
45
- fixture.componentRef.setInput('formato', column.format ?? 'text');
46
- fixture.componentRef.setInput('column', column);
47
- fixture.componentRef.setInput('cell', celda({ column, ...cell }));
48
- fixture.detectChanges();
49
- await fixture.whenStable();
50
- for (
51
- let intento = 0;
52
- intento < 100 && fixture.nativeElement.querySelector('app-skeleton');
53
- intento++
54
- ) {
55
- fixture.detectChanges();
56
- await new Promise((resolve) => setTimeout(resolve, 1));
57
- }
58
- fixture.detectChanges();
59
- return fixture.nativeElement as HTMLElement;
60
- }
61
-
62
- /** Texto de la celda con los espacios duros de `Intl` normalizados. */
63
- function texto(nodo: HTMLElement): string {
64
- return (nodo.textContent ?? '').replace(/\u00a0/g, ' ');
65
- }
66
-
67
- /** Celda mínima; cada caso sobreescribe lo que necesita. */
68
- function celda(parcial: { column: ListColumn } & Partial<ColumnCell>): ColumnCell {
69
- return {
70
- row: {},
71
- fields: [],
72
- title: 'Una fila',
73
- canUpdate: false,
74
- saving: false,
75
- currency: 'PEN',
76
- ...parcial,
77
- };
78
- }
79
-
80
- it('los 7 formatos de la unión están registrados', () => {
81
- // `ListColumnFormat` vive en tipos y el manifiesto en runtime: sólo un
82
- // test reconcilia los dos (mismo tripwire que campos y widgets).
83
- expect(COLUMN_FORMAT_TYPES.length).toBe(7);
84
- });
85
-
86
- describe('text', () => {
87
- const col: ListColumn = { key: 'nombre', label: 'Nombre', format: 'text' };
88
-
89
- it('pinta el valor crudo', async () => {
90
- const nodo = await pintar(col, { row: { nombre: 'ORD-42' } });
91
- expect(nodo.textContent).toContain('ORD-42');
92
- });
93
-
94
- it('null y undefined salen vacíos', async () => {
95
- expect((await pintar(col, { row: { nombre: null } })).textContent?.trim()).toBe('');
96
- expect((await pintar(col, { row: {} })).textContent?.trim()).toBe('');
97
- });
98
-
99
- it('un objeto sale [object Object] (degradación heredada)', async () => {
100
- const nodo = await pintar(col, { row: { nombre: { a: 1 } } });
101
- expect(nodo.textContent).toContain('[object Object]');
102
- });
103
- });
104
-
105
- describe('number', () => {
106
- const col: ListColumn = { key: 'stock', label: 'Stock', format: 'number' };
107
-
108
- it('agrupa con separador es-PE', async () => {
109
- const nodo = await pintar(col, { row: { stock: 1234567.5 } });
110
- expect(nodo.textContent).toContain('1,234,567.5');
111
- });
112
-
113
- it('no numérico sale crudo y null sigue saliendo «0»', async () => {
114
- expect((await pintar(col, { row: { stock: 'varios' } })).textContent).toContain('varios');
115
- // Quirk heredado de `formatNumber`: `Number(null)` es 0 y por eso la
116
- // lista ya mostraba «0» en vez de vacío. Se conserva — cambiarlo es
117
- // otra decisión, no este registro.
118
- expect((await pintar(col, { row: { stock: null } })).textContent?.trim()).toBe('0');
119
- });
120
- });
121
-
122
- describe('currency', () => {
123
- const col: ListColumn = { key: 'price', label: 'Precio', format: 'currency' };
124
-
125
- it('usa la moneda que entrega la vista', async () => {
126
- const nodo = await pintar(col, { row: { price: 1234.5 } });
127
- // `Intl` separa el símbolo con espacio duro (U+00A0): se normaliza para
128
- // que el aserto no dependa de ese byte.
129
- expect(texto(nodo)).toContain('S/ 1,234.50');
130
- });
131
-
132
- it('cambia de moneda con la celda', async () => {
133
- const nodo = await pintar(col, { row: { price: 1234.5 }, currency: 'USD' });
134
- expect(texto(nodo)).toContain('USD 1,234.50');
135
- });
136
- });
137
-
138
- describe('date', () => {
139
- const col: ListColumn = { key: 'fecha', label: 'Fecha', format: 'date' };
140
-
141
- it('formato corto es-PE en UTC', async () => {
142
- const nodo = await pintar(col, { row: { fecha: '2026-12-25' } });
143
- expect(nodo.textContent).toContain('25/12/2026');
144
- });
145
-
146
- it('no parseable sale crudo', async () => {
147
- expect((await pintar(col, { row: { fecha: 'ayer' } })).textContent).toContain('ayer');
148
- });
149
- });
150
-
151
- describe('badge', () => {
152
- const col: ListColumn = { key: 'status', label: 'Estado', format: 'badge' };
153
-
154
- it('clasifica el estado como el display del detalle (D41)', async () => {
155
- // `warning` se pinta como `accent` (bg-accent/20 + text-accent-text).
156
- const pendiente = await pintar(col, { row: { status: 'PENDIENTE' } });
157
- expect(pendiente.querySelector('app-badge')?.className).toContain('bg-accent/20');
158
-
159
- const entregado = await pintar(col, { row: { status: 'ENTREGADO' } });
160
- expect(entregado.querySelector('app-badge')?.className).toContain('bg-success');
161
-
162
- const cancelado = await pintar(col, { row: { status: 'Cancelado' } });
163
- expect(cancelado.querySelector('app-badge')?.className).toContain('bg-danger');
164
-
165
- const otro = await pintar(col, { row: { status: 'Vigente' } });
166
- expect(otro.querySelector('app-badge')?.className).toContain('bg-neutral');
167
- });
168
-
169
- it('un select pinta la etiqueta de la opción, no el valor crudo', async () => {
170
- const nodo = await pintar(col, {
171
- row: { status: 'preparacion' },
172
- fields: [
173
- {
174
- key: 'status',
175
- label: 'Estado',
176
- type: 'select',
177
- options: [
178
- { value: 'preparacion', label: 'En preparación' },
179
- { value: 'entregado', label: 'Entregado' },
180
- ],
181
- },
182
- ],
183
- });
184
- expect(nodo.textContent).toContain('En preparación');
185
- });
186
-
187
- it('el vacío sale «Sin dato» en danger', async () => {
188
- const nodo = await pintar(col, { row: { status: '' } });
189
- expect(nodo.textContent).toContain('Sin dato');
190
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-danger');
191
- });
192
-
193
- it('un booleano usa trueLabel/falseLabel del campo', async () => {
194
- const nodo = await pintar(col, {
195
- row: { status: true },
196
- fields: [{ key: 'status', label: 'Estado', type: 'boolean', trueLabel: 'Vigente' }],
197
- });
198
- expect(nodo.textContent).toContain('Vigente');
199
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-success');
200
- });
201
- });
202
-
203
- describe('boolean', () => {
204
- const col: ListColumn = { key: 'active', label: 'Activo', format: 'boolean' };
205
- const booleano = { key: 'active', label: 'Activo', type: 'boolean' as const };
206
-
207
- it('con permiso y campo booleano dibuja el interruptor', async () => {
208
- const nodo = await pintar(col, {
209
- row: { active: true },
210
- fields: [booleano],
211
- canUpdate: true,
212
- });
213
- const box = nodo.querySelector<HTMLInputElement>('input[type="checkbox"]');
214
- expect(box, 'debe dibujarse el interruptor').not.toBeNull();
215
- expect(box?.checked).toBe(true);
216
- expect(box?.getAttribute('aria-label')).toBe('Activo: Una fila');
217
- });
218
-
219
- it('sin permiso cae al badge', async () => {
220
- const nodo = await pintar(col, { row: { active: true }, fields: [booleano] });
221
- expect(nodo.querySelector('input[type="checkbox"]')).toBeNull();
222
- expect(nodo.textContent).toContain('Sí');
223
- });
224
-
225
- it('mientras la fila guarda, el interruptor queda bloqueado', async () => {
226
- const nodo = await pintar(col, {
227
- row: { active: false },
228
- fields: [booleano],
229
- canUpdate: true,
230
- saving: true,
231
- });
232
- const box = nodo.querySelector<HTMLInputElement>('input[type="checkbox"]');
233
- expect(box?.disabled, 'mientras guarda, la fila está bloqueada').toBe(true);
234
- });
235
-
236
- it('al alternar escribe por la celda', async () => {
237
- const toggle = vi.fn();
238
- const nodo = await pintar(col, {
239
- row: { active: false },
240
- fields: [booleano],
241
- canUpdate: true,
242
- toggle,
243
- });
244
- nodo.querySelector<HTMLInputElement>('input[type="checkbox"]')!.click();
245
- expect(toggle).toHaveBeenCalledWith(true);
246
- });
247
- });
248
-
249
- describe('thumbnail', () => {
250
- const col: ListColumn = { key: 'image_url', label: 'Imagen', format: 'thumbnail' };
251
-
252
- it('pinta la imagen con su alt', async () => {
253
- const nodo = await pintar(col, { row: { image_url: 'https://x.test/a.png' } });
254
- const img = nodo.querySelector('img');
255
- expect(img?.getAttribute('src')).toBe('https://x.test/a.png');
256
- expect(img?.getAttribute('alt')).toBe('');
257
- });
258
-
259
- it('toma el primer item de images[] con su image_alt', async () => {
260
- const nodo = await pintar(
261
- { key: 'images', label: 'Imágenes', format: 'thumbnail' },
262
- { row: { images: [{ image_url: 'https://x.test/b.png', image_alt: 'Frente' }] } },
263
- );
264
- expect(nodo.querySelector('img')?.getAttribute('src')).toBe('https://x.test/b.png');
265
- expect(nodo.querySelector('img')?.getAttribute('alt')).toBe('Frente');
266
- });
267
-
268
- it('sin URL pinta el guion', async () => {
269
- const nodo = await pintar(col, { row: { image_url: '' } });
270
- expect(nodo.textContent).toContain('—');
271
- expect(nodo.querySelector('img')).toBeNull();
272
- });
273
- });
274
- });