@tinya-code/gas-admin-ui 0.2.0-alpha.12 → 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 (369) hide show
  1. package/README.md +222 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +3 -15
  4. package/src/lib/actions/action-registry.spec.ts +52 -0
  5. package/src/lib/actions/action-registry.ts +126 -0
  6. package/src/lib/actions/action-service.spec.ts +215 -0
  7. package/src/lib/actions/action-service.ts +87 -0
  8. package/src/lib/actions/descriptors.spec.ts +155 -0
  9. package/src/lib/actions/descriptors.ts +154 -0
  10. package/src/lib/columns/column-cell.ts +33 -0
  11. package/src/lib/columns/column-defaults.spec.ts +99 -0
  12. package/src/lib/columns/column-defaults.ts +84 -0
  13. package/src/lib/columns/column-format.spec.ts +274 -0
  14. package/src/lib/columns/descriptors.ts +113 -0
  15. package/src/lib/columns/format-badge.ts +51 -0
  16. package/src/lib/columns/format-boolean.ts +58 -0
  17. package/src/lib/columns/format-currency.ts +30 -0
  18. package/src/lib/columns/format-date.ts +35 -0
  19. package/src/lib/columns/format-number.ts +32 -0
  20. package/src/lib/columns/format-text.ts +23 -0
  21. package/src/lib/columns/format-thumbnail.ts +63 -0
  22. package/src/lib/core/adapters/firebase-auth.adapter.ts +6 -0
  23. package/src/lib/core/guards/auth.guard.spec.ts +88 -0
  24. package/src/lib/core/guards/auth.guard.ts +48 -0
  25. package/src/lib/core/guards/unsaved-changes.guard.ts +16 -0
  26. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +182 -0
  27. package/src/lib/core/interceptors/api-error.interceptor.ts +87 -0
  28. package/src/lib/core/models/api.model.ts +104 -0
  29. package/src/lib/core/models/schema-descriptions.ts +118 -0
  30. package/src/lib/core/models/schema.model.ts +1097 -0
  31. package/src/lib/core/registry/composition-validator.spec.ts +358 -0
  32. package/src/lib/core/registry/composition-validator.ts +270 -0
  33. package/src/lib/core/registry/field-validators.spec.ts +199 -0
  34. package/src/lib/core/registry/field-validators.ts +440 -0
  35. package/src/lib/core/registry/render-host.spec.ts +208 -0
  36. package/src/lib/core/registry/render-host.ts +646 -0
  37. package/src/lib/core/registry/render-registry.spec.ts +96 -0
  38. package/src/lib/core/registry/render-registry.ts +312 -0
  39. package/src/lib/core/registry/schema-catalog.ts +156 -0
  40. package/src/lib/core/services/api.service.spec.ts +1142 -0
  41. package/src/lib/core/services/api.service.ts +371 -0
  42. package/src/lib/core/services/auth.service.spec.ts +653 -0
  43. package/src/lib/core/services/auth.service.ts +503 -0
  44. package/src/lib/core/services/config.service.spec.ts +121 -0
  45. package/src/lib/core/services/config.service.ts +119 -0
  46. package/src/lib/core/services/data-source.service.spec.ts +179 -0
  47. package/src/lib/core/services/data-source.service.ts +142 -0
  48. package/src/lib/core/services/error-mapper.service.spec.ts +50 -0
  49. package/src/lib/core/services/error-mapper.service.ts +49 -0
  50. package/src/lib/core/services/notification.service.ts +73 -0
  51. package/src/lib/core/services/relation-drawer.service.ts +41 -0
  52. package/src/lib/core/services/theme.service.spec.ts +106 -0
  53. package/src/lib/core/services/theme.service.ts +86 -0
  54. package/src/lib/core/services/transport.spec.ts +198 -0
  55. package/src/lib/core/services/transport.ts +164 -0
  56. package/src/lib/core/services/upload.service.ts +81 -0
  57. package/src/lib/core/testing/categories.schema.ts +125 -0
  58. package/src/lib/core/testing/orders.schema.ts +372 -0
  59. package/src/lib/core/testing/products.schema.ts +258 -0
  60. package/src/lib/core/testing/site.schema.ts +195 -0
  61. package/src/lib/core/testing/test-catalog.ts +21 -0
  62. package/src/lib/core/tokens.ts +112 -0
  63. package/src/lib/core/utils/clipboard.spec.ts +55 -0
  64. package/src/lib/core/utils/clipboard.ts +90 -0
  65. package/src/lib/core/utils/context-resolver.spec.ts +95 -0
  66. package/src/lib/core/utils/context-resolver.ts +101 -0
  67. package/src/lib/core/utils/response-unwrapper.spec.ts +70 -0
  68. package/src/lib/core/utils/response-unwrapper.ts +103 -0
  69. package/src/lib/core/utils/source-options.spec.ts +96 -0
  70. package/src/lib/core/utils/source-options.ts +54 -0
  71. package/src/lib/core/utils/template-interpolator.spec.ts +59 -0
  72. package/src/lib/core/utils/template-interpolator.ts +56 -0
  73. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +207 -0
  74. package/src/lib/core/view-navigation/view-navigation.service.ts +132 -0
  75. package/src/lib/fields/boolean/boolean.descriptor.ts +11 -0
  76. package/src/lib/fields/boolean/boolean.ts +40 -0
  77. package/src/lib/fields/color/color.descriptor.ts +12 -0
  78. package/src/lib/fields/color/color.ts +34 -0
  79. package/src/lib/fields/currency/currency.descriptor.ts +12 -0
  80. package/src/lib/fields/currency/currency.ts +67 -0
  81. package/src/lib/fields/date/date.descriptor.ts +12 -0
  82. package/src/lib/fields/date/date.ts +36 -0
  83. package/src/lib/fields/descriptors.ts +122 -0
  84. package/src/lib/fields/display/display-badge.ts +65 -0
  85. package/src/lib/fields/display/display-date.ts +39 -0
  86. package/src/lib/fields/display/display-defaults.ts +84 -0
  87. package/src/lib/fields/display/display-file.ts +41 -0
  88. package/src/lib/fields/display/display-image.ts +54 -0
  89. package/src/lib/fields/display/display-list.ts +107 -0
  90. package/src/lib/fields/display/display-number.ts +41 -0
  91. package/src/lib/fields/display/display-text.ts +42 -0
  92. package/src/lib/fields/display/display.spec.ts +242 -0
  93. package/src/lib/fields/dropdown/dropdown.descriptor.ts +12 -0
  94. package/src/lib/fields/dropdown/dropdown.ts +45 -0
  95. package/src/lib/fields/email/email.descriptor.ts +12 -0
  96. package/src/lib/fields/email/email.ts +28 -0
  97. package/src/lib/fields/field-aria.ts +60 -0
  98. package/src/lib/fields/field-host/field-host.spec.ts +118 -0
  99. package/src/lib/fields/field-host/field-host.ts +47 -0
  100. package/src/lib/fields/field-node.ts +88 -0
  101. package/src/lib/fields/file/file.descriptor.ts +14 -0
  102. package/src/lib/fields/file/file.spec.ts +134 -0
  103. package/src/lib/fields/file/file.ts +281 -0
  104. package/src/lib/fields/group/group.descriptor.ts +21 -0
  105. package/src/lib/fields/group/group.ts +110 -0
  106. package/src/lib/fields/image/image.descriptor.ts +12 -0
  107. package/src/lib/fields/image/image.spec.ts +117 -0
  108. package/src/lib/fields/image/image.ts +281 -0
  109. package/src/lib/fields/key-value/key-value.descriptor.ts +11 -0
  110. package/src/lib/fields/key-value/key-value.ts +283 -0
  111. package/src/lib/fields/list/list.descriptor.ts +21 -0
  112. package/src/lib/fields/list/list.ts +376 -0
  113. package/src/lib/fields/multiselect/multiselect.descriptor.ts +11 -0
  114. package/src/lib/fields/multiselect/multiselect.spec.ts +142 -0
  115. package/src/lib/fields/multiselect/multiselect.ts +152 -0
  116. package/src/lib/fields/number/number.descriptor.ts +12 -0
  117. package/src/lib/fields/number/number.ts +40 -0
  118. package/src/lib/fields/phone/phone.descriptor.ts +12 -0
  119. package/src/lib/fields/phone/phone.ts +46 -0
  120. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +12 -0
  121. package/src/lib/fields/readonly-text/readonly-text.ts +58 -0
  122. package/src/lib/fields/relation/relation.descriptor.ts +12 -0
  123. package/src/lib/fields/relation/relation.spec.ts +193 -0
  124. package/src/lib/fields/relation/relation.ts +224 -0
  125. package/src/lib/fields/rich-select/rich-select.descriptor.ts +12 -0
  126. package/src/lib/fields/rich-select/rich-select.ts +175 -0
  127. package/src/lib/fields/select/radio-mode.ts +25 -0
  128. package/src/lib/fields/select/select.descriptor.ts +12 -0
  129. package/src/lib/fields/select/select.spec.ts +162 -0
  130. package/src/lib/fields/select/select.ts +210 -0
  131. package/src/lib/fields/slug/slug.descriptor.ts +19 -0
  132. package/src/lib/fields/slug/slug.ts +67 -0
  133. package/src/lib/fields/string-list/string-list.descriptor.ts +11 -0
  134. package/src/lib/fields/string-list/string-list.ts +222 -0
  135. package/src/lib/fields/text/text.descriptor.ts +12 -0
  136. package/src/lib/fields/text/text.ts +35 -0
  137. package/src/lib/fields/textarea/textarea.descriptor.ts +12 -0
  138. package/src/lib/fields/textarea/textarea.spec.ts +117 -0
  139. package/src/lib/fields/textarea/textarea.ts +126 -0
  140. package/src/lib/fields/time/time.descriptor.ts +12 -0
  141. package/src/lib/fields/time/time.ts +28 -0
  142. package/src/lib/fields/unknown-render/unknown-render.ts +49 -0
  143. package/src/lib/fields/url/url.descriptor.ts +12 -0
  144. package/src/lib/fields/url/url.ts +53 -0
  145. package/src/lib/gas-admin-ui.spec.ts +21 -0
  146. package/src/lib/gas-admin-ui.ts +9 -0
  147. package/src/lib/layouts/descriptors.ts +9 -0
  148. package/src/lib/pages/dashboard/dashboard.ts +167 -0
  149. package/src/lib/pages/detail-view/detail-view.spec.ts +333 -0
  150. package/src/lib/pages/detail-view/detail-view.ts +570 -0
  151. package/src/lib/pages/drawer-form/drawer-form.ts +228 -0
  152. package/src/lib/pages/form-view/form-model.ts +88 -0
  153. package/src/lib/pages/form-view/form-schema.ts +255 -0
  154. package/src/lib/pages/form-view/form-view.ts +1622 -0
  155. package/src/lib/pages/list-view/list-view.formats.spec.ts +214 -0
  156. package/src/lib/pages/list-view/list-view.ts +882 -0
  157. package/src/lib/pages/login/login.spec.ts +109 -0
  158. package/src/lib/pages/login/login.ts +227 -0
  159. package/src/lib/pages/resource-page/resource-page.ts +234 -0
  160. package/src/lib/shared/components/badge/badge.ts +35 -0
  161. package/src/lib/shared/components/button/button.ts +65 -0
  162. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +48 -0
  163. package/src/lib/shared/components/copy-button/copy-button.ts +56 -0
  164. package/src/lib/shared/components/copy-share/copy-share.spec.ts +122 -0
  165. package/src/lib/shared/components/copy-share/copy-share.ts +107 -0
  166. package/src/lib/shared/components/drawer/drawer.spec.ts +127 -0
  167. package/src/lib/shared/components/drawer/drawer.ts +172 -0
  168. package/src/lib/shared/components/empty-state/empty-state.ts +30 -0
  169. package/src/lib/shared/components/modal/modal.spec.ts +149 -0
  170. package/src/lib/shared/components/modal/modal.ts +145 -0
  171. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +165 -0
  172. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +159 -0
  173. package/src/lib/shared/components/skeleton/skeleton.ts +31 -0
  174. package/src/lib/shared/components/toast/toast.ts +58 -0
  175. package/src/lib/shared/utils/col-span.ts +25 -0
  176. package/src/lib/shared/utils/condition-evaluator.ts +53 -0
  177. package/src/lib/shared/utils/depends-on.ts +48 -0
  178. package/src/lib/shared/utils/dialog-focus.ts +28 -0
  179. package/src/lib/shared/utils/field-path.ts +49 -0
  180. package/src/lib/shared/utils/gap-sorting.ts +144 -0
  181. package/src/lib/shared/utils/seed.spec.ts +64 -0
  182. package/src/lib/shared/utils/seed.ts +149 -0
  183. package/src/lib/shared/utils/slugify.ts +13 -0
  184. package/src/lib/shared/utils/validators.ts +41 -0
  185. package/src/lib/shell/layout/layout.ts +63 -0
  186. package/src/lib/shell/shell.routes.spec.ts +59 -0
  187. package/src/lib/shell/shell.routes.ts +122 -0
  188. package/src/lib/shell/sidebar/sidebar.ts +139 -0
  189. package/src/lib/shell/theme-toggle/theme-toggle.ts +74 -0
  190. package/src/lib/views/calendar-view/calendar-model.ts +426 -0
  191. package/src/lib/views/calendar-view/calendar-view.spec.ts +557 -0
  192. package/src/lib/views/calendar-view/calendar-view.ts +568 -0
  193. package/src/lib/views/composer/composer-host.spec.ts +301 -0
  194. package/src/lib/views/composer/composer-host.ts +248 -0
  195. package/src/lib/views/composer/composer-imports.spec.ts +54 -0
  196. package/src/lib/views/composer/view-context.spec.ts +117 -0
  197. package/src/lib/views/composer/view-context.ts +109 -0
  198. package/src/lib/views/composer/view-slot.spec.ts +130 -0
  199. package/src/lib/views/composer/view-slot.ts +178 -0
  200. package/src/lib/views/descriptors.ts +46 -0
  201. package/src/lib/views/kanban-view/kanban-model.ts +173 -0
  202. package/src/lib/views/kanban-view/kanban-view.spec.ts +540 -0
  203. package/src/lib/views/kanban-view/kanban-view.ts +327 -0
  204. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +17 -0
  205. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +66 -0
  206. package/src/lib/widgets/bar-chart/bar-chart.ts +76 -0
  207. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +17 -0
  208. package/src/lib/widgets/chart-line/chart-line.spec.ts +113 -0
  209. package/src/lib/widgets/chart-line/chart-line.ts +219 -0
  210. package/src/lib/widgets/descriptors.ts +29 -0
  211. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +41 -0
  212. package/src/lib/widgets/metric-card/metric-card.spec.ts +52 -0
  213. package/src/lib/widgets/metric-card/metric-card.ts +48 -0
  214. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +13 -0
  215. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +61 -0
  216. package/src/lib/widgets/quick-actions/quick-actions.ts +100 -0
  217. package/src/lib/widgets/record-list/record-list.descriptor.ts +16 -0
  218. package/src/lib/widgets/record-list/record-list.spec.ts +79 -0
  219. package/src/lib/widgets/record-list/record-list.ts +115 -0
  220. package/src/lib/widgets/series.spec.ts +42 -0
  221. package/src/lib/widgets/series.ts +56 -0
  222. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +19 -0
  223. package/src/lib/widgets/status-progress/status-progress.spec.ts +63 -0
  224. package/src/lib/widgets/status-progress/status-progress.ts +104 -0
  225. package/src/lib/widgets/widget-host/widget-host.spec.ts +179 -0
  226. package/src/lib/widgets/widget-host/widget-host.ts +99 -0
  227. package/src/public-api.ts +104 -0
  228. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  229. package/tsconfig.lib.json +13 -0
  230. package/tsconfig.lib.prod.json +11 -0
  231. package/tsconfig.spec.json +10 -0
  232. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +0 -84
  233. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +0 -1
  234. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +0 -140
  235. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +0 -1
  236. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +0 -113
  237. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +0 -1
  238. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +0 -163
  239. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +0 -1
  240. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +0 -1027
  241. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +0 -1
  242. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +0 -278
  243. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +0 -1
  244. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +0 -107
  245. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +0 -1
  246. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +0 -101
  247. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +0 -1
  248. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +0 -141
  249. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +0 -1
  250. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +0 -88
  251. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +0 -1
  252. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +0 -107
  253. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +0 -1
  254. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +0 -140
  255. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +0 -1
  256. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +0 -119
  257. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +0 -1
  258. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +0 -125
  259. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +0 -1
  260. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +0 -152
  261. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +0 -1
  262. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +0 -211
  263. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +0 -1
  264. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +0 -116
  265. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +0 -1
  266. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +0 -111
  267. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +0 -1
  268. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +0 -122
  269. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +0 -1
  270. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +0 -107
  271. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +0 -1
  272. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +0 -109
  273. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +0 -1
  274. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +0 -45
  275. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +0 -1
  276. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +0 -50
  277. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +0 -1
  278. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +0 -24
  279. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +0 -1
  280. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +0 -27
  281. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +0 -1
  282. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +0 -408
  283. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +0 -1
  284. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs +0 -4516
  285. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs.map +0 -1
  286. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +0 -82
  287. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +0 -1
  288. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +0 -105
  289. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +0 -1
  290. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +0 -65
  291. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +0 -1
  292. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +0 -65
  293. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +0 -1
  294. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +0 -65
  295. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +0 -1
  296. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +0 -59
  297. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +0 -1
  298. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +0 -94
  299. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +0 -1
  300. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +0 -72
  301. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +0 -1
  302. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +0 -238
  303. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +0 -1
  304. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +0 -416
  305. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +0 -1
  306. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +0 -439
  307. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +0 -1
  308. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +0 -513
  309. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +0 -1
  310. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs +0 -637
  311. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs.map +0 -1
  312. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +0 -127
  313. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +0 -1
  314. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +0 -251
  315. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +0 -1
  316. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +0 -66
  317. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +0 -1
  318. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +0 -114
  319. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +0 -1
  320. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +0 -116
  321. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +0 -1
  322. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +0 -235
  323. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +0 -1
  324. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +0 -8
  325. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +0 -1
  326. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +0 -124
  327. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +0 -1
  328. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +0 -249
  329. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +0 -1
  330. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +0 -39
  331. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +0 -1
  332. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +0 -309
  333. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +0 -1
  334. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs +0 -576
  335. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs.map +0 -1
  336. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +0 -161
  337. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +0 -1
  338. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +0 -11
  339. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +0 -685
  340. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +0 -1
  341. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs +0 -80
  342. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs.map +0 -1
  343. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +0 -296
  344. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +0 -1
  345. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +0 -119
  346. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +0 -1
  347. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +0 -158
  348. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +0 -1
  349. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +0 -26
  350. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +0 -1
  351. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +0 -205
  352. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +0 -1
  353. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +0 -432
  354. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +0 -1
  355. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +0 -36
  356. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +0 -1
  357. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +0 -107
  358. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +0 -1
  359. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +0 -223
  360. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +0 -1
  361. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +0 -107
  362. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +0 -1
  363. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +0 -60
  364. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +0 -1
  365. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +0 -141
  366. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +0 -1
  367. package/fesm2022/tinya-code-gas-admin-ui.mjs +0 -4599
  368. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +0 -1
  369. package/types/tinya-code-gas-admin-ui.d.ts +0 -3632
@@ -0,0 +1,96 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import {
4
+ get,
5
+ isSupported,
6
+ register,
7
+ resolve,
8
+ unregister,
9
+ type RenderDescriptor,
10
+ } from './render-registry';
11
+
12
+ /** Los 21 tipos de campo que la UI sabe dibujar (R3.3). */
13
+ const CAMPOS = [
14
+ 'text',
15
+ 'textarea',
16
+ 'slug',
17
+ 'number',
18
+ 'currency',
19
+ 'boolean',
20
+ 'select',
21
+ 'multiselect',
22
+ 'url',
23
+ 'email',
24
+ 'phone',
25
+ 'date',
26
+ 'time',
27
+ 'readonly-text',
28
+ 'group',
29
+ 'list',
30
+ 'string-list',
31
+ 'key-value',
32
+ 'relation',
33
+ 'image',
34
+ 'file',
35
+ ] as const;
36
+
37
+ /** Componente que sólo puede salir si el registro no resuelve. */
38
+ class SinRenderizador {}
39
+
40
+ describe('render-registry', () => {
41
+ it('registra y devuelve el descriptor por (kind, type)', () => {
42
+ const descriptor: RenderDescriptor = {
43
+ kind: 'view',
44
+ type: 'ficha-de-prueba',
45
+ since: '9.9',
46
+ load: async () => SinRenderizador,
47
+ };
48
+
49
+ register('view', descriptor);
50
+ try {
51
+ expect(get('view', 'ficha-de-prueba')).toBe(descriptor);
52
+ expect(get('field', 'ficha-de-prueba')).toBeUndefined();
53
+ } finally {
54
+ // El catálogo es GLOBAL: sin retirarla, la entrada de prueba contamina
55
+ // `renderKinds()` y el tripwire de contract.spec.ts flashea según el
56
+ // orden de ejecución (R7.6).
57
+ unregister('view', 'ficha-de-prueba');
58
+ }
59
+ });
60
+
61
+ it('isSupported sólo mira dentro de su kind', () => {
62
+ expect(isSupported('field', 'texto-que-no-existe')).toBe(false);
63
+ expect(isSupported('widget', 'text')).toBe(false);
64
+ });
65
+
66
+ it('los 21 tipos de campo están en el catálogo', () => {
67
+ for (const type of CAMPOS) {
68
+ expect(isSupported('field', type), `falta el descriptor de "${type}"`).toBe(true);
69
+ }
70
+ });
71
+
72
+ // Son 21 imports dinámicos de componentes reales: con el suite completo
73
+ // compitiendo por el hilo, el default de 10 s se queda corto y el gate se
74
+ // pone rojo por reloj, no por código.
75
+ it('los 21 tipos de campo resuelven su componente real', async () => {
76
+ for (const type of CAMPOS) {
77
+ const component = await resolve('field', type, SinRenderizador);
78
+ expect(component, `"${type}" resolvió el fallback`).not.toBe(SinRenderizador);
79
+ }
80
+ }, 30_000);
81
+
82
+ it('devuelve el fallback cuando el tipo no está registrado', async () => {
83
+ await expect(resolve('field', 'no-existe', SinRenderizador)).resolves.toBe(SinRenderizador);
84
+ });
85
+
86
+ it('el descriptor declara kind, since y carga perezosa', () => {
87
+ for (const type of CAMPOS) {
88
+ const descriptor = get('field', type)!;
89
+ expect(descriptor.kind, type).toBe('field');
90
+ expect(descriptor.type, type).toBe(type);
91
+ expect(descriptor.since, type).toBeTruthy();
92
+ expect(typeof descriptor.load, type).toBe('function');
93
+ expect(descriptor.surfaces, type).toContain('form');
94
+ }
95
+ });
96
+ });
@@ -0,0 +1,312 @@
1
+ import {
2
+ isDevMode,
3
+ makeEnvironmentProviders,
4
+ provideAppInitializer,
5
+ type EnvironmentProviders,
6
+ type TemplateRef,
7
+ type Type,
8
+ } from '@angular/core';
9
+
10
+ import type { RootTree } from '../../fields/field-node';
11
+ import type { SeedKind } from '../../shared/utils/seed';
12
+ import { columnFormatDescriptors } from '../../columns/descriptors';
13
+ import { fieldDescriptors } from '../../fields/descriptors';
14
+ import { layoutDescriptors } from '../../layouts/descriptors';
15
+ import { widgetDescriptors } from '../../widgets/descriptors';
16
+ import { viewDescriptors } from '../../views/descriptors';
17
+ import type { FieldSchema, LayoutMode, ListColumn, WidgetSchema } from '../models/schema.model';
18
+
19
+ /**
20
+ * Registro único de render (R3.1 · `doc/plan-refactor-motor.md` §3.1).
21
+ *
22
+ * Un solo sitio declara qué componentes sabe dibujar la UI: cada tipo de
23
+ * campo, widget, acción o vista aporta un `RenderDescriptor` y el registro
24
+ * lo resuelve por `(kind, type)`. Los hosts dejan de mantener `Set`s de tipos
25
+ * e imports a mano — **en runtime el registro es la única fuente de verdad**.
26
+ *
27
+ * Se carga a scope de módulo y no desde DI: `buildFormSchema()` es una
28
+ * función pura que consulta el registro sin inyectar nada, así que un
29
+ * registro llenado únicamente por un provider dejaría esa consulta correr
30
+ * contra un catálogo vacío. `provideRenderDescriptors()` existe igualmente
31
+ * como punto de entrada explícito para `app.config.ts` (R3.2).
32
+ *
33
+ * Autodescubrimiento (D9-1): se opta por **registro manual** — un manifiesto
34
+ * con una línea por descriptor — porque `import.meta.glob` no está
35
+ * implementada por el bundler de producción (`@angular/build:application`
36
+ * usa esbuild) y la llamada cruda sobreviviría en `dist/`, rompiendo el
37
+ * arranque. Con Vite sólo en el dev-server y en el runner de tests, además,
38
+ * el comportamiento habría diferido entre `npm test` y `npm run build`.
39
+ */
40
+
41
+ /** Qué clase de cosa se está resolviendo. Identificador único dentro de su `kind`. */
42
+ export type RenderKind = 'field' | 'column-format' | 'widget' | 'action' | 'view' | 'layout';
43
+ export type ComponentRenderKind = Exclude<RenderKind, 'layout'>;
44
+
45
+ /** Superficies en las que un descriptor puede aparecer. */
46
+ export type RenderSurface = 'form' | 'display' | 'list' | 'filter';
47
+
48
+ /**
49
+ * Qué puede describir un `RenderDescriptor`: un campo del formulario, un
50
+ * widget del dashboard o una columna de listado (R4.3).
51
+ *
52
+ * Es el tipo del input `config` del host. Los descriptores sólo comparten
53
+ * `key` y `label`; lo demás lo decide cada `kind`, y quien necesita el resto
54
+ * lo castea con su propia mirada (`cfgCampo()`, que es lo que el host ya
55
+ * hacía antes de que existieran las columnas).
56
+ */
57
+ export type RenderConfig = FieldSchema | WidgetSchema | ListColumn;
58
+
59
+ /**
60
+ * Contexto de render que el host expone por DI (R3.4 · `doc/plan-refactor-motor.md` §3.4).
61
+ *
62
+ * Los controles viven en un componente distinto por cada tipo, así que en vez
63
+ * de repetir cinco inputs en los 20 el host lo provee una sola vez y cada
64
+ * control lo inyecta si lo necesita — el mismo criterio que ya usaba
65
+ * `FIELD_ARIA`.
66
+ *
67
+ * `tree` viaja en el contexto y no como input suelto porque es **por
68
+ * instancia**: los hijos de un `group` o de un `list` navegan su subárbol, no
69
+ * el del padre.
70
+ *
71
+ * Vive acá y no en `render-host.ts` porque el contrato de los descriptores
72
+ * (`RenderExtras`) necesita nombrarlo: el descriptor de un campo compuesto
73
+ * decide qué se le pasa al componente y eso sólo es escribible conociendo el
74
+ * tipo. `render-host.ts` lo re-exporta para no mover a sus consumidores.
75
+ */
76
+ export interface RenderContext {
77
+ /** Árbol del formulario del nivel de este campo. */
78
+ tree: RootTree;
79
+ /** Errores del backend por ruta (`address.street`, `faq[2].answer`). */
80
+ serverErrors: Record<string, string>;
81
+ /** Prefijo de ruta de este campo en el registro raíz (`address.`). */
82
+ pathPrefix: string;
83
+ /** Si el registro ya existe (lo consume `slug` con `lockAfterCreate`). */
84
+ exists: boolean;
85
+ /** Recurso dueño del formulario (lo consume `image` para la firma, §11.2). */
86
+ resource: string;
87
+ }
88
+
89
+ /**
90
+ * Contexto vacío con el que arranca `RenderHost.ctx`.
91
+ *
92
+ * Sólo lo alcanza quien renderiza sin contexto — los widgets, que no forman
93
+ * parte de un formulario. Un campo montado sin `ctx` es un error de
94
+ * programación y `childTree` lo dice con su propio mensaje, igual que lo
95
+ * decía el `input.required` anterior.
96
+ */
97
+ export const RENDER_CONTEXT_VACIO: RenderContext = {
98
+ tree: undefined as unknown as RootTree,
99
+ serverErrors: {},
100
+ pathPrefix: '',
101
+ exists: false,
102
+ resource: '',
103
+ };
104
+
105
+ /**
106
+ * Segundo argumento de `RenderDescriptor.inputs`.
107
+ *
108
+ * Aporta lo que el host conoce y el descriptor no: el contexto de formulario
109
+ * (sólo para campos), el payload del dato (sólo para widgets) y los dos
110
+ * templates con los que se componen `group` y `list`.
111
+ */
112
+ export interface RenderExtras {
113
+ /** Contexto del nivel; `RENDER_CONTEXT_VACIO` cuando no hay formulario. */
114
+ ctx: RenderContext;
115
+ /** Payload del widget (`<app-widget-host [data]>`); `null` en campos. */
116
+ data: unknown;
117
+ /** Template del contenido de un `group`. */
118
+ groupContent?: TemplateRef<unknown>;
119
+ /** Template de los hijos de un `list`. */
120
+ childTemplate?: TemplateRef<unknown>;
121
+ }
122
+
123
+ /**
124
+ * Declaración de un componente renderizable.
125
+ *
126
+ * No lleva `configSchema`: esa cláusula de `refactormotor.md` no existe en
127
+ * el código y el plan la descartó (D17).
128
+ */
129
+ export interface RenderDescriptor<C = unknown> {
130
+ /** Clase de cosa. */
131
+ kind: ComponentRenderKind;
132
+ /** Identificador `kebab-case`, único dentro de `kind`. */
133
+ type: string;
134
+ /** Versión del contrato en que apareció (`doc/refactormotor.md`). */
135
+ since: string;
136
+ /**
137
+ * Carga perezosa del componente. El registro se resuelve sin arrastrar el
138
+ * bundle: los descriptores sólo guardan el cierre, no la clase.
139
+ */
140
+ load: () => Promise<Type<any>>;
141
+ /** Superficies en las que se usa. Sólo lo que se pueda evidenciar en el código. */
142
+ surfaces?: RenderSurface[];
143
+ /** Valores por defecto de la configuración del descriptor. */
144
+ defaults?: Partial<C>;
145
+ /**
146
+ * Forma del valor inicial que siembra este campo en el modelo del
147
+ * formulario (D32 · R3.8).
148
+ *
149
+ * **Dato, no función**: un nombre resuelto por `shared/utils/seed.ts`, no
150
+ * una clausura. Así el descriptor sigue siendo puro —`kind`, `type`,
151
+ * `load`, `surfaces`, `seed`— y `seed.ts` es el único dueño de recorrer
152
+ * un árbol de campos. La alternativa (`seed: (cfg) => …`) obligaría a que
153
+ * `group` importara `seedFields`, lo que cerraría un ciclo
154
+ * registro → manifiesto → descriptor → `seed` → registro.
155
+ *
156
+ * Sólo los campos lo declaran. **Obligatorio para `kind: 'field'`** — lo
157
+ * vigila `core/registry/contract.spec.ts`, porque la exhaustividad de una
158
+ * unión de strings no puede imponerse en tiempo de compilación.
159
+ */
160
+ seed?: SeedKind;
161
+ /**
162
+ * Cableado del componente: qué inputs recibe y con qué valor.
163
+ *
164
+ * Es **la** pieza que mantiene el host genérico: sin esto el motor tendría
165
+ * que saber que `metric-card` recibe `label/value/hint` y que `group`
166
+ * necesita además el template de sus hijos, y «añadir un tipo» volvería a
167
+ * tocar `render-host.ts` (R3.8). Cada descriptor declara el suyo y el host
168
+ * sólo hace `ngComponentOutletInputs = descriptor.inputs(config, extras)`.
169
+ *
170
+ * No es obligatorio: el 80 % de los tipos comparten la forma estándar de su
171
+ * `kind` — `{field, tree}` en campos, `{widget, data}` en widgets — y para
172
+ * ellos el host aplica esa forma por defecto. Se declara sólo cuando el
173
+ * componente se desvía de ella.
174
+ */
175
+ inputs?: (config: C, extras: RenderExtras) => Record<string, unknown>;
176
+ }
177
+
178
+ /** Declaración de un layout manejado por el host de formularios. */
179
+ export interface LayoutDescriptor {
180
+ kind: 'layout';
181
+ type: LayoutMode;
182
+ since: string;
183
+ }
184
+
185
+ /** Catálogo en memoria: `kind:type` → descriptor. */
186
+ const RENDERERS = new Map<string, RenderDescriptor>();
187
+ const LAYOUTS = new Map<string, LayoutDescriptor>();
188
+
189
+ function keyOf(kind: RenderKind, type: string): string {
190
+ return `${kind}:${type}`;
191
+ }
192
+
193
+ /**
194
+ * Registra un descriptor. Idempotente por clave: volver a registrar el mismo
195
+ * `(kind, type)` lo sobrescribe, lo que permite que un módulo se recargue en
196
+ * desarrollo sin duplicar entradas.
197
+ */
198
+ export function register(kind: 'layout', descriptor: LayoutDescriptor): void;
199
+ export function register(kind: ComponentRenderKind, descriptor: RenderDescriptor): void;
200
+ export function register(kind: RenderKind, descriptor: RenderDescriptor | LayoutDescriptor): void {
201
+ if (kind === 'layout') {
202
+ if (!('kind' in descriptor) || descriptor.kind !== 'layout') {
203
+ throw new Error(`El descriptor de layout "${descriptor.type}" no declara kind: "layout".`);
204
+ }
205
+ LAYOUTS.set(descriptor.type, descriptor);
206
+ return;
207
+ }
208
+ if (descriptor.kind === 'layout') {
209
+ throw new Error(
210
+ `El descriptor de layout "${descriptor.type}" no puede registrarse como ${kind}.`,
211
+ );
212
+ }
213
+ RENDERERS.set(keyOf(kind, descriptor.type), descriptor);
214
+ }
215
+
216
+ /**
217
+ * Quita un descriptor (R7.6). Simétrico a `register`: los specs que
218
+ * registran entradas de prueba deben retirarlas, o el catálogo global queda
219
+ * contaminado para cualquier otro spec que lea `renderKinds()` (flaky por
220
+ * orden de ejecución).
221
+ */
222
+ export function unregister(kind: RenderKind, type: string): void {
223
+ if (kind === 'layout') {
224
+ LAYOUTS.delete(type);
225
+ } else {
226
+ RENDERERS.delete(keyOf(kind, type));
227
+ }
228
+ }
229
+
230
+ /** Descriptor declarado para `(kind, type)`, o `undefined` si nadie lo registró. */
231
+ export function get(kind: ComponentRenderKind, type: string): RenderDescriptor | undefined {
232
+ return RENDERERS.get(keyOf(kind, type));
233
+ }
234
+
235
+ /** ¿La UI sabe dibujar este `(kind, type)`? Reemplaza a los `Set`s de los hosts. */
236
+ export function isSupported(kind: RenderKind, type: string): boolean {
237
+ return kind === 'layout' ? LAYOUTS.has(type) : RENDERERS.has(keyOf(kind, type));
238
+ }
239
+
240
+ /**
241
+ * Componente para `(kind, type)`, o `fallback` si el tipo no está en el
242
+ * catálogo.
243
+ *
244
+ * Es **asíncrona** porque `load()` importa el componente bajo demanda; el
245
+ * `fallback` es síncrono y sólo se usa cuando no hay descriptor. Un fallo de
246
+ * `load()` NO se traga: propagarlo es lo que hace visible un descriptor mal
247
+ * escrito, y la política «nunca pantalla rota» la resuelve el llamante con el
248
+ * `fallback` que ya recibe.
249
+ */
250
+ export async function resolve<C = unknown>(
251
+ kind: ComponentRenderKind,
252
+ type: string,
253
+ fallback: Type<C>,
254
+ ): Promise<Type<C>> {
255
+ const descriptor = get(kind, type);
256
+ if (!descriptor) return fallback;
257
+ return (await descriptor.load()) as Type<C>;
258
+ }
259
+
260
+ // Catálogo a scope de módulo: se registra al importar, sin esperar a DI.
261
+ for (const descriptor of [
262
+ ...fieldDescriptors,
263
+ ...widgetDescriptors,
264
+ ...columnFormatDescriptors,
265
+ ...viewDescriptors,
266
+ ...layoutDescriptors,
267
+ ]) {
268
+ if (descriptor.kind === 'layout') {
269
+ register('layout', descriptor);
270
+ } else {
271
+ register(descriptor.kind, descriptor);
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Punto de entrada para `app.config.ts` (R3.2).
277
+ *
278
+ * El catálogo ya quedó cargado al importar este módulo; el provider sirve
279
+ * para que el arranque sea explícito y para avisar en desarrollo si el
280
+ * manifiesto vino vacío — que es exactamente lo que pasaría si alguien
281
+ * borra una línea del manifiesto sin reemplazarla.
282
+ */
283
+ export function provideRenderDescriptors(): EnvironmentProviders {
284
+ return makeEnvironmentProviders([
285
+ provideAppInitializer(() => {
286
+ if (isDevMode() && RENDERERS.size === 0 && LAYOUTS.size === 0) {
287
+ console.warn('[render-registry] el catálogo de descriptores vino vacío');
288
+ }
289
+ }),
290
+ ]);
291
+ }
292
+
293
+ /** Cuántos descriptores hay registrados. Sólo para comprobaciones y tests. */
294
+ export function renderDescriptorCount(): number {
295
+ return RENDERERS.size + LAYOUTS.size;
296
+ }
297
+
298
+ /**
299
+ * `kind`s que hoy tienen al menos un descriptor.
300
+ *
301
+ * Existe para el test de exhaustividad (R3.7): él recorre los schemas de los
302
+ * `kind`s que tienen registro y **falla** si aparece un `kind` con descriptor
303
+ * que nadie recorre — de lo contrario «tener registro» y «estar cubierto»
304
+ * serían dos afirmaciones distintas que nadie reconcilia.
305
+ */
306
+ export function renderKinds(): RenderKind[] {
307
+ const kinds = new Set<RenderKind>([...RENDERERS.values()].map((descriptor) => descriptor.kind));
308
+ if (LAYOUTS.size > 0) {
309
+ kinds.add('layout');
310
+ }
311
+ return [...kinds];
312
+ }
@@ -0,0 +1,156 @@
1
+ import {
2
+ EnvironmentProviders,
3
+ InjectionToken,
4
+ Provider,
5
+ inject,
6
+ provideAppInitializer,
7
+ } from '@angular/core';
8
+ import { provideHttpClient, withInterceptors } from '@angular/common/http';
9
+
10
+ import { apiErrorInterceptor } from '../interceptors/api-error.interceptor';
11
+ import { AuthService } from '../services/auth.service';
12
+ import { ConfigService } from '../services/config.service';
13
+ import type { AuthSchema, ResourceSchema, ResponseUnwrap } from '../models/schema.model';
14
+ import type { FirebaseAuthAdapter } from '../adapters/firebase-auth.adapter';
15
+ import { API_DRIVER, DEFAULT_RESPONSE_UNWRAP, FIREBASE_AUTH_ADAPTER, VALUE_SOURCES } from '../tokens';
16
+ import type { ValueSources } from '../tokens';
17
+
18
+
19
+ /**
20
+ * Catálogo de schemas del consumidor (F1 · G-F2).
21
+ *
22
+ * Antes de la extracción el motor importaba `getSchema` del
23
+ * `schemas/registry.ts` de la app. Ese acoplamiento se rompe con un
24
+ * catálogo a nivel módulo: el consumidor llama
25
+ * `provideGasAdmin({ schemas, auth })` en su `app.config.ts` y el motor
26
+ * resuelve en runtime con la MISMA semántica que antes (un solo catálogo
27
+ * por aplicación, seteado una vez en el bootstrap).
28
+ *
29
+ * `provideGasAdmin` se ejecuta al evaluarse el `app.config` (módulo), y
30
+ * todo uso del catálogo (guards, componentes, rutas dinámicas) ocurre en
31
+ * runtime posterior al bootstrap — el orden es determinístico.
32
+ */
33
+
34
+ let catalog: readonly ResourceSchema[] = [];
35
+ let authCatalog: AuthSchema | undefined;
36
+
37
+ /** Fija el catálogo (uso interno de `provideGasAdmin`; testable directo). */
38
+ export function setSchemaCatalog(
39
+ schemas: readonly ResourceSchema[],
40
+ auth?: AuthSchema,
41
+ ): void {
42
+ catalog = schemas;
43
+ authCatalog = auth;
44
+ }
45
+
46
+ /** Busca un schema por `id`; `undefined` si no existe. */
47
+ export function getSchema(id: string): ResourceSchema | undefined {
48
+ return catalog.find((schema) => schema.id === id);
49
+ }
50
+
51
+ /** Catálogo completo en orden (menú lateral). */
52
+ export function allSchemas(): readonly ResourceSchema[] {
53
+ return catalog;
54
+ }
55
+
56
+ /** Declaración de la pantalla de login; `undefined` sin `auth` en config. */
57
+ export function getAuth(): AuthSchema | undefined {
58
+ return authCatalog;
59
+ }
60
+
61
+ /** Token DI del catálogo (para inyectarlo donde un `inject()` es posible). */
62
+ export const GAS_SCHEMAS = new InjectionToken<readonly ResourceSchema[]>(
63
+ 'gas.admin.schemas',
64
+ );
65
+
66
+ /** Configuración del motor. */
67
+ export interface GasAdminConfig {
68
+ /** Catálogo ordenado de recursos (menú + rutas + resolución `getSchema`). */
69
+ schemas: readonly ResourceSchema[];
70
+ /** Declaración de la pantalla de login (opcional: sin ella, sin `/login`). */
71
+ auth?: AuthSchema;
72
+ /**
73
+ * Driver de transporte HTTP.
74
+ *
75
+ * - `'gas'` (default): tunnel `POST text/plain` con envelope Apps Script.
76
+ * - `'rest'`: verbos HTTP reales con `Authorization: Bearer` en cabeceras.
77
+ *
78
+ * Sin declaración el motor usa `'gas'` — cero impacto en consumidores existentes.
79
+ */
80
+ driver?: 'gas' | 'rest';
81
+ /**
82
+ * Fuentes de contexto que el consumidor aporta para marcadores en paths de
83
+ * endpoints: `{ <fuente> }` / `{ <fuente>.<ruta> }` se resuelven en el
84
+ * momento de la petición contra este registro más las fuentes construidas
85
+ * `auth` (sesión) y `config` (config global).
86
+ *
87
+ * Opcional: sin él, sólo existen `auth` y `config`. Declararlo no cambia
88
+ * ningún path que no lleve marcadores — cero impacto en schemas existentes.
89
+ */
90
+ valueSources?: ValueSources;
91
+ /**
92
+ * Unwrap de respuesta global por defecto. Se fusiona con la declaración
93
+ * `endpoint.responseUnwrap` de cada recurso (la del recurso tiene prioridad
94
+ * en claves declaradas). Opcional: sin él, sólo aplica lo declarado por
95
+ * recurso — cero impacto en schemas existentes (R2).
96
+ */
97
+ defaultResponseUnwrap?: ResponseUnwrap;
98
+ }
99
+
100
+ /**
101
+ * Wiring completo del motor: catálogo + HTTP con el interceptor de
102
+ * errores del envelope + loaders de config y sesión en el bootstrap
103
+ * (antes en el `app.config` del consumidor).
104
+ *
105
+ * El consumidor conserva `provideRouter` y `{ provide: API_URL, ... }`
106
+ * (su environment decide la URL del Web App).
107
+ */
108
+ export function provideGasAdmin(
109
+ config: GasAdminConfig,
110
+ ): (Provider | EnvironmentProviders)[] {
111
+ setSchemaCatalog(config.schemas, config.auth);
112
+ // Singletons de configuración: los declara el catálogo, no el servicio.
113
+ // Un singleton nuevo con `endpoint.get` se carga solo.
114
+ const configEndpoints = () =>
115
+ config.schemas.flatMap((schema) =>
116
+ schema.kind === 'singleton' && schema.endpoint?.get
117
+ ? [{ get: schema.endpoint.get }]
118
+ : [],
119
+ );
120
+ return [
121
+ { provide: GAS_SCHEMAS, useValue: config.schemas },
122
+ // Driver de transporte: 'gas' por defecto para cero breaking changes.
123
+ { provide: API_DRIVER, useValue: config.driver ?? 'gas' },
124
+ // Fuentes de contexto del consumidor: vacío por defecto ⇒ sólo `auth` y
125
+ // `config`, que el motor arma por su cuenta en cada petición.
126
+ { provide: VALUE_SOURCES, useValue: config.valueSources ?? {} },
127
+ // Unwrap global por defecto: undefined si no se declara ⇒ sólo aplica lo
128
+ // declarado por recurso (R2, cero impacto en schemas existentes).
129
+ { provide: DEFAULT_RESPONSE_UNWRAP, useValue: config.defaultResponseUnwrap },
130
+ // Sin `authInterceptor` en modo GAS: el token viaja en el cuerpo del envelope
131
+ // (baseapi §2.3, criterio 11: ninguna cabecera custom).
132
+ // En modo REST el token viaja como cabecera `Authorization` dentro de ApiService.
133
+ provideHttpClient(withInterceptors([apiErrorInterceptor])),
134
+ // Carga de config en bootstrap (fuera del constructor del servicio):
135
+ // un singleton que falle no rompe el arranque.
136
+ provideAppInitializer(() => inject(ConfigService).load(configEndpoints())),
137
+ // Sesión (R2.12): revalida contra `/auth/me` el token que restauró el
138
+ // AuthService de `sessionStorage`. Corre ANTES del primer guard.
139
+ provideAppInitializer(() => inject(AuthService).restore()),
140
+ ];
141
+ }
142
+
143
+ /**
144
+ * Registra una implementación concreta de FirebaseAuthAdapter en el árbol de DI.
145
+ * Usar junto con provideGasAdmin() en app.config.ts al configurar proveedores federados
146
+ * (como 'google') o autenticación por Firebase.
147
+ *
148
+ * @example
149
+ * // app.config.ts
150
+ * provideGasAdmin({ schemas, auth }),
151
+ * provideFirebaseAdapter(new MyFirebaseAuthAdapter(getAuth(firebaseApp))),
152
+ */
153
+ export function provideFirebaseAdapter(adapter: FirebaseAuthAdapter): Provider {
154
+ return { provide: FIREBASE_AUTH_ADAPTER, useValue: adapter };
155
+ }
156
+