@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,540 +0,0 @@
1
- import { setSchemaCatalog } from '../../core/registry/schema-catalog';
2
- import { testCatalog } from '../../core/testing/test-catalog';
3
-
4
- setSchemaCatalog(testCatalog);
5
-
6
- import { ComponentFixture, TestBed } from '@angular/core/testing';
7
- import { ActivatedRoute } from '@angular/router';
8
- import { of } from 'rxjs';
9
- import { describe, expect, it, vi } from 'vitest';
10
-
11
- import { ApiError } from '../../core/models/api.model';
12
- import type {
13
- KanbanViewConfig,
14
- ResourceSchema,
15
- SelectionBinding,
16
- } from '../../core/models/schema.model';
17
- import { DataSourceService, type SourceRow } from '../../core/services/data-source.service';
18
- import { CARD_NO_TITLE, cardSubtitle, cardTitle, mapKanbanRows } from './kanban-model';
19
- import { KanbanView } from './kanban-view';
20
-
21
- /**
22
- * R9.8.4 — generic `KanbanView`.
23
- *
24
- * The pure model (grouping, card title/subtitle) is tested directly; the
25
- * component is tested against a stubbed `DataSourceService` + a stubbed
26
- * `ActivatedRoute.data` carrying `uiView` and the schema — the exact harness
27
- * of `calendar-view.spec.ts`, because the shell mounts views via
28
- * `loadComponent` with NO input bindings.
29
- */
30
-
31
- const BASE_CONFIG: KanbanViewConfig = {
32
- groupField: 'status',
33
- columns: [
34
- { value: 'todo', label: 'Por hacer' },
35
- { value: 'doing', label: 'En curso' },
36
- { value: 'done', label: 'Hecho' },
37
- ],
38
- titleField: 'name',
39
- subtitleField: 'owner',
40
- };
41
-
42
- function kanbanSchema(config: KanbanViewConfig | null = BASE_CONFIG): ResourceSchema {
43
- return {
44
- id: 'kanban_tasks',
45
- label: 'Tarea',
46
- labelPlural: 'Tareas',
47
- kind: 'collection',
48
- endpoint: { list: '/admin/kanban_tasks' },
49
- keyField: 'slug',
50
- titleField: 'name',
51
- listColumns: [],
52
- fields: [
53
- { type: 'text', key: 'slug', label: 'Slug' },
54
- { type: 'text', key: 'name', label: 'Nombre' },
55
- { type: 'text', key: 'owner', label: 'Responsable' },
56
- { type: 'select', key: 'status', label: 'Estado', options: [] },
57
- ],
58
- uiViews: config === null ? { board: { type: 'list' } } : { board: { type: 'kanban', config } },
59
- };
60
- }
61
-
62
- type RowsBehavior = SourceRow[] | 'pending' | 'reject';
63
-
64
- interface Harness {
65
- fixture: ComponentFixture<KanbanView>;
66
- component: KanbanView;
67
- rowsMock: ReturnType<typeof vi.fn>;
68
- el: HTMLElement;
69
- }
70
-
71
- async function create(options: {
72
- rows?: RowsBehavior;
73
- /** Custom fetcher — lets a test resolve two loads out of order. */
74
- rowsImpl?: () => Promise<SourceRow[]>;
75
- config?: KanbanViewConfig | null;
76
- /** Route data override — the schema travels here, never as an input. */
77
- data?: Record<string, unknown>;
78
- }): Promise<Harness> {
79
- const rowsBehavior = options.rows ?? [];
80
- const rowsMock = options.rowsImpl
81
- ? vi.fn(options.rowsImpl)
82
- : vi.fn(() => {
83
- if (rowsBehavior === 'pending') return new Promise<SourceRow[]>(() => {});
84
- if (rowsBehavior === 'reject') {
85
- return Promise.reject(new ApiError(500, 'Fallo del servidor'));
86
- }
87
- return Promise.resolve(rowsBehavior);
88
- });
89
-
90
- const data =
91
- options.data ??
92
- ({
93
- // `uiView` names the view within `uiViews`; the schema travels by route
94
- // data because the shell mounts views with `loadComponent` (no input
95
- // bindings) and the schema registry is immutable.
96
- uiView: 'board',
97
- schema: kanbanSchema(options.config === null ? null : (options.config ?? BASE_CONFIG)),
98
- } satisfies Record<string, unknown>);
99
-
100
- await TestBed.configureTestingModule({
101
- imports: [KanbanView],
102
- providers: [
103
- { provide: ActivatedRoute, useValue: { data: of(data) } },
104
- { provide: DataSourceService, useValue: { rows: rowsMock } },
105
- ],
106
- }).compileComponents();
107
-
108
- const fixture = TestBed.createComponent(KanbanView);
109
- fixture.detectChanges();
110
- await fixture.whenStable();
111
- fixture.detectChanges();
112
- return { fixture, component: fixture.componentInstance, rowsMock, el: fixture.nativeElement };
113
- }
114
-
115
- /** `value` of every painted column, in DOM order. */
116
- function columnValues(el: HTMLElement): string[] {
117
- return [...el.querySelectorAll('[data-column]')].map(
118
- (node) => node.getAttribute('data-column') ?? '',
119
- );
120
- }
121
-
122
- /** Title of each card of a column, in order (first `p` of every card). */
123
- function cardTitles(el: HTMLElement, value: string): string[] {
124
- return [...el.querySelectorAll(`[data-column="${value}"] li`)].map(
125
- (card) => card.querySelector('p')?.textContent?.trim() ?? '',
126
- );
127
- }
128
-
129
- // ─────────────────────────────────────────────────────────────
130
- // Pure model — grouping
131
- // ─────────────────────────────────────────────────────────────
132
-
133
- describe('kanban-model — mapKanbanRows', () => {
134
- it('agrupa por groupField respetando el orden declarado y las columnas vacías', () => {
135
- const rows: SourceRow[] = [
136
- { slug: 't1', name: 'Deploy', status: 'done' },
137
- { slug: 't2', name: 'Diseño', status: 'todo' },
138
- { slug: 't3', name: 'QA', status: 'todo' },
139
- ];
140
- const { columns, unknown } = mapKanbanRows(rows, BASE_CONFIG, {});
141
- expect(unknown).toHaveLength(0);
142
- expect(columns.map((column) => column.value)).toEqual(['todo', 'doing', 'done']);
143
- expect(columns.map((column) => column.label)).toEqual(['Por hacer', 'En curso', 'Hecho']);
144
- // la columna declarada sin filas SIGUE ahí (vacía, no ausente)
145
- expect(columns[1].rows).toEqual([]);
146
- expect(columns[0].rows.map((row) => row['slug'])).toEqual(['t2', 't3']);
147
- expect(columns[2].rows.map((row) => row['slug'])).toEqual(['t1']);
148
- });
149
-
150
- it('un valor no declarado queda como columna propia, después de las declaradas', () => {
151
- const rows: SourceRow[] = [
152
- { slug: 't1', status: 'blocked' },
153
- { slug: 't2', status: 'todo' },
154
- { slug: 't3', status: 'blocked' },
155
- ];
156
- const { columns } = mapKanbanRows(rows, BASE_CONFIG, {});
157
- expect(columns.map((column) => column.value)).toEqual(['todo', 'doing', 'done', 'blocked']);
158
- // rótulo = el valor crudo: lo no declarado se VE, no se esconde
159
- expect(columns[3].label).toBe('blocked');
160
- expect(columns[3].rows.map((row) => row['slug'])).toEqual(['t1', 't3']);
161
- expect(columns.reduce((total, column) => total + column.rows.length, 0)).toBe(3);
162
- });
163
-
164
- it('un valor vacío o ausente va a «unknown», nunca se pierde', () => {
165
- const rows: SourceRow[] = [
166
- { slug: 't1', name: 'Sin estado', status: '' },
167
- { slug: 't2', name: 'Sin clave' },
168
- { slug: 't3', name: 'Nulo', status: null },
169
- { slug: 't4', name: 'Ok', status: 'todo' },
170
- ];
171
- const { columns, unknown } = mapKanbanRows(rows, BASE_CONFIG, {});
172
- expect(unknown.map((row) => row['slug'])).toEqual(['t1', 't2', 't3']);
173
- expect(unknown).toHaveLength(3);
174
- // ninguna fila queda fuera del recuento total
175
- const total = columns.reduce((sum, column) => sum + column.rows.length, 0) + unknown.length;
176
- expect(total).toBe(rows.length);
177
- expect(columns.map((column) => column.value)).toEqual(['todo', 'doing', 'done']);
178
- });
179
-
180
- it('es estable: el orden de inserción dentro de cada columna se conserva', () => {
181
- const rows: SourceRow[] = [
182
- { slug: 'a', status: 'todo' },
183
- { slug: 'b', status: 'todo' },
184
- { slug: 'c', status: 'todo' },
185
- ];
186
- const first = mapKanbanRows(rows, BASE_CONFIG, {});
187
- const second = mapKanbanRows(rows, BASE_CONFIG, {});
188
- expect(first.columns[0].rows.map((row) => row['slug'])).toEqual(['a', 'b', 'c']);
189
- expect(second.columns[0].rows.map((row) => row['slug'])).toEqual(['a', 'b', 'c']);
190
- // mismo input ⇒ misma salida (pura)
191
- expect(second.columns.map((column) => column.value)).toEqual(
192
- first.columns.map((column) => column.value),
193
- );
194
- });
195
-
196
- it('labelFor sólo decora el rótulo de los valores no declarados', () => {
197
- const rows: SourceRow[] = [
198
- { slug: 't1', status: 'blocked' },
199
- { slug: 't2', status: 'todo' },
200
- ];
201
- const { columns } = mapKanbanRows(rows, BASE_CONFIG, {
202
- labelFor: (value) => `Sin columna: ${value}`,
203
- });
204
- expect(columns[0].label).toBe('Por hacer'); // declarada: intocable
205
- expect(columns[3].label).toBe('Sin columna: blocked');
206
- });
207
-
208
- it('una celda objeto se reduce a su etiqueta legible, nunca a [object Object]', () => {
209
- const rows: SourceRow[] = [{ slug: 't1', status: { label: 'En curso' } }];
210
- const { columns, unknown } = mapKanbanRows(rows, BASE_CONFIG, {});
211
- expect(unknown).toHaveLength(0);
212
- expect(columns.map((column) => column.value)).toContain('En curso');
213
- // un objeto sin escalar legible no puede nombrar una columna: va a unknown
214
- const orphan = mapKanbanRows([{ slug: 't2', status: { weird: true } }], BASE_CONFIG, {});
215
- expect(orphan.unknown.map((row) => row['slug'])).toEqual(['t2']);
216
- expect(JSON.stringify(orphan)).not.toContain('[object Object]');
217
- });
218
- });
219
-
220
- // ─────────────────────────────────────────────────────────────
221
- // Pure model — card title / subtitle
222
- // ─────────────────────────────────────────────────────────────
223
-
224
- describe('kanban-model — cardTitle / cardSubtitle', () => {
225
- const schema = kanbanSchema();
226
-
227
- it('cardTitle: config.titleField → schema.titleField → keyField', () => {
228
- const cfg: KanbanViewConfig = { ...BASE_CONFIG, titleField: 'owner' };
229
- expect(cardTitle({ slug: 't1', name: 'Deploy', owner: 'Ana' }, cfg, schema)).toBe('Ana');
230
- // sin titleField en la config ⇒ el titleField del schema
231
- const withoutTitle: KanbanViewConfig = { groupField: 'status', columns: BASE_CONFIG.columns };
232
- expect(cardTitle({ slug: 't1', name: 'Deploy' }, withoutTitle, schema)).toBe('Deploy');
233
- // ni config ni fila con título legible ⇒ la clave del registro
234
- expect(cardTitle({ slug: 't1' }, withoutTitle, schema)).toBe('t1');
235
- });
236
-
237
- it('cardTitle nunca pinta undefined ni [object Object]', () => {
238
- const cfg: KanbanViewConfig = { ...BASE_CONFIG, titleField: 'name' };
239
- const row: SourceRow = { slug: 't9', name: { weird: true } };
240
- const title = cardTitle(row, cfg, schema);
241
- expect(title).toBe('t9'); // cae a la clave
242
- expect(title).not.toContain('[object Object]');
243
- expect(cardTitle({ slug: 't9', name: { label: 'Legible' } }, cfg, schema)).toBe('Legible');
244
- expect(cardTitle({ slug: 't9', name: '' }, cfg, schema)).toBe('t9');
245
- });
246
-
247
- it('cardTitle con ningún candidato legible ⇒ «Sin título» visible', () => {
248
- const cfg: KanbanViewConfig = { groupField: 'status', columns: BASE_CONFIG.columns };
249
- expect(cardTitle({}, cfg, schema)).toBe(CARD_NO_TITLE);
250
- expect(CARD_NO_TITLE).toBe('Sin título');
251
- });
252
-
253
- it('cardSubtitle: valor de config.subtitleField si lo hay, si no vacío', () => {
254
- expect(cardSubtitle({ slug: 't1', owner: 'Ana' }, BASE_CONFIG, schema)).toBe('Ana');
255
- expect(cardSubtitle({ slug: 't1' }, BASE_CONFIG, schema)).toBe('');
256
- const noSubtitle: KanbanViewConfig = {
257
- groupField: 'status',
258
- columns: BASE_CONFIG.columns,
259
- titleField: 'name',
260
- };
261
- expect(cardSubtitle({ slug: 't1', owner: 'Ana' }, noSubtitle, schema)).toBe('');
262
- });
263
- });
264
-
265
- // ─────────────────────────────────────────────────────────────
266
- // Component
267
- // ─────────────────────────────────────────────────────────────
268
-
269
- describe('KanbanView', () => {
270
- it('pinta las columnas declaradas en orden, con rótulo y conteo en texto', async () => {
271
- const { el } = await create({
272
- rows: [
273
- { slug: 't1', name: 'Deploy', status: 'done' },
274
- { slug: 't2', name: 'Diseño', owner: 'Ana', status: 'todo' },
275
- { slug: 't3', name: 'QA', status: 'todo' },
276
- ],
277
- });
278
-
279
- expect(columnValues(el)).toEqual(['todo', 'doing', 'done']);
280
- expect(el.querySelector('[data-column="todo"] h3')?.textContent).toBe('Por hacer');
281
- expect(cardTitles(el, 'todo')).toEqual(['Diseño', 'QA']);
282
- expect(cardTitles(el, 'done')).toEqual(['Deploy']);
283
-
284
- // el conteo es TEXTO, no color: va en el badge y en el aria-label
285
- const badge = el.querySelector('[data-column="todo"] header span')?.textContent ?? '';
286
- expect(badge).toContain('2');
287
- expect(badge).toContain('tarjetas');
288
- expect(el.querySelector('section[aria-label="Por hacer: 2 tarjetas"]')).not.toBeNull();
289
- expect(el.querySelector('section[aria-label="Hecho: 1 tarjeta"]')).not.toBeNull();
290
- });
291
-
292
- it('un valor no declarado se ve como columna propia al final', async () => {
293
- const { el } = await create({
294
- rows: [
295
- { slug: 't1', name: 'Bloqueada', status: 'blocked' },
296
- { slug: 't2', name: 'Diseño', status: 'todo' },
297
- ],
298
- });
299
- expect(columnValues(el)).toEqual(['todo', 'doing', 'done', 'blocked']);
300
- expect(el.querySelector('[data-column="blocked"] h3')?.textContent).toBe('blocked');
301
- expect(cardTitles(el, 'blocked')).toEqual(['Bloqueada']);
302
- });
303
-
304
- it('las filas sin grupo van a la columna «Sin valor» al final', async () => {
305
- const { el } = await create({
306
- rows: [
307
- { slug: 't1', name: 'Sin estado', status: '' },
308
- { slug: 't2', name: 'Sin clave' },
309
- { slug: 't3', name: 'Diseño', status: 'todo' },
310
- ],
311
- });
312
- expect(columnValues(el)).toEqual(['todo', 'doing', 'done', '__sin_valor__']);
313
- expect(el.querySelector('[data-column="__sin_valor__"] h3')?.textContent).toBe('Sin valor');
314
- expect(cardTitles(el, '__sin_valor__')).toEqual(['Sin estado', 'Sin clave']);
315
- expect(el.querySelector('section[aria-label="Sin valor: 2 tarjetas"]')).not.toBeNull();
316
- });
317
-
318
- it('pinta título y subtítulo con sus fallbacks (clave, sin segundo renglón)', async () => {
319
- const { el } = await create({
320
- rows: [
321
- { slug: 't1', name: 'Deploy', owner: 'Ana', status: 'todo' },
322
- { slug: 't2', name: '', owner: '', status: 'todo' },
323
- ],
324
- });
325
- const cards = [...el.querySelectorAll('[data-column="todo"] li')];
326
- expect(cards).toHaveLength(2);
327
- expect(cards[0].textContent).toContain('Deploy');
328
- expect(cards[0].textContent).toContain('Ana');
329
- // sin título legible ⇒ la clave; sin subtítulo ⇒ un solo renglón
330
- expect(cards[1].querySelector('p')?.textContent?.trim()).toBe('t2');
331
- expect(cards[1].querySelectorAll('p')).toHaveLength(1);
332
- expect(cards[1].textContent).not.toContain('[object Object]');
333
- });
334
-
335
- it('muestra «Sin tarjetas» en la columna declarada vacía', async () => {
336
- const { el } = await create({ rows: [{ slug: 't1', name: 'Diseño', status: 'todo' }] });
337
- expect(el.querySelector('[data-column="doing"]')?.textContent).toContain('Sin tarjetas');
338
- expect(el.querySelector('[data-column="todo"]')?.textContent).not.toContain('Sin tarjetas');
339
- // sin filas desconocidas NO se pinta la columna «Sin valor»
340
- expect(columnValues(el)).toEqual(['todo', 'doing', 'done']);
341
- });
342
-
343
- it('muestra el skeleton mientras la fuente no responde', async () => {
344
- const { el } = await create({ rows: 'pending' });
345
- expect(el.querySelector('app-skeleton')).not.toBeNull();
346
- expect(el.querySelector('section')?.getAttribute('aria-busy')).toBe('true');
347
- });
348
-
349
- it('pinta el estado de error con el mensaje mapeado', async () => {
350
- const { el } = await create({ rows: 'reject' });
351
- expect(el.querySelector('app-empty-state')?.textContent).toContain(
352
- 'No se pudo cargar el tablero',
353
- );
354
- expect(el.textContent).toContain('Fallo del servidor');
355
- expect(columnValues(el)).toEqual([]);
356
- });
357
-
358
- it('pinta la config inválida como estado vacío, sin pedir filas', async () => {
359
- const { el, rowsMock } = await create({ config: null });
360
- expect(el.textContent).toContain('Configuración inválida');
361
- expect(rowsMock).not.toHaveBeenCalled();
362
- });
363
-
364
- it('resuelve el schema desde route data, sin ningún input', async () => {
365
- // The shell mounts views via `loadComponent` (no input bindings), so
366
- // there is NO input to set: the schema must come from route data.
367
- const { component, rowsMock } = await create({ rows: [] });
368
- expect(component.schema()?.id).toBe('kanban_tasks');
369
- expect(component.config()?.groupField).toBe('status');
370
- expect(rowsMock).toHaveBeenCalledWith({ resource: 'kanban_tasks' }, undefined);
371
- });
372
-
373
- it('resuelve el schema por resourceId en route data (la ruta de producción)', async () => {
374
- const { component, el, rowsMock } = await create({
375
- data: { uiView: 'list', resourceId: 'products' },
376
- });
377
- expect(component.schema()?.id).toBe('products');
378
- // products no declara una vista kanban usable ⇒ estado inválido, sin fetch
379
- expect(component.config()).toBeUndefined();
380
- expect(el.textContent).toContain('Configuración inválida');
381
- expect(rowsMock).not.toHaveBeenCalled();
382
- });
383
-
384
- it('sin schema ni resourceId en route data pinta «Configuración inválida»', async () => {
385
- // Regression the old spec missed: `input.required` never received a
386
- // schema in production. With neither `schema` nor `resourceId` there is
387
- // nothing to resolve, and the only honest render is the invalid-config
388
- // empty state (no board, no fetch).
389
- const rowsMock = vi.fn(() => Promise.resolve<SourceRow[]>([]));
390
- await TestBed.configureTestingModule({
391
- imports: [KanbanView],
392
- providers: [
393
- { provide: ActivatedRoute, useValue: { data: of({ uiView: 'board' }) } },
394
- { provide: DataSourceService, useValue: { rows: rowsMock } },
395
- ],
396
- }).compileComponents();
397
- const fixture = TestBed.createComponent(KanbanView);
398
- fixture.detectChanges();
399
- await fixture.whenStable();
400
- fixture.detectChanges();
401
- expect(fixture.nativeElement.textContent).toContain('Configuración inválida');
402
- expect(rowsMock).not.toHaveBeenCalled();
403
- });
404
-
405
- it('pide la fuente declarada y, sin source, el listado del propio recurso', async () => {
406
- const declared = await create({
407
- rows: [],
408
- config: { ...BASE_CONFIG, source: { resource: 'oth', view: 'por_estado' } },
409
- });
410
- expect(declared.rowsMock).toHaveBeenCalledWith(
411
- { resource: 'oth', view: 'por_estado' },
412
- undefined,
413
- );
414
- });
415
- });
416
-
417
- // ─────────────────────────────────────────────────────────────
418
- // R9.9.4 · decision table — selection contract + load race
419
- // ─────────────────────────────────────────────────────────────
420
-
421
- describe('KanbanView — contrato de selección declarado (R9.9.4)', () => {
422
- const ROUTE: SelectionBinding = {
423
- on: 'open',
424
- mode: 'route',
425
- target: { resource: 'orders', view: 'detail', params: ['key'] },
426
- };
427
- const ROWS: SourceRow[] = [{ slug: 't-1', name: 'Tarea 1', status: 'todo' }];
428
-
429
- function boardData(extra: Record<string, unknown>): Record<string, unknown> {
430
- return { uiView: 'board', schema: kanbanSchema(), ...extra };
431
- }
432
-
433
- it("mode:'route' ⇒ la tarjeta emite con la acción declarada", async () => {
434
- const emit = vi.fn();
435
- const h = await create({ rows: ROWS, data: boardData({ select: ROUTE, emit }) });
436
-
437
- (h.el.querySelector('[data-column="todo"] li') as HTMLElement).click();
438
-
439
- expect(emit).toHaveBeenCalledTimes(1);
440
- expect(emit).toHaveBeenCalledWith({
441
- resource: 'kanban_tasks',
442
- key: 't-1',
443
- action: 'open',
444
- });
445
- expect(h.el.querySelector('[data-column="todo"] li')?.getAttribute('data-selectable')).toBe(
446
- 'true',
447
- );
448
- });
449
-
450
- it("mode:'none' ⇒ la tarjeta es inerte aunque tenga emit disponible", async () => {
451
- const emit = vi.fn();
452
- const h = await create({
453
- rows: ROWS,
454
- data: boardData({ select: { on: 'open', mode: 'none' }, emit }),
455
- });
456
-
457
- (h.el.querySelector('[data-column="todo"] li') as HTMLElement).click();
458
-
459
- expect(emit).not.toHaveBeenCalled();
460
- });
461
-
462
- it('sin select declarado ⇒ el clic de tarjeta no emite nada (comportamiento actual)', async () => {
463
- const emit = vi.fn();
464
- const h = await create({ rows: ROWS, data: boardData({ emit }) });
465
-
466
- (h.el.querySelector('[data-column="todo"] li') as HTMLElement).click();
467
-
468
- expect(emit).not.toHaveBeenCalled();
469
- expect(h.el.querySelector('[data-column="todo"] li')?.hasAttribute('data-selectable')).toBe(
470
- false,
471
- );
472
- });
473
-
474
- // ── R9.8.7 — operabilidad con teclado ──
475
-
476
- it('la tarjeta seleccionable es focusable y Enter/Space activan la selección', async () => {
477
- const emit = vi.fn();
478
- const h = await create({ rows: ROWS, data: boardData({ select: ROUTE, emit }) });
479
- const card = h.el.querySelector('[data-column="todo"] li') as HTMLElement;
480
-
481
- expect(card.getAttribute('tabindex')).toBe('0');
482
- expect(card.getAttribute('role')).toBe('button');
483
-
484
- card.focus();
485
- expect(document.activeElement).toBe(card);
486
-
487
- card.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
488
- expect(emit).toHaveBeenCalledTimes(1);
489
- expect(emit).toHaveBeenCalledWith({ resource: 'kanban_tasks', key: 't-1', action: 'open' });
490
-
491
- card.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }));
492
- expect(emit).toHaveBeenCalledTimes(2);
493
- });
494
-
495
- it('sin binding declarado la tarjeta no es focusable (comportamiento local intacto)', async () => {
496
- const emit = vi.fn();
497
- const h = await create({ rows: ROWS, data: boardData({ emit }) });
498
- const card = h.el.querySelector('[data-column="todo"] li') as HTMLElement;
499
-
500
- expect(card.hasAttribute('tabindex')).toBe(false);
501
- expect(card.hasAttribute('role')).toBe(false);
502
-
503
- card.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
504
- expect(emit).not.toHaveBeenCalled();
505
- });
506
-
507
- it('cargas fuera de orden ⇒ sólo la última respuesta se pinta (loadEpoch)', async () => {
508
- let resolverPrimera!: (rows: SourceRow[]) => void;
509
- let resolverSegunda!: (rows: SourceRow[]) => void;
510
- const primera = new Promise<SourceRow[]>((r) => (resolverPrimera = r));
511
- const segunda = new Promise<SourceRow[]>((r) => (resolverSegunda = r));
512
- const pendientes = [primera, segunda];
513
- let llamada = 0;
514
-
515
- const h = await create({
516
- rowsImpl: () => {
517
- const p = pendientes[llamada++];
518
- // Non-null: el harness sólo dispara dos cargas (load inicial + retry).
519
- return p ?? Promise.resolve<SourceRow[]>([]);
520
- },
521
- });
522
- expect(h.rowsMock).toHaveBeenCalledTimes(1);
523
-
524
- h.component.retry(); // segunda carga, epoch 2
525
- expect(h.rowsMock).toHaveBeenCalledTimes(2);
526
-
527
- // Responder la SEGUNDA primero…
528
- resolverSegunda([{ slug: 'nueva', name: 'Nueva', status: 'todo' }]);
529
- await h.fixture.whenStable();
530
- h.fixture.detectChanges();
531
- expect(h.el.textContent ?? '').toContain('Nueva');
532
-
533
- // …y la PRIMERA tarde: no debe pisar lo ya pintado.
534
- resolverPrimera([{ slug: 'vieja', name: 'Vieja', status: 'todo' }]);
535
- await h.fixture.whenStable();
536
- h.fixture.detectChanges();
537
- expect(h.el.textContent ?? '').toContain('Nueva');
538
- expect(h.el.textContent ?? '').not.toContain('Vieja');
539
- });
540
- });