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

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/ng-package.json +7 -0
  2. package/package.json +3 -15
  3. package/src/lib/actions/action-registry.spec.ts +52 -0
  4. package/src/lib/actions/action-registry.ts +126 -0
  5. package/src/lib/actions/action-service.spec.ts +215 -0
  6. package/src/lib/actions/action-service.ts +87 -0
  7. package/src/lib/actions/descriptors.spec.ts +155 -0
  8. package/src/lib/actions/descriptors.ts +154 -0
  9. package/src/lib/columns/column-cell.ts +33 -0
  10. package/src/lib/columns/column-defaults.spec.ts +99 -0
  11. package/src/lib/columns/column-defaults.ts +84 -0
  12. package/src/lib/columns/column-format.spec.ts +274 -0
  13. package/src/lib/columns/descriptors.ts +113 -0
  14. package/src/lib/columns/format-badge.ts +51 -0
  15. package/src/lib/columns/format-boolean.ts +58 -0
  16. package/src/lib/columns/format-currency.ts +30 -0
  17. package/src/lib/columns/format-date.ts +35 -0
  18. package/src/lib/columns/format-number.ts +32 -0
  19. package/src/lib/columns/format-text.ts +23 -0
  20. package/src/lib/columns/format-thumbnail.ts +63 -0
  21. package/src/lib/core/adapters/firebase-auth.adapter.ts +6 -0
  22. package/src/lib/core/guards/auth.guard.spec.ts +88 -0
  23. package/src/lib/core/guards/auth.guard.ts +48 -0
  24. package/src/lib/core/guards/unsaved-changes.guard.ts +16 -0
  25. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +182 -0
  26. package/src/lib/core/interceptors/api-error.interceptor.ts +87 -0
  27. package/src/lib/core/models/api.model.ts +104 -0
  28. package/src/lib/core/models/schema-descriptions.ts +118 -0
  29. package/src/lib/core/models/schema.model.ts +1097 -0
  30. package/src/lib/core/registry/composition-validator.spec.ts +358 -0
  31. package/src/lib/core/registry/composition-validator.ts +270 -0
  32. package/src/lib/core/registry/field-validators.spec.ts +199 -0
  33. package/src/lib/core/registry/field-validators.ts +440 -0
  34. package/src/lib/core/registry/render-host.spec.ts +208 -0
  35. package/src/lib/core/registry/render-host.ts +646 -0
  36. package/src/lib/core/registry/render-registry.spec.ts +96 -0
  37. package/src/lib/core/registry/render-registry.ts +312 -0
  38. package/src/lib/core/registry/schema-catalog.ts +156 -0
  39. package/src/lib/core/services/api.service.spec.ts +1142 -0
  40. package/src/lib/core/services/api.service.ts +371 -0
  41. package/src/lib/core/services/auth.service.spec.ts +653 -0
  42. package/src/lib/core/services/auth.service.ts +503 -0
  43. package/src/lib/core/services/config.service.spec.ts +121 -0
  44. package/src/lib/core/services/config.service.ts +119 -0
  45. package/src/lib/core/services/data-source.service.spec.ts +179 -0
  46. package/src/lib/core/services/data-source.service.ts +142 -0
  47. package/src/lib/core/services/error-mapper.service.spec.ts +50 -0
  48. package/src/lib/core/services/error-mapper.service.ts +49 -0
  49. package/src/lib/core/services/notification.service.ts +73 -0
  50. package/src/lib/core/services/relation-drawer.service.ts +41 -0
  51. package/src/lib/core/services/theme.service.spec.ts +106 -0
  52. package/src/lib/core/services/theme.service.ts +86 -0
  53. package/src/lib/core/services/transport.spec.ts +198 -0
  54. package/src/lib/core/services/transport.ts +164 -0
  55. package/src/lib/core/services/upload.service.ts +81 -0
  56. package/src/lib/core/testing/categories.schema.ts +125 -0
  57. package/src/lib/core/testing/orders.schema.ts +372 -0
  58. package/src/lib/core/testing/products.schema.ts +258 -0
  59. package/src/lib/core/testing/site.schema.ts +195 -0
  60. package/src/lib/core/testing/test-catalog.ts +21 -0
  61. package/src/lib/core/tokens.ts +112 -0
  62. package/src/lib/core/utils/clipboard.spec.ts +55 -0
  63. package/src/lib/core/utils/clipboard.ts +90 -0
  64. package/src/lib/core/utils/context-resolver.spec.ts +95 -0
  65. package/src/lib/core/utils/context-resolver.ts +101 -0
  66. package/src/lib/core/utils/response-unwrapper.spec.ts +70 -0
  67. package/src/lib/core/utils/response-unwrapper.ts +103 -0
  68. package/src/lib/core/utils/source-options.spec.ts +96 -0
  69. package/src/lib/core/utils/source-options.ts +54 -0
  70. package/src/lib/core/utils/template-interpolator.spec.ts +59 -0
  71. package/src/lib/core/utils/template-interpolator.ts +56 -0
  72. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +207 -0
  73. package/src/lib/core/view-navigation/view-navigation.service.ts +132 -0
  74. package/src/lib/fields/boolean/boolean.descriptor.ts +11 -0
  75. package/src/lib/fields/boolean/boolean.ts +40 -0
  76. package/src/lib/fields/color/color.descriptor.ts +12 -0
  77. package/src/lib/fields/color/color.ts +34 -0
  78. package/src/lib/fields/currency/currency.descriptor.ts +12 -0
  79. package/src/lib/fields/currency/currency.ts +67 -0
  80. package/src/lib/fields/date/date.descriptor.ts +12 -0
  81. package/src/lib/fields/date/date.ts +36 -0
  82. package/src/lib/fields/descriptors.ts +122 -0
  83. package/src/lib/fields/display/display-badge.ts +65 -0
  84. package/src/lib/fields/display/display-date.ts +39 -0
  85. package/src/lib/fields/display/display-defaults.ts +84 -0
  86. package/src/lib/fields/display/display-file.ts +41 -0
  87. package/src/lib/fields/display/display-image.ts +54 -0
  88. package/src/lib/fields/display/display-list.ts +107 -0
  89. package/src/lib/fields/display/display-number.ts +41 -0
  90. package/src/lib/fields/display/display-text.ts +42 -0
  91. package/src/lib/fields/display/display.spec.ts +242 -0
  92. package/src/lib/fields/dropdown/dropdown.descriptor.ts +12 -0
  93. package/src/lib/fields/dropdown/dropdown.ts +45 -0
  94. package/src/lib/fields/email/email.descriptor.ts +12 -0
  95. package/src/lib/fields/email/email.ts +28 -0
  96. package/src/lib/fields/field-aria.ts +60 -0
  97. package/src/lib/fields/field-host/field-host.spec.ts +118 -0
  98. package/src/lib/fields/field-host/field-host.ts +47 -0
  99. package/src/lib/fields/field-node.ts +88 -0
  100. package/src/lib/fields/file/file.descriptor.ts +14 -0
  101. package/src/lib/fields/file/file.spec.ts +134 -0
  102. package/src/lib/fields/file/file.ts +281 -0
  103. package/src/lib/fields/group/group.descriptor.ts +21 -0
  104. package/src/lib/fields/group/group.ts +110 -0
  105. package/src/lib/fields/image/image.descriptor.ts +12 -0
  106. package/src/lib/fields/image/image.spec.ts +117 -0
  107. package/src/lib/fields/image/image.ts +281 -0
  108. package/src/lib/fields/key-value/key-value.descriptor.ts +11 -0
  109. package/src/lib/fields/key-value/key-value.ts +283 -0
  110. package/src/lib/fields/list/list.descriptor.ts +21 -0
  111. package/src/lib/fields/list/list.ts +376 -0
  112. package/src/lib/fields/multiselect/multiselect.descriptor.ts +11 -0
  113. package/src/lib/fields/multiselect/multiselect.spec.ts +142 -0
  114. package/src/lib/fields/multiselect/multiselect.ts +152 -0
  115. package/src/lib/fields/number/number.descriptor.ts +12 -0
  116. package/src/lib/fields/number/number.ts +40 -0
  117. package/src/lib/fields/phone/phone.descriptor.ts +12 -0
  118. package/src/lib/fields/phone/phone.ts +46 -0
  119. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +12 -0
  120. package/src/lib/fields/readonly-text/readonly-text.ts +58 -0
  121. package/src/lib/fields/relation/relation.descriptor.ts +12 -0
  122. package/src/lib/fields/relation/relation.spec.ts +193 -0
  123. package/src/lib/fields/relation/relation.ts +224 -0
  124. package/src/lib/fields/rich-select/rich-select.descriptor.ts +12 -0
  125. package/src/lib/fields/rich-select/rich-select.ts +175 -0
  126. package/src/lib/fields/select/radio-mode.ts +25 -0
  127. package/src/lib/fields/select/select.descriptor.ts +12 -0
  128. package/src/lib/fields/select/select.spec.ts +162 -0
  129. package/src/lib/fields/select/select.ts +210 -0
  130. package/src/lib/fields/slug/slug.descriptor.ts +19 -0
  131. package/src/lib/fields/slug/slug.ts +67 -0
  132. package/src/lib/fields/string-list/string-list.descriptor.ts +11 -0
  133. package/src/lib/fields/string-list/string-list.ts +222 -0
  134. package/src/lib/fields/text/text.descriptor.ts +12 -0
  135. package/src/lib/fields/text/text.ts +35 -0
  136. package/src/lib/fields/textarea/textarea.descriptor.ts +12 -0
  137. package/src/lib/fields/textarea/textarea.spec.ts +117 -0
  138. package/src/lib/fields/textarea/textarea.ts +126 -0
  139. package/src/lib/fields/time/time.descriptor.ts +12 -0
  140. package/src/lib/fields/time/time.ts +28 -0
  141. package/src/lib/fields/unknown-render/unknown-render.ts +49 -0
  142. package/src/lib/fields/url/url.descriptor.ts +12 -0
  143. package/src/lib/fields/url/url.ts +53 -0
  144. package/src/lib/gas-admin-ui.spec.ts +21 -0
  145. package/src/lib/gas-admin-ui.ts +9 -0
  146. package/src/lib/layouts/descriptors.ts +9 -0
  147. package/src/lib/pages/dashboard/dashboard.ts +167 -0
  148. package/src/lib/pages/detail-view/detail-view.spec.ts +333 -0
  149. package/src/lib/pages/detail-view/detail-view.ts +570 -0
  150. package/src/lib/pages/drawer-form/drawer-form.ts +228 -0
  151. package/src/lib/pages/form-view/form-model.ts +88 -0
  152. package/src/lib/pages/form-view/form-schema.ts +255 -0
  153. package/src/lib/pages/form-view/form-view.ts +1622 -0
  154. package/src/lib/pages/list-view/list-view.formats.spec.ts +214 -0
  155. package/src/lib/pages/list-view/list-view.ts +882 -0
  156. package/src/lib/pages/login/login.spec.ts +109 -0
  157. package/src/lib/pages/login/login.ts +227 -0
  158. package/src/lib/pages/resource-page/resource-page.ts +234 -0
  159. package/src/lib/shared/components/badge/badge.ts +35 -0
  160. package/src/lib/shared/components/button/button.ts +65 -0
  161. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +48 -0
  162. package/src/lib/shared/components/copy-button/copy-button.ts +56 -0
  163. package/src/lib/shared/components/copy-share/copy-share.spec.ts +122 -0
  164. package/src/lib/shared/components/copy-share/copy-share.ts +107 -0
  165. package/src/lib/shared/components/drawer/drawer.spec.ts +127 -0
  166. package/src/lib/shared/components/drawer/drawer.ts +172 -0
  167. package/src/lib/shared/components/empty-state/empty-state.ts +30 -0
  168. package/src/lib/shared/components/modal/modal.spec.ts +149 -0
  169. package/src/lib/shared/components/modal/modal.ts +145 -0
  170. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +165 -0
  171. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +159 -0
  172. package/src/lib/shared/components/skeleton/skeleton.ts +31 -0
  173. package/src/lib/shared/components/toast/toast.ts +58 -0
  174. package/src/lib/shared/utils/col-span.ts +25 -0
  175. package/src/lib/shared/utils/condition-evaluator.ts +53 -0
  176. package/src/lib/shared/utils/depends-on.ts +48 -0
  177. package/src/lib/shared/utils/dialog-focus.ts +28 -0
  178. package/src/lib/shared/utils/field-path.ts +49 -0
  179. package/src/lib/shared/utils/gap-sorting.ts +144 -0
  180. package/src/lib/shared/utils/seed.spec.ts +64 -0
  181. package/src/lib/shared/utils/seed.ts +149 -0
  182. package/src/lib/shared/utils/slugify.ts +13 -0
  183. package/src/lib/shared/utils/validators.ts +41 -0
  184. package/src/lib/shell/layout/layout.ts +63 -0
  185. package/src/lib/shell/shell.routes.spec.ts +59 -0
  186. package/src/lib/shell/shell.routes.ts +122 -0
  187. package/src/lib/shell/sidebar/sidebar.ts +139 -0
  188. package/src/lib/shell/theme-toggle/theme-toggle.ts +74 -0
  189. package/src/lib/views/calendar-view/calendar-model.ts +426 -0
  190. package/src/lib/views/calendar-view/calendar-view.spec.ts +557 -0
  191. package/src/lib/views/calendar-view/calendar-view.ts +568 -0
  192. package/src/lib/views/composer/composer-host.spec.ts +301 -0
  193. package/src/lib/views/composer/composer-host.ts +248 -0
  194. package/src/lib/views/composer/composer-imports.spec.ts +54 -0
  195. package/src/lib/views/composer/view-context.spec.ts +117 -0
  196. package/src/lib/views/composer/view-context.ts +109 -0
  197. package/src/lib/views/composer/view-slot.spec.ts +130 -0
  198. package/src/lib/views/composer/view-slot.ts +178 -0
  199. package/src/lib/views/descriptors.ts +46 -0
  200. package/src/lib/views/kanban-view/kanban-model.ts +173 -0
  201. package/src/lib/views/kanban-view/kanban-view.spec.ts +540 -0
  202. package/src/lib/views/kanban-view/kanban-view.ts +327 -0
  203. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +17 -0
  204. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +66 -0
  205. package/src/lib/widgets/bar-chart/bar-chart.ts +76 -0
  206. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +17 -0
  207. package/src/lib/widgets/chart-line/chart-line.spec.ts +113 -0
  208. package/src/lib/widgets/chart-line/chart-line.ts +219 -0
  209. package/src/lib/widgets/descriptors.ts +29 -0
  210. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +41 -0
  211. package/src/lib/widgets/metric-card/metric-card.spec.ts +52 -0
  212. package/src/lib/widgets/metric-card/metric-card.ts +48 -0
  213. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +13 -0
  214. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +61 -0
  215. package/src/lib/widgets/quick-actions/quick-actions.ts +100 -0
  216. package/src/lib/widgets/record-list/record-list.descriptor.ts +16 -0
  217. package/src/lib/widgets/record-list/record-list.spec.ts +79 -0
  218. package/src/lib/widgets/record-list/record-list.ts +115 -0
  219. package/src/lib/widgets/series.spec.ts +42 -0
  220. package/src/lib/widgets/series.ts +56 -0
  221. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +19 -0
  222. package/src/lib/widgets/status-progress/status-progress.spec.ts +63 -0
  223. package/src/lib/widgets/status-progress/status-progress.ts +104 -0
  224. package/src/lib/widgets/widget-host/widget-host.spec.ts +179 -0
  225. package/src/lib/widgets/widget-host/widget-host.ts +99 -0
  226. package/src/public-api.ts +104 -0
  227. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  228. package/tsconfig.lib.json +13 -0
  229. package/tsconfig.lib.prod.json +11 -0
  230. package/tsconfig.spec.json +10 -0
  231. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +0 -84
  232. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +0 -1
  233. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +0 -140
  234. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +0 -1
  235. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +0 -113
  236. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +0 -1
  237. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +0 -163
  238. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +0 -1
  239. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +0 -1027
  240. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +0 -1
  241. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +0 -278
  242. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +0 -1
  243. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +0 -107
  244. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +0 -1
  245. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +0 -101
  246. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +0 -1
  247. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +0 -141
  248. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +0 -1
  249. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +0 -88
  250. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +0 -1
  251. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +0 -107
  252. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +0 -1
  253. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +0 -140
  254. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +0 -1
  255. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +0 -119
  256. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +0 -1
  257. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +0 -125
  258. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +0 -1
  259. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +0 -152
  260. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +0 -1
  261. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +0 -211
  262. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +0 -1
  263. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +0 -116
  264. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +0 -1
  265. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +0 -111
  266. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +0 -1
  267. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +0 -122
  268. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +0 -1
  269. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +0 -107
  270. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +0 -1
  271. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +0 -109
  272. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +0 -1
  273. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +0 -45
  274. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +0 -1
  275. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +0 -50
  276. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +0 -1
  277. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +0 -24
  278. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +0 -1
  279. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +0 -27
  280. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +0 -1
  281. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +0 -408
  282. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +0 -1
  283. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs +0 -4516
  284. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs.map +0 -1
  285. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +0 -82
  286. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +0 -1
  287. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +0 -105
  288. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +0 -1
  289. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +0 -65
  290. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +0 -1
  291. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +0 -65
  292. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +0 -1
  293. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +0 -65
  294. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +0 -1
  295. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +0 -59
  296. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +0 -1
  297. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +0 -94
  298. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +0 -1
  299. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +0 -72
  300. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +0 -1
  301. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +0 -238
  302. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +0 -1
  303. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +0 -416
  304. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +0 -1
  305. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +0 -439
  306. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +0 -1
  307. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +0 -513
  308. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +0 -1
  309. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs +0 -637
  310. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs.map +0 -1
  311. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +0 -127
  312. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +0 -1
  313. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +0 -251
  314. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +0 -1
  315. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +0 -66
  316. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +0 -1
  317. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +0 -114
  318. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +0 -1
  319. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +0 -116
  320. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +0 -1
  321. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +0 -235
  322. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +0 -1
  323. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +0 -8
  324. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +0 -1
  325. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +0 -124
  326. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +0 -1
  327. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +0 -249
  328. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +0 -1
  329. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +0 -39
  330. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +0 -1
  331. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +0 -309
  332. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +0 -1
  333. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs +0 -576
  334. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs.map +0 -1
  335. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +0 -161
  336. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +0 -1
  337. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +0 -11
  338. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +0 -685
  339. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +0 -1
  340. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs +0 -80
  341. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs.map +0 -1
  342. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +0 -296
  343. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +0 -1
  344. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +0 -119
  345. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +0 -1
  346. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +0 -158
  347. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +0 -1
  348. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +0 -26
  349. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +0 -1
  350. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +0 -205
  351. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +0 -1
  352. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +0 -432
  353. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +0 -1
  354. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +0 -36
  355. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +0 -1
  356. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +0 -107
  357. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +0 -1
  358. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +0 -223
  359. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +0 -1
  360. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +0 -107
  361. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +0 -1
  362. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +0 -60
  363. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +0 -1
  364. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +0 -141
  365. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +0 -1
  366. package/fesm2022/tinya-code-gas-admin-ui.mjs +0 -4599
  367. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +0 -1
  368. package/types/tinya-code-gas-admin-ui.d.ts +0 -3632
@@ -0,0 +1,182 @@
1
+ import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
2
+ import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
3
+ import { TestBed } from '@angular/core/testing';
4
+ import { provideRouter } from '@angular/router';
5
+
6
+ import { ApiError } from '../models/api.model';
7
+ import { API_URL } from '../tokens';
8
+ import { AuthService, SESSION_TOKEN_KEY, SESSION_USER_KEY } from '../services/auth.service';
9
+ import { apiErrorInterceptor } from './api-error.interceptor';
10
+
11
+ /**
12
+ * Emite `body` en el canal de éxito (el backend responde 200 con el error
13
+ * dentro) y devuelve el `ApiError` que el interceptor lanzó.
14
+ * A nivel de módulo: lo usan el describe de mensajes y el de R2.9.
15
+ */
16
+ function errorFromBody(body: object): ApiError {
17
+ const http = TestBed.inject(HttpClient);
18
+ const mock = TestBed.inject(HttpTestingController);
19
+ let lanzado: unknown;
20
+ http.get('/recursos').subscribe({
21
+ error: (e: unknown) => {
22
+ lanzado = e;
23
+ },
24
+ });
25
+ mock.expectOne('/recursos').flush(body);
26
+ mock.verify();
27
+ return lanzado as ApiError;
28
+ }
29
+
30
+ /**
31
+ * Plan 7.3 — mensajes en lenguaje humano (guía §2).
32
+ *
33
+ * Dos canales distintos: el body del backend (que ya escribe en español) y
34
+ * el transporte (red caída, proxy, 5xx), que sin normalizar deja en pantalla
35
+ * el texto crudo de Angular: «Http failure response for http://…».
36
+ *
37
+ * **R2.9** — desde que el interceptor entrega los `AUTH_*` a
38
+ * `AuthService.applyAuthCode`, necesita poder inyectarlo: por eso acá hay
39
+ * router y `API_URL`, que son las dependencias de ese servicio.
40
+ */
41
+ describe('apiErrorInterceptor — mensajes humanos', () => {
42
+ beforeEach(() => {
43
+ sessionStorage.clear();
44
+ TestBed.configureTestingModule({
45
+ providers: [
46
+ provideHttpClient(withInterceptors([apiErrorInterceptor])),
47
+ provideHttpClientTesting(),
48
+ provideRouter([]),
49
+ { provide: API_URL, useValue: '/api' },
50
+ ],
51
+ });
52
+ });
53
+
54
+ afterEach(() => sessionStorage.clear());
55
+
56
+ function failWith(status: number, body?: unknown): string {
57
+ const http = TestBed.inject(HttpClient);
58
+ const mock = TestBed.inject(HttpTestingController);
59
+ let message = '';
60
+ http.get('/recursos').subscribe({
61
+ error: (error: unknown) => {
62
+ message = error instanceof ApiError ? error.message : String(error);
63
+ },
64
+ });
65
+ const request = mock.expectOne('/recursos');
66
+ if (status === 0) {
67
+ // Red caída: el backend no llegó a responder.
68
+ request.error(new ErrorEvent('error'));
69
+ } else {
70
+ // `flush` con status fuera de 2xx materializa un `HttpErrorResponse`.
71
+ request.flush(body ?? '', { status, statusText: 'ERR' });
72
+ }
73
+ mock.verify();
74
+ return message;
75
+ }
76
+
77
+ it('un 5xx se explica en español, no con el texto crudo de Angular', () => {
78
+ expect(failWith(500)).toBe(
79
+ 'El servidor tuvo un problema. Vuelve a intentarlo en unos segundos.',
80
+ );
81
+ });
82
+
83
+ it('la red caída (status 0) dice que no hubo conexión', () => {
84
+ expect(failWith(0)).toBe('No se pudo conectar con el servidor. Revisa tu conexión.');
85
+ });
86
+
87
+ it('un 403 habla de permisos', () => {
88
+ expect(failWith(403)).toBe('No tienes permisos para realizar esta acción.');
89
+ });
90
+
91
+ it('conserva el mensaje del backend cuando viene en el body (canal de éxito)', () => {
92
+ expect(
93
+ failWith(200, {
94
+ error: { status: 422, message: 'Ya existe un registro con este valor', path: 'name' },
95
+ }),
96
+ ).toBe('Ya existe un registro con este valor');
97
+ });
98
+
99
+ /**
100
+ * D42 — el422 manda sus rutas en `error.errors[]`, NO en `path`: sin
101
+ * modelar esa lista el form veía «Errores de validación» y no pintaba
102
+ * ningún campo (base.md §5, guía §10).
103
+ */
104
+ it('conserva errors[] completo (path, message, code) en el ApiError', () => {
105
+ const error = errorFromBody({
106
+ error: {
107
+ status: 422,
108
+ message: 'Errores de validación',
109
+ errors: [
110
+ {
111
+ path: 'sku',
112
+ message: 'Debe tener al menos 5 caracteres.',
113
+ code: 'VALIDATION_MIN_LENGTH',
114
+ },
115
+ { path: 'faq[2].answer', message: 'Campo obligatorio.', code: 'VALIDATION_REQUIRED' },
116
+ ],
117
+ },
118
+ });
119
+ expect(error.status).toBe(422);
120
+ expect(error.message).toBe('Errores de validación');
121
+ expect(error.issues).toEqual([
122
+ { path: 'sku', message: 'Debe tener al menos 5 caracteres.', code: 'VALIDATION_MIN_LENGTH' },
123
+ { path: 'faq[2].answer', message: 'Campo obligatorio.', code: 'VALIDATION_REQUIRED' },
124
+ ]);
125
+ // Sin `path` en el sobre no hay fieldPath: las rutas vienen en los issues.
126
+ expect(error.fieldPath).toBeUndefined();
127
+ });
128
+ });
129
+
130
+ /**
131
+ * R2.9 — éste es el ÚNICO puente entre el sobre de error y la tabla de
132
+ * §4.5. Si el interceptor dejara de llamar a `applyAuthCode`, el front se
133
+ * quedaría en una pantalla caducada sin reloguear: por eso el puente se
134
+ * prueba acá y las cinco filas de la tabla, en `auth.service.spec.ts`.
135
+ */
136
+ describe('apiErrorInterceptor — entrega de los códigos de sesión (R2.9)', () => {
137
+ beforeEach(() => {
138
+ sessionStorage.clear();
139
+ sessionStorage.setItem(SESSION_TOKEN_KEY, 'tok-vigente');
140
+ sessionStorage.setItem(SESSION_USER_KEY, JSON.stringify({ id: 'u_1', role: 'admin' }));
141
+ TestBed.configureTestingModule({
142
+ providers: [
143
+ provideHttpClient(withInterceptors([apiErrorInterceptor])),
144
+ provideHttpClientTesting(),
145
+ provideRouter([]),
146
+ { provide: API_URL, useValue: '/api' },
147
+ ],
148
+ });
149
+ });
150
+
151
+ afterEach(() => sessionStorage.clear());
152
+
153
+ it('conserva el `code` en el ApiError que recibe el llamador', () => {
154
+ const error = errorFromBody({
155
+ error: { status: 401, message: 'No autorizado', code: 'AUTH_EXPIRED' },
156
+ });
157
+ expect(error.code).toBe('AUTH_EXPIRED');
158
+ expect(error.status).toBe(401);
159
+ });
160
+
161
+ it('un error SIN código de sesión no toca la sesión', () => {
162
+ errorFromBody({ error: { status: 422, message: 'Datos no válidos', path: 'name' } });
163
+ expect(sessionStorage.getItem(SESSION_TOKEN_KEY)).toBe('tok-vigente');
164
+ expect(TestBed.inject(AuthService).isAuthenticated()).toBe(true);
165
+ });
166
+
167
+ it('FORBIDDEN deja al usuario DENTRO de la sesión (§4.5)', () => {
168
+ errorFromBody({ error: { status: 403, message: 'Prohibido', code: 'FORBIDDEN' } });
169
+ expect(sessionStorage.getItem(SESSION_TOKEN_KEY)).toBe('tok-vigente');
170
+ expect(TestBed.inject(AuthService).isAuthenticated()).toBe(true);
171
+ });
172
+
173
+ it('AUTH_INVALID borra token y usuario ANTES de nada más (§5.4)', () => {
174
+ errorFromBody({ error: { status: 401, message: 'No autorizado', code: 'AUTH_INVALID' } });
175
+ expect(sessionStorage.getItem(SESSION_TOKEN_KEY)).toBeNull();
176
+ expect(sessionStorage.getItem(SESSION_USER_KEY)).toBeNull();
177
+ const auth = TestBed.inject(AuthService);
178
+ expect(auth.token()).toBeNull();
179
+ expect(auth.user()).toBeNull();
180
+ expect(auth.isAuthenticated()).toBe(false);
181
+ });
182
+ });
@@ -0,0 +1,87 @@
1
+ import { HttpErrorResponse, HttpInterceptorFn, HttpResponse } from '@angular/common/http';
2
+ import { inject } from '@angular/core';
3
+ import { catchError, map, throwError } from 'rxjs';
4
+
5
+ import { ApiError } from '../models/api.model';
6
+ import type { ApiErrorBody } from '../models/api.model';
7
+ import { AuthService } from '../services/auth.service';
8
+
9
+ /**
10
+ * Mensaje humano para un error HTTP real (§2).
11
+ *
12
+ * El backend siempre responde 200 con el error dentro del body —eso ya
13
+ * viene en español—, así que esto sólo cubre lo que el transporte falla:
14
+ * red caída, proxy y 5xx. Sin esto el usuario ve el texto crudo de Angular
15
+ * («Http failure response for http://…»), que es inglés técnico.
16
+ */
17
+ function httpMessage(status: number): string {
18
+ switch (status) {
19
+ case 0:
20
+ return 'No se pudo conectar con el servidor. Revisa tu conexión.';
21
+ case 401:
22
+ return 'Tu sesión ha expirado. Vuelve a iniciar sesión.';
23
+ case 403:
24
+ return 'No tienes permisos para realizar esta acción.';
25
+ case 404:
26
+ return 'No se encontró el recurso solicitado.';
27
+ case 409:
28
+ return 'El registro cambió o ya existe. Recarga la página y vuelve a intentarlo.';
29
+ case 413:
30
+ return 'El archivo es demasiado grande.';
31
+ case 422:
32
+ return 'Los datos enviados no son válidos.';
33
+ default:
34
+ if (status >= 500) {
35
+ return 'El servidor tuvo un problema. Vuelve a intentarlo en unos segundos.';
36
+ }
37
+ return status >= 400 ? 'No se pudo completar la operación.' : 'Error inesperado.';
38
+ }
39
+ }
40
+
41
+ function isErrorBody(body: unknown): body is ApiErrorBody {
42
+ if (typeof body !== 'object' || body === null) {
43
+ return false;
44
+ }
45
+ const error = (body as ApiErrorBody).error;
46
+ return typeof error === 'object' && error !== null && typeof error.message === 'string';
47
+ }
48
+
49
+ /**
50
+ * El backend responde SIEMPRE HTTP 200 y pone los errores en el body
51
+ * (api.md §7), así que se detectan en el canal de **éxito** y se relanzan
52
+ * como `ApiError` (con `fieldPath` cuando el backend envía `path`).
53
+ * Los errores HTTP reales (red caída, proxy) también se normalizan.
54
+ *
55
+ * **R2.9 — paso dos de dos.** Éste archivo es el ÚNICO punto donde el
56
+ * sobre de error se abre; lo que decide qué ocurre con un `AUTH_*` es
57
+ * `AuthService.applyAuthCode` (la tabla de §4.5). Aquí sólo se le entrega
58
+ * el código y se propaga el `ApiError` con él — un segundo sitio que
59
+ * «interprete» el código sería una regla duplicada y, a la larga, una que
60
+ * se contradiga con la primera.
61
+ */
62
+ export const apiErrorInterceptor: HttpInterceptorFn = (req, next) => {
63
+ const auth = inject(AuthService);
64
+
65
+ return next(req).pipe(
66
+ map((event) => {
67
+ if (event instanceof HttpResponse && isErrorBody(event.body)) {
68
+ const { status, message, path, code, errors } = event.body.error;
69
+ // R2.9: ésta es la ÚNICA llamada a la tabla de §4.5.
70
+ auth.applyAuthCode(code);
71
+ // `errors[]` es el422 con rutas (D42): va entero al ApiError para que
72
+ // `ErrorMapperService` lo convierta en `serverErrors[prefix + key]`.
73
+ throw new ApiError(status, message, path, code, errors ?? []);
74
+ }
75
+ return event;
76
+ }),
77
+ catchError((err: unknown) => {
78
+ if (err instanceof ApiError) {
79
+ return throwError(() => err);
80
+ }
81
+ if (err instanceof HttpErrorResponse) {
82
+ return throwError(() => new ApiError(err.status, httpMessage(err.status)));
83
+ }
84
+ return throwError(() => err);
85
+ }),
86
+ );
87
+ };
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Contrato HTTP con el backend (doc/baseapi.md §8 «Errores»).
3
+ *
4
+ * El backend responde SIEMPRE HTTP 200; los errores viajan en el body
5
+ * con `{ error: { status, message, errors?: [{ path, message }] } }`.
6
+ * El interceptor (Fase 3) los convierte en `ApiError`.
7
+ */
8
+
9
+ /**
10
+ * Un error con ruta del422 (auth.md §6): `path` para pintarlo en el campo y
11
+ * `code` MAYUS_SNAKE (`VALIDATION_MIN_LENGTH`) para mapearlo sin leer texto.
12
+ */
13
+ export interface ApiIssue {
14
+ /** Ruta del campo afectado (`faq[2].answer`, `sku`). */
15
+ path: string;
16
+ /** Mensaje en español, listo para pintar. */
17
+ message: string;
18
+ /** Código estable del validador (B11); el mensaje puede cambiar, el código no. */
19
+ code?: string;
20
+ }
21
+
22
+ /** Shape del body de error (doc/baseapi.md §8 «Errores»). */
23
+ export interface ApiErrorBody {
24
+ error: {
25
+ status: number;
26
+ message: string;
27
+ /** Ruta del campo afectado cuando el backend la envía (base.md §10). */
28
+ path?: string;
29
+ /**
30
+ * Código de sesión de §4.5 (R2.9): `AUTH_REQUIRED` · `AUTH_INVALID` ·
31
+ * `AUTH_EXPIRED` · `FORBIDDEN` · `RATE_LIMITED`. Aparece SÓLO en esas
32
+ * cinco respuestas — el sobre de error es aditivo (O7 / D10-5).
33
+ */
34
+ code?: string;
35
+ /**
36
+ * Errores de validación con ruta (base.md §5, guía §10): el 422 los manda
37
+ * ACÁ (`error.errors[]`), no en `path`. Sin modelarlos el form veía
38
+ * «Errores de validación» genérico y ningún campo se pintaba (D42).
39
+ */
40
+ errors?: ApiIssue[];
41
+ };
42
+ }
43
+
44
+ /** Error de API estandarizado que lanza el interceptor de errores. */
45
+ export class ApiError extends Error {
46
+ readonly status: number;
47
+ /** Ruta del campo que provocó el error (ej. `faq[2].answer`), si existe. */
48
+ readonly fieldPath?: string;
49
+ /** Código de sesión de §4.5 si el backend lo envió; `undefined` en el resto. */
50
+ readonly code?: string;
51
+ /** Issues con ruta (422); vacío cuando el error no trae `errors[]`. */
52
+ readonly issues: readonly ApiIssue[];
53
+
54
+ constructor(
55
+ status: number,
56
+ message: string,
57
+ fieldPath?: string,
58
+ code?: string,
59
+ issues: readonly ApiIssue[] = [],
60
+ ) {
61
+ super(message);
62
+ this.name = 'ApiError';
63
+ this.status = status;
64
+ this.fieldPath = fieldPath;
65
+ this.code = code;
66
+ this.issues = issues;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * `meta.renewedToken` (auth.md §3.2/§3.4): el back lo adjunta a la respuesta
72
+ * cuando la vida del token bajó del umbral de renovación. Es el ÚNICO modo
73
+ * de que el front se entere — el token nuevo no viaja en cabeceras ni en la
74
+ * URL. Devuelve `null` cuando no hay renovación (que es lo normal).
75
+ *
76
+ * Vive acá y no en el `ApiService` porque lo consumen DOS servicios
77
+ * (`ApiService` y `AuthService`) y éste modelo no importa a ninguno de los
78
+ * dos: sin este archivo no hay ciclo de imports.
79
+ */
80
+ export function renewedTokenOf(body: unknown): string | null {
81
+ if (body === null || typeof body !== 'object') return null;
82
+ const meta = (body as { meta?: unknown }).meta;
83
+ if (meta === null || typeof meta !== 'object') return null;
84
+ const token = (meta as { renewedToken?: unknown }).renewedToken;
85
+ return typeof token === 'string' && token !== '' ? token : null;
86
+ }
87
+
88
+ /**
89
+ * Resultado de una página para `ApiService.listPage()`.
90
+ *
91
+ * El backend envía la metadata de paginación dentro del sobre (típicamente
92
+ * en `meta`); el motor la extrae según la declaración `responseUnwrap.pagination`
93
+ * y la entrega en este shape. `list()` NO usa este tipo: sigue devolviendo `T[]`.
94
+ */
95
+ export interface PageResult<T> {
96
+ /** Registros de la página actual. */
97
+ items: T[];
98
+ /** Cursor para pedir la página siguiente; `null` cuando no hay más. */
99
+ nextCursor: string | null;
100
+ /** Total de registros del conjunto, si el backend lo informa; `0` si no. */
101
+ total: number;
102
+ /** `true` si hay al menos una página más. `false` sin cursor informativo. */
103
+ hasMore: boolean;
104
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Descripciones centralizadas del catálogo de campos del motor `@tinya-code/gas-admin-ui`.
3
+ *
4
+ * Este archivo es el único lugar donde se editan los textos descriptivos de
5
+ * cada propiedad del schema. Los JSDoc de `schema.model.ts` usan estos mismos
6
+ * textos para que el editor (VSCode) muestre tooltips al pasar el cursor
7
+ * sobre una propiedad del schema del consumidor.
8
+ *
9
+ * Estructura: clave de propiedad → descripción en español.
10
+ *
11
+ * Uso en el consumidor (loyalty-admin, etc.):
12
+ * import { schemaDescriptions } from '@tinya-code/gas-admin-ui';
13
+ * schemaDescriptions['docLink']; // 'URL de documentación externa para este campo.'
14
+ *
15
+ * Nota: este objeto no se renderiza en la UI; solo existe para documentación
16
+ * y tooltips del editor. Para renderizar tooltips en el formulario usa
17
+ * `description` en cada campo del schema del consumidor.
18
+ */
19
+
20
+ export const schemaDescriptions = {
21
+ // ── Propiedades comunes a todo campo (FieldBase) ───────────────────────
22
+ key: 'Nombre de la propiedad en el JSON que envía/recibe el back.',
23
+ label: 'Rótulo visible para el usuario en el formulario y la ficha.',
24
+ help: 'Texto corto de ayuda que se muestra debajo del campo.',
25
+ placeholder: 'Texto sugerente que se muestra dentro del input cuando está vacío.',
26
+ required: 'Si es obligatorio. El back también lo valida (R7.4).',
27
+ default: 'Valor por defecto si el registro no trae este campo (ej. `default: "none"` en un `select`/`dropdown`).',
28
+ readonly: 'Si el campo es solo lectura (no editable en el formulario).',
29
+ readonlyOn: 'Bloquea el campo solo en creación, solo en edición o siempre.',
30
+ readonlyWhen: 'Condición bajo la cual el campo es solo lectura (expresión sobre otros campos).',
31
+ visibleWhen: 'Condición bajo la cual el campo se muestra u oculta.',
32
+ hiddenOn: 'Oculta el campo en creación, en edición o siempre.',
33
+ dependsOn: 'Selección dependiente (guía §1: país → ciudad). Clave del campo padre del mismo nivel.',
34
+ validators: 'Reglas de validación (mínimo, máximo, patrón, unicidad, etc.).',
35
+ width: 'Ancho en la grilla del formulario (1–12), igual que un widget del dashboard.',
36
+ section: 'Id de la sección/pestaña del layout a la que pertenece (base.md §4).',
37
+ read: 'Código de nivel de acceso requerido para leer el campo.',
38
+ write: 'Código de nivel de acceso requerido para escribir el campo.',
39
+ description: 'Descripción corta de para qué sirve este campo. Se muestra como tooltip al pasar el cursor sobre el rótulo.',
40
+ docLink: 'URL de documentación externa para este campo (se abre al hacer clic en el tooltip).',
41
+
42
+ // ── Opciones de select/dropdown ───────────────────────────────────────
43
+ value: 'Valor que se envía al back cuando se elige esta opción.',
44
+ labelOption: 'Texto visible de la opción.',
45
+ disabled: 'Si la opción está deshabilitada (no se puede elegir).',
46
+
47
+ // ── Campos específicos ─────────────────────────────────────────────────
48
+ type: 'Tipo de campo: `text`, `color`, `number`, `currency`, `boolean`, `select`, `dropdown`, `rich-select`, `multiselect`, `url`, `email`, `phone`, `date`, `time`, `readonly-text`, `slug`, `textarea`, `relation`, `image`, `file`, `group`, `list`, `string-list`, `key-value`.',
49
+ maxLength: 'Longitud máxima de caracteres permitida.',
50
+ pattern: 'Expresión regular que debe cumplir el valor.',
51
+ rows: 'Número de filas visibles del textarea.',
52
+ minWords: 'Cantidad mínima de palabras.',
53
+ maxWords: 'Cantidad máxima de palabras.',
54
+ tokens: 'Marcadores insertables como chips bajo el área (plantillas de mensaje).',
55
+ from: 'Campo del registro del que se autogenera el slug.',
56
+ lockAfterCreate: 'Bloquea el campo una vez creado el registro (por defecto: sí).',
57
+ min: 'Valor mínimo permitido.',
58
+ max: 'Valor máximo permitido.',
59
+ step: 'Incremento entre valores permitidos.',
60
+ decimals: 'Número de decimales mostrados.',
61
+ currencyFrom: 'Campo del registro del que se toma la moneda (ej. `currency`).',
62
+ trueLabel: 'Texto que se muestra cuando el valor es verdadero.',
63
+ falseLabel: 'Texto que se muestra cuando el valor es falso.',
64
+ source: 'De dónde salen las opciones: `{ resource, view?, params?, … }` (F8 · R6.5).',
65
+ resource: 'Recurso declarado (`resource.id`): su listado es el de las opciones.',
66
+ view: 'Vista declarada en `resource.views` (opcional): filtra en el back.',
67
+ params: 'Valores interpolados para la vista (`{campo}` ← contexto).',
68
+ labelField: 'Etiqueta por defecto de las filas (si no, `titleField` del recurso).',
69
+ valueField: 'Valor por defecto de las filas (si no, `keyField` del recurso).',
70
+ secondaryField: 'Segundo dato a mostrar junto a la etiqueta (ej. "Juan Pérez · DNI 123").',
71
+ onlyActive: 'Cargar solo registros activos (lo exige además la FK en el back).',
72
+ accept: 'Tipos aceptados (ej. `image/*`, `image/png,image/jpeg` o `pdf,docx`).',
73
+ maxSizeMB: 'Tamaño máximo del archivo en megabytes.',
74
+ aspectRatio: 'Relación de aspecto de la vista previa (ej. `16/9`).',
75
+ previewSize: 'Tamaño de la vista previa.',
76
+ formatCurrency: 'Campo del registro del que se toma la moneda (ej. `currency`).',
77
+ display: 'Presentación del grupo: `card`, `collapsible` o `inline`.',
78
+ fields: 'Campos de cada item (cualquier tipo, incluso `group` o `list`).',
79
+ minItems: 'Cantidad mínima de items.',
80
+ maxItems: 'Cantidad máxima de items.',
81
+ sortable: 'Si se puede reordenar (por defecto: sí).',
82
+ positionField: 'Campo donde se guarda el orden dentro de cada item (`position`).',
83
+ addLabel: 'Etiqueta del botón para agregar un item nuevo.',
84
+ emptyText: 'Texto que se muestra cuando no hay items.',
85
+ itemDisplay: 'Cómo se muestra cada item: `card`, `row` o `accordion`.',
86
+ itemFields: 'Campos de cada item (cualquier tipo, incluso `group` o `list`).',
87
+ itemTitle: 'Campo del item usado como título cuando está colapsado.',
88
+ primaryFirst: 'El primer item tiene significado especial (ej. imagen principal).',
89
+ itemType: 'Tipo permitido de cada item (base.md §9: solo `text`, `url` o `email`).',
90
+ sort: 'Si la lista se ordena alfabéticamente o por posición.',
91
+ filter: 'Si el listado permite filtrado por texto.',
92
+ search: 'Campos buscables en el listado.',
93
+ filters: 'Filtros declarados para el listado.',
94
+ listColumns: 'Columnas que se muestran en el listado.',
95
+ searchable: 'Si el campo es buscable.',
96
+ filterable: 'Si el campo es filtrable.',
97
+ sortableItems: 'Si los items de la lista se pueden reordenar.',
98
+ groupBy: 'Campo por el que agrupar los items.',
99
+ cardWidth: 'Ancho de cada tarjeta de opción en la grilla (1–12). Por defecto `4` (3 tarjetas por fila en escritorio).',
100
+ cardCols: 'Cuántas tarjetas mostrar por fila en el punto de ruptura `lg`. Sobrescribe el cálculo automático basado en `cardWidth`.',
101
+ hintMetric: 'Texto secundario bajo la cifra (estático, va en el schema).',
102
+ unitChart: 'Sufijo de las cifras del eje («unidades», «S/»).',
103
+ segments: 'Segmentos de la barra de distribución porcentual.',
104
+ actions: 'Acciones de navegación por fila.',
105
+ labelAction: 'Etiqueta de la acción.',
106
+ icon: 'Icono de la acción.',
107
+ navigateTo: 'Ruta de destino de la acción.',
108
+ variant: 'Variante visual: `primary`, `secondary` u `outline`.',
109
+
110
+ // ── Widgets de dashboard ──────────────────────────────────────────────
111
+ widgets: 'Widgets del panel. Se declara en `ResourceSchema.widgets` — no en `fields`, porque un KPI no es un campo.',
112
+ mobileWidth: 'Ancho en la grilla en mobile (1–12). Por defecto `12` (ancho completo, apilado).',
113
+ sourceWidget: 'De dónde saca sus datos: `DataSource` o `{ kind: "payload" }`.',
114
+ hintWidget: 'Texto secundario bajo la cifra (estático, va en el schema).',
115
+ unitWidget: 'Sufijo de las cifras del eje.',
116
+ } as const;
117
+
118
+ export type SchemaDescriptionKey = keyof typeof schemaDescriptions;