@perspective-dev/viewer 4.0.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 (394) hide show
  1. package/LICENSE.md +193 -0
  2. package/README.md +4 -0
  3. package/dist/cdn/perspective-viewer.js +3 -0
  4. package/dist/cdn/perspective-viewer.js.map +7 -0
  5. package/dist/css/dracula.css +1 -0
  6. package/dist/css/gruvbox-dark.css +1 -0
  7. package/dist/css/gruvbox.css +1 -0
  8. package/dist/css/icons.css +1 -0
  9. package/dist/css/intl/de.css +1 -0
  10. package/dist/css/intl/es.css +1 -0
  11. package/dist/css/intl/fr.css +1 -0
  12. package/dist/css/intl/ja.css +1 -0
  13. package/dist/css/intl/pt.css +1 -0
  14. package/dist/css/intl/zh.css +1 -0
  15. package/dist/css/intl.css +1 -0
  16. package/dist/css/monokai.css +1 -0
  17. package/dist/css/pro-dark.css +1 -0
  18. package/dist/css/pro.css +1 -0
  19. package/dist/css/solarized-dark.css +1 -0
  20. package/dist/css/solarized.css +1 -0
  21. package/dist/css/themes.css +1 -0
  22. package/dist/css/vaporwave.css +1 -0
  23. package/dist/css/variables.css +0 -0
  24. package/dist/esm/bootstrap.d.ts +1 -0
  25. package/dist/esm/extensions.d.ts +70 -0
  26. package/dist/esm/perspective-viewer.d.ts +39 -0
  27. package/dist/esm/perspective-viewer.inline.js +3 -0
  28. package/dist/esm/perspective-viewer.inline.js.map +7 -0
  29. package/dist/esm/perspective-viewer.js +3 -0
  30. package/dist/esm/perspective-viewer.js.map +7 -0
  31. package/dist/esm/plugin.d.ts +195 -0
  32. package/dist/esm/ts-rs/Aggregate.d.ts +1 -0
  33. package/dist/esm/ts-rs/ColumnConfigValues.d.ts +31 -0
  34. package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +1 -0
  35. package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +15 -0
  36. package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +18 -0
  37. package/dist/esm/ts-rs/DatetimeColorMode.d.ts +1 -0
  38. package/dist/esm/ts-rs/DatetimeFormatType.d.ts +6 -0
  39. package/dist/esm/ts-rs/Expressions.d.ts +3 -0
  40. package/dist/esm/ts-rs/Filter.d.ts +2 -0
  41. package/dist/esm/ts-rs/FilterReducer.d.ts +1 -0
  42. package/dist/esm/ts-rs/FilterTerm.d.ts +2 -0
  43. package/dist/esm/ts-rs/FormatMode.d.ts +1 -0
  44. package/dist/esm/ts-rs/FormatUnit.d.ts +1 -0
  45. package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +1 -0
  46. package/dist/esm/ts-rs/NumberForegroundMode.d.ts +1 -0
  47. package/dist/esm/ts-rs/OptionalUpdate.d.ts +1 -0
  48. package/dist/esm/ts-rs/PluginConfig.d.ts +2 -0
  49. package/dist/esm/ts-rs/RoundingMode.d.ts +1 -0
  50. package/dist/esm/ts-rs/RoundingPriority.d.ts +1 -0
  51. package/dist/esm/ts-rs/Scalar.d.ts +5 -0
  52. package/dist/esm/ts-rs/SignDisplay.d.ts +1 -0
  53. package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +1 -0
  54. package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +6 -0
  55. package/dist/esm/ts-rs/Sort.d.ts +2 -0
  56. package/dist/esm/ts-rs/SortDir.d.ts +1 -0
  57. package/dist/esm/ts-rs/StringColorMode.d.ts +1 -0
  58. package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +1 -0
  59. package/dist/esm/ts-rs/UseGrouping.d.ts +1 -0
  60. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +102 -0
  61. package/dist/esm/ts-rs/serde_json/JsonValue.d.ts +3 -0
  62. package/dist/wasm/perspective-viewer.d.ts +1291 -0
  63. package/dist/wasm/perspective-viewer.js +3883 -0
  64. package/dist/wasm/perspective-viewer.wasm +0 -0
  65. package/dist/wasm/perspective-viewer.wasm.d.ts +142 -0
  66. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline0.js +1 -0
  67. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline1.js +1 -0
  68. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline2.js +1 -0
  69. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline3.js +44 -0
  70. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline4.js +1 -0
  71. package/package.json +55 -0
  72. package/src/less/aggregate-selector.less +72 -0
  73. package/src/less/column-dropdown.less +95 -0
  74. package/src/less/column-selector.less +551 -0
  75. package/src/less/column-settings-panel.less +255 -0
  76. package/src/less/column-style.less +319 -0
  77. package/src/less/column-symbol-attributes.less +73 -0
  78. package/src/less/config-selector.less +363 -0
  79. package/src/less/containers/dropdown-menu.less +94 -0
  80. package/src/less/containers/pairs-list.less +46 -0
  81. package/src/less/containers/radio-list.less +29 -0
  82. package/src/less/containers/scroll-panel.less +27 -0
  83. package/src/less/containers/split-panel.less +80 -0
  84. package/src/less/containers/tabs.less +90 -0
  85. package/src/less/dom/checkbox.less +100 -0
  86. package/src/less/dom/scrollbar.less +35 -0
  87. package/src/less/dom/select.less +63 -0
  88. package/src/less/empty-column.less +72 -0
  89. package/src/less/expression-editor.less +152 -0
  90. package/src/less/filter-dropdown.less +53 -0
  91. package/src/less/filter-item.less +126 -0
  92. package/src/less/form/code-editor.less +137 -0
  93. package/src/less/form/debug.less +88 -0
  94. package/src/less/function-dropdown.less +45 -0
  95. package/src/less/plugin-selector.less +173 -0
  96. package/src/less/render-warning.less +81 -0
  97. package/src/less/status-bar.less +551 -0
  98. package/src/less/type-icon.less +68 -0
  99. package/src/less/viewer.less +368 -0
  100. package/src/rust/components/column_dropdown.rs +162 -0
  101. package/src/rust/components/column_selector/active_column.rs +462 -0
  102. package/src/rust/components/column_selector/add_expression_button.rs +59 -0
  103. package/src/rust/components/column_selector/aggregate_selector.rs +186 -0
  104. package/src/rust/components/column_selector/config_selector.rs +674 -0
  105. package/src/rust/components/column_selector/empty_column.rs +134 -0
  106. package/src/rust/components/column_selector/expression_toolbar.rs +45 -0
  107. package/src/rust/components/column_selector/filter_column.rs +530 -0
  108. package/src/rust/components/column_selector/inactive_column.rs +221 -0
  109. package/src/rust/components/column_selector/invalid_column.rs +37 -0
  110. package/src/rust/components/column_selector/pivot_column.rs +93 -0
  111. package/src/rust/components/column_selector/sort_column.rs +135 -0
  112. package/src/rust/components/column_selector.rs +426 -0
  113. package/src/rust/components/column_settings_sidebar/attributes_tab.rs +34 -0
  114. package/src/rust/components/column_settings_sidebar/mod.rs +17 -0
  115. package/src/rust/components/column_settings_sidebar/save_settings.rs +68 -0
  116. package/src/rust/components/column_settings_sidebar/sidebar.rs +396 -0
  117. package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +177 -0
  118. package/src/rust/components/column_settings_sidebar/style_tab/stub.rs +34 -0
  119. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +101 -0
  120. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_config.rs +24 -0
  121. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +185 -0
  122. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +55 -0
  123. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +131 -0
  124. package/src/rust/components/column_settings_sidebar/style_tab.rs +231 -0
  125. package/src/rust/components/containers/dragdrop_list.rs +325 -0
  126. package/src/rust/components/containers/dropdown_menu.rs +104 -0
  127. package/src/rust/components/containers/kvpair.rs +47 -0
  128. package/src/rust/components/containers/mod.rs +28 -0
  129. package/src/rust/components/containers/scroll_panel.rs +311 -0
  130. package/src/rust/components/containers/scroll_panel_item.rs +111 -0
  131. package/src/rust/components/containers/select.rs +269 -0
  132. package/src/rust/components/containers/sidebar.rs +89 -0
  133. package/src/rust/components/containers/split_panel.rs +483 -0
  134. package/src/rust/components/containers/tab_list.rs +104 -0
  135. package/src/rust/components/containers/tests/mod.rs +11 -0
  136. package/src/rust/components/containers/tests/split_panel.rs +91 -0
  137. package/src/rust/components/containers/trap_door_panel.rs +50 -0
  138. package/src/rust/components/copy_dropdown.rs +136 -0
  139. package/src/rust/components/datetime_column_style/custom.rs +222 -0
  140. package/src/rust/components/datetime_column_style/simple.rs +122 -0
  141. package/src/rust/components/datetime_column_style.rs +284 -0
  142. package/src/rust/components/editable_header.rs +183 -0
  143. package/src/rust/components/empty_row.rs +169 -0
  144. package/src/rust/components/error_message.rs +56 -0
  145. package/src/rust/components/export_dropdown.rs +153 -0
  146. package/src/rust/components/expression_editor.rs +153 -0
  147. package/src/rust/components/filter_dropdown.rs +144 -0
  148. package/src/rust/components/font_loader.rs +254 -0
  149. package/src/rust/components/form/code_editor.rs +286 -0
  150. package/src/rust/components/form/color_range_selector.rs +115 -0
  151. package/src/rust/components/form/color_selector.rs +54 -0
  152. package/src/rust/components/form/debug.rs +253 -0
  153. package/src/rust/components/form/highlight.rs +50 -0
  154. package/src/rust/components/form/mod.rs +29 -0
  155. package/src/rust/components/form/number_field.rs +72 -0
  156. package/src/rust/components/form/number_input.rs +45 -0
  157. package/src/rust/components/form/number_range_field.rs +77 -0
  158. package/src/rust/components/form/optional_field.rs +53 -0
  159. package/src/rust/components/form/select_field.rs +104 -0
  160. package/src/rust/components/function_dropdown.rs +151 -0
  161. package/src/rust/components/mod.rs +45 -0
  162. package/src/rust/components/modal.rs +171 -0
  163. package/src/rust/components/number_column_style.rs +522 -0
  164. package/src/rust/components/plugin_selector.rs +196 -0
  165. package/src/rust/components/render_warning.rs +178 -0
  166. package/src/rust/components/status_bar.rs +315 -0
  167. package/src/rust/components/status_bar_counter.rs +229 -0
  168. package/src/rust/components/status_indicator.rs +164 -0
  169. package/src/rust/components/string_column_style.rs +186 -0
  170. package/src/rust/components/style/local_style.rs +35 -0
  171. package/src/rust/components/style/mod.rs +52 -0
  172. package/src/rust/components/style/style_cache.rs +132 -0
  173. package/src/rust/components/style/style_provider.rs +65 -0
  174. package/src/rust/components/style_controls/number_string_format/digits_section.rs +140 -0
  175. package/src/rust/components/style_controls/number_string_format/misc_section.rs +56 -0
  176. package/src/rust/components/style_controls/number_string_format/style_section.rs +69 -0
  177. package/src/rust/components/style_controls/number_string_format/types.rs +31 -0
  178. package/src/rust/components/style_controls/number_string_format.rs +259 -0
  179. package/src/rust/components/style_controls.rs +15 -0
  180. package/src/rust/components/type_icon.rs +53 -0
  181. package/src/rust/components/viewer.rs +668 -0
  182. package/src/rust/config/columns_config.rs +132 -0
  183. package/src/rust/config/datetime_column_style/color_mode.rs +62 -0
  184. package/src/rust/config/datetime_column_style/custom.rs +121 -0
  185. package/src/rust/config/datetime_column_style/custom_format.rs +90 -0
  186. package/src/rust/config/datetime_column_style/simple.rs +55 -0
  187. package/src/rust/config/datetime_column_style/simple_format.rs +86 -0
  188. package/src/rust/config/datetime_column_style.rs +104 -0
  189. package/src/rust/config/mod.rs +30 -0
  190. package/src/rust/config/number_column_style.rs +138 -0
  191. package/src/rust/config/number_string_format/enums.rs +298 -0
  192. package/src/rust/config/number_string_format.rs +269 -0
  193. package/src/rust/config/string_column_style.rs +140 -0
  194. package/src/rust/config/view_config.rs +24 -0
  195. package/src/rust/config/viewer_config.rs +337 -0
  196. package/src/rust/custom_elements/column_dropdown.rs +123 -0
  197. package/src/rust/custom_elements/copy_dropdown.rs +112 -0
  198. package/src/rust/custom_elements/debug_plugin.rs +114 -0
  199. package/src/rust/custom_elements/export_dropdown.rs +112 -0
  200. package/src/rust/custom_elements/filter_dropdown.rs +179 -0
  201. package/src/rust/custom_elements/function_dropdown.rs +115 -0
  202. package/src/rust/custom_elements/mod.rs +24 -0
  203. package/src/rust/custom_elements/modal.rs +395 -0
  204. package/src/rust/custom_elements/viewer.rs +880 -0
  205. package/src/rust/custom_events.rs +214 -0
  206. package/src/rust/dragdrop.rs +362 -0
  207. package/src/rust/exprtk/cursor.rs +81 -0
  208. package/src/rust/exprtk/mod.rs +17 -0
  209. package/src/rust/exprtk/tokenize/comment.rs +21 -0
  210. package/src/rust/exprtk/tokenize/number.rs +44 -0
  211. package/src/rust/exprtk/tokenize/string.rs +98 -0
  212. package/src/rust/exprtk/tokenize/symbol.rs +26 -0
  213. package/src/rust/exprtk/tokenize.rs +190 -0
  214. package/src/rust/js/clipboard.rs +77 -0
  215. package/src/rust/js/clipboard_item.rs +21 -0
  216. package/src/rust/js/intersection_observer.rs +32 -0
  217. package/src/rust/js/mimetype.rs +42 -0
  218. package/src/rust/js/mod.rs +29 -0
  219. package/src/rust/js/plugin.rs +167 -0
  220. package/src/rust/js/resize_observer.rs +37 -0
  221. package/src/rust/js/testing.rs +149 -0
  222. package/src/rust/lib.rs +116 -0
  223. package/src/rust/model/columns_iter_set.rs +340 -0
  224. package/src/rust/model/copy_export.rs +157 -0
  225. package/src/rust/model/create_col.rs +59 -0
  226. package/src/rust/model/edit_expression.rs +95 -0
  227. package/src/rust/model/export_app.rs +58 -0
  228. package/src/rust/model/export_method.rs +151 -0
  229. package/src/rust/model/get_viewer_config.rs +85 -0
  230. package/src/rust/model/intersection_observer.rs +81 -0
  231. package/src/rust/model/is_invalid_drop.rs +36 -0
  232. package/src/rust/model/mod.rs +93 -0
  233. package/src/rust/model/plugin_column_styles.rs +106 -0
  234. package/src/rust/model/resize_observer.rs +98 -0
  235. package/src/rust/model/restore_and_render.rs +113 -0
  236. package/src/rust/model/structural.rs +73 -0
  237. package/src/rust/model/update_and_render.rs +74 -0
  238. package/src/rust/presentation.rs +370 -0
  239. package/src/rust/renderer/activate.rs +49 -0
  240. package/src/rust/renderer/limits.rs +200 -0
  241. package/src/rust/renderer/plugin_store.rs +45 -0
  242. package/src/rust/renderer/registry.rs +135 -0
  243. package/src/rust/renderer/render_timer.rs +185 -0
  244. package/src/rust/renderer.rs +463 -0
  245. package/src/rust/session/column_defaults_update.rs +141 -0
  246. package/src/rust/session/drag_drop_update.rs +179 -0
  247. package/src/rust/session/metadata.rs +308 -0
  248. package/src/rust/session/replace_expression_update.rs +131 -0
  249. package/src/rust/session/view_subscription.rs +189 -0
  250. package/src/rust/session.rs +794 -0
  251. package/src/rust/utils/browser/blob.rs +49 -0
  252. package/src/rust/utils/browser/download.rs +26 -0
  253. package/src/rust/utils/browser/mod.rs +24 -0
  254. package/src/rust/utils/browser/request_animation_frame.rs +76 -0
  255. package/src/rust/utils/browser/selection.rs +79 -0
  256. package/src/rust/utils/browser/tests/debounce.rs +114 -0
  257. package/src/rust/utils/browser/tests/mod.rs +13 -0
  258. package/src/rust/utils/custom_element.rs +85 -0
  259. package/src/rust/utils/datetime.rs +49 -0
  260. package/src/rust/utils/debounce.rs +54 -0
  261. package/src/rust/utils/hooks/mod.rs +15 -0
  262. package/src/rust/utils/hooks/use_async_callback.rs +53 -0
  263. package/src/rust/utils/mod.rs +114 -0
  264. package/src/rust/utils/number_format.rs +48 -0
  265. package/src/rust/utils/pubsub.rs +222 -0
  266. package/src/rust/utils/scope.rs +54 -0
  267. package/src/rust/utils/tee.rs +88 -0
  268. package/src/rust/utils/tests/mod.rs +14 -0
  269. package/src/rust/utils/tests/pubsub.rs +95 -0
  270. package/src/rust/utils/tests/request_animation_frame.rs +42 -0
  271. package/src/rust/utils/wasm_abi.rs +61 -0
  272. package/src/rust/utils/weak_scope.rs +39 -0
  273. package/src/svg/align-scroll-icon.svg +7 -0
  274. package/src/svg/bg-pattern.png +0 -0
  275. package/src/svg/boolean-type.svg +3 -0
  276. package/src/svg/checkbox-checked-icon.svg +7 -0
  277. package/src/svg/checkbox-hover.svg +4 -0
  278. package/src/svg/checkbox-off.svg +4 -0
  279. package/src/svg/checkbox-on.svg +4 -0
  280. package/src/svg/checkbox-unchecked-icon.svg +3 -0
  281. package/src/svg/close-icon.svg +6 -0
  282. package/src/svg/column-settings-icon.svg +6 -0
  283. package/src/svg/datagrid-select-column.svg +15 -0
  284. package/src/svg/datagrid-select-region.svg +15 -0
  285. package/src/svg/datagrid-select-row.svg +13 -0
  286. package/src/svg/datagrid.svg +13 -0
  287. package/src/svg/date-type.svg +23 -0
  288. package/src/svg/downloading.gif +0 -0
  289. package/src/svg/drag-handle.svg +10 -0
  290. package/src/svg/drawer-bg-pattern-hidpi.png +0 -0
  291. package/src/svg/drawer-tab-hover.svg +8 -0
  292. package/src/svg/drawer-tab-invert-hover.svg +9 -0
  293. package/src/svg/drawer-tab-invert.svg +8 -0
  294. package/src/svg/drawer-tab.svg +7 -0
  295. package/src/svg/dropdown-selector-light.svg +3 -0
  296. package/src/svg/dropdown-selector.svg +3 -0
  297. package/src/svg/duplicate-icon.svg +4 -0
  298. package/src/svg/editable-icon.svg +5 -0
  299. package/src/svg/export-icon.svg +4 -0
  300. package/src/svg/expression.svg +10 -0
  301. package/src/svg/free-scroll-icon.svg +5 -0
  302. package/src/svg/inactive-mouseover.svg +4 -0
  303. package/src/svg/mega-menu-icons-candlestick.svg +38 -0
  304. package/src/svg/mega-menu-icons-datagrid.svg +38 -0
  305. package/src/svg/mega-menu-icons-heatmap.svg +60 -0
  306. package/src/svg/mega-menu-icons-map-scatter.svg +43 -0
  307. package/src/svg/mega-menu-icons-ohlc.svg +40 -0
  308. package/src/svg/mega-menu-icons-sunburst.svg +39 -0
  309. package/src/svg/mega-menu-icons-treemap.svg +44 -0
  310. package/src/svg/mega-menu-icons-x-bar.svg +36 -0
  311. package/src/svg/mega-menu-icons-x-y-line.svg +38 -0
  312. package/src/svg/mega-menu-icons-x-y-scatter.svg +72 -0
  313. package/src/svg/mega-menu-icons-y-area.svg +73 -0
  314. package/src/svg/mega-menu-icons-y-bar.svg +36 -0
  315. package/src/svg/mega-menu-icons-y-line.svg +36 -0
  316. package/src/svg/mega-menu-icons-y-scatter.svg +72 -0
  317. package/src/svg/number-type.svg +4 -0
  318. package/src/svg/radio-hover.svg +4 -0
  319. package/src/svg/radio-off.svg +3 -0
  320. package/src/svg/radio-on.svg +4 -0
  321. package/src/svg/read-only-icon.svg +6 -0
  322. package/src/svg/revert-icon.svg +4 -0
  323. package/src/svg/sort-abs-asc-icon.svg +3 -0
  324. package/src/svg/sort-abs-col-asc-icon.svg +3 -0
  325. package/src/svg/sort-abs-col-desc-icon.svg +3 -0
  326. package/src/svg/sort-abs-desc-icon.svg +3 -0
  327. package/src/svg/sort-asc-icon.svg +4 -0
  328. package/src/svg/sort-col-asc-icon.svg +4 -0
  329. package/src/svg/sort-col-desc-icon.svg +4 -0
  330. package/src/svg/sort-desc-icon.svg +4 -0
  331. package/src/svg/sort-none-icon.svg +3 -0
  332. package/src/svg/status_error.svg +70 -0
  333. package/src/svg/status_ok.svg +26 -0
  334. package/src/svg/string-type.svg +8 -0
  335. package/src/svg/theme-icon.svg +5 -0
  336. package/src/svg/updating.gif +0 -0
  337. package/src/themes/dracula.less +101 -0
  338. package/src/themes/gruvbox-dark.less +116 -0
  339. package/src/themes/gruvbox.less +152 -0
  340. package/src/themes/icons.less +130 -0
  341. package/src/themes/intl/de.less +102 -0
  342. package/src/themes/intl/es.less +102 -0
  343. package/src/themes/intl/fr.less +102 -0
  344. package/src/themes/intl/ja.less +102 -0
  345. package/src/themes/intl/pt.less +102 -0
  346. package/src/themes/intl/zh.less +102 -0
  347. package/src/themes/intl.less +102 -0
  348. package/src/themes/monokai.less +107 -0
  349. package/src/themes/pro-dark.less +147 -0
  350. package/src/themes/pro.less +186 -0
  351. package/src/themes/solarized-dark.less +78 -0
  352. package/src/themes/solarized.less +102 -0
  353. package/src/themes/themes.less +21 -0
  354. package/src/themes/vaporwave.less +145 -0
  355. package/src/themes/variables.less +24 -0
  356. package/src/ts/bootstrap.ts +26 -0
  357. package/src/ts/extensions.ts +124 -0
  358. package/src/ts/perspective-viewer.cdn.ts +19 -0
  359. package/src/ts/perspective-viewer.inline.ts +23 -0
  360. package/src/ts/perspective-viewer.ts +59 -0
  361. package/src/ts/plugin.ts +279 -0
  362. package/src/ts/ts-rs/Aggregate.ts +3 -0
  363. package/src/ts/ts-rs/ColumnConfigValues.ts +14 -0
  364. package/src/ts/ts-rs/CustomDatetimeFormat.ts +3 -0
  365. package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +5 -0
  366. package/src/ts/ts-rs/CustomNumberFormatConfig.ts +8 -0
  367. package/src/ts/ts-rs/DatetimeColorMode.ts +3 -0
  368. package/src/ts/ts-rs/DatetimeFormatType.ts +8 -0
  369. package/src/ts/ts-rs/Expressions.ts +3 -0
  370. package/src/ts/ts-rs/Filter.ts +4 -0
  371. package/src/ts/ts-rs/FilterReducer.ts +3 -0
  372. package/src/ts/ts-rs/FilterTerm.ts +4 -0
  373. package/src/ts/ts-rs/FormatMode.ts +3 -0
  374. package/src/ts/ts-rs/FormatUnit.ts +3 -0
  375. package/src/ts/ts-rs/NumberBackgroundMode.ts +3 -0
  376. package/src/ts/ts-rs/NumberForegroundMode.ts +3 -0
  377. package/src/ts/ts-rs/OnUpdateData.ts +8 -0
  378. package/src/ts/ts-rs/OptionalUpdate.ts +3 -0
  379. package/src/ts/ts-rs/PluginConfig.ts +4 -0
  380. package/src/ts/ts-rs/RoundingMode.ts +3 -0
  381. package/src/ts/ts-rs/RoundingPriority.ts +3 -0
  382. package/src/ts/ts-rs/Scalar.ts +7 -0
  383. package/src/ts/ts-rs/SignDisplay.ts +3 -0
  384. package/src/ts/ts-rs/SimpleDatetimeFormat.ts +3 -0
  385. package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +4 -0
  386. package/src/ts/ts-rs/Sort.ts +4 -0
  387. package/src/ts/ts-rs/SortDir.ts +3 -0
  388. package/src/ts/ts-rs/StringColorMode.ts +3 -0
  389. package/src/ts/ts-rs/TrailingZeroDisplay.ts +3 -0
  390. package/src/ts/ts-rs/UseGrouping.ts +3 -0
  391. package/src/ts/ts-rs/ViewOnUpdateResp.ts +3 -0
  392. package/src/ts/ts-rs/ViewerConfigUpdate.ts +90 -0
  393. package/src/ts/ts-rs/serde_json/JsonValue.ts +3 -0
  394. package/tsconfig.json +15 -0
@@ -0,0 +1,463 @@
1
+ // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
+ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
+ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
+ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
+ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
+ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
+ // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
+ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
+ // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
+ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
+
13
+ //! `Renderer` owns the JavaScript Custom Element plugin, as well as
14
+ //! associated state such as column restrictions and `plugin_config`
15
+ //! (de-)serialization.
16
+ //!
17
+ //! `Renderer` wraps a smart pointer and is meant to be shared among many
18
+ //! references throughout the application.
19
+
20
+ mod activate;
21
+ mod limits;
22
+ mod plugin_store;
23
+ mod registry;
24
+ mod render_timer;
25
+
26
+ use std::cell::{Ref, RefCell};
27
+ use std::collections::HashMap;
28
+ use std::future::Future;
29
+ use std::ops::Deref;
30
+ use std::pin::Pin;
31
+ use std::rc::Rc;
32
+
33
+ use futures::future::{join_all, select_all};
34
+ use perspective_client::ViewWindow;
35
+ use perspective_js::json;
36
+ use perspective_js::utils::ApiResult;
37
+ use wasm_bindgen::prelude::*;
38
+ use web_sys::*;
39
+ use yew::html::ImplicitClone;
40
+
41
+ use self::activate::*;
42
+ use self::limits::*;
43
+ use self::plugin_store::*;
44
+ pub use self::registry::*;
45
+ use self::render_timer::*;
46
+ use crate::config::*;
47
+ use crate::js::plugin::*;
48
+ use crate::presentation::ColumnConfigMap;
49
+ use crate::session::*;
50
+ use crate::utils::*;
51
+
52
+ #[derive(Clone)]
53
+ pub struct Renderer(Rc<RendererData>);
54
+
55
+ /// Immutable state
56
+ pub struct RendererData {
57
+ plugin_data: RefCell<RendererMutData>,
58
+ draw_lock: DebounceMutex,
59
+ pub plugin_changed: PubSub<JsPerspectiveViewerPlugin>,
60
+ pub render_limits_changed: PubSub<(bool, RenderLimits)>,
61
+ pub style_changed: PubSub<()>,
62
+ pub reset_changed: PubSub<()>,
63
+ }
64
+
65
+ /// Mutable state
66
+ pub struct RendererMutData {
67
+ viewer_elem: HtmlElement,
68
+ metadata: ViewConfigRequirements,
69
+ plugin_store: PluginStore,
70
+ plugins_idx: Option<usize>,
71
+ timer: MovingWindowRenderTimer,
72
+ selection: Option<ViewWindow>,
73
+ pending_plugin: Option<usize>,
74
+ }
75
+
76
+ type RenderLimits = (usize, usize, Option<usize>, Option<usize>);
77
+
78
+ impl Deref for Renderer {
79
+ type Target = RendererData;
80
+
81
+ fn deref(&self) -> &Self::Target {
82
+ &self.0
83
+ }
84
+ }
85
+
86
+ impl PartialEq for Renderer {
87
+ fn eq(&self, other: &Self) -> bool {
88
+ Rc::ptr_eq(&self.0, &other.0)
89
+ }
90
+ }
91
+
92
+ impl ImplicitClone for Renderer {}
93
+
94
+ impl Deref for RendererData {
95
+ type Target = RefCell<RendererMutData>;
96
+
97
+ fn deref(&self) -> &Self::Target {
98
+ &self.plugin_data
99
+ }
100
+ }
101
+
102
+ type TaskResult = ApiResult<JsValue>;
103
+ type TimeoutTask<'a> = Pin<Box<dyn Future<Output = Option<TaskResult>> + 'a>>;
104
+
105
+ /// How long to await a call to the plugin's `draw()` before resizing.
106
+ static PRESIZE_TIMEOUT: i32 = 500;
107
+
108
+ impl Renderer {
109
+ pub fn new(viewer_elem: &HtmlElement) -> Self {
110
+ Self(Rc::new(RendererData {
111
+ plugin_data: RefCell::new(RendererMutData {
112
+ viewer_elem: viewer_elem.clone(),
113
+ metadata: ViewConfigRequirements::default(),
114
+ plugin_store: PluginStore::default(),
115
+ plugins_idx: None,
116
+ selection: None,
117
+ timer: MovingWindowRenderTimer::default(),
118
+ pending_plugin: None,
119
+ }),
120
+ draw_lock: Default::default(),
121
+ plugin_changed: Default::default(),
122
+ render_limits_changed: Default::default(),
123
+ style_changed: Default::default(),
124
+ reset_changed: Default::default(),
125
+ }))
126
+ }
127
+
128
+ pub async fn reset(&self, columns_config: Option<&ColumnConfigMap>) -> ApiResult<()> {
129
+ self.0.borrow_mut().plugins_idx = None;
130
+ if let Ok(plugin) = self.get_active_plugin() {
131
+ plugin.restore(&json!({}), columns_config)?;
132
+ }
133
+
134
+ Ok(())
135
+ }
136
+
137
+ pub fn delete(&self) -> ApiResult<()> {
138
+ // self.get_active_plugin()?.delete();
139
+ self.0.plugin_data.borrow().viewer_elem.set_inner_text("");
140
+
141
+ // self.plugin_data.borrow_mut().metadata = ViewConfigRequirements::default();
142
+ let new_state = Self::new(&self.plugin_data.borrow().viewer_elem);
143
+ std::mem::swap(
144
+ &mut *self.plugin_data.borrow_mut(),
145
+ &mut *new_state.plugin_data.borrow_mut(),
146
+ );
147
+
148
+ Ok(())
149
+ }
150
+
151
+ pub fn metadata(&self) -> Ref<'_, ViewConfigRequirements> {
152
+ Ref::map(self.borrow(), |x| &x.metadata)
153
+ }
154
+
155
+ pub fn is_chart(&self) -> bool {
156
+ let plugin = self.get_active_plugin().unwrap();
157
+ plugin.name().as_str() != "Datagrid"
158
+ }
159
+
160
+ /// Return all plugin instances, whether they are active or not. Useful
161
+ /// for configuring all or specific plugins at application init.
162
+ pub fn get_all_plugins(&self) -> Vec<JsPerspectiveViewerPlugin> {
163
+ self.0.borrow_mut().plugin_store.plugins().clone()
164
+ }
165
+
166
+ /// Return all plugin names, whether they are active or not.
167
+ pub fn get_all_plugin_categories(&self) -> HashMap<String, Vec<String>> {
168
+ self.0.borrow_mut().plugin_store.plugin_records().clone()
169
+ }
170
+
171
+ /// Gets the currently active plugin. Calling this method before a plugin
172
+ /// has been selected will cause the default (first) plugin to be
173
+ /// selected, and doing so when no plugins have been registered is an
174
+ /// error.
175
+ pub fn get_active_plugin(&self) -> ApiResult<JsPerspectiveViewerPlugin> {
176
+ if self.0.borrow().plugins_idx.is_none() {
177
+ let _ = self.apply_pending_plugin()?;
178
+ }
179
+
180
+ let idx = self.0.borrow().plugins_idx.unwrap_or(0);
181
+ let result = self.0.borrow_mut().plugin_store.plugins().get(idx).cloned();
182
+ Ok(result.ok_or("No Plugin")?)
183
+ }
184
+
185
+ /// Gets a specific `JsPerspectiveViewerPlugin` by name.
186
+ ///
187
+ /// # Arguments
188
+ /// - `name` The plugin name to lookup.
189
+ pub fn get_plugin(&self, name: &str) -> ApiResult<JsPerspectiveViewerPlugin> {
190
+ let idx = self.find_plugin_idx(name);
191
+ let idx = idx.ok_or_else(|| JsValue::from(format!("No Plugin `{name}`")))?;
192
+ let result = self.0.borrow_mut().plugin_store.plugins().get(idx).cloned();
193
+ Ok(result.unwrap())
194
+ }
195
+
196
+ pub async fn restyle_all(&self, view: &perspective_client::View) -> ApiResult<JsValue> {
197
+ let plugins = self.get_all_plugins();
198
+ let tasks = plugins
199
+ .iter()
200
+ .map(|plugin| plugin.restyle(view.clone().into()));
201
+
202
+ join_all(tasks)
203
+ .await
204
+ .into_iter()
205
+ .collect::<Result<Vec<_>, _>>()
206
+ .map(|_| JsValue::UNDEFINED)
207
+ }
208
+
209
+ pub fn set_throttle(&self, val: Option<f64>) {
210
+ self.0.borrow_mut().timer.set_throttle(val);
211
+ }
212
+
213
+ pub fn set_selection(&self, window: Option<ViewWindow>) {
214
+ self.borrow_mut().selection = window
215
+ }
216
+
217
+ pub fn get_selection(&self) -> Option<ViewWindow> {
218
+ self.borrow().selection.clone()
219
+ }
220
+
221
+ pub fn disable_active_plugin_render_warning(&self) {
222
+ self.borrow_mut().metadata.render_warning = false;
223
+ self.get_active_plugin().unwrap().set_render_warning(false);
224
+ }
225
+
226
+ pub fn get_next_plugin_metadata(
227
+ &self,
228
+ update: &PluginUpdate,
229
+ ) -> Option<ViewConfigRequirements> {
230
+ let default_plugin_name = PLUGIN_REGISTRY.default_plugin_name();
231
+ let name = match update {
232
+ PluginUpdate::Missing => return None,
233
+ PluginUpdate::SetDefault => default_plugin_name.as_str(),
234
+ PluginUpdate::Update(plugin) => plugin,
235
+ };
236
+
237
+ let idx = self.find_plugin_idx(name).expect("f");
238
+
239
+ let changed = !matches!(
240
+ self.0.borrow().plugins_idx,
241
+ Some(selected_idx) if selected_idx == idx
242
+ );
243
+
244
+ if changed {
245
+ self.borrow_mut().pending_plugin = Some(idx);
246
+ self.get_plugin(name)
247
+ .and_then(|x| x.get_requirements())
248
+ .ok()
249
+ } else {
250
+ None
251
+ }
252
+ }
253
+
254
+ pub fn apply_pending_plugin(&self) -> ApiResult<bool> {
255
+ let xxx = self.borrow_mut().pending_plugin.take();
256
+ if let Some(idx) = xxx {
257
+ let changed = !matches!(
258
+ self.0.borrow().plugins_idx,
259
+ Some(selected_idx) if selected_idx == idx
260
+ );
261
+
262
+ if changed {
263
+ self.borrow_mut().plugins_idx = Some(idx);
264
+ let plugin: JsPerspectiveViewerPlugin = self.get_active_plugin()?;
265
+ self.borrow_mut().metadata = plugin.get_requirements()?;
266
+ self.plugin_changed.emit(plugin);
267
+ }
268
+
269
+ Ok(changed)
270
+ } else {
271
+ if self.0.borrow().plugins_idx.is_none() {
272
+ self.set_plugin(Some(&PLUGIN_REGISTRY.default_plugin_name()))?;
273
+ }
274
+
275
+ Ok(false)
276
+ }
277
+ }
278
+
279
+ fn set_plugin(&self, name: Option<&str>) -> ApiResult<bool> {
280
+ self.borrow_mut().pending_plugin = None;
281
+ let default_plugin_name = PLUGIN_REGISTRY.default_plugin_name();
282
+ let name = name.unwrap_or(default_plugin_name.as_str());
283
+ let idx = self
284
+ .find_plugin_idx(name)
285
+ .ok_or_else(|| JsValue::from(format!("Unknown plugin '{name}'")))?;
286
+
287
+ let changed = !matches!(
288
+ self.0.borrow().plugins_idx,
289
+ Some(selected_idx) if selected_idx == idx
290
+ );
291
+
292
+ if changed {
293
+ self.borrow_mut().plugins_idx = Some(idx);
294
+ let plugin: JsPerspectiveViewerPlugin = self.get_active_plugin()?;
295
+ self.borrow_mut().metadata = plugin.get_requirements()?;
296
+ self.plugin_changed.emit(plugin);
297
+ }
298
+
299
+ Ok(changed)
300
+ }
301
+
302
+ pub async fn with_lock<T>(self, task: impl Future<Output = ApiResult<T>>) -> ApiResult<T> {
303
+ let draw_mutex = self.draw_lock();
304
+ draw_mutex.lock(task).await
305
+ }
306
+
307
+ pub async fn resize(&self) -> ApiResult<()> {
308
+ let draw_mutex = self.draw_lock();
309
+ let timer = self.render_timer();
310
+ draw_mutex
311
+ .debounce(async {
312
+ set_timeout(timer.get_throttle()).await?;
313
+ let jsplugin = self.get_active_plugin()?;
314
+ jsplugin.resize().await?;
315
+ Ok(())
316
+ })
317
+ .await
318
+ }
319
+
320
+ /// This will take a future which _should_ create a new view and then will
321
+ /// draw it.
322
+ pub async fn draw(&self, session: impl Future<Output = ApiResult<&Session>>) -> ApiResult<()> {
323
+ self.draw_plugin(session, false).await
324
+ }
325
+
326
+ /// This will update an already existing view
327
+ pub async fn update(&self, session: &Session) -> ApiResult<()> {
328
+ self.draw_plugin(async { Ok(session) }, true).await
329
+ }
330
+
331
+ async fn draw_plugin(
332
+ &self,
333
+ session: impl Future<Output = ApiResult<&Session>>,
334
+ is_update: bool,
335
+ ) -> ApiResult<()> {
336
+ let timer = self.render_timer();
337
+ let task = async move {
338
+ if is_update {
339
+ set_timeout(timer.get_throttle()).await?;
340
+ }
341
+
342
+ if let Some(view) = session.await?.get_view() {
343
+ timer.capture_time(self.draw_view(&view, is_update)).await
344
+ } else {
345
+ Ok(())
346
+ }
347
+ };
348
+
349
+ let draw_mutex = self.draw_lock();
350
+ if is_update {
351
+ draw_mutex.debounce(task).await
352
+ } else {
353
+ draw_mutex.lock(task).await
354
+ }
355
+ }
356
+
357
+ async fn draw_view(&self, view: &perspective_client::View, is_update: bool) -> ApiResult<()> {
358
+ let plugin = self.get_active_plugin()?;
359
+ let meta = self.metadata().clone();
360
+ let limits = get_row_and_col_limits(view, &meta).await?;
361
+ self.render_limits_changed.emit((is_update, limits));
362
+ let viewer_elem = &self.0.borrow().viewer_elem.clone();
363
+ if is_update {
364
+ let task = plugin.update(view.clone().into(), limits.2, limits.3, false);
365
+ activate_plugin(viewer_elem, &plugin, task).await
366
+ } else {
367
+ let task = plugin.draw(view.clone().into(), limits.2, limits.3, false);
368
+ activate_plugin(viewer_elem, &plugin, task).await
369
+ }
370
+ }
371
+
372
+ /// Decide whether to draw plugin or self first based on whether the panel
373
+ /// is opening or closing, then draw with a timeout. If the timeout
374
+ /// triggers, draw self and resolve `on_toggle` but still await the
375
+ /// completion of the draw task
376
+ pub async fn presize(
377
+ &self,
378
+ open: bool,
379
+ panel_task: impl Future<Output = ApiResult<()>>,
380
+ ) -> ApiResult<JsValue> {
381
+ let render_task = self.resize_with_timeout(open);
382
+ let result = if open {
383
+ panel_task.await?;
384
+ render_task.await
385
+ } else {
386
+ let result = render_task.await;
387
+ panel_task.await?;
388
+ result
389
+ };
390
+
391
+ match result {
392
+ Ok(x) => x,
393
+ Err(cont) => {
394
+ tracing::warn!("Presize took longer than {}ms", PRESIZE_TIMEOUT);
395
+ cont.await.unwrap()
396
+ },
397
+ }
398
+ }
399
+
400
+ /// Lock on `resize()` task, in parallel with a timeout. In the return
401
+ /// type, `Result::Err` contains the continuation task, which must be
402
+ /// awaited lest the plugin draw itself never trigger.
403
+ async fn resize_with_timeout(&self, open: bool) -> Result<TaskResult, TimeoutTask<'_>> {
404
+ let task = async move {
405
+ if open {
406
+ self.get_active_plugin()?.resize().await
407
+ } else {
408
+ self.resize_with_explicit_dimensions().await
409
+ }
410
+ };
411
+
412
+ let draw_lock = self.draw_lock();
413
+ let tasks: [TimeoutTask<'_>; 2] = [
414
+ Box::pin(async move { Some(draw_lock.lock(task).await) }),
415
+ Box::pin(async {
416
+ set_timeout(PRESIZE_TIMEOUT).await.unwrap();
417
+ None
418
+ }),
419
+ ];
420
+
421
+ let (x, _, y) = select_all(tasks.into_iter()).await;
422
+ x.ok_or_else(|| y.into_iter().next().unwrap())
423
+ }
424
+
425
+ /// Resize the `<div>` offscreen, then resize the plugin
426
+ async fn resize_with_explicit_dimensions(&self) -> TaskResult {
427
+ let plugin = self.get_active_plugin()?;
428
+ let main_panel: &web_sys::HtmlElement = plugin.unchecked_ref();
429
+ let new_width = format!("{}px", &self.0.borrow().viewer_elem.client_width());
430
+ let new_height = format!("{}px", &self.0.borrow().viewer_elem.client_height());
431
+ main_panel.style().set_property("width", &new_width)?;
432
+ main_panel.style().set_property("height", &new_height)?;
433
+ let result = plugin.resize().await;
434
+ main_panel.style().set_property("width", "")?;
435
+ main_panel.style().set_property("height", "")?;
436
+ result
437
+ }
438
+
439
+ fn draw_lock(&self) -> DebounceMutex {
440
+ self.draw_lock.clone()
441
+ }
442
+
443
+ pub fn render_timer(&self) -> MovingWindowRenderTimer {
444
+ self.0.borrow().timer.clone()
445
+ }
446
+
447
+ fn find_plugin_idx(&self, name: &str) -> Option<usize> {
448
+ let short_name = make_short_name(name);
449
+ self.0
450
+ .borrow_mut()
451
+ .plugin_store
452
+ .plugins()
453
+ .iter()
454
+ .position(|elem| make_short_name(&elem.name()).contains(&short_name))
455
+ }
456
+ }
457
+
458
+ fn make_short_name(name: &str) -> String {
459
+ name.to_lowercase()
460
+ .chars()
461
+ .filter(|x| x.is_alphabetic())
462
+ .collect()
463
+ }
@@ -0,0 +1,141 @@
1
+ // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
+ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
+ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
+ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
+ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
+ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
+ // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
+ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
+ // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
+ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
+
13
+ use std::iter::IntoIterator;
14
+
15
+ use itertools::Itertools;
16
+ use perspective_client::config::*;
17
+
18
+ use super::metadata::*;
19
+ use crate::js::plugin::*;
20
+
21
+ #[extend::ext]
22
+ pub impl ViewConfigUpdate {
23
+ /// Appends additional columns to the `columns` field of this
24
+ /// `ViewConfigUpdate` by picking appropriate new columns from the
25
+ /// `SessionMetadata`, give the necessary column requirements of the plugin
26
+ /// provided by a `ViewConfigRequirements`. For example, an "X/Y Scatter"
27
+ /// chart needs a minimum of 2 numeric columns to be drawable.
28
+ fn set_update_column_defaults(
29
+ &mut self,
30
+ metadata: &SessionMetadata,
31
+ columns: &[Option<String>],
32
+ requirements: &ViewConfigRequirements,
33
+ ) {
34
+ if let (
35
+ None,
36
+ ViewConfigRequirements {
37
+ min: Some(min_cols),
38
+ names,
39
+ ..
40
+ },
41
+ ) = (&self.columns, &requirements)
42
+ {
43
+ // first try to take 2 numeric columns from existing config
44
+ let numeric_config_columns = columns
45
+ .iter()
46
+ .flatten()
47
+ .filter(|x| {
48
+ matches!(
49
+ metadata.get_column_table_type(x),
50
+ Some(ColumnType::Float | ColumnType::Integer)
51
+ )
52
+ })
53
+ .take(*min_cols)
54
+ .cloned()
55
+ .map(Some)
56
+ .collect::<Vec<_>>();
57
+
58
+ if numeric_config_columns.len() == *min_cols {
59
+ self.columns = Some(
60
+ numeric_config_columns
61
+ .into_iter()
62
+ .pad_using(names.as_ref().map_or(0, |x| x.len()), |_| None)
63
+ .collect::<Vec<_>>(),
64
+ );
65
+ } else {
66
+ // Append numeric columns from all columns and try again
67
+ let config_columns = numeric_config_columns
68
+ .clone()
69
+ .into_iter()
70
+ .chain(
71
+ metadata
72
+ .get_table_columns()
73
+ .into_iter()
74
+ .flatten()
75
+ .filter(|x| {
76
+ !numeric_config_columns
77
+ .iter()
78
+ .any(|y| y.as_ref() == Some(*x))
79
+ })
80
+ .filter(|x| {
81
+ matches!(
82
+ metadata.get_column_table_type(x),
83
+ Some(ColumnType::Float | ColumnType::Integer)
84
+ )
85
+ })
86
+ .cloned()
87
+ .map(Some),
88
+ )
89
+ .take(*min_cols)
90
+ .collect::<Vec<_>>();
91
+
92
+ if config_columns.len() == *min_cols {
93
+ self.columns = Some(
94
+ config_columns
95
+ .into_iter()
96
+ .pad_using(names.as_ref().map_or(0, |x| x.len()), |_| None)
97
+ .collect::<Vec<_>>(),
98
+ );
99
+ } else {
100
+ self.columns = Some(
101
+ metadata
102
+ .get_table_columns()
103
+ .into_iter()
104
+ .flatten()
105
+ .take(*min_cols)
106
+ .cloned()
107
+ .map(Some)
108
+ .collect::<Vec<_>>(),
109
+ );
110
+ }
111
+ }
112
+ } else if self.columns.is_none() {
113
+ let mut columns = columns.to_vec();
114
+ let initial_len = columns.len();
115
+ if let Some(last_filled) = columns.iter().rposition(|x| x.is_some()) {
116
+ columns.truncate(last_filled + 1);
117
+ if let ViewConfigRequirements {
118
+ names: Some(names), ..
119
+ } = &requirements
120
+ {
121
+ columns = columns
122
+ .into_iter()
123
+ .enumerate()
124
+ .filter(|(idx, x)| *idx < names.len() || x.is_some())
125
+ .map(|(_, x)| x)
126
+ .pad_using(names.len(), |_| None)
127
+ .collect::<Vec<_>>();
128
+ } else {
129
+ columns = columns
130
+ .into_iter()
131
+ .filter(|x| x.is_some())
132
+ .collect::<Vec<_>>();
133
+ }
134
+
135
+ if initial_len != columns.len() {
136
+ self.columns = Some(columns);
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }