@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,119 +0,0 @@
1
- import { inject, Service, signal } from '@angular/core';
2
- import { catchError, firstValueFrom, forkJoin, of } from 'rxjs';
3
-
4
- import { ApiService } from './api.service';
5
- import type { ResourceEndpoints } from '../models/schema.model';
6
-
7
- /**
8
- * Servicio global de configuración: reúne los singletons declarativos y los
9
- * deja disponibles para interpolación de plantillas (enlaces públicos,
10
- * mensajes para compartir).
11
- *
12
- * Es genérico a propósito: NO conoce ningún singleton concreto. Los
13
- * endpoints los inyecta `app.config.ts` con `provideAppInitializer`,
14
- * derivándolos del registry — agregar un singleton de configuración nuevo
15
- * = declarar su schema, sin tocar este fichero (refactormotor.md §1 — el
16
- * schema es el único plano de control).
17
- *
18
- * No hay efectos en el constructor: la carga es explícita (`load`), así un
19
- * TestBed que sólo provee un ApiService parcial no recibe una llamada
20
- * síncrona a `get` durante la construcción.
21
- */
22
- @Service()
23
- export class ConfigService {
24
- private readonly api = inject(ApiService, { optional: true });
25
-
26
- /** Mapa reactivo de configuración global (p. ej. `public_base_url`). */
27
- readonly globalConfig = signal<Record<string, unknown>>({
28
- // Fallback genérico: el origen actual. Lo que declare el singleton
29
- // (p. ej. `share_message_template`) lo pone el backend, no el front.
30
- public_base_url: typeof window !== 'undefined' ? window.location.origin : '',
31
- });
32
-
33
- /** Endpoints conocidos; los guarda `load` para que `ensureLoaded` pueda reintentar. */
34
- private endpoints: readonly ResourceEndpoints[] = [];
35
-
36
- /**
37
- * `true` cuando la última carga terminó SIN fallos. Si algún singleton
38
- * falló (o ninguno respondió), queda `false` y el próximo punto crítico
39
- * vuelve a intentar: no hay estado «cargado a medias para siempre».
40
- */
41
- private loaded = false;
42
-
43
- /** Carga en curso: `ensureLoaded` la reutiliza en vez de duplicar viajes. */
44
- private inFlight: Promise<void> | null = null;
45
-
46
- /**
47
- * Carga todos los endpoints de configuración recibidos. Silenciosa: un
48
- * singleton que falle o que devuelva vacío no rompe nada, simplemente no
49
- * aporta claves (y deja `loaded = false` para poder reintentar).
50
- */
51
- load(endpoints: readonly ResourceEndpoints[]): void {
52
- this.endpoints = endpoints;
53
- void this.ensure();
54
- }
55
-
56
- /**
57
- * Garantiza la config global antes de un punto que la necesita.
58
- *
59
- * El load del bootstrap NO es bloqueante y sólo intenta una vez: si la app
60
- * arrancó sin sesión (el 401 de los singletons se traga en el `catchError`)
61
- * o la red tardó, la sesión seguía con la config vacía y, por ejemplo, el
62
- * mensaje de `copy-share` degradaba a «sólo la URL» (R8.7). Acá el reintento
63
- * corre con la sesión ya iniciada y responde bien; si ya se cargó, es un
64
- * no-op síncrono.
65
- */
66
- ensureLoaded(): Promise<void> {
67
- return this.ensure();
68
- }
69
-
70
- private ensure(): Promise<void> {
71
- if (this.loaded) return Promise.resolve();
72
- if (this.inFlight) return this.inFlight;
73
- if (!this.api || typeof this.api.get !== 'function' || this.endpoints.length === 0) {
74
- return Promise.resolve();
75
- }
76
-
77
- this.inFlight = firstValueFrom(
78
- forkJoin(
79
- this.endpoints.map((endpoint) =>
80
- this.api!.get<Record<string, unknown>>(endpoint).pipe(
81
- // `null` marca el fallo: con `of({})` un singleton caído era
82
- // indistinguible de uno realmente vacío y la carga quedaría
83
- // «hecha» sin datos.
84
- catchError(() => of(null)),
85
- ),
86
- ),
87
- ),
88
- ).then((blocks) => {
89
- this.inFlight = null;
90
- blocks.forEach((data) => {
91
- if (data && typeof data === 'object' && Object.keys(data).length > 0) {
92
- this.globalConfig.update((current) => ({ ...current, ...data }));
93
- }
94
- });
95
- this.loaded = blocks.every((data) => data !== null);
96
- });
97
-
98
- return this.inFlight;
99
- }
100
-
101
- /**
102
- * Contexto de datos para interpolar plantillas del schema
103
- * (`urlTemplate`, `shareTextTemplate`, `postCreate.description`, …).
104
- *
105
- * Sólo aporta datos y la base pública — la FORMA de la URL pública
106
- * (`/p/{ref}`) la declara el propio schema en su `urlTemplate`; este
107
- * servicio no decide cómo se arma el enlace.
108
- */
109
- buildInterpolationContext(record: Record<string, unknown>): Record<string, unknown> {
110
- const config = this.globalConfig();
111
- const baseUrl = String(config['public_base_url'] || window.location.origin).replace(/\/+$/, '');
112
-
113
- return {
114
- ...config,
115
- ...record,
116
- public_base_url: baseUrl,
117
- };
118
- }
119
- }
@@ -1,179 +0,0 @@
1
- import { testCatalog } from '../testing/test-catalog';
2
-
3
- setSchemaCatalog(testCatalog);
4
-
5
- import { TestBed } from '@angular/core/testing';
6
- import { of, throwError } from 'rxjs';
7
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
8
-
9
- import type { DataSource } from '../models/schema.model';
10
- import { getSchema, setSchemaCatalog } from '../registry/schema-catalog';
11
- import { ApiService } from './api.service';
12
- import { DataSourceService, dataSourceKey, interpolateParams } from './data-source.service';
13
-
14
- /** Filas mínimas: el motor no impone forma a las columnas. */
15
- const FILAS = [
16
- { slug: 'bebidas', name: 'Bebidas', active: true },
17
- { slug: 'pan', name: 'Pan', active: false },
18
- ];
19
-
20
- describe('DataSourceService', () => {
21
- const listSpy = vi.fn();
22
-
23
- beforeEach(async () => {
24
- listSpy.mockReset();
25
- listSpy.mockImplementation(() => of([...FILAS]));
26
- await TestBed.configureTestingModule({
27
- providers: [{ provide: ApiService, useValue: { list: listSpy } }],
28
- }).compileComponents();
29
- });
30
-
31
- afterEach(() => {
32
- vi.useRealTimers();
33
- });
34
-
35
- const ds = (): DataSourceService => TestBed.inject(DataSourceService);
36
-
37
- // ── interpolateParams ──────────────────────────────────────────────────
38
-
39
- describe('interpolateParams', () => {
40
- it('resuelve {campo} contra el contexto', () => {
41
- expect(interpolateParams({ categoria: '{slug}' }, { slug: 'bebidas' })).toEqual({
42
- categoria: 'bebidas',
43
- });
44
- });
45
-
46
- it("un valor que se resuelve vacío se OMITE (no viaja `''`)", () => {
47
- // Mandar `''` haría que el back comparara contra filas realmente
48
- // vacías: el parámetro ausente es fail-closed, el vacío no.
49
- expect(interpolateParams({ categoria: '{slug}', origen: 'manual' }, {})).toEqual({
50
- origen: 'manual',
51
- });
52
- expect(interpolateParams({ categoria: '{slug}' }, { slug: null })).toEqual({});
53
- });
54
-
55
- it('sin params devuelve objeto vacío y no explota con contexto ausente', () => {
56
- expect(interpolateParams(undefined)).toEqual({});
57
- expect(interpolateParams({ categoria: '{slug}' })).toEqual({});
58
- });
59
- });
60
-
61
- // ── dataSourceKey ──────────────────────────────────────────────────────
62
-
63
- describe('dataSourceKey', () => {
64
- const base: DataSource = { resource: 'categories', view: 'activos' };
65
-
66
- it('la clave es resource|view|params con las claves ordenadas', () => {
67
- expect(dataSourceKey({ ...base, params: { b: '2', a: '1' } })).toBe(
68
- 'categories|activos|a=1&b=2',
69
- );
70
- // Mismo pedido, distinto orden de escritura ⇒ MISMA entrada de caché.
71
- expect(dataSourceKey({ ...base, params: { a: '1', b: '2' } })).toBe(
72
- dataSourceKey({ ...base, params: { b: '2', a: '1' } }),
73
- );
74
- });
75
-
76
- it('un {campo} que cambia es OTRA clave', () => {
77
- const source: DataSource = { resource: 'orders', params: { cliente: '{dni}' } };
78
- expect(dataSourceKey(source, { dni: '1' })).not.toBe(dataSourceKey(source, { dni: '2' }));
79
- });
80
-
81
- it('una view distinta es otra clave; sin view queda el hueco', () => {
82
- expect(dataSourceKey({ resource: 'categories' })).toBe('categories||');
83
- expect(dataSourceKey({ resource: 'categories', view: 'activos' })).toBe(
84
- 'categories|activos|',
85
- );
86
- });
87
- });
88
-
89
- // ── rows: payload, caché y errores ─────────────────────────────────────
90
-
91
- describe('rows', () => {
92
- const source: DataSource = { resource: 'categories', view: 'activos' };
93
-
94
- it('pide el endpoint del recurso con { view, params } declarados', async () => {
95
- await ds().rows({ ...source, params: { orden: 'asc' } });
96
- expect(listSpy).toHaveBeenCalledTimes(1);
97
- // El servicio resuelve el id contra el registry y manda SU endpoint:
98
- // el componente nunca arma una URL.
99
- expect(listSpy).toHaveBeenCalledWith(getSchema('categories')!.endpoint, {
100
- view: 'activos',
101
- params: { orden: 'asc' },
102
- });
103
- });
104
-
105
- it('sin view ni params manda payload vacío (lectura llana)', async () => {
106
- await ds().rows({ resource: 'categories' });
107
- expect(listSpy).toHaveBeenCalledWith(getSchema('categories')!.endpoint, {});
108
- });
109
-
110
- it('la misma clave se pide UNA vez (caché por resource+view+params)', async () => {
111
- await ds().rows(source);
112
- await ds().rows(source);
113
- await ds().rows({ resource: 'categories', view: 'activos' });
114
- expect(listSpy).toHaveBeenCalledTimes(1);
115
- });
116
-
117
- it('parámetros resueltos distintos ⇒ otra vuelta', async () => {
118
- const conParam: DataSource = { resource: 'orders', params: { cliente: '{dni}' } };
119
- await ds().rows(conParam, { dni: '1' });
120
- await ds().rows(conParam, { dni: '2' });
121
- expect(listSpy).toHaveBeenCalledTimes(2);
122
- });
123
-
124
- it('`fresh` salta la caché (recarga tras una escritura)', async () => {
125
- await ds().rows(source);
126
- await ds().rows(source, undefined, true);
127
- expect(listSpy).toHaveBeenCalledTimes(2);
128
- });
129
-
130
- it('pasado el TTL vuelve a pedir (frescura, no inmortalidad)', async () => {
131
- vi.useFakeTimers();
132
- await ds().rows(source);
133
- vi.advanceTimersByTime(30_001);
134
- await ds().rows(source);
135
- expect(listSpy).toHaveBeenCalledTimes(2);
136
- });
137
-
138
- it('un error NO queda cacheado: el siguiente intento vuelve a pedir', async () => {
139
- listSpy.mockImplementationOnce(() => throwError(() => new Error('503')));
140
- await expect(ds().rows(source)).rejects.toThrow('503');
141
- await ds().rows(source);
142
- expect(listSpy).toHaveBeenCalledTimes(2);
143
- });
144
-
145
- it('una respuesta que no es lista llega como [] (el consumidor decide)', async () => {
146
- listSpy.mockImplementationOnce(() => of({ items: FILAS }));
147
- await expect(ds().rows(source)).resolves.toEqual([]);
148
- });
149
-
150
- it('un id inexistente es error de configuración y NO pide a la red', async () => {
151
- await expect(ds().rows({ resource: 'fantasma' })).rejects.toThrow(
152
- 'Recurso desconocido: fantasma',
153
- );
154
- expect(listSpy).not.toHaveBeenCalled();
155
- });
156
- });
157
-
158
- // ── invalidate ─────────────────────────────────────────────────────────
159
-
160
- describe('invalidate', () => {
161
- it('sin argumento vacía toda la caché', async () => {
162
- await ds().rows({ resource: 'categories' });
163
- await ds().rows({ resource: 'products' });
164
- ds().invalidate();
165
- await ds().rows({ resource: 'categories' });
166
- await ds().rows({ resource: 'products' });
167
- expect(listSpy).toHaveBeenCalledTimes(4);
168
- });
169
-
170
- it('con resourceId sólo tira las de ESE recurso (prefijo de clave)', async () => {
171
- await ds().rows({ resource: 'categories' });
172
- await ds().rows({ resource: 'products' });
173
- ds().invalidate('categories');
174
- await ds().rows({ resource: 'categories' });
175
- await ds().rows({ resource: 'products' });
176
- expect(listSpy).toHaveBeenCalledTimes(3);
177
- });
178
- });
179
- });
@@ -1,142 +0,0 @@
1
- import { inject, Service } from '@angular/core';
2
- import { firstValueFrom } from 'rxjs';
3
-
4
- import type { DataSource } from '../models/schema.model';
5
- import { interpolateTemplate } from '../utils/template-interpolator';
6
- import { getSchema } from '../registry/schema-catalog';
7
- import { ApiService } from './api.service';
8
-
9
- /** Fila cruda de un listado: el motor no impone forma a las columnas. */
10
- export type SourceRow = Record<string, unknown>;
11
-
12
- /**
13
- * Cuánto se reutiliza una respuesta pedida igual (F8 · R6.5).
14
- *
15
- * Un panel de administración lee mucho y escribe poco: medio minuto de
16
- * frescura cubre un recorrido por varios formularios sin repetir la misma
17
- * vuelta. Es una decisión de UX, no de contrato — `invalidate()` la salta
18
- * cuando el usuario acaba de crear lo que la fuente lista.
19
- */
20
- const TTL_MS = 30_000;
21
-
22
- /** Techo de claves cacheadas: un Map sin límite es una fuga en una sesión larga. */
23
- const MAX_CLAVES = 100;
24
-
25
- /**
26
- * `source.params` con cada `{campo}` resuelto contra `ctx`.
27
- *
28
- * - Un valor que se resuelve **vacío se OMITE** en vez de mandar `''`: el
29
- * back distingue «parámetro ausente» (fail-closed ⇒ sin filas) de un
30
- * `eq ''` que podría cruzarse con filas realmente vacías.
31
- * - Un parámetro sin marcador `{}` es literal y viaja tal cual.
32
- */
33
- export function interpolateParams(
34
- params: Record<string, string> | undefined,
35
- ctx?: Record<string, unknown>,
36
- ): Record<string, string> {
37
- const out: Record<string, string> = {};
38
- if (params === undefined) return out;
39
- for (const name of Object.keys(params)) {
40
- const raw = params[name];
41
- const value = interpolateTemplate(raw, ctx ?? {});
42
- if (value !== '') out[name] = value;
43
- }
44
- return out;
45
- }
46
-
47
- /**
48
- * Clave de caché de una fuente: `resource|view|params` (F8 · R6.5).
49
- *
50
- * Los parámetros van **resueltos** y ordenados, así que dos fuentes que
51
- * terminan pidiendo lo mismo comparten entrada, y un `{campo}` que cambia
52
- * es otra entrada. Pura: es también el valor que `resource({ params })` de
53
- * Angular compara para decidir si vuelve a cargar.
54
- */
55
- export function dataSourceKey(source: DataSource, ctx?: Record<string, unknown>): string {
56
- const params = interpolateParams(source.params, ctx);
57
- const names = Object.keys(params).sort();
58
- const query = names
59
- .map((name) => `${encodeURIComponent(name)}=${encodeURIComponent(params[name])}`)
60
- .join('&');
61
- return `${source.resource}|${source.view ?? ''}|${query}`;
62
- }
63
-
64
- /**
65
- * Fetcher único de `source` (F8 · R6.5): relations, selects y widgets del
66
- * panel piden sus filas ACÁ y no cada uno desde su componente.
67
- *
68
- * - **Caché por `resource+view+params`** con TTL e invalidación explícita —
69
- * es la pieza que evita que seis widgets del panel disparen seis vueltas
70
- * iguales a la misma vista.
71
- * - **Deduplicación de vuelta en vuelo**: dos consumidores que pidan la misma
72
- * clave en el mismo ciclo comparten la promesa (no la respuesta, la vuelta).
73
- * - Un error **no queda cacheado**: se borra la entrada para que la recarga
74
- * del consumidor vuelva a intentarlo en vez de devolver siempre la misma
75
- * rechazada.
76
- */
77
- @Service()
78
- export class DataSourceService {
79
- private readonly api = inject(ApiService);
80
-
81
- private readonly cache = new Map<string, { promise: Promise<SourceRow[]>; at: number }>();
82
-
83
- /**
84
- * Filas de la fuente declarada.
85
- *
86
- * `fresh` salta la caché (recarga tras una escritura); `ctx` sólo se usa
87
- * para resolver `{campo}` en `params` y no cambia la forma de la respuesta.
88
- */
89
- async rows(
90
- source: DataSource,
91
- ctx?: Record<string, unknown>,
92
- fresh = false,
93
- ): Promise<SourceRow[]> {
94
- const key = dataSourceKey(source, ctx);
95
- if (!fresh) {
96
- const hit = this.cache.get(key);
97
- if (hit !== undefined && Date.now() - hit.at < TTL_MS) return hit.promise;
98
- }
99
- const promise = this.fetch(source, ctx).catch((error: unknown) => {
100
- this.cache.delete(key);
101
- throw error;
102
- });
103
- this.cache.set(key, { promise, at: Date.now() });
104
- if (this.cache.size > MAX_CLAVES) {
105
- // El Map conserva el orden de inserción: sale la más vieja.
106
- const oldest = this.cache.keys().next();
107
- if (!oldest.done) this.cache.delete(oldest.value);
108
- }
109
- return promise;
110
- }
111
-
112
- /**
113
- * Vacía las filas ya pedidas. Sin argumento, todas; con un `resourceId`,
114
- * sólo las de ese recurso (lo que acaba de crear el drawer de relación).
115
- */
116
- invalidate(resourceId?: string): void {
117
- if (resourceId === undefined) {
118
- this.cache.clear();
119
- return;
120
- }
121
- const prefix = `${resourceId}|`;
122
- for (const key of [...this.cache.keys()]) {
123
- if (key.startsWith(prefix)) this.cache.delete(key);
124
- }
125
- }
126
-
127
- private async fetch(source: DataSource, ctx?: Record<string, unknown>): Promise<SourceRow[]> {
128
- const target = getSchema(source.resource);
129
- if (!target) {
130
- // Un id que ni siquiera existe en el registry es error de
131
- // configuración, no de red: el consumidor lo pinta como «no se
132
- // pudieron cargar» con este texto.
133
- throw new Error(`Recurso desconocido: ${source.resource}`);
134
- }
135
- const payload: Record<string, unknown> = {};
136
- if (source.view !== undefined && source.view !== '') payload['view'] = source.view;
137
- const params = interpolateParams(source.params, ctx);
138
- if (Object.keys(params).length > 0) payload['params'] = params;
139
- const rows = await firstValueFrom(this.api.list<SourceRow>(target.endpoint, payload));
140
- return Array.isArray(rows) ? rows : [];
141
- }
142
- }
@@ -1,50 +0,0 @@
1
- import { ApiError } from '../models/api.model';
2
- import { ErrorMapperService } from './error-mapper.service';
3
-
4
- /**
5
- * D42 — el422 con `errors[]` tiene que llegar PINTADO campo a campo.
6
- *
7
- * La clave que devuelve `map` es exactamente la que después resuelve el
8
- * host como `serverErrors[prefix + key]` (render-host:529), así que aquí se
9
- * comprueba la forma entera: varias rutas a la vez, el fallback a `general`
10
- * cuando ninguna ruta es pintable y el caso viejo del `path` del sobre.
11
- */
12
- describe('ErrorMapperService — errores de validación con ruta', () => {
13
- const mapper = new ErrorMapperService();
14
-
15
- it('varios issues con ruta → un campo por ruta, con su mensaje', () => {
16
- const error = new ApiError(422, 'Errores de validación', undefined, undefined, [
17
- { path: 'sku', message: 'Debe tener al menos 5 caracteres.', code: 'VALIDATION_MIN_LENGTH' },
18
- { path: 'faq[2].answer', message: 'Campo obligatorio.', code: 'VALIDATION_REQUIRED' },
19
- ]);
20
- expect(mapper.map(error)).toEqual({
21
- fields: {
22
- sku: 'Debe tener al menos 5 caracteres.',
23
- 'faq[2].answer': 'Campo obligatorio.',
24
- },
25
- });
26
- });
27
-
28
- it('sin ninguna ruta pintable, el mensaje del sobre queda en general', () => {
29
- const sinRutas = new ApiError(422, 'Errores de validación', undefined, undefined, [
30
- { path: '', message: 'Esto no es pintable' },
31
- ]);
32
- expect(mapper.map(sinRutas)).toEqual({ fields: {}, general: 'Errores de validación' });
33
-
34
- const sinIssues = new ApiError(409, 'El registro cambió o ya existe.');
35
- expect(mapper.map(sinIssues)).toEqual({
36
- fields: {},
37
- general: 'El registro cambió o ya existe.',
38
- });
39
- });
40
-
41
- it('conserva el caso viejo: `path` suelto en el sobre → un campo', () => {
42
- const error = new ApiError(422, 'Ya existe un registro con este valor', 'name');
43
- expect(mapper.map(error)).toEqual({ fields: { name: 'Ya existe un registro con este valor' } });
44
- });
45
-
46
- it('un error que no es de la API cae en general', () => {
47
- expect(mapper.map(new Error('boom'))).toEqual({ fields: {}, general: 'boom' });
48
- expect(mapper.map('¿esto?')).toEqual({ fields: {}, general: 'Error inesperado' });
49
- });
50
- });
@@ -1,49 +0,0 @@
1
- import { Service } from '@angular/core';
2
-
3
- import { ApiError } from '../models/api.model';
4
-
5
- export interface MappedError {
6
- /** Errores por ruta de campo (ej. `faq[2].answer`); se pintan en el campo exacto. */
7
- fields: Record<string, string>;
8
- /** Mensaje general; presente cuando el error no tiene ruta de campo (base.md §10). */
9
- general?: string;
10
- }
11
-
12
- /**
13
- * Convierte un error recibido en el formato que consume la UI:
14
- * rutas de campo para pintar el error donde corresponde, o mensaje general.
15
- *
16
- * Un422 trae VARIOS issues con ruta (`error.errors[]`, auth.md §6); cada uno
17
- * se convierte en `fields[path] = mensaje`, que es exactamente la clave que
18
- * después resuelve el host como `serverErrors[prefix + key]`. Si al final no
19
- * hay ninguna ruta pintable (error sin `errors[]`, issue sin `path`), el
20
- * mensaje del sobre queda en `general` como hasta ahora (base.md §10).
21
- */
22
- @Service()
23
- export class ErrorMapperService {
24
- map(error: unknown): MappedError {
25
- if (error instanceof ApiError) {
26
- const fields: Record<string, string> = {};
27
- for (const issue of error.issues) {
28
- if (issue.path) {
29
- fields[issue.path] = issue.message;
30
- }
31
- }
32
- // Sobre con `path` suelto (sin `errors[]`): misma historia, un campo.
33
- if (error.fieldPath && fields[error.fieldPath] === undefined) {
34
- fields[error.fieldPath] = error.message;
35
- }
36
- if (Object.keys(fields).length > 0) {
37
- return { fields };
38
- }
39
- }
40
- return { fields: {}, general: this.messageOf(error) };
41
- }
42
-
43
- messageOf(error: unknown): string {
44
- if (error instanceof Error) {
45
- return error.message;
46
- }
47
- return 'Error inesperado';
48
- }
49
- }
@@ -1,73 +0,0 @@
1
- import { Service, signal } from '@angular/core';
2
-
3
- export type ToastKind = 'success' | 'error' | 'info';
4
-
5
- export interface Toast {
6
- id: number;
7
- kind: ToastKind;
8
- message: string;
9
- }
10
-
11
- export interface ConfirmOptions {
12
- title: string;
13
- message: string;
14
- confirmLabel?: string;
15
- cancelLabel?: string;
16
- }
17
-
18
- /**
19
- * Notificaciones de la app: toasts (señales, se renderizan en `app-toast`,
20
- * Fase 5) y un diálogo de confirmación con respuesta como `Promise`
21
- * (base.md §10: borrado con confirmación, aviso de cambios sin guardar).
22
- */
23
- @Service()
24
- export class NotificationService {
25
- readonly toasts = signal<Toast[]>([]);
26
- /** Confirmación en curso; `null` = sin diálogo. */
27
- readonly confirmation = signal<ConfirmOptions | null>(null);
28
-
29
- private nextId = 1;
30
- private pendingResolve: ((accepted: boolean) => void) | null = null;
31
-
32
- success(message: string): void {
33
- this.push('success', message);
34
- }
35
-
36
- error(message: string): void {
37
- this.push('error', message);
38
- }
39
-
40
- info(message: string): void {
41
- this.push('info', message);
42
- }
43
-
44
- dismiss(id: number): void {
45
- this.toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
46
- }
47
-
48
- /** Abre el diálogo de confirmación y espera la respuesta del usuario. */
49
- confirm(options: ConfirmOptions): Promise<boolean> {
50
- // Solo una confirmación a la vez: la anterior se responde como rechazo.
51
- this.pendingResolve?.(false);
52
- this.confirmation.set(options);
53
- return new Promise<boolean>((resolve) => {
54
- this.pendingResolve = resolve;
55
- });
56
- }
57
-
58
- /** Resuelve la confirmación pendiente (lo llama el componente de diálogo, Fase 5). */
59
- resolveConfirmation(accepted: boolean): void {
60
- this.confirmation.set(null);
61
- const resolve = this.pendingResolve;
62
- this.pendingResolve = null;
63
- resolve?.(accepted);
64
- }
65
-
66
- private push(kind: ToastKind, message: string): void {
67
- const id = this.nextId++;
68
- this.toasts.update((toasts) => [...toasts, { id, kind, message }]);
69
- if (kind !== 'error') {
70
- setTimeout(() => this.dismiss(id), 4000);
71
- }
72
- }
73
- }
@@ -1,41 +0,0 @@
1
- import { Service, signal } from '@angular/core';
2
-
3
- /** Pedido de «Crear nuevo» lanzado desde el dropdown de una relación. */
4
- export interface RelationCreateRequest {
5
- /** Recurso a crear (el `source.resource` de la relación). */
6
- resource: string;
7
- /**
8
- * Se invoca con la clave recién creada. Vive en la relación porque es ella
9
- * la que tiene que recargar sus opciones y preseleccionar el valor.
10
- */
11
- onCreated: (key: string) => void;
12
- }
13
-
14
- /**
15
- * Puente entre el control `relation` y el drawer que abre el formulario.
16
- *
17
- * Existe como señal inyectable y NO como un `output()` encadenado porque el
18
- * camino directo — `relation → DrawerForm → FieldHost → relation` — arma un
19
- * ciclo de imports de módulos: `field-host` se decoraría con
20
- * `FieldRelation === undefined` y Angular tiraría `Cannot read properties of
21
- * undefined (reading 'ɵcmp')`. El campo no puede importar un componente que,
22
- * a su vez, lo importa a él.
23
- *
24
- * Sólo hay un drawer a la vez, así que una única señal alcanza: quien lo
25
- * abre lo cierra con `clear()` al recibir `close`/`saved`.
26
- */
27
- @Service()
28
- export class RelationDrawerService {
29
- private readonly pending = signal<RelationCreateRequest | null>(null);
30
-
31
- /** Pedido en curso; `null` cuando no hay panel abierto. */
32
- readonly request = this.pending.asReadonly();
33
-
34
- open(resource: string, onCreated: (key: string) => void): void {
35
- this.pending.set({ resource, onCreated });
36
- }
37
-
38
- clear(): void {
39
- this.pending.set(null);
40
- }
41
- }