@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,90 +0,0 @@
1
- /**
2
- * Mensaje completo a copiar o compartir.
3
- *
4
- * `shareTextTemplate` es el MENSAJE FORMATEADO por el schema (el que trae
5
- * saludo, ref, PIN o el enlace ya escrito dentro), mientras que `urlTemplate`
6
- * es sólo el enlace. Los tres caminos —copiar, compartir nativo y WhatsApp—
7
- * deben ofrecer el mismo texto: antes `copy()` y la acción del listado sólo
8
- * escribían `url`, así que el operador se quedaba sin el mensaje.
9
- *
10
- * Tres casos, sin perder información y sin duplicar el enlace:
11
- * - sin `shareText` → sólo la URL
12
- * - `shareText` con el sitio ya mencionado → el mensaje tal cual
13
- * - `shareText` sin el sitio → mensaje + espacio + URL
14
- *
15
- * "Sitio" se decide por ORIGIN, no por la URL exacta: la plantilla puede
16
- * referenciar sólo la base (`{public_base_url}` → `https://ejemplo.com`)
17
- * o la URL completa con el path (`…/p/{ref}`); en ambos casos el mensaje
18
- * YA apunta al sitio y no se le pega nada al final. Antes se comparaba
19
- * contra la URL completa, así que un mensaje con la base recibía la URL
20
- * con código duplicada al final.
21
- *
22
- * @param url Enlace resuelto (`urlTemplate`).
23
- * @param shareText Mensaje formateado opcional (`shareTextTemplate`).
24
- */
25
- export function buildShareMessage(url: string, shareText?: string): string {
26
- const text = (shareText ?? '').trim();
27
- if (!text) return url;
28
- if (url && mentionsSite(text, url)) return text;
29
- return url ? `${text} ${url}` : text;
30
- }
31
-
32
- /** ¿El mensaje ya apunta al sitio de `url` (origin o URL exacta)? */
33
- function mentionsSite(text: string, url: string): boolean {
34
- if (text.includes(url)) return true;
35
- try {
36
- const { origin } = new URL(url);
37
- return origin !== 'null' && text.includes(origin);
38
- } catch {
39
- // `url` relativa (`/p/123`): sin origin que comparar, sólo la URL exacta.
40
- return false;
41
- }
42
- }
43
-
44
- /**
45
- * Escribe en el portapapeles sin reventar: primero la API moderna, después
46
- * el `textarea` + `execCommand` (obsoleto, pero sigue siendo el fallback
47
- * que existe en contextos no seguros).
48
- *
49
- * Único punto del admin que sabe cómo copiar: `copy-share`, las acciones de
50
- * fila del listado y cualquier widget futuro comparten este camino, en vez
51
- * de reimplementar cada uno sus propios fallbacks.
52
- *
53
- * @returns `true` si el texto quedó copiado por alguna de las vías.
54
- */
55
- export async function writeClipboard(text: string): Promise<boolean> {
56
- const clipboard = typeof navigator !== 'undefined' ? navigator.clipboard : undefined;
57
- if (clipboard && typeof clipboard.writeText === 'function') {
58
- try {
59
- await clipboard.writeText(text);
60
- return true;
61
- } catch {
62
- // Permiso denegado o contexto no seguro: sigue al fallback legado.
63
- }
64
- }
65
- return legacyCopy(text);
66
- }
67
-
68
- function legacyCopy(text: string): boolean {
69
- if (typeof document === 'undefined' || typeof document.execCommand !== 'function') {
70
- return false;
71
- }
72
- const area = document.createElement('textarea');
73
- area.value = text;
74
- area.setAttribute('readonly', '');
75
- area.style.position = 'fixed';
76
- area.style.top = '0';
77
- area.style.opacity = '0';
78
- document.body.appendChild(area);
79
- area.select();
80
-
81
- let copied = false;
82
- try {
83
- copied = document.execCommand('copy');
84
- } catch {
85
- copied = false;
86
- }
87
-
88
- document.body.removeChild(area);
89
- return copied;
90
- }
@@ -1,95 +0,0 @@
1
- import { resolveEndpointPath } from './context-resolver';
2
-
3
- /**
4
- * Plan `doc/context-sources-plan.md` · Fase 2.
5
- *
6
- * TDD: éstos son los tests RED del resolver puro. Congelan las reglas del
7
- * contrato: resolución anidada, escalares, codificación, pereza (sin
8
- * marcadores no se llama a ninguna fuente) y TODOS los casos fail-loud.
9
- */
10
- describe('context-resolver — marcadores en paths de endpoints', () => {
11
- const fuentes = {
12
- auth: () => ({ user: { id: 'u_9', name: 'Ana' }, token: 'tok' }),
13
- config: () => ({ pais: 'AR' }),
14
- tenant: () => 'acme',
15
- numero: () => 7,
16
- ruta: () => 'a b/c',
17
- vacio: () => '',
18
- nulo: () => null,
19
- objeto: () => ({ a: 1 }),
20
- rota: () => {
21
- throw new Error('boom fuente');
22
- },
23
- };
24
-
25
- // ── Casos felices ────────────────────────────────────────────────────────
26
- it('resuelve una ruta anidada {auth.user.id}', () => {
27
- expect(resolveEndpointPath('/businesses/{auth.user.id}/orders', fuentes)).toBe(
28
- '/businesses/u_9/orders',
29
- );
30
- });
31
-
32
- it('resuelve la fuente entera {tenant}', () => {
33
- expect(resolveEndpointPath('/tenants/{tenant}/orders', fuentes)).toBe('/tenants/acme/orders');
34
- });
35
-
36
- it('convierte escalares a texto', () => {
37
- expect(resolveEndpointPath('/page/{numero}', fuentes)).toBe('/page/7');
38
- });
39
-
40
- it('codifica cada valor como segmento de URL', () => {
41
- expect(resolveEndpointPath('/x/{ruta}/y', fuentes)).toBe('/x/a%20b%2Fc/y');
42
- });
43
-
44
- it('resuelve varios marcadores en un mismo path', () => {
45
- expect(
46
- resolveEndpointPath('/tenants/{tenant}/businesses/{auth.user.id}/paises/{config.pais}', fuentes),
47
- ).toBe('/tenants/acme/businesses/u_9/paises/AR');
48
- });
49
-
50
- it('sin marcadores devuelve el path tal cual y NO llama a ninguna fuente', () => {
51
- const perezosa = {
52
- auth: () => {
53
- throw new Error('no debe evaluarse sin marcadores');
54
- },
55
- };
56
- expect(resolveEndpointPath('/admin/products', perezosa)).toBe('/admin/products');
57
- });
58
-
59
- it('resuelve un marcador dentro de un path que ya lleva query string', () => {
60
- expect(resolveEndpointPath('/orders?owner={auth.user.id}&limit=10', fuentes)).toBe(
61
- '/orders?owner=u_9&limit=10',
62
- );
63
- });
64
-
65
- // ── Fail loud ────────────────────────────────────────────────────────────
66
- it('valor ausente ⇒ error que nombra el path y el marcador', () => {
67
- const path = '/x/{auth.user.nope}/y';
68
- expect(() => resolveEndpointPath(path, fuentes)).toThrow(path);
69
- expect(() => resolveEndpointPath(path, fuentes)).toThrow('auth.user.nope');
70
- });
71
-
72
- it('valor vacío ⇒ error, nunca un segmento vacío en la URL', () => {
73
- expect(() => resolveEndpointPath('/x/{vacio}/y', fuentes)).toThrow('/x/{vacio}/y');
74
- });
75
-
76
- it('valor nulo ⇒ error', () => {
77
- expect(() => resolveEndpointPath('/x/{nulo}', fuentes)).toThrow('nulo');
78
- });
79
-
80
- it('fuente no registrada ⇒ error con el nombre de la fuente', () => {
81
- expect(() => resolveEndpointPath('/x/{desconocida.id}', fuentes)).toThrow('desconocida');
82
- });
83
-
84
- it('getter que revienta ⇒ su error se propaga tal cual', () => {
85
- expect(() => resolveEndpointPath('/x/{rota}', fuentes)).toThrow('boom fuente');
86
- });
87
-
88
- it('{key} sin resolver ⇒ error que aclara que sólo aplica a operaciones con clave', () => {
89
- expect(() => resolveEndpointPath('/x/{key}', fuentes)).toThrow('key');
90
- });
91
-
92
- it('valor no escalar ⇒ error, nunca [object Object] en la URL', () => {
93
- expect(() => resolveEndpointPath('/x/{objeto}', fuentes)).toThrow('objeto');
94
- });
95
- });
@@ -1,101 +0,0 @@
1
- /**
2
- * Resolución de marcadores de contexto en paths de endpoints.
3
- *
4
- * Plan `doc/context-sources-plan.md` · Fase 2. Lógica PURA: ni HTTP ni DI —
5
- * recibe un path y un mapa de getters de fuentes y devuelve el path ya
6
- * resuelto, o revienta.
7
- *
8
- * Reglas del contrato (R1–R4 del plan):
9
- *
10
- * - `{<fuente>}` / `{<fuente>.<ruta.anidada>}` → valor de la fuente en el
11
- * momento de la llamada (los getters se evalúan SOLO si hay marcadores).
12
- * - Cada valor se codifica como segmento de URL (`encodeURIComponent`).
13
- * - **Fail loud**: fuente no registrada, valor ausente/vacío, valor no
14
- * escalar o `{key}` sin resolver ⇒ error que nombra el path y el marcador.
15
- * Jamás se devuelve un segmento vacío ni el texto literal del marcador.
16
- * - Sin marcadores ⇒ el path vuelve intacto y ninguna fuente se evalúa.
17
- *
18
- * OJO con `interpolateTemplate` (R3): su semántica «ausente ⇒ cadena vacía»
19
- * es correcta para acciones y fuentes de datos, pero acá sería un 404 mudo.
20
- * Por eso la lectura y la validación viven en este fichero y ese helper no
21
- * se toca.
22
- */
23
-
24
- /** `{nombre}` o `{nombre.ruta.anidada}` — misma forma que usa el interpolador. */
25
- const MARKER = /\{([a-zA-Z0-9_.]+)\}/g;
26
-
27
- /**
28
- * Resuelve los marcadores de `path` contra `sources`.
29
- *
30
- * @param path Path declarado en `ResourceEndpoints`, tal cual vino del schema.
31
- * @param sources Getters por nombre de fuente (`auth`, `config`, `valueSources`…).
32
- * @returns El path con cada marcador sustituido y codificado.
33
- * @throws Error nombrando path y marcador ante cualquier valor irresoluble.
34
- */
35
- export function resolveEndpointPath(
36
- path: string,
37
- sources: Readonly<Record<string, () => unknown>>,
38
- ): string {
39
- if (!path.includes('{')) return path;
40
- return path.replace(MARKER, (marker, nombre: string) =>
41
- sustituir(path, marker, nombre, sources),
42
- );
43
- }
44
-
45
- /** Sustituye UN marcador. `path` completo sólo viaja para el mensaje de error. */
46
- function sustituir(
47
- path: string,
48
- marker: string,
49
- nombre: string,
50
- sources: Readonly<Record<string, () => unknown>>,
51
- ): string {
52
- if (nombre === 'key') {
53
- throw new Error(
54
- `[gas-admin-ui] path '${path}': ${marker} llegó sin resolver — ` +
55
- `la clave sólo la sustituyen get/update/remove antes de resolver el contexto.`,
56
- );
57
- }
58
-
59
- const punto = nombre.indexOf('.');
60
- const fuente = punto === -1 ? nombre : nombre.slice(0, punto);
61
- const getter = sources[fuente];
62
- if (typeof getter !== 'function') {
63
- throw new Error(
64
- `[gas-admin-ui] path '${path}': no se pudo resolver ${marker} — ` +
65
- `la fuente '${fuente}' no está registrada.`,
66
- );
67
- }
68
-
69
- // El getter se evalúa acá y sólo acá: si revienta, su error se propaga.
70
- const valor = punto === -1 ? getter() : leerRuta(getter(), nombre.slice(punto + 1));
71
-
72
- if (valor === undefined || valor === null) {
73
- throw new Error(
74
- `[gas-admin-ui] path '${path}': no se pudo resolver ${marker} — sin valor para '${nombre}'.`,
75
- );
76
- }
77
- if (typeof valor === 'object') {
78
- throw new Error(
79
- `[gas-admin-ui] path '${path}': no se pudo resolver ${marker} — ` +
80
- `el valor de '${fuente}' no es un segmento de URL (no es escalar).`,
81
- );
82
- }
83
-
84
- const texto = String(valor);
85
- if (texto === '') {
86
- throw new Error(
87
- `[gas-admin-ui] path '${path}': no se pudo resolver ${marker} — valor vacío en '${fuente}'.`,
88
- );
89
- }
90
- return encodeURIComponent(texto);
91
- }
92
-
93
- /** Lectura profunda `a.b.c` sobre el valor de la fuente; inexistente ⇒ `undefined`. */
94
- function leerRuta(valor: unknown, ruta: string): unknown {
95
- let actual: unknown = valor;
96
- for (const paso of ruta.split('.')) {
97
- if (actual === null || typeof actual !== 'object') return undefined;
98
- actual = (actual as Record<string, unknown>)[paso];
99
- }
100
- return actual;
101
- }
@@ -1,70 +0,0 @@
1
- import { extractPagination } from './response-unwrapper';
2
-
3
- // Extracción de metadata de paginación (plan doc/engine-refactor-plan.md · Fase 2.2)
4
- // Lo consume `listPage()` (Fase 3); acá se prueba la utilidad pura.
5
- describe('extractPagination', () => {
6
- it('lee cursor/total/hasMore de meta cuando metaKey está declarado', () => {
7
- const raw = { data: [{ slug: 'a' }], meta: { cursor: 'c1', count: 10, more: true } };
8
- const result = extractPagination(raw, {
9
- dataKey: 'data',
10
- metaKey: 'meta',
11
- pagination: { cursorKey: 'cursor', totalKey: 'count', hasMoreKey: 'more' },
12
- });
13
- expect(result).toEqual({ nextCursor: 'c1', total: 10, hasMore: true });
14
- });
15
-
16
- it('auto-detecta claves comunes (nextCursor, total, hasMore) en el body', () => {
17
- const raw = { items: [{ slug: 'a' }], nextCursor: 'tok', total: 42, hasMore: true };
18
- expect(extractPagination(raw, { dataKey: 'items' })).toEqual({
19
- nextCursor: 'tok',
20
- total: 42,
21
- hasMore: true,
22
- });
23
- });
24
-
25
- it('sin cursor ni claves de paginación ⇒ nextCursor null, total 0, hasMore false', () => {
26
- const raw = { items: [{ slug: 'a' }] };
27
- expect(extractPagination(raw, undefined)).toEqual({
28
- nextCursor: null,
29
- total: 0,
30
- hasMore: false,
31
- });
32
- });
33
-
34
- it('con cursor presente y sin flag hasMore explícito ⇒ hasMore true (derivado)', () => {
35
- const raw = { items: [], nextCursor: 'c2' };
36
- expect(extractPagination(raw, undefined)).toEqual({
37
- nextCursor: 'c2',
38
- total: 0,
39
- hasMore: true,
40
- });
41
- });
42
-
43
- it('metaKey declarado pero ausente en el body ⇒ cae al body', () => {
44
- const raw = { items: [], nextCursor: 'c3', total: 7 };
45
- const result = extractPagination(raw, { dataKey: 'items', metaKey: 'meta' });
46
- expect(result).toEqual({ nextCursor: 'c3', total: 7, hasMore: true });
47
- });
48
-
49
- it('cursor vacío string se trata como ausente (nextCursor null, hasMore false)', () => {
50
- const raw = { items: [], nextCursor: '' };
51
- expect(extractPagination(raw, undefined)).toEqual({
52
- nextCursor: null,
53
- total: 0,
54
- hasMore: false,
55
- });
56
- });
57
-
58
- it('cuerpo no-objeto ⇒ sin paginación (no lanza)', () => {
59
- expect(extractPagination(null, undefined)).toEqual({
60
- nextCursor: null,
61
- total: 0,
62
- hasMore: false,
63
- });
64
- });
65
-
66
- it('hasMoreKey explícito tiene prioridad sobre el derivado del cursor', () => {
67
- const raw = { items: [], nextCursor: 'c9', hasMore: false };
68
- expect(extractPagination(raw, undefined).hasMore).toBe(false);
69
- });
70
- });
@@ -1,103 +0,0 @@
1
- /**
2
- * Desempaquetado opt-in de respuestas HTTP anidadas (`{ data, meta }`,
3
- * `{ items, total }`, o claves arbitrarias).
4
- *
5
- * El motor NO asume un sobre: sólo desempaqueta cuando la declaración
6
- * `ResponseUnwrap` está presente. Sin ella, el comportamiento actual se
7
- * conserva (arreglo plano, `{ items }`, u objeto crudo).
8
- *
9
- * Mantener esta lógica aquí (y no en `ApiService`) deja el servicio enfocado
10
- * en el despacho y facilita la prueba de las reglas de unwrap.
11
- */
12
-
13
- import type { ResponseUnwrap } from '../models/schema.model';
14
-
15
- export type UnwrapOperation = 'list' | 'get' | 'create' | 'update' | 'remove';
16
-
17
- /**
18
- * Devuelve `true` si la declaración `unwrap` aplica a la operación dada.
19
- * Si `apply` falta, se asume `'all'` (decisión fija del plan).
20
- */
21
- export function appliesTo(unwrap: ResponseUnwrap, operation: UnwrapOperation): boolean {
22
- const apply = unwrap.apply ?? 'all';
23
- return apply === 'all' || apply === operation;
24
- }
25
-
26
- /**
27
- * Extrae el payload declarado por `unwrap.dataKey` del cuerpo `raw`.
28
- *
29
- * - Si `unwrap` no aplica a `operation`, devuelve `raw` tal cual.
30
- * - Si aplica y `raw` tiene la clave, devuelve su valor.
31
- * - Si aplica y la clave falta, lanza un `Error` descriptivo (no silencia).
32
- */
33
- export function unwrapResponse(raw: unknown, unwrap: ResponseUnwrap | undefined, operation: UnwrapOperation): unknown {
34
- if (!unwrap || !appliesTo(unwrap, operation)) {
35
- return raw;
36
- }
37
- if (raw !== null && typeof raw === 'object' && !Array.isArray(raw)) {
38
- const record = raw as Record<string, unknown>;
39
- if (Object.prototype.hasOwnProperty.call(record, unwrap.dataKey)) {
40
- return record[unwrap.dataKey];
41
- }
42
- }
43
- throw new Error(
44
- `Response unwrap declared dataKey '${unwrap.dataKey}' but it is missing in the response for operation '${operation}'`,
45
- );
46
- }
47
-
48
- /** Metadata de paginación extraída del sobre; la consume `ApiService.listPage()`. */
49
- export interface PaginationMeta {
50
- nextCursor: string | null;
51
- total: number;
52
- hasMore: boolean;
53
- }
54
-
55
- const NO_PAGINATION: PaginationMeta = { nextCursor: null, total: 0, hasMore: false };
56
-
57
- /**
58
- * Extrae la metadata de paginación del cuerpo `raw` según la declaración
59
- * `unwrap.pagination` (cursorKey/totalKey/hasMoreKey).
60
- *
61
- * - Con `metaKey` declarado Y presente en el body, las claves se leen de ese
62
- * sub-objeto; si no, del body raíz.
63
- * - Sin claves declaradas se auto-detectan las comunes: `nextCursor`,
64
- * `total`, `hasMore`.
65
- * - `hasMore` explícito (boolean) tiene prioridad; sin él se deriva del
66
- * cursor: presente ⇒ `true`, ausente/vacío ⇒ `false`.
67
- * - Cuerpo no-objeto ⇒ sin paginación. Nunca lanza: la paginación es
68
- * opt-in y su ausencia sólo significa `hasMore = false`.
69
- */
70
- export function extractPagination(
71
- raw: unknown,
72
- unwrap: ResponseUnwrap | undefined,
73
- ): PaginationMeta {
74
- if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
75
- return { ...NO_PAGINATION };
76
- }
77
- const body = raw as Record<string, unknown>;
78
-
79
- let source = body;
80
- const metaKey = unwrap?.metaKey;
81
- if (metaKey) {
82
- const meta = body[metaKey];
83
- if (meta !== null && typeof meta === 'object' && !Array.isArray(meta)) {
84
- source = meta as Record<string, unknown>;
85
- }
86
- }
87
-
88
- const cursorKey = unwrap?.pagination?.cursorKey ?? 'nextCursor';
89
- const totalKey = unwrap?.pagination?.totalKey ?? 'total';
90
- const hasMoreKey = unwrap?.pagination?.hasMoreKey ?? 'hasMore';
91
-
92
- const cursorValue = source[cursorKey] ?? body[cursorKey];
93
- const nextCursor = typeof cursorValue === 'string' && cursorValue !== '' ? cursorValue : null;
94
-
95
- const totalValue = source[totalKey] ?? body[totalKey];
96
- const total = typeof totalValue === 'number' ? totalValue : 0;
97
-
98
- const hasMoreValue = source[hasMoreKey] ?? body[hasMoreKey];
99
- const hasMore =
100
- typeof hasMoreValue === 'boolean' ? hasMoreValue : nextCursor !== null;
101
-
102
- return { nextCursor, total, hasMore };
103
- }
@@ -1,96 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import type { DataSource, ResourceSchema } from '../models/schema.model';
4
- import { optionsFromRows } from './source-options';
5
-
6
- const TARGET: ResourceSchema = {
7
- id: 'categories',
8
- label: 'Categoría',
9
- labelPlural: 'Categorías',
10
- kind: 'collection',
11
- endpoint: { list: '/admin/categories' },
12
- keyField: 'slug',
13
- titleField: 'name',
14
- listColumns: [],
15
- fields: [],
16
- };
17
-
18
- const FILAS = [
19
- { slug: 'bebidas', name: 'Bebidas', description: 'Frías', active: true },
20
- { slug: 'pan', name: '', description: '', active: false },
21
- ];
22
-
23
- const source = (extra: Partial<DataSource> = {}): DataSource => ({
24
- resource: 'categories',
25
- ...extra,
26
- });
27
-
28
- describe('optionsFromRows', () => {
29
- it('usa valueField/labelField declarados en la fuente', () => {
30
- const opciones = optionsFromRows(FILAS, {
31
- source: source({ valueField: 'slug', labelField: 'name' }),
32
- target: TARGET,
33
- });
34
- expect(opciones).toEqual([
35
- { value: 'bebidas', label: 'Bebidas' },
36
- { value: 'pan', label: 'pan' }, // label vacío ⇒ cae al valor
37
- ]);
38
- });
39
-
40
- it('sin los campos declarados cae a keyField/titleField del recurso destino', () => {
41
- const opciones = optionsFromRows(FILAS, { source: source(), target: TARGET });
42
- expect(opciones[0]).toEqual({ value: 'bebidas', label: 'Bebidas' });
43
- });
44
-
45
- it('sin nada declarado el valor es `id` (último recurso conocido)', () => {
46
- const opciones = optionsFromRows([{ id: 'x' }], {
47
- source: source(),
48
- target: undefined,
49
- });
50
- expect(opciones).toEqual([{ value: 'x', label: 'x' }]);
51
- });
52
-
53
- it('una fila sin valor no es opción: no hay qué seleccionar', () => {
54
- const opciones = optionsFromRows(
55
- [{ slug: '', name: 'Vacía' }, { name: 'Sin clave' }, { slug: null, name: 'Nula' }],
56
- { source: source({ valueField: 'slug', labelField: 'name' }), target: TARGET },
57
- );
58
- expect(opciones).toEqual([]);
59
- });
60
-
61
- it('`onlyActive` descarta las inactivas en el cliente', () => {
62
- const opciones = optionsFromRows(FILAS, {
63
- source: source({ valueField: 'slug', labelField: 'name' }),
64
- target: TARGET,
65
- onlyActive: true,
66
- });
67
- expect(opciones.map((o) => o.value)).toEqual(['bebidas']);
68
- });
69
-
70
- it('secondaryField añade el dato con « · », y se cae si no hay dato', () => {
71
- const opciones = optionsFromRows(
72
- [
73
- { slug: 'a', name: 'A', description: 'Frías' },
74
- { slug: 'b', name: 'B', description: '' },
75
- { slug: 'c', name: 'C' },
76
- ],
77
- {
78
- source: source({ valueField: 'slug', labelField: 'name' }),
79
- target: TARGET,
80
- secondaryField: 'description',
81
- },
82
- );
83
- expect(opciones.map((o) => o.label)).toEqual(['A · Frías', 'B', 'C']);
84
- });
85
-
86
- it('no muta las filas de entrada', () => {
87
- const filas = [{ slug: 'a', name: 'A', active: false }];
88
- const copia = JSON.parse(JSON.stringify(filas));
89
- optionsFromRows(filas, {
90
- source: source({ valueField: 'slug', labelField: 'name' }),
91
- target: TARGET,
92
- onlyActive: true,
93
- });
94
- expect(filas).toEqual(copia);
95
- });
96
- });
@@ -1,54 +0,0 @@
1
- import type { DataSource, ResourceSchema, SelectOption } from '../models/schema.model';
2
-
3
- /** Contexto de mapeo: la fuente declarada más las particularidades del campo. */
4
- export interface RowsToOptions {
5
- /** Fuente de la que salieron las filas (F8 · R6.5). */
6
- source: DataSource;
7
- /** Schema del recurso destino: aporta `keyField`/`titleField` por defecto. */
8
- target: ResourceSchema | undefined;
9
- /** Descarta filas con `active: false` (`relation.onlyActive`). */
10
- onlyActive?: boolean;
11
- /** Dato secundario junto a la etiqueta («Juan Pérez · DNI 123»). */
12
- secondaryField?: string;
13
- }
14
-
15
- /**
16
- * Filas de una fuente declarada → opciones de desplegable (F8 · R6.5).
17
- *
18
- * Es el ÚNICO punto que traduce filas a `SelectOption`: antes esa regla
19
- * estaba escrita dos veces (en `relation` y cada consumidor montaba su
20
- * propia petición). Con `source` compartido, relaciones y desplegables con
21
- * datos remotos pasan por acá.
22
- *
23
- * Reglas, en orden:
24
- * - valor: `source.valueField` → `target.keyField` → `id`;
25
- * - etiqueta: `source.labelField` → `target.titleField` → el valor;
26
- * - fila sin valor (vacío o inexistente) no es opción: no hay qué seleccionar;
27
- * - `onlyActive` descarta las inactivas en el cliente — el back ya las excluye
28
- * de su FK, pero una lista cacheada puede traer una fila vieja.
29
- */
30
- export function optionsFromRows(
31
- rows: readonly Record<string, unknown>[],
32
- { source, target, onlyActive, secondaryField }: RowsToOptions,
33
- ): SelectOption[] {
34
- const valueKey = source.valueField ?? target?.keyField ?? 'id';
35
- const labelKey = source.labelField ?? target?.titleField ?? valueKey;
36
- const options: SelectOption[] = [];
37
- for (const row of rows) {
38
- if (onlyActive === true && row['active'] === false) continue;
39
- const value = row[valueKey];
40
- if (value === undefined || value === null || value === '') continue;
41
- const label = row[labelKey];
42
- const primary = typeof label === 'string' && label !== '' ? label : String(value);
43
- options.push({ value: String(value), label: withSecondary(primary, row, secondaryField) });
44
- }
45
- return options;
46
- }
47
-
48
- /** Etiqueta con su dato secundario, o la etiqueta tal cual si no hay. */
49
- function withSecondary(primary: string, row: Record<string, unknown>, key?: string): string {
50
- if (key === undefined) return primary;
51
- const secondary = row[key];
52
- if (secondary === undefined || secondary === null || secondary === '') return primary;
53
- return `${primary} · ${String(secondary)}`;
54
- }
@@ -1,59 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { interpolateTemplate } from './template-interpolator';
3
-
4
- describe('interpolateTemplate', () => {
5
- it('1. interpola variables simples en la plantilla', () => {
6
- const template = 'https://ejemplo.com/p/{ref}?cliente={customer_name}';
7
- const data = { ref: 'ORD-123', customer_name: 'Juan Perez' };
8
-
9
- const result = interpolateTemplate(template, data);
10
-
11
- expect(result).toBe('https://ejemplo.com/p/ORD-123?cliente=Juan Perez');
12
- });
13
-
14
- it('2. reemplaza variables nulas o indefinidas por cadena vacía', () => {
15
- const template = 'Pedido {ref} - Estado: {status}';
16
- const data = { ref: 'ORD-999' };
17
-
18
- const result = interpolateTemplate(template, data);
19
-
20
- expect(result).toBe('Pedido ORD-999 - Estado: ');
21
- });
22
-
23
- it('3. resuelve claves anidadas usando notación de punto', () => {
24
- const template = 'ID: {order.meta.id} - Nombre: {order.customer.name}';
25
- const data = {
26
- order: {
27
- meta: { id: 'M-55' },
28
- customer: { name: 'Maria' },
29
- },
30
- };
31
-
32
- const result = interpolateTemplate(template, data);
33
-
34
- expect(result).toBe('ID: M-55 - Nombre: Maria');
35
- });
36
-
37
- it('4. recurre al contexto adicional si la clave no está en data', () => {
38
- const template = '{public_base_url}/p/{ref}';
39
- const data = { ref: 'PED-404' };
40
- const extraContext = { public_base_url: 'https://retiro.tienda.com' };
41
-
42
- const result = interpolateTemplate(template, data, extraContext);
43
-
44
- expect(result).toBe('https://retiro.tienda.com/p/PED-404');
45
- });
46
-
47
- it('5. devuelve la misma plantilla si no contiene marcadores', () => {
48
- const template = 'Texto plano sin variables';
49
- const result = interpolateTemplate(template, { a: 1 });
50
-
51
- expect(result).toBe('Texto plano sin variables');
52
- });
53
-
54
- it('6. maneja plantillas vacías o nulas sin romper', () => {
55
- expect(interpolateTemplate('', { ref: '123' })).toBe('');
56
- // @ts-expect-error probando valor nulo
57
- expect(interpolateTemplate(null, { ref: '123' })).toBe('');
58
- });
59
- });