@platforma-sdk/model 1.79.27 → 1.80.0

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 (356) hide show
  1. package/dist/block_model.d.ts +2 -0
  2. package/dist/block_model.d.ts.map +1 -1
  3. package/dist/columns/column.cjs +28 -0
  4. package/dist/columns/column.cjs.map +1 -0
  5. package/dist/columns/column.d.ts +30 -0
  6. package/dist/columns/column.d.ts.map +1 -0
  7. package/dist/columns/column.js +27 -0
  8. package/dist/columns/column.js.map +1 -0
  9. package/dist/columns/column_lazy.cjs +248 -0
  10. package/dist/columns/column_lazy.cjs.map +1 -0
  11. package/dist/columns/column_lazy.d.ts +137 -0
  12. package/dist/columns/column_lazy.d.ts.map +1 -0
  13. package/dist/columns/column_lazy.js +245 -0
  14. package/dist/columns/column_lazy.js.map +1 -0
  15. package/dist/columns/column_providers/index.cjs +62 -0
  16. package/dist/columns/column_providers/index.cjs.map +1 -0
  17. package/dist/columns/column_providers/index.d.ts +30 -0
  18. package/dist/columns/column_providers/index.d.ts.map +1 -0
  19. package/dist/columns/column_providers/index.js +53 -0
  20. package/dist/columns/column_providers/index.js.map +1 -0
  21. package/dist/columns/column_providers/providers.cjs +123 -0
  22. package/dist/columns/column_providers/providers.cjs.map +1 -0
  23. package/dist/columns/column_providers/providers.d.ts +75 -0
  24. package/dist/columns/column_providers/providers.d.ts.map +1 -0
  25. package/dist/columns/column_providers/providers.js +118 -0
  26. package/dist/columns/column_providers/providers.js.map +1 -0
  27. package/dist/columns/column_providers/types.d.ts +23 -0
  28. package/dist/columns/column_providers/types.d.ts.map +1 -0
  29. package/dist/columns/column_recipes/column_discovered_recipe.cjs +180 -0
  30. package/dist/columns/column_recipes/column_discovered_recipe.cjs.map +1 -0
  31. package/dist/columns/column_recipes/column_discovered_recipe.d.ts +120 -0
  32. package/dist/columns/column_recipes/column_discovered_recipe.d.ts.map +1 -0
  33. package/dist/columns/column_recipes/column_discovered_recipe.js +180 -0
  34. package/dist/columns/column_recipes/column_discovered_recipe.js.map +1 -0
  35. package/dist/columns/column_recipes/column_filtered_recipe.cjs +133 -0
  36. package/dist/columns/column_recipes/column_filtered_recipe.cjs.map +1 -0
  37. package/dist/columns/column_recipes/column_filtered_recipe.d.ts +75 -0
  38. package/dist/columns/column_recipes/column_filtered_recipe.d.ts.map +1 -0
  39. package/dist/columns/column_recipes/column_filtered_recipe.js +133 -0
  40. package/dist/columns/column_recipes/column_filtered_recipe.js.map +1 -0
  41. package/dist/columns/column_recipes/column_overrided_recipe.cjs +101 -0
  42. package/dist/columns/column_recipes/column_overrided_recipe.cjs.map +1 -0
  43. package/dist/columns/column_recipes/column_overrided_recipe.d.ts +73 -0
  44. package/dist/columns/column_recipes/column_overrided_recipe.d.ts.map +1 -0
  45. package/dist/columns/column_recipes/column_overrided_recipe.js +101 -0
  46. package/dist/columns/column_recipes/column_overrided_recipe.js.map +1 -0
  47. package/dist/columns/column_recipes/index.cjs +72 -0
  48. package/dist/columns/column_recipes/index.cjs.map +1 -0
  49. package/dist/columns/column_recipes/index.d.ts +52 -0
  50. package/dist/columns/column_recipes/index.d.ts.map +1 -0
  51. package/dist/columns/column_recipes/index.js +68 -0
  52. package/dist/columns/column_recipes/index.js.map +1 -0
  53. package/dist/columns/column_recipes/leaf_rebrand.cjs +22 -0
  54. package/dist/columns/column_recipes/leaf_rebrand.cjs.map +1 -0
  55. package/dist/columns/column_recipes/leaf_rebrand.js +22 -0
  56. package/dist/columns/column_recipes/leaf_rebrand.js.map +1 -0
  57. package/dist/columns/column_recipes/types.d.ts +101 -0
  58. package/dist/columns/column_recipes/types.d.ts.map +1 -0
  59. package/dist/columns/columns_collection.cjs +124 -0
  60. package/dist/columns/columns_collection.cjs.map +1 -0
  61. package/dist/columns/columns_collection.d.ts +64 -0
  62. package/dist/columns/columns_collection.d.ts.map +1 -0
  63. package/dist/columns/columns_collection.js +122 -0
  64. package/dist/columns/columns_collection.js.map +1 -0
  65. package/dist/columns/derive_axis_values_labels.cjs +76 -0
  66. package/dist/columns/derive_axis_values_labels.cjs.map +1 -0
  67. package/dist/columns/derive_axis_values_labels.d.ts +30 -0
  68. package/dist/columns/derive_axis_values_labels.d.ts.map +1 -0
  69. package/dist/columns/derive_axis_values_labels.js +76 -0
  70. package/dist/columns/derive_axis_values_labels.js.map +1 -0
  71. package/dist/columns/expand_by_partition.cjs +53 -56
  72. package/dist/columns/expand_by_partition.cjs.map +1 -1
  73. package/dist/columns/expand_by_partition.d.ts +22 -18
  74. package/dist/columns/expand_by_partition.d.ts.map +1 -1
  75. package/dist/columns/expand_by_partition.js +55 -58
  76. package/dist/columns/expand_by_partition.js.map +1 -1
  77. package/dist/columns/index.cjs +44 -18
  78. package/dist/columns/index.d.ts +15 -7
  79. package/dist/columns/index.js +12 -6
  80. package/dist/columns/utils.cjs +186 -0
  81. package/dist/columns/utils.cjs.map +1 -0
  82. package/dist/columns/utils.d.ts +96 -0
  83. package/dist/columns/utils.d.ts.map +1 -0
  84. package/dist/columns/utils.js +179 -0
  85. package/dist/columns/utils.js.map +1 -0
  86. package/dist/components/PFrameForGraphs.cjs +1 -0
  87. package/dist/components/PFrameForGraphs.cjs.map +1 -1
  88. package/dist/components/PFrameForGraphs.d.ts +1 -1
  89. package/dist/components/PFrameForGraphs.d.ts.map +1 -1
  90. package/dist/components/PFrameForGraphs.js +1 -0
  91. package/dist/components/PFrameForGraphs.js.map +1 -1
  92. package/dist/components/PlDataTable/columnResolver.cjs +28 -0
  93. package/dist/components/PlDataTable/columnResolver.cjs.map +1 -0
  94. package/dist/components/PlDataTable/columnResolver.js +28 -0
  95. package/dist/components/PlDataTable/columnResolver.js.map +1 -0
  96. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs +4 -2
  97. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.cjs.map +1 -1
  98. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js +4 -2
  99. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV2.js.map +1 -1
  100. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.cjs +20 -25
  101. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.cjs.map +1 -1
  102. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.js +20 -25
  103. package/dist/components/PlDataTable/createPlDataTable/createPTableDefV3.js.map +1 -1
  104. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +58 -26
  105. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -1
  106. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts +1 -1
  107. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts.map +1 -1
  108. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +60 -28
  109. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -1
  110. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +224 -194
  111. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  112. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +13 -16
  113. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts.map +1 -1
  114. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +228 -198
  115. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  116. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +40 -98
  117. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
  118. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts +17 -8
  119. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts.map +1 -1
  120. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +40 -98
  121. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
  122. package/dist/components/PlDataTable/createPlDataTable/index.cjs +1 -1
  123. package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -1
  124. package/dist/components/PlDataTable/createPlDataTable/index.d.ts +2 -2
  125. package/dist/components/PlDataTable/createPlDataTable/index.js +2 -2
  126. package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -1
  127. package/dist/components/PlDataTable/createPlDataTable/utils.cjs +51 -169
  128. package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
  129. package/dist/components/PlDataTable/createPlDataTable/utils.d.ts +1 -1
  130. package/dist/components/PlDataTable/createPlDataTable/utils.d.ts.map +1 -1
  131. package/dist/components/PlDataTable/createPlDataTable/utils.js +52 -166
  132. package/dist/components/PlDataTable/createPlDataTable/utils.js.map +1 -1
  133. package/dist/components/PlDataTable/createPlDataTableSheet.cjs.map +1 -1
  134. package/dist/components/PlDataTable/createPlDataTableSheet.d.ts +1 -1
  135. package/dist/components/PlDataTable/createPlDataTableSheet.js.map +1 -1
  136. package/dist/components/PlDataTable/index.cjs +1 -1
  137. package/dist/components/PlDataTable/index.d.ts +4 -4
  138. package/dist/components/PlDataTable/index.js +2 -2
  139. package/dist/components/PlDataTable/labels.cjs +0 -1
  140. package/dist/components/PlDataTable/labels.cjs.map +1 -1
  141. package/dist/components/PlDataTable/labels.js +0 -1
  142. package/dist/components/PlDataTable/labels.js.map +1 -1
  143. package/dist/components/PlDataTable/state-migration.cjs +107 -10
  144. package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
  145. package/dist/components/PlDataTable/state-migration.d.ts +5 -4
  146. package/dist/components/PlDataTable/state-migration.d.ts.map +1 -1
  147. package/dist/components/PlDataTable/state-migration.js +107 -10
  148. package/dist/components/PlDataTable/state-migration.js.map +1 -1
  149. package/dist/components/PlDataTable/typesV7.d.ts +1 -36
  150. package/dist/components/PlDataTable/typesV7.d.ts.map +1 -1
  151. package/dist/components/PlDataTable/typesV8.d.ts +123 -0
  152. package/dist/components/PlDataTable/typesV8.d.ts.map +1 -0
  153. package/dist/components/PlDatasetSelector/build_dataset_options.cjs +27 -34
  154. package/dist/components/PlDatasetSelector/build_dataset_options.cjs.map +1 -1
  155. package/dist/components/PlDatasetSelector/build_dataset_options.d.ts.map +1 -1
  156. package/dist/components/PlDatasetSelector/build_dataset_options.js +27 -34
  157. package/dist/components/PlDatasetSelector/build_dataset_options.js.map +1 -1
  158. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs +28 -33
  159. package/dist/components/PlDatasetSelector/enrichment_discovery.cjs.map +1 -1
  160. package/dist/components/PlDatasetSelector/enrichment_discovery.js +29 -34
  161. package/dist/components/PlDatasetSelector/enrichment_discovery.js.map +1 -1
  162. package/dist/components/PlDatasetSelector/filter_discovery.cjs +27 -17
  163. package/dist/components/PlDatasetSelector/filter_discovery.cjs.map +1 -1
  164. package/dist/components/PlDatasetSelector/filter_discovery.d.ts +24 -10
  165. package/dist/components/PlDatasetSelector/filter_discovery.d.ts.map +1 -1
  166. package/dist/components/PlDatasetSelector/filter_discovery.js +28 -18
  167. package/dist/components/PlDatasetSelector/filter_discovery.js.map +1 -1
  168. package/dist/components/PlDatasetSelector/index.d.ts +2 -2
  169. package/dist/components/index.cjs +1 -1
  170. package/dist/components/index.d.ts +5 -5
  171. package/dist/components/index.js +2 -2
  172. package/dist/filters/converters/filterToQuery.cjs +5 -6
  173. package/dist/filters/converters/filterToQuery.cjs.map +1 -1
  174. package/dist/filters/converters/filterToQuery.d.ts +12 -3
  175. package/dist/filters/converters/filterToQuery.d.ts.map +1 -1
  176. package/dist/filters/converters/filterToQuery.js +5 -6
  177. package/dist/filters/converters/filterToQuery.js.map +1 -1
  178. package/dist/filters/converters/index.d.ts +2 -2
  179. package/dist/filters/index.d.ts +2 -2
  180. package/dist/index.cjs +64 -35
  181. package/dist/index.d.ts +23 -15
  182. package/dist/index.js +15 -9
  183. package/dist/labels/derive_distinct_labels.cjs.map +1 -1
  184. package/dist/labels/derive_distinct_labels.d.ts +1 -2
  185. package/dist/labels/derive_distinct_labels.d.ts.map +1 -1
  186. package/dist/labels/derive_distinct_labels.js.map +1 -1
  187. package/dist/labels/derive_distinct_tooltips.cjs +1 -1
  188. package/dist/labels/derive_distinct_tooltips.cjs.map +1 -1
  189. package/dist/labels/derive_distinct_tooltips.d.ts +6 -3
  190. package/dist/labels/derive_distinct_tooltips.d.ts.map +1 -1
  191. package/dist/labels/derive_distinct_tooltips.js +1 -1
  192. package/dist/labels/derive_distinct_tooltips.js.map +1 -1
  193. package/dist/package.cjs +1 -1
  194. package/dist/package.js +1 -1
  195. package/dist/pframe_utils/axes.cjs.map +1 -1
  196. package/dist/pframe_utils/axes.d.ts +2 -2
  197. package/dist/pframe_utils/axes.d.ts.map +1 -1
  198. package/dist/pframe_utils/axes.js.map +1 -1
  199. package/dist/pframe_utils/columns.cjs +6 -10
  200. package/dist/pframe_utils/columns.cjs.map +1 -1
  201. package/dist/pframe_utils/columns.d.ts +4 -4
  202. package/dist/pframe_utils/columns.d.ts.map +1 -1
  203. package/dist/pframe_utils/columns.js +7 -11
  204. package/dist/pframe_utils/columns.js.map +1 -1
  205. package/dist/pframe_utils/index.cjs.map +1 -1
  206. package/dist/pframe_utils/index.d.ts +1 -1
  207. package/dist/pframe_utils/index.d.ts.map +1 -1
  208. package/dist/pframe_utils/index.js.map +1 -1
  209. package/dist/render/accessor.cjs +15 -16
  210. package/dist/render/accessor.cjs.map +1 -1
  211. package/dist/render/accessor.d.ts +7 -10
  212. package/dist/render/accessor.d.ts.map +1 -1
  213. package/dist/render/accessor.js +15 -16
  214. package/dist/render/accessor.js.map +1 -1
  215. package/dist/render/api.cjs +34 -36
  216. package/dist/render/api.cjs.map +1 -1
  217. package/dist/render/api.d.ts +30 -20
  218. package/dist/render/api.d.ts.map +1 -1
  219. package/dist/render/api.js +35 -38
  220. package/dist/render/api.js.map +1 -1
  221. package/dist/render/index.cjs +4 -0
  222. package/dist/render/index.d.ts +4 -4
  223. package/dist/render/index.js +3 -2
  224. package/dist/render/internal.cjs +3 -2
  225. package/dist/render/internal.cjs.map +1 -1
  226. package/dist/render/internal.d.ts +17 -9
  227. package/dist/render/internal.d.ts.map +1 -1
  228. package/dist/render/internal.js +3 -2
  229. package/dist/render/internal.js.map +1 -1
  230. package/dist/render/util/axis_filtering.cjs.map +1 -1
  231. package/dist/render/util/axis_filtering.js.map +1 -1
  232. package/dist/render/util/column_collection.cjs +6 -4
  233. package/dist/render/util/column_collection.cjs.map +1 -1
  234. package/dist/render/util/column_collection.d.ts +9 -9
  235. package/dist/render/util/column_collection.d.ts.map +1 -1
  236. package/dist/render/util/column_collection.js +6 -4
  237. package/dist/render/util/column_collection.js.map +1 -1
  238. package/dist/render/util/index.d.ts +2 -2
  239. package/dist/render/util/pcolumn_data.cjs +1 -1
  240. package/dist/render/util/pcolumn_data.cjs.map +1 -1
  241. package/dist/render/util/pcolumn_data.d.ts +3 -3
  242. package/dist/render/util/pcolumn_data.d.ts.map +1 -1
  243. package/dist/render/util/pcolumn_data.js +1 -1
  244. package/dist/render/util/pcolumn_data.js.map +1 -1
  245. package/dist/services/block_services.cjs +2 -1
  246. package/dist/services/block_services.cjs.map +1 -1
  247. package/dist/services/block_services.d.ts +1 -0
  248. package/dist/services/block_services.d.ts.map +1 -1
  249. package/dist/services/block_services.js +2 -1
  250. package/dist/services/block_services.js.map +1 -1
  251. package/dist/services/get_services.cjs +2 -2
  252. package/dist/services/get_services.cjs.map +1 -1
  253. package/dist/services/get_services.d.ts +4 -1
  254. package/dist/services/get_services.d.ts.map +1 -1
  255. package/dist/services/get_services.js +2 -2
  256. package/dist/services/get_services.js.map +1 -1
  257. package/package.json +10 -8
  258. package/src/columns/__test_helpers__/collection_driver.ts +197 -0
  259. package/src/columns/__test_helpers__/stub_registry.ts +134 -0
  260. package/src/columns/column.ts +46 -0
  261. package/src/columns/column_lazy.test.ts +201 -0
  262. package/src/columns/column_lazy.ts +311 -0
  263. package/src/columns/column_providers/index.ts +78 -0
  264. package/src/columns/column_providers/providers.ts +193 -0
  265. package/src/columns/column_providers/types.ts +24 -0
  266. package/src/columns/column_recipes/column_discovered_recipe.ts +231 -0
  267. package/src/columns/column_recipes/column_filtered_recipe.ts +184 -0
  268. package/src/columns/column_recipes/column_overrided_recipe.ts +146 -0
  269. package/src/columns/column_recipes/column_recipes.test.ts +681 -0
  270. package/src/columns/column_recipes/index.ts +127 -0
  271. package/src/columns/column_recipes/leaf_rebrand.ts +28 -0
  272. package/src/columns/column_recipes/types.ts +113 -0
  273. package/src/columns/columns_collection.test.ts +164 -0
  274. package/src/columns/columns_collection.ts +170 -0
  275. package/src/columns/derive_axis_values_labels.ts +98 -0
  276. package/src/columns/expand_by_partition.test.ts +146 -110
  277. package/src/columns/expand_by_partition.ts +72 -84
  278. package/src/columns/index.ts +7 -5
  279. package/src/columns/utils.test.ts +249 -0
  280. package/src/columns/utils.ts +226 -0
  281. package/src/components/PFrameForGraphs.ts +3 -1
  282. package/src/components/PlAnnotations/filters_ui.test.ts +46 -47
  283. package/src/components/PlDataTable/columnResolver.test.ts +122 -0
  284. package/src/components/PlDataTable/columnResolver.ts +57 -0
  285. package/src/components/PlDataTable/createPlDataTable/createPTableDefV2.ts +9 -9
  286. package/src/components/PlDataTable/createPlDataTable/createPTableDefV3.ts +31 -63
  287. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +85 -58
  288. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +316 -354
  289. package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +48 -144
  290. package/src/components/PlDataTable/createPlDataTable/index.ts +2 -2
  291. package/src/components/PlDataTable/createPlDataTable/utils.test.ts +60 -69
  292. package/src/components/PlDataTable/createPlDataTable/utils.ts +65 -173
  293. package/src/components/PlDataTable/createPlDataTableSheet.ts +1 -1
  294. package/src/components/PlDataTable/index.ts +4 -2
  295. package/src/components/PlDataTable/labels.ts +4 -33
  296. package/src/components/PlDataTable/state-migration.ts +151 -22
  297. package/src/components/PlDataTable/typesV8.ts +188 -0
  298. package/src/components/PlDatasetSelector/build_dataset_options.ts +35 -60
  299. package/src/components/PlDatasetSelector/enrichment_discovery.ts +65 -61
  300. package/src/components/PlDatasetSelector/filter_discovery.test.ts +110 -72
  301. package/src/components/PlDatasetSelector/filter_discovery.ts +51 -31
  302. package/src/filters/converters/filterToQuery.test.ts +15 -8
  303. package/src/filters/converters/filterToQuery.ts +22 -9
  304. package/src/filters/converters/filterUiToExpressionImpl.test.ts +35 -36
  305. package/src/labels/derive_distinct_labels.ts +1 -1
  306. package/src/labels/derive_distinct_tooltips.test.ts +7 -4
  307. package/src/labels/derive_distinct_tooltips.ts +3 -3
  308. package/src/pframe_utils/axes.ts +2 -2
  309. package/src/pframe_utils/columns.ts +14 -23
  310. package/src/pframe_utils/index.ts +1 -1
  311. package/src/render/accessor.ts +35 -38
  312. package/src/render/api.ts +45 -61
  313. package/src/render/index.ts +2 -1
  314. package/src/render/internal.ts +43 -10
  315. package/src/render/util/axis_filtering.ts +0 -1
  316. package/src/render/util/column_collection.ts +17 -17
  317. package/src/render/util/pcolumn_data.ts +5 -9
  318. package/src/services/block_services.ts +1 -0
  319. package/src/services/get_services.ts +5 -2
  320. package/dist/columns/column_collection_builder.cjs +0 -241
  321. package/dist/columns/column_collection_builder.cjs.map +0 -1
  322. package/dist/columns/column_collection_builder.d.ts +0 -119
  323. package/dist/columns/column_collection_builder.d.ts.map +0 -1
  324. package/dist/columns/column_collection_builder.js +0 -241
  325. package/dist/columns/column_collection_builder.js.map +0 -1
  326. package/dist/columns/column_selector.cjs +0 -49
  327. package/dist/columns/column_selector.cjs.map +0 -1
  328. package/dist/columns/column_selector.d.ts +0 -33
  329. package/dist/columns/column_selector.d.ts.map +0 -1
  330. package/dist/columns/column_selector.js +0 -47
  331. package/dist/columns/column_selector.js.map +0 -1
  332. package/dist/columns/column_snapshot.cjs +0 -19
  333. package/dist/columns/column_snapshot.cjs.map +0 -1
  334. package/dist/columns/column_snapshot.d.ts +0 -39
  335. package/dist/columns/column_snapshot.d.ts.map +0 -1
  336. package/dist/columns/column_snapshot.js +0 -18
  337. package/dist/columns/column_snapshot.js.map +0 -1
  338. package/dist/columns/column_snapshot_provider.cjs +0 -137
  339. package/dist/columns/column_snapshot_provider.cjs.map +0 -1
  340. package/dist/columns/column_snapshot_provider.d.ts +0 -74
  341. package/dist/columns/column_snapshot_provider.d.ts.map +0 -1
  342. package/dist/columns/column_snapshot_provider.js +0 -133
  343. package/dist/columns/column_snapshot_provider.js.map +0 -1
  344. package/dist/columns/ctx_column_sources.cjs +0 -80
  345. package/dist/columns/ctx_column_sources.cjs.map +0 -1
  346. package/dist/columns/ctx_column_sources.d.ts +0 -30
  347. package/dist/columns/ctx_column_sources.d.ts.map +0 -1
  348. package/dist/columns/ctx_column_sources.js +0 -79
  349. package/dist/columns/ctx_column_sources.js.map +0 -1
  350. package/src/columns/column_collection_builder.test.ts +0 -484
  351. package/src/columns/column_collection_builder.ts +0 -485
  352. package/src/columns/column_selector.test.ts +0 -90
  353. package/src/columns/column_selector.ts +0 -100
  354. package/src/columns/column_snapshot.ts +0 -58
  355. package/src/columns/column_snapshot_provider.ts +0 -194
  356. package/src/columns/ctx_column_sources.ts +0 -99
@@ -1,53 +1,68 @@
1
1
  import type {
2
- AxisId,
3
- CanonicalizedJson,
2
+ ColumnUniversalId,
4
3
  FilterSpecNode,
5
- PColumn,
6
4
  PObjectId,
7
5
  PTableColumnId,
8
- PTableColumnIdAxis,
9
6
  PTableColumnIdColumn,
10
7
  PTableSorting,
11
- PColumnSpec,
12
8
  MultiColumnSelector,
13
- PFrameSpecDriver,
14
- DiscoveredPColumnId,
9
+ ColumnSelector,
15
10
  } from "@milaboratories/pl-model-common";
16
- import { canonicalizeJson, getAxisId, parseJson, uniqueBy } from "@milaboratories/pl-model-common";
17
- import { collectFilterSpecColumns, traverseFilterSpec } from "../../../filters/traverse";
18
- import type { RenderCtxBase, PColumnDataUniversal } from "../../../render";
19
- import { isEmpty } from "es-toolkit/compat";
20
- import type { PlDataTableFilters, PlDataTableFilterSpecLeaf, PlDataTableModel } from "../typesV7";
11
+ import {
12
+ canonicalizeAxisId,
13
+ dedupColumns,
14
+ extractPObjectId,
15
+ uniqueBy,
16
+ } from "@milaboratories/pl-model-common";
17
+ import { collectFilterSpecColumns } from "../../../filters/traverse";
18
+ import { createColumnResolver, type ColumnResolver } from "../columnResolver";
19
+ import type { RenderCtxBase } from "../../../render";
20
+ import type {
21
+ PlDataTableColumnsMeta,
22
+ PlDataTableFilters,
23
+ PlDataTableFilterSpecLeaf,
24
+ PlDataTableModel,
25
+ } from "../typesV8";
21
26
  import { upgradePlDataTableStateV2 } from "../state-migration";
22
27
  import type { PlDataTableStateV2 } from "../state-migration";
23
- import type { ColumnSelector, ColumnSnapshot, ColumnVariant, MatchingMode } from "../../../columns";
28
+ import type { MatchingMode } from "@milaboratories/pl-model-common";
29
+ import {
30
+ isLeafColumn,
31
+ hitQualifications,
32
+ collectLinkerColumns,
33
+ queriesQualifications,
34
+ type ColumnRecipe,
35
+ } from "../../../columns";
24
36
  import type { DeriveLabelsOptions } from "../../../labels/derive_distinct_labels";
25
37
  import {
26
38
  deriveAllLabels,
27
- deriveAllTooltips,
28
39
  evaluateRules,
40
+ getEffectiveVisibility,
41
+ getOrderPriority,
29
42
  isColumnHidden,
30
- isColumnOptional,
31
- withHidenAxesAnnotations,
32
- withLabelAnnotations,
33
- withTableVisualAnnotations,
34
- withInfoAnnotations,
35
- withDataStatusAnnotations,
43
+ buildDataStatusMap,
44
+ toRuleColumn,
36
45
  } from "./utils";
37
- import type { PrimaryEntry, SecondaryGroup } from "./createPTableDefV3";
38
46
  import { createPTableDefV3 } from "./createPTableDefV3";
39
47
  import {
40
- discoverLabelColumnVariants,
41
- discoverTableColumnSnaphots,
48
+ discoverLabelColumns,
49
+ discoverTableColumns,
42
50
  type DiscoverTableColumnOptions,
43
51
  } from "./discoverColumns";
44
- import { getField, isNil, isPlainObject, throwError, type Nil } from "@milaboratories/helpers";
45
- import { flow } from "es-toolkit";
52
+ import { isNil, isPlainObject, type Nil } from "@milaboratories/helpers";
53
+ import { uniq } from "es-toolkit";
46
54
 
47
- export type createPlDataTableOptionsV3 = {
55
+ export type createPlDataTableOptionsV3 = (
56
+ | {
57
+ columns: Nil | DiscoverTableColumnOptions;
58
+ }
59
+ | {
60
+ primaryColumns: ColumnRecipe[];
61
+ columns: Nil | ColumnRecipe[];
62
+ }
63
+ ) & {
48
64
  tableState?: PlDataTableStateV2;
49
65
 
50
- columns: Nil | DiscoverTableColumnOptions | TableColumnVariant[];
51
66
  filters?: PlDataTableFilters;
52
67
  sorting?: PTableSorting[];
53
68
  primaryJoinType?: "inner" | "full";
@@ -56,7 +71,7 @@ export type createPlDataTableOptionsV3 = {
56
71
  displayOptions?: ColumnsDisplayOptions;
57
72
  };
58
73
 
59
- /** Structured source config — selectors/anchors instead of raw ColumnSource. */
74
+ /** Structured source config — selectors/anchors instead of raw ColumnsSource. */
60
75
  export type ColumnsSelectorConfig = {
61
76
  include?: MultiColumnSelector | MultiColumnSelector[];
62
77
  exclude?: MultiColumnSelector | MultiColumnSelector[];
@@ -72,309 +87,285 @@ export type ColumnsDisplayOptions = {
72
87
  };
73
88
 
74
89
  export type ColumnOrderRule = {
75
- match: ColumnMatcher | ColumnSelector;
90
+ match: ColumnSelector;
76
91
  /** Higher number = further left in table */
77
92
  priority: number;
78
93
  };
79
94
 
80
95
  export type ColumnVisibilityRule = {
81
- match: ColumnMatcher | ColumnSelector;
96
+ match: ColumnSelector;
82
97
  visibility: "default" | "optional" | "hidden";
83
98
  };
84
99
 
85
- export type ColumnMatcher = (spec: PColumnSpec) => boolean;
86
-
87
100
  export function createPlDataTableV3<A, U>(
88
101
  ctx: RenderCtxBase<A, U>,
89
102
  options: createPlDataTableOptionsV3,
90
103
  ): PlDataTableModel | undefined {
91
- const pframeSpec = ctx.getService("pframeSpec");
92
104
  const state = upgradePlDataTableStateV2(options.tableState);
93
105
  const primaryJoinType = options.primaryJoinType ?? "full";
94
106
 
95
- const discovered = isPlainObject(options.columns)
96
- ? discoverTableColumnSnaphots(ctx, options.columns)
97
- : isNil(options.columns)
98
- ? options.columns
99
- : uniqueBy(
100
- [...options.columns, ...discoverLabelColumnVariants(ctx, options.columns)],
101
- (c) => c.column.id,
102
- );
103
- if (isNil(discovered) || discovered.length === 0) return undefined;
107
+ const resolved = resolveInputColumns(ctx, options);
108
+ if (resolved === undefined) return undefined;
109
+ const { primary, secondary } = resolved;
110
+ if (primary.length === 0) return undefined;
104
111
 
105
- const splited = splitDiscoveredColumns(discovered);
112
+ const { direct, linked } = splitByTopology(secondary);
106
113
 
114
+ const allColumns = [...primary, ...secondary];
107
115
  const derivedLabels = deriveAllLabels({
108
- columns: discovered
109
- .map((dc) => ({
110
- id: dc.column.id,
111
- spec: dc.column.spec,
112
- linkerPath: dc.path,
113
- qualifications: dc.qualifications,
114
- }))
115
- .filter((v) => !isColumnHidden(v.spec)),
116
+ // Skip hidden columns when deriving labels — they don't appear in the
117
+ // table, so they shouldn't influence label disambiguation (#1623).
118
+ columns: allColumns.filter((c) => !isColumnHidden(c.getSpec())).map(toLabelableColumn),
116
119
  deriveLabelsOptions: {
117
120
  includeNativeLabel: true,
118
121
  ...options.labelsOptions,
119
122
  },
120
123
  });
121
124
 
122
- const derivedTooltips = deriveAllTooltips({
123
- columns: discovered.map((dc) => ({
124
- id: dc.column.id,
125
- originalId: getField(dc, "originalId"),
126
- spec: dc.column.spec,
127
- linkerPath: dc.path,
128
- qualifications: dc.qualifications,
129
- })),
130
- });
131
-
132
- const annotated = annotateColumnGroups({
133
- pframeSpec,
134
- ...splited,
135
- derivedLabels,
136
- derivedTooltips,
137
- displayOptions: options.displayOptions,
138
- });
139
-
140
- const primarySnapshots = annotated.direct.filter((c) => c.isPrimary);
141
- const secondarySnapshots = annotated.direct.filter((c) => !c.isPrimary);
142
-
143
- if (primarySnapshots.length === 0) return undefined;
125
+ // Rule-based visibility/order maps (keyed by bare PObjectId). Computed once
126
+ // here: `computeHiddenColumns` needs visibility to decide the visible set,
127
+ // and `buildColumnsMeta` (below, once the visible set is known) reuses both.
128
+ const allColumnsForRules = [...primary, ...direct, ...linked, ...collectLinkerSnapshots(linked)];
129
+ const visibilityByColId = evaluateRules(
130
+ options.displayOptions?.visibility ?? [],
131
+ allColumnsForRules,
132
+ );
133
+ const orderByColId = evaluateRules(options.displayOptions?.ordering ?? [], allColumnsForRules);
144
134
 
145
- const columnIsAvailable = createColumnValidationById([
146
- ...annotated.direct.map((v) => v.column),
147
- ...annotated.linked.flatMap((lc) => [...(lc.path ?? []).map((s) => s.linker), lc.column]),
148
- ]);
135
+ const resolver = createColumnResolver(
136
+ [...primary, ...direct, ...linked.flatMap((lc) => [...collectLinkerColumns(lc), lc])],
137
+ { warn: ctx.logWarn.bind(ctx) },
138
+ );
149
139
 
150
- const remapedDefaultFilters = remapFilterColumnIds(options.filters, discovered);
140
+ const remapedDefaultFilters = remapFilterColumnIds(options.filters, resolver);
151
141
  const filters = filterFilters(
152
142
  concatFilters(
153
143
  state.pTableParams.filters,
154
144
  state.pTableParams.defaultFilters ?? remapedDefaultFilters,
155
145
  ),
156
- columnIsAvailable,
146
+ resolver,
157
147
  );
158
148
 
159
149
  const sorting = filterSorting(
160
- resolveSorting(state.pTableParams.sorting, remapSortingColumnIds(options.sorting, discovered)),
161
- columnIsAvailable,
150
+ resolveSorting(state.pTableParams.sorting, remapSortingColumnIds(options.sorting, resolver)),
151
+ resolver,
162
152
  );
163
153
 
164
- const primaryEntries: PrimaryEntry<undefined | PColumnDataUniversal>[] = primarySnapshots.map(
165
- (v) => ({ column: resolveSnapshot(v.column) }),
166
- );
167
- const secondaryGroups: SecondaryGroup<undefined | PColumnDataUniversal>[] = buildSecondaryGroups(
168
- secondarySnapshots,
169
- annotated.linked,
170
- );
171
154
  const fullDef = createPTableDefV3({
172
155
  primaryJoinType,
173
- primary: primaryEntries,
174
- secondary: secondaryGroups,
156
+ primary,
157
+ secondary: [...direct, ...linked],
175
158
  filters,
176
159
  sorting,
177
160
  });
178
161
 
179
162
  const fullHandle = ctx.createPTableV2(fullDef);
180
163
  // TODO: is workaround for dropdown suggestions.
181
- // Pframe have not equivalent data for columns relativly to Ptable
182
- const pframeHandle = ctx.createPFrame([
183
- ...annotated.direct.map((v) => resolveSnapshot(v.column)),
184
- ...annotated.linked.map((v) => resolveSnapshot(v.column)),
185
- ...collectLinkerSnapshots(annotated.linked).map(resolveSnapshot),
186
- ]);
164
+ // Pframe have not equivalent data for columns relativly to Ptable.
165
+ // PFrame is the physical column registry — one entry per bare PObjectId,
166
+ // so strip the rich recipe ids down to their physical leaf id and dedupe:
167
+ // multiple discovered variants of the same hit collapse to the same bare id.
168
+ const pframeHandle = ctx.createPFrame(
169
+ uniq([
170
+ ...primary.map((v) => extractPObjectId(v.id)),
171
+ ...direct.map((v) => extractPObjectId(v.id)),
172
+ ...linked.map((v) => extractPObjectId(v.id)),
173
+ ]),
174
+ );
187
175
 
188
176
  const hiddenSpecs = state.pTableParams.hiddenColIds;
189
- const hiddenColumnIds = computeHiddenColumns(
190
- [...annotated.direct, ...annotated.linked].map((v) => v.column),
177
+ const hiddenColumnIds = computeHiddenColumns({
178
+ columns: [...primary, ...direct, ...linked],
179
+ visibilityByColId,
191
180
  sorting,
192
181
  filters,
193
182
  hiddenSpecs,
194
- );
183
+ });
195
184
 
196
- const visible = buildVisibleColumns(annotated, hiddenColumnIds);
185
+ const visible = {
186
+ primary,
187
+ direct: direct.filter((c) => !hiddenColumnIds.has(c.id)),
188
+ linked: linked.filter((c) => !hiddenColumnIds.has(c.id)),
189
+ };
197
190
  const visibleDef = createPTableDefV3({
198
191
  primaryJoinType,
199
- primary: primaryEntries,
200
- secondary: buildSecondaryGroups(
201
- visible.direct.filter((c) => !c.isPrimary),
202
- visible.linked,
203
- ),
192
+ primary,
193
+ secondary: [...visible.direct, ...visible.linked],
204
194
  filters,
205
195
  sorting,
206
196
  });
207
197
  const visibleHandle = ctx.createPTableV2(visibleDef);
208
198
 
199
+ // Built here, where the visible set is known: per-column data status is
200
+ // computed for visible columns only (the probe is meaningful only for what
201
+ // the user sees), while label/visibility/order/axes cover all columns.
202
+ const columnsMeta = buildColumnsMeta({
203
+ fullColumns: [...primary, ...direct, ...linked],
204
+ visibleColumns: [...visible.primary, ...visible.direct, ...visible.linked],
205
+ primaryColumns: primary,
206
+ derivedLabels,
207
+ visibilityByColId,
208
+ orderByColId,
209
+ });
210
+
209
211
  return {
210
212
  sourceId: state.pTableParams.sourceId,
211
213
  fullTableHandle: fullHandle,
212
214
  fullPframeHandle: pframeHandle,
213
215
  visibleTableHandle: visibleHandle,
214
216
  defaultFilters: remapedDefaultFilters,
217
+ columnsMeta,
215
218
  } satisfies PlDataTableModel;
216
219
  }
217
220
 
218
- export type TableColumnVariant = (
219
- | ColumnVariant<PObjectId>
220
- | (ColumnVariant<DiscoveredPColumnId> & { readonly originalId: PObjectId })
221
- ) & {
222
- readonly isPrimary?: boolean;
223
- };
224
-
225
- type SplitDiscoveredColumns = {
226
- readonly direct: TableColumnVariant[];
227
- readonly linked: TableColumnVariant[];
221
+ type ResolvedColumns = {
222
+ readonly primary: ColumnRecipe[];
223
+ readonly secondary: ColumnRecipe[];
228
224
  };
229
225
 
230
- type AnnotatedColumnGroups = {
231
- readonly direct: TableColumnVariant[];
232
- readonly linked: TableColumnVariant[];
233
- };
234
-
235
- type VisibleColumns = {
236
- readonly direct: TableColumnVariant[];
237
- readonly linked: TableColumnVariant[];
238
- };
226
+ /** Normalize either option branch into a {primary, secondary} pair of recipes. */
227
+ function resolveInputColumns<A, U>(
228
+ ctx: RenderCtxBase<A, U>,
229
+ options: createPlDataTableOptionsV3,
230
+ ): ResolvedColumns | undefined {
231
+ if ("primaryColumns" in options) {
232
+ const primary = options.primaryColumns;
233
+ const secondary = options.columns ?? [];
234
+ const labels = discoverLabelColumns(ctx, primary, [...primary, ...secondary]);
235
+ // Exclude from secondary anything already present in primary: a label
236
+ // column the block hands in as primary can be re-discovered here as a
237
+ // label for that same axis, landing in the table twice with the same id.
238
+ const primaryIds = new Set(primary.map((c) => c.id));
239
+ return {
240
+ primary,
241
+ secondary: dedupColumns(
242
+ [...secondary, ...labels].filter((c) => !primaryIds.has(c.id)),
243
+ (c) => c.id,
244
+ (c) => c.getSpec(),
245
+ ),
246
+ };
247
+ }
248
+
249
+ if (isPlainObject(options.columns)) {
250
+ return discoverTableColumns(ctx, options.columns);
251
+ }
252
+
253
+ return undefined;
254
+ }
239
255
 
240
- /** Split discovered columns into direct (no linker path) and linked (with linker path). */
241
- function splitDiscoveredColumns(columns: TableColumnVariant[]): SplitDiscoveredColumns {
242
- const direct = columns.filter((dc) => (dc.path?.length ?? 0) === 0);
243
- const linked = columns.filter((dc) => (dc.path?.length ?? 0) > 0);
256
+ /** Split secondary recipes by query topology: leaves (no linker chain) vs joined. */
257
+ function splitByTopology(columns: ColumnRecipe[]): {
258
+ direct: ColumnRecipe[];
259
+ linked: ColumnRecipe[];
260
+ } {
261
+ const direct: ColumnRecipe[] = [];
262
+ const linked: ColumnRecipe[] = [];
263
+ for (const c of columns) {
264
+ if (isLeafColumn(c)) direct.push(c);
265
+ else linked.push(c);
266
+ }
244
267
  return { direct, linked };
245
268
  }
246
269
 
247
- /** All linker snapshots across the given linked columns, deduped by id. */
248
- function collectLinkerSnapshots(linked: TableColumnVariant[]): ColumnSnapshot<PObjectId>[] {
270
+ /** All linker recipes across the given linked columns, deduped by id. */
271
+ function collectLinkerSnapshots(linked: ColumnRecipe[]): ColumnRecipe[] {
249
272
  return uniqueBy(
250
- linked.flatMap((lc) => (lc.path ?? []).map((s) => s.linker)),
273
+ linked.flatMap((c) => collectLinkerColumns(c)),
251
274
  (c) => c.id,
252
275
  );
253
276
  }
254
277
 
255
- /**
256
- * Annotate all column groups with derived labels and display-rule annotations.
257
- * Evaluates `displayOptions` rules against all discovered columns (direct,
258
- * linked, labels, linkers) and writes the winning visibility/priority into
259
- * column annotations via `withTableVisualAnnotations`.
260
- */
261
- function annotateColumnGroups(params: {
262
- direct: TableColumnVariant[];
263
- linked: TableColumnVariant[];
264
- derivedLabels: Record<string, string>;
265
- derivedTooltips: Record<string, string>;
266
- displayOptions?: ColumnsDisplayOptions;
267
- pframeSpec: PFrameSpecDriver;
268
- }): AnnotatedColumnGroups {
269
- const { direct, linked, derivedLabels, derivedTooltips, displayOptions, pframeSpec } = params;
270
-
271
- const allColumnsForRules = [
272
- ...direct.map((v) => v.column),
273
- ...linked.map((v) => v.column),
274
- ...collectLinkerSnapshots(linked),
275
- ];
276
- const visibilityByColId = evaluateRules(
277
- displayOptions?.visibility ?? [],
278
- allColumnsForRules,
279
- pframeSpec,
280
- );
281
- const orderByColId = evaluateRules(
282
- displayOptions?.ordering ?? [],
283
- allColumnsForRules,
284
- pframeSpec,
285
- );
286
-
287
- const directAnnotated = liftToVariantColumns(
288
- direct,
289
- flow(
290
- (cols) => withDataStatusAnnotations(cols),
291
- (cols) => withLabelAnnotations(derivedLabels, cols),
292
- (cols) => withInfoAnnotations(derivedTooltips, cols),
293
- (cols) => withTableVisualAnnotations(visibilityByColId, orderByColId, cols),
294
- ),
295
- );
296
-
297
- const linkedAnnotated = liftToVariantColumns(
298
- linked,
299
- flow(
300
- (cols) => withDataStatusAnnotations(cols),
301
- (cols) => withHidenAxesAnnotations(cols),
302
- (cols) => withLabelAnnotations(derivedLabels, cols),
303
- (cols) => withInfoAnnotations(derivedTooltips, cols),
304
- (cols) => withTableVisualAnnotations(visibilityByColId, orderByColId, cols),
305
- ),
306
- ).map((lc) => ({ ...lc, path: annotateLinkerPath(derivedLabels, lc.path) }));
307
-
278
+ function toLabelableColumn(col: ColumnRecipe) {
308
279
  return {
309
- direct: directAnnotated,
310
- linked: linkedAnnotated,
280
+ id: col.id,
281
+ spec: col.getSpec(),
282
+ linkerPath: collectLinkerColumns(col).map((linker) => ({
283
+ linker: { spec: linker.getSpec() },
284
+ })),
285
+ qualifications: {
286
+ forHit: [...hitQualifications(col)],
287
+ forQueries: queriesQualifications(col),
288
+ },
311
289
  };
312
290
  }
313
291
 
314
- /** Lift a snapshot-array transform so it runs on the inner `column` of each variant. */
315
- function liftToVariantColumns<
316
- V extends { readonly column: ColumnSnapshot<PObjectId | DiscoveredPColumnId> },
317
- >(
318
- variants: V[],
319
- fn: (
320
- cols: ColumnSnapshot<PObjectId | DiscoveredPColumnId>[],
321
- ) => ColumnSnapshot<PObjectId | DiscoveredPColumnId>[],
322
- ): V[] {
323
- const cols = fn(variants.map((v) => v.column));
324
- if (cols.length !== variants.length)
325
- throw new Error(
326
- `liftToVariantColumns: fn must preserve array length (got ${cols.length}, expected ${variants.length})`,
327
- );
328
- return variants.map((v, i) => ({ ...v, column: cols[i] }));
329
- }
330
-
331
- function annotateLinkerPath(
332
- derivedLabels: Record<string, string>,
333
- path: TableColumnVariant["path"],
334
- ): TableColumnVariant["path"] {
335
- if (isNil(path) || path.length === 0) return path;
336
- const annotatedLinkers = withHidenAxesAnnotations(
337
- withLabelAnnotations(
338
- derivedLabels,
339
- path.map((s) => s.linker),
340
- ),
292
+ /**
293
+ * Compute display metadata as a sidecar keyed by each emitted column's
294
+ * `ColumnUniversalId` (and axis `AxisId`), instead of baking it into the specs
295
+ * via `withSpecs`. Spec overrides change a recipe's id, so the same physical
296
+ * column reached two ways would diverge into two ids and render twice; keeping
297
+ * meta out of the spec preserves identity and lets dedup collapse such cases.
298
+ * The UI overlays this onto the engine-emitted specs at render time.
299
+ */
300
+ function buildColumnsMeta(params: {
301
+ /** Every column in the table (primary + secondary) — drives `columns` and `axes`. */
302
+ fullColumns: ColumnRecipe[];
303
+ /** The visible subset — `status` is probed for these only. */
304
+ visibleColumns: ColumnRecipe[];
305
+ /** The primary join columns — their axes are the visible index; all other axes are hidden. */
306
+ primaryColumns: ColumnRecipe[];
307
+ derivedLabels: Record<string, string>;
308
+ visibilityByColId: Map<PObjectId, ColumnVisibilityRule>;
309
+ orderByColId: Map<PObjectId, ColumnOrderRule>;
310
+ }): PlDataTableColumnsMeta {
311
+ const { fullColumns, visibleColumns, primaryColumns, derivedLabels } = params;
312
+ const { visibilityByColId, orderByColId } = params;
313
+ // Status only for visible columns — the probe is meaningful only for what the
314
+ // user actually sees; non-visible columns get no `status`.
315
+ const visibleStatus = buildDataStatusMap(visibleColumns);
316
+
317
+ const columns = fullColumns.reduce<PlDataTableColumnsMeta["columns"]>((acc, c) => {
318
+ const rc = toRuleColumn(c);
319
+ acc[c.id] = {
320
+ label: derivedLabels[c.id],
321
+ visibility: getEffectiveVisibility(rc, visibilityByColId),
322
+ order: getOrderPriority(rc, orderByColId),
323
+ status: visibleStatus[c.id],
324
+ };
325
+ return acc;
326
+ }, {});
327
+
328
+ // Only primary columns declare the table's visible axes. Any axis introduced
329
+ // solely by a secondary column (a linker-bridge axis, or a distinct-domain
330
+ // copy) is flagged hidden — otherwise it renders as a second index axis.
331
+ const primaryAxisKeys = new Set(
332
+ primaryColumns.flatMap((c) => c.getSpec().axesSpec.map((a) => canonicalizeAxisId(a))),
341
333
  );
342
- return path.map((s, i) => ({ ...s, linker: annotatedLinkers[i] }));
343
- }
344
-
345
- /** Build an index of all valid column IDs (axes + columns) for filter/sorting validation. */
346
- function createColumnValidationById(
347
- fullColumns: { readonly id: PObjectId; readonly spec: PColumnSpec }[],
348
- ) {
349
- const axisIds = uniqueBy(
350
- fullColumns.flatMap((c) => c.spec.axesSpec.map(getAxisId)),
351
- (a) => canonicalizeJson<AxisId>(a),
334
+ const axes = fullColumns.reduce<PlDataTableColumnsMeta["axes"]>(
335
+ (acc, c) =>
336
+ c.getSpec().axesSpec.reduce((inner, ax) => {
337
+ const key = canonicalizeAxisId(ax);
338
+ if (inner[key] === undefined) inner[key] = { hidden: !primaryAxisKeys.has(key) };
339
+ return inner;
340
+ }, acc),
341
+ {},
352
342
  );
353
343
 
354
- const allIds: PTableColumnId[] = [
355
- ...axisIds.map((a) => ({ type: "axis", id: a }) satisfies PTableColumnIdAxis),
356
- ...fullColumns.map((c) => ({ type: "column", id: c.id }) satisfies PTableColumnIdColumn),
357
- ];
358
-
359
- const validIdSet = new Set(allIds.map((c) => canonicalizeJson<PTableColumnId>(c)));
360
-
361
- return (id: string): boolean => {
362
- return validIdSet.has(id as CanonicalizedJson<PTableColumnId>);
363
- };
344
+ return { columns, axes };
364
345
  }
365
346
 
366
- /** Drop filter leaves whose column references are not available in the table. */
347
+ /** Drop filter leaves whose column references cannot be resolved; rewrite the
348
+ * resolvable ones through the resolver. Prune empty and/or/not groups. */
367
349
  function filterFilters(
368
350
  filters: Nil | PlDataTableFilters,
369
- isValidColumnId: (id: string) => boolean,
351
+ resolver: ColumnResolver,
370
352
  ): Nil | PlDataTableFilters {
371
353
  if (isNil(filters)) return filters;
372
354
 
373
- const isLeafValid = (leaf: PlDataTableFilterSpecLeaf): boolean => {
374
- if (leaf.type === undefined) return true;
375
- if ("column" in leaf && !isValidColumnId(leaf.column)) return false;
376
- if ("rhs" in leaf && !isValidColumnId(leaf.rhs)) return false;
377
- return true;
355
+ const rewriteLeaf = (leaf: PlDataTableFilterSpecLeaf): Nil | PlDataTableFilterSpecLeaf => {
356
+ if (leaf.type === undefined) return leaf;
357
+ const result = { ...leaf };
358
+ if ("column" in result) {
359
+ const c = resolver(result.column);
360
+ if (isNil(c)) return undefined;
361
+ result.column = c;
362
+ }
363
+ if ("rhs" in result) {
364
+ const c = resolver(result.rhs);
365
+ if (isNil(c)) return undefined;
366
+ result.rhs = c;
367
+ }
368
+ return result;
378
369
  };
379
370
 
380
371
  const prune = (node: PlDataTableFilterNode): Nil | PlDataTableFilterNode => {
@@ -382,13 +373,14 @@ function filterFilters(
382
373
  const kept = node.filters
383
374
  .map((f) => prune(f))
384
375
  .filter((f): f is PlDataTableFilterNode => !isNil(f));
376
+ if (kept.length === 0) return undefined;
385
377
  return { type: node.type, filters: kept };
386
378
  }
387
379
  if (node.type === "not") {
388
380
  const inner = prune(node.filter);
389
381
  return isNil(inner) ? undefined : { type: "not", filter: inner };
390
382
  }
391
- return isLeafValid(node) ? node : undefined;
383
+ return rewriteLeaf(node);
392
384
  };
393
385
 
394
386
  return prune(filters) as Nil | PlDataTableFilters;
@@ -404,59 +396,41 @@ function concatFilters(
404
396
  return { ...a, filters: [...a.filters, ...b.filters] };
405
397
  }
406
398
 
407
- /** Pick user sorting from state if non-empty, otherwise fall back to options default. */
399
+ /** Pick user sorting from state if set, otherwise fall back to options default.
400
+ * null = user has not touched sorting → use default;
401
+ * [] = user has explicitly cleared sorting → no sorting (default ignored). */
408
402
  function resolveSorting(
409
- userSorting: PTableSorting[],
403
+ userSorting: Nil | PTableSorting[],
410
404
  defaultSorting: Nil | PTableSorting[],
411
405
  ): PTableSorting[] {
412
- return (isEmpty(userSorting) ? defaultSorting : userSorting) ?? [];
406
+ return (isNil(userSorting) ? defaultSorting : userSorting) ?? [];
413
407
  }
414
408
 
415
- /** Drop sorting entries whose column is not available in the table. */
416
- function filterSorting(
417
- sorting: PTableSorting[],
418
- isValidColumnId: (id: string) => boolean,
419
- ): PTableSorting[] {
420
- return sorting.filter((s) => isValidColumnId(canonicalizeJson<PTableColumnId>(s.column)));
421
- }
422
-
423
- function buildSecondaryGroups(
424
- direct: TableColumnVariant[],
425
- linked: TableColumnVariant[],
426
- ): SecondaryGroup<undefined | PColumnDataUniversal>[] {
427
- return [
428
- ...direct.map(
429
- (c): SecondaryGroup<undefined | PColumnDataUniversal> => ({
430
- entries: [{ column: resolveSnapshot(c.column), qualifications: c.qualifications?.forHit }],
431
- primaryQualifications: c.qualifications?.forQueries,
432
- }),
433
- ),
434
- ...linked.map(
435
- (lc): SecondaryGroup<undefined | PColumnDataUniversal> => ({
436
- entries: [
437
- {
438
- column: resolveSnapshot(lc.column),
439
- linkers: lc.path?.map((s) => resolveSnapshot(s.linker)),
440
- qualifications: lc.qualifications?.forHit,
441
- },
442
- ],
443
- primaryQualifications: lc.qualifications?.forQueries,
444
- }),
445
- ),
446
- ];
409
+ /** Rewrite sorting entries through the resolver; drop those that fail to resolve. */
410
+ function filterSorting(sorting: PTableSorting[], resolver: ColumnResolver): PTableSorting[] {
411
+ return sorting.flatMap((s) => {
412
+ const col = resolver(s.column);
413
+ return isNil(col) ? [] : [{ ...s, column: col }];
414
+ });
447
415
  }
448
416
 
449
- /** Determine which columns should be hidden based on state or optional-column defaults. */
450
- function computeHiddenColumns(
451
- columns: { readonly id: PObjectId; readonly spec: PColumnSpec }[],
452
- sorting: Nil | PTableSorting[],
453
- filters: Nil | PlDataTableFilters,
454
- hiddenSpecs: Nil | PTableColumnId[],
455
- ): Set<PObjectId> {
456
- const alwaysHidden = columns.filter((c) => isColumnHidden(c.spec)).map((c) => c.id);
417
+ /** Determine which columns should be hidden based on state or optional-column defaults.
418
+ * Keyed by the recipe's logical {@link ColumnUniversalId} (rich) — variants of
419
+ * the same physical column are independently visible/hidden. */
420
+ function computeHiddenColumns(params: {
421
+ columns: ColumnRecipe[];
422
+ visibilityByColId: Map<PObjectId, ColumnVisibilityRule>;
423
+ sorting: Nil | PTableSorting[];
424
+ filters: Nil | PlDataTableFilters;
425
+ hiddenSpecs: Nil | PTableColumnId[];
426
+ }): Set<ColumnUniversalId> {
427
+ const { columns, visibilityByColId, sorting, filters, hiddenSpecs } = params;
428
+ const visibilityOf = (c: ColumnRecipe) =>
429
+ getEffectiveVisibility(toRuleColumn(c), visibilityByColId);
430
+ const alwaysHidden = columns.filter((c) => visibilityOf(c) === "hidden").map((c) => c.id);
457
431
  const optionalHidden = !isNil(hiddenSpecs)
458
432
  ? hiddenSpecs.filter((s): s is PTableColumnIdColumn => s.type === "column").map((s) => s.id)
459
- : columns.filter((c) => isColumnOptional(c.spec)).map((c) => c.id);
433
+ : columns.filter((c) => visibilityOf(c) === "optional").map((c) => c.id);
460
434
  const initial = [...alwaysHidden, ...optionalHidden];
461
435
  const preserved = collectPreservedColumnIds(sorting, filters);
462
436
 
@@ -467,99 +441,87 @@ function computeHiddenColumns(
467
441
  function collectPreservedColumnIds(
468
442
  sorting: Nil | PTableSorting[],
469
443
  filters: Nil | PlDataTableFilters,
470
- ): Set<PObjectId> {
444
+ ): Set<ColumnUniversalId> {
471
445
  const sortedIds = (sorting ?? [])
472
446
  .map((s) => s.column)
473
447
  .filter((c): c is PTableColumnIdColumn => c.type === "column")
474
448
  .map((c) => c.id);
475
449
 
476
450
  const filterIds = !isNil(filters)
477
- ? collectFilterSpecColumns(filters).flatMap((c) => {
478
- const obj = parseJson(c);
479
- return obj.type === "column" ? [obj.id] : [];
480
- })
451
+ ? collectFilterSpecColumns(filters).flatMap((c) => (c.type === "column" ? [c.id] : []))
481
452
  : [];
482
453
 
483
- return new Set<PObjectId>([...sortedIds, ...filterIds]);
454
+ return new Set<ColumnUniversalId>([...sortedIds, ...filterIds]);
484
455
  }
485
456
 
486
- /** Filter annotated columns to only visible ones, re-matching label columns for the visible subset. */
487
- function buildVisibleColumns(
488
- annotated: AnnotatedColumnGroups,
489
- hiddenColumns: Set<PObjectId>,
490
- ): VisibleColumns {
491
- const direct = annotated.direct.filter((c) => !hiddenColumns.has(c.column.id));
492
- const linked = annotated.linked.filter((c) => !hiddenColumns.has(c.column.id));
493
- return { direct, linked };
494
- }
495
-
496
- /** Resolve a ColumnSnapshot to a PColumn with lazily-evaluated data. */
497
- function resolveSnapshot(
498
- snap: ColumnSnapshot<PObjectId>,
499
- ): PColumn<undefined | PColumnDataUniversal> {
500
- return { id: snap.id, spec: snap.spec, data: snap.data?.get() };
501
- }
502
-
503
- /** Remap column references in sorting entries. */
457
+ /** Remap column references in sorting entries through the resolver.
458
+ * Unresolved entries are dropped with a warning (best-effort contract). */
504
459
  function remapSortingColumnIds(
505
460
  sorting: Nil | PTableSorting[],
506
- columns: TableColumnVariant[],
461
+ resolver: ColumnResolver,
507
462
  ): Nil | PTableSorting[] {
508
463
  return sorting?.flatMap((s) => {
509
- if (s.column.type === "axis") return [s]; // Axis references are unaffected by column ID remapping
510
-
511
- const id = s.column.id;
512
- const column = columns.find((c) => (getField(c, "originalId") ?? c.column.id) === id);
513
- if (column === undefined) return [];
514
-
515
- return [
516
- {
517
- ...s,
518
- column: {
519
- type: "column" as const,
520
- id: column.column.id,
521
- },
522
- },
523
- ];
464
+ const col = resolver(s.column);
465
+ if (isNil(col)) {
466
+ console.warn(
467
+ `Sorting column ${JSON.stringify(s.column)} does not match any discovered column — dropped.`,
468
+ );
469
+ return [];
470
+ }
471
+ return [{ ...s, column: col }];
524
472
  });
525
473
  }
526
474
 
527
475
  type PlDataTableFilterNode = FilterSpecNode<PlDataTableFilterSpecLeaf>;
528
476
 
529
- /** Remap column references in a filter tree. */
477
+ /** Remap column references in a filter tree through the resolver.
478
+ * Unresolved leaves are dropped with a warning; empty groups are pruned. */
530
479
  function remapFilterColumnIds(
531
480
  filters: Nil | PlDataTableFilters,
532
- columns: TableColumnVariant[],
481
+ resolver: ColumnResolver,
533
482
  ): Nil | PlDataTableFilters {
534
483
  if (isNil(filters)) return filters;
535
484
 
536
- const map = (
537
- tableColumnId: CanonicalizedJson<PTableColumnId>,
538
- ): CanonicalizedJson<PTableColumnId> => {
539
- const parsed = parseJson<PTableColumnId>(tableColumnId);
540
- if (parsed.type === "axis") return tableColumnId; // Axis references are unaffected by column ID remapping
541
-
542
- const originalId = parsed.id;
543
- const column =
544
- columns.find((c) => (getField(c, "originalId") ?? c.column.id) === originalId) ??
545
- throwError(`Column ID "${parsed.id}" in filters does not match any discovered column`);
546
-
547
- return canonicalizeJson<PTableColumnId>({
548
- type: "column",
549
- id: column.column.id,
550
- });
485
+ const mapLeaf = (leaf: PlDataTableFilterSpecLeaf): Nil | PlDataTableFilterSpecLeaf => {
486
+ if (leaf.type === undefined) return leaf;
487
+ const result = { ...leaf };
488
+ if ("column" in result) {
489
+ const c = resolver(result.column);
490
+ if (isNil(c)) {
491
+ console.warn(
492
+ `Filter column ${JSON.stringify(result.column)} does not match any discovered column — dropped.`,
493
+ );
494
+ return undefined;
495
+ }
496
+ result.column = c;
497
+ }
498
+ if ("rhs" in result) {
499
+ const c = resolver(result.rhs);
500
+ if (isNil(c)) {
501
+ console.warn(
502
+ `Filter rhs ${JSON.stringify(result.rhs)} does not match any discovered column — dropped.`,
503
+ );
504
+ return undefined;
505
+ }
506
+ result.rhs = c;
507
+ }
508
+ return result;
551
509
  };
552
510
 
553
- return traverseFilterSpec(filters, {
554
- leaf: (leaf): PlDataTableFilterNode => {
555
- if (leaf.type === undefined) return leaf;
556
- const result = { ...leaf };
557
- if ("column" in result) result.column = map(result.column);
558
- if ("rhs" in result) result.rhs = map(result.rhs);
559
- return result;
560
- },
561
- and: (results): PlDataTableFilterNode => ({ type: "and", filters: results }),
562
- or: (results): PlDataTableFilterNode => ({ type: "or", filters: results }),
563
- not: (result): PlDataTableFilterNode => ({ type: "not", filter: result }),
564
- }) as PlDataTableFilters;
511
+ const prune = (node: PlDataTableFilterNode): Nil | PlDataTableFilterNode => {
512
+ if (node.type === "and" || node.type === "or") {
513
+ const kept = node.filters
514
+ .map((f) => prune(f))
515
+ .filter((f): f is PlDataTableFilterNode => !isNil(f));
516
+ if (kept.length === 0) return undefined;
517
+ return { type: node.type, filters: kept };
518
+ }
519
+ if (node.type === "not") {
520
+ const inner = prune(node.filter);
521
+ return isNil(inner) ? undefined : { type: "not", filter: inner };
522
+ }
523
+ return mapLeaf(node);
524
+ };
525
+
526
+ return prune(filters) as Nil | PlDataTableFilters;
565
527
  }