@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,179 @@
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 perspective_client::config::*;
14
+
15
+ use crate::dragdrop::{DragEffect, DragTarget};
16
+ use crate::js::plugin::ViewConfigRequirements;
17
+
18
+ #[allow(clippy::too_many_arguments)]
19
+ #[extend::ext]
20
+ pub impl ViewConfig {
21
+ /// Create an update for this `ViewConfig` which applies a drag/drop action.
22
+ /// This method is designed to be called from `crate::session`.
23
+ fn create_drag_drop_update(
24
+ &self,
25
+ column: String,
26
+ col_type: ColumnType,
27
+ index: usize,
28
+ drop: DragTarget,
29
+ drag: DragEffect,
30
+ requirements: &ViewConfigRequirements,
31
+ features: &perspective_client::Features,
32
+ ) -> ViewConfigUpdate {
33
+ let mut config = self.clone();
34
+ let mut update = ViewConfigUpdate::default();
35
+ let is_to_swap = requirements.is_swap(index);
36
+ let from_index = config
37
+ .columns
38
+ .iter()
39
+ .position(|x| x.as_ref() == Some(&column));
40
+
41
+ let is_from_required = from_index
42
+ .and_then(|x| requirements.min.map(|z| x < z))
43
+ .unwrap_or_default();
44
+
45
+ let is_from_swap = from_index
46
+ .map(|x| requirements.is_swap(x))
47
+ .unwrap_or_default();
48
+
49
+ let is_to_empty = config
50
+ .columns
51
+ .get(index)
52
+ .map(|x| x.is_none())
53
+ .unwrap_or_default();
54
+
55
+ let is_swap_to_after_last = index == config.columns.len() && from_index.is_some();
56
+ match drag {
57
+ DragEffect::Copy => (),
58
+ DragEffect::Move(DragTarget::Active) => {
59
+ let is_to_group_or_split =
60
+ matches!(drop, DragTarget::GroupBy | DragTarget::SplitBy);
61
+
62
+ if ((!is_to_swap && is_from_swap)
63
+ || (is_to_swap && !is_from_swap && is_to_empty)
64
+ || is_to_group_or_split)
65
+ && config.columns.len() > 1
66
+ && !is_from_required
67
+ && !is_swap_to_after_last
68
+ {
69
+ // Is not a swap
70
+ if !is_to_swap && !is_to_group_or_split {
71
+ config.columns.iter_mut().for_each(|x| {
72
+ if x.as_ref() == Some(&column) {
73
+ *x = None;
74
+ }
75
+ });
76
+ } else {
77
+ config.columns.retain(|x| x.as_ref() != Some(&column));
78
+ }
79
+
80
+ update.columns = Some(config.columns.clone());
81
+ }
82
+ },
83
+ DragEffect::Move(DragTarget::GroupBy) => {
84
+ config.group_by.retain(|x| x != &column);
85
+ update.group_by = Some(config.group_by.clone());
86
+ },
87
+ DragEffect::Move(DragTarget::SplitBy) => {
88
+ config.split_by.retain(|x| x != &column);
89
+ update.split_by = Some(config.split_by.clone());
90
+ },
91
+ DragEffect::Move(DragTarget::Sort) => {
92
+ config.sort.retain(|x| x.0 != column);
93
+ update.sort = Some(config.sort.clone());
94
+ },
95
+ DragEffect::Move(DragTarget::Filter) => {
96
+ config.filter.retain(|x| x.column() != column);
97
+ update.filter = Some(config.filter.clone());
98
+ },
99
+ }
100
+
101
+ match drop {
102
+ DragTarget::Active => {
103
+ if !is_swap_to_after_last {
104
+ if is_to_swap || is_from_required {
105
+ let column = Some(column);
106
+ config.columns.extend(std::iter::repeat_n(None, {
107
+ let fill_to = requirements
108
+ .names
109
+ .as_ref()
110
+ .map(|x| std::cmp::max(x.len() - 1, index))
111
+ .unwrap_or(index);
112
+
113
+ if fill_to >= (config.columns.len() - 1) {
114
+ fill_to + 1 - config.columns.len()
115
+ } else {
116
+ 0
117
+ }
118
+ }));
119
+
120
+ if let Some(prev) = config.columns.iter().position(|x| *x == column) {
121
+ config.columns.swap(index, prev);
122
+ } else {
123
+ config.columns[index] = column;
124
+ }
125
+ } else {
126
+ config.columns.retain(|x| x.as_ref() != Some(&column));
127
+ config.columns.extend(std::iter::repeat_n(
128
+ None,
129
+ if index >= config.columns.len() {
130
+ index - config.columns.len()
131
+ } else {
132
+ 0
133
+ },
134
+ ));
135
+
136
+ if is_to_empty {
137
+ config.columns[index] = Some(column)
138
+ } else {
139
+ config.columns.insert(index, Some(column));
140
+ }
141
+ }
142
+
143
+ update.columns = Some(config.columns);
144
+ }
145
+ },
146
+ DragTarget::GroupBy => {
147
+ config.group_by.retain(|x| x != &column);
148
+ let index = std::cmp::min(index, config.group_by.len());
149
+ config.group_by.insert(index, column);
150
+ update.group_by = Some(config.group_by);
151
+ },
152
+ DragTarget::SplitBy => {
153
+ config.split_by.retain(|x| x != &column);
154
+ let index = std::cmp::min(index, config.split_by.len());
155
+ config.split_by.insert(index, column);
156
+ update.split_by = Some(config.split_by);
157
+ },
158
+ DragTarget::Sort => {
159
+ let index = std::cmp::min(index, config.sort.len());
160
+ config.sort.insert(index, Sort(column, SortDir::Asc));
161
+ update.sort = Some(config.sort);
162
+ },
163
+ DragTarget::Filter => {
164
+ let index = std::cmp::min(index, config.filter.len());
165
+ config.filter.insert(
166
+ index,
167
+ Filter::new(
168
+ &column,
169
+ features.default_op(col_type).unwrap_or(""),
170
+ FilterTerm::Scalar(Scalar::Null),
171
+ ),
172
+ );
173
+ update.filter = Some(config.filter);
174
+ },
175
+ }
176
+
177
+ update
178
+ }
179
+ }
@@ -0,0 +1,308 @@
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::collections::{HashMap, HashSet};
14
+ use std::iter::IntoIterator;
15
+ use std::ops::{Deref, DerefMut};
16
+
17
+ use perspective_client::config::*;
18
+ use perspective_js::apierror;
19
+
20
+ use crate::components::viewer::ColumnLocator;
21
+ use crate::*;
22
+
23
+ struct SessionViewExpressionMetadata {
24
+ edited: HashMap<String, String>,
25
+ expressions: perspective_client::ExprValidationResult,
26
+ }
27
+
28
+ /// Metadata state reflects data we could fetch from a `View`, but would like to
29
+ /// do so without `async`. It must be recreated by any `async` method which
30
+ /// changes the `View` and may temporarily be out-of-sync with the
31
+ /// `View`/`ViewConfig`.
32
+ #[derive(Default)]
33
+ pub struct SessionMetadata(Option<SessionMetadataState>);
34
+
35
+ impl Deref for SessionMetadata {
36
+ type Target = Option<SessionMetadataState>;
37
+
38
+ fn deref(&self) -> &Self::Target {
39
+ &self.0
40
+ }
41
+ }
42
+
43
+ impl DerefMut for SessionMetadata {
44
+ fn deref_mut(&mut self) -> &mut Self::Target {
45
+ &mut self.0
46
+ }
47
+ }
48
+
49
+ /// TODO the multiple `Option` types could probably be merged since they are
50
+ /// populated within an async lock
51
+ #[derive(Default)]
52
+ pub struct SessionMetadataState {
53
+ features: perspective_client::Features,
54
+ column_names: Vec<String>,
55
+ table_schema: HashMap<String, ColumnType>,
56
+ edit_port: f64,
57
+ view_schema: Option<HashMap<String, ColumnType>>,
58
+ expr_meta: Option<SessionViewExpressionMetadata>,
59
+ }
60
+
61
+ impl SessionMetadata {
62
+ /// Creates a new `SessionMetadata` from a `JsPerspectiveTable`.
63
+ pub(super) async fn from_table(table: &perspective_client::Table) -> ApiResult<Self> {
64
+ let features = table.get_features().await?.clone();
65
+ let column_names = table.columns().await?;
66
+ let table_schema = table.schema().await?;
67
+ let edit_port = table.make_port().await? as f64;
68
+ Ok(Self(Some(SessionMetadataState {
69
+ features,
70
+ column_names,
71
+ table_schema,
72
+ edit_port,
73
+ ..SessionMetadataState::default()
74
+ })))
75
+ }
76
+
77
+ pub(super) fn update_view_schema(
78
+ &mut self,
79
+ view_schema: &HashMap<String, ColumnType>,
80
+ ) -> ApiResult<()> {
81
+ self.as_mut().unwrap().view_schema = Some(view_schema.clone());
82
+ Ok(())
83
+ }
84
+
85
+ pub(super) fn update_expressions(
86
+ &mut self,
87
+ valid_recs: &perspective_client::ExprValidationResult,
88
+ ) -> ApiResult<HashSet<String>> {
89
+ if !valid_recs.errors.is_empty() {
90
+ return Err(apierror!(InvalidViewerConfigExpressionsError(
91
+ valid_recs.clone().into(),
92
+ )));
93
+ }
94
+
95
+ let mut edited = self
96
+ .as_mut()
97
+ .unwrap()
98
+ .expr_meta
99
+ .take()
100
+ .map(|x| x.edited)
101
+ .unwrap_or_default();
102
+
103
+ edited.retain(|k, _| valid_recs.expression_alias.contains_key(k));
104
+ self.as_mut().unwrap().expr_meta = Some(SessionViewExpressionMetadata {
105
+ expressions: valid_recs.clone(),
106
+ edited,
107
+ });
108
+
109
+ Ok(valid_recs.expression_schema.keys().cloned().collect())
110
+ }
111
+
112
+ /// Get the `Table`'s supported features.
113
+ pub fn get_features(&self) -> Option<&'_ perspective_client::Features> {
114
+ Some(&self.as_ref()?.features)
115
+ }
116
+
117
+ /// Returns the unique column names in this session that are expression
118
+ /// columns.
119
+ pub fn get_expression_columns(&self) -> impl Iterator<Item = &'_ String> {
120
+ maybe!(Some(
121
+ self.as_ref()?
122
+ .expr_meta
123
+ .as_ref()?
124
+ .expressions
125
+ .expression_schema
126
+ .keys()
127
+ ))
128
+ .into_iter()
129
+ .flatten()
130
+ }
131
+
132
+ /// Returns the full original expression `String` for an expression alias.
133
+ /// TODO should expressions be `Rc`?
134
+ ///
135
+ /// # Arguments
136
+ /// - `alias` An alias name for an expression column in this `Session`.
137
+ pub fn get_expression_by_alias(&self, alias: &str) -> Option<String> {
138
+ self.as_ref()?
139
+ .expr_meta
140
+ .as_ref()?
141
+ .expressions
142
+ .expression_alias
143
+ .get(alias)
144
+ .cloned()
145
+ }
146
+
147
+ /// Returns the edited expression `String` (e.g. the not-yet-saved, edited
148
+ /// expression state of a column, if any) for an expression alias.
149
+ ///
150
+ /// # Arguments
151
+ /// - `alias` An alias name for an expression column in this `Session`.
152
+ pub fn get_edit_by_alias(&self, alias: &str) -> Option<String> {
153
+ maybe!(
154
+ self.as_ref()?
155
+ .expr_meta
156
+ .as_ref()?
157
+ .edited
158
+ .get(alias)
159
+ .cloned()
160
+ )
161
+ }
162
+
163
+ pub fn set_edit_by_alias(&mut self, alias: &str, edit: String) {
164
+ drop(maybe!(
165
+ self.as_mut()?
166
+ .expr_meta
167
+ .as_mut()?
168
+ .edited
169
+ .insert(alias.to_owned(), edit)
170
+ ))
171
+ }
172
+
173
+ pub fn clear_edit_by_alias(&mut self, alias: &str) {
174
+ drop(maybe!(
175
+ self.as_mut()?.expr_meta.as_mut()?.edited.remove(alias)
176
+ ))
177
+ }
178
+
179
+ pub fn get_table_columns(&self) -> Option<&'_ Vec<String>> {
180
+ self.as_ref().map(|meta| &meta.column_names)
181
+ }
182
+
183
+ pub fn is_column_expression(&self, name: &str) -> bool {
184
+ let is_expr = maybe!(Some(
185
+ self.as_ref()?
186
+ .expr_meta
187
+ .as_ref()?
188
+ .expressions
189
+ .expression_schema
190
+ .contains_key(name)
191
+ ));
192
+
193
+ is_expr.unwrap_or_default()
194
+ }
195
+
196
+ /// This function will find a currently existing column. If you want to
197
+ /// create a new expression column, use ColumnLocator::Expr(None)
198
+ pub fn get_column_locator(&self, name: Option<String>) -> Option<ColumnLocator> {
199
+ name.and_then(|name| {
200
+ self.as_ref().and_then(|meta| {
201
+ if self.is_column_expression(&name) {
202
+ Some(ColumnLocator::Expression(name))
203
+ } else {
204
+ meta.column_names
205
+ .iter()
206
+ .find_map(|n| (n == &name).then_some(ColumnLocator::Table(name.clone())))
207
+ }
208
+ })
209
+ })
210
+ }
211
+
212
+ /// Creates a new column name by appending a numeral corresponding to the
213
+ /// number of columns with that name.
214
+ pub fn make_new_column_name(&self, col: Option<&str>) -> String {
215
+ let mut i = 0;
216
+ loop {
217
+ i += 1;
218
+ let name = format!("{} {i}", col.unwrap_or("New Column"));
219
+ if self.get_column_table_type(&name).is_none() {
220
+ return name;
221
+ }
222
+ }
223
+ }
224
+
225
+ pub fn get_edit_port(&self) -> Option<f64> {
226
+ self.as_ref().map(|meta| meta.edit_port)
227
+ }
228
+
229
+ /// Returns the type of a column name relative to the `Table`. Despite the
230
+ /// name, `get_column_table_type()` also returns the `Table` type for
231
+ /// Expressions, which despite living on the `View` still have a `table`
232
+ /// type associated with them pre-aggregation.
233
+ ///
234
+ /// # Arguments
235
+ /// - `name` The column name (or expresison alias) to retrieve a principal
236
+ /// type.
237
+ pub fn get_column_table_type(&self, name: &str) -> Option<ColumnType> {
238
+ maybe!({
239
+ let meta = self.as_ref()?;
240
+ meta.table_schema.get(name).cloned().or_else(|| {
241
+ meta.expr_meta
242
+ .as_ref()?
243
+ .expressions
244
+ .expression_schema
245
+ .get(name)
246
+ .cloned()
247
+ })
248
+ })
249
+ }
250
+
251
+ /// Returns the type of a column name relative to the `View`, including
252
+ /// expression columns which were part of the `ViewConfig`. Types
253
+ /// returned from the `View` incorporate the type transform applied by
254
+ /// their aggregate if applicable, so may differ from the type returned
255
+ /// by `get_column_table_type()`.
256
+ ///
257
+ /// # Arguments
258
+ /// - `name` The column name (or expresison alias) to retrieve a `View`
259
+ /// type.
260
+ pub fn get_column_view_type(&self, name: &str) -> Option<ColumnType> {
261
+ maybe!(self.as_ref()?.view_schema.as_ref()?.get(name)).cloned()
262
+ }
263
+
264
+ pub fn get_column_aggregates<'a>(
265
+ &'a self,
266
+ name: &str,
267
+ ) -> Option<Box<dyn Iterator<Item = Aggregate> + 'a>> {
268
+ let coltype = self.get_column_table_type(name)?;
269
+ let f = self.get_features()?.aggregates.get(&(coltype as u32))?;
270
+
271
+ let aggregates = f
272
+ .aggregates
273
+ .iter()
274
+ .flat_map(move |x| {
275
+ if x.args.is_empty() {
276
+ Some(vec![Aggregate::SingleAggregate(x.name.to_string())])
277
+ } else {
278
+ // todo: handle multi args
279
+ let dtype = x.args.first().unwrap();
280
+ Some(
281
+ self.get_expression_columns()
282
+ .cloned()
283
+ .chain(self.get_table_columns()?.clone().into_iter())
284
+ .map(move |name| {
285
+ self.get_column_table_type(&name)
286
+ .map(|coltype| (name, coltype))
287
+ })
288
+ .collect::<Option<Vec<_>>>()?
289
+ .into_iter()
290
+ .filter(move |(_, coltype)| {
291
+ *coltype as i32 == *dtype
292
+ || (coltype == &ColumnType::Integer
293
+ && *dtype == ColumnType::Float as i32)
294
+ || (coltype == &ColumnType::Float
295
+ && *dtype == ColumnType::Integer as i32)
296
+ })
297
+ .map(|(name, _)| {
298
+ Aggregate::MultiAggregate(x.name.to_string(), vec![name])
299
+ })
300
+ .collect(),
301
+ )
302
+ }
303
+ })
304
+ .flatten();
305
+
306
+ Some(Box::new(aggregates))
307
+ }
308
+ }
@@ -0,0 +1,131 @@
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::collections::HashMap;
14
+
15
+ use perspective_client::config::*;
16
+
17
+ #[extend::ext]
18
+ pub impl ViewConfig {
19
+ /// Create an update for this `ViewConfig` that replaces an expression
20
+ /// column with a new one, e.g. when a user edits an expression. This may
21
+ /// changed either the expression alias, the expression itself, or both; as
22
+ /// well as any other fields that reference the expression column by alias.
23
+ ///
24
+ /// This method is designed to be called from `crate::session` which can
25
+ /// fill in `old_expression` and `new_alias`.
26
+ fn create_replace_expression_update(
27
+ &self,
28
+ old_expr: &Expression,
29
+ new_expr: &Expression,
30
+ ) -> ViewConfigUpdate {
31
+ let expression = new_expr;
32
+ let Self {
33
+ columns,
34
+ expressions,
35
+ group_by,
36
+ split_by,
37
+ sort,
38
+ filter,
39
+ aggregates,
40
+ filter_op: _,
41
+ group_by_depth: _,
42
+ } = self.clone();
43
+
44
+ let expressions = expressions
45
+ .iter()
46
+ .map(|(serde_name, serde_expr)| {
47
+ if &old_expr.name == serde_name {
48
+ expression.to_owned()
49
+ } else {
50
+ Expression::new(Some(serde_name.into()), serde_expr.into())
51
+ }
52
+ })
53
+ .collect::<Expressions>();
54
+
55
+ let aggregates = aggregates
56
+ .into_iter()
57
+ .map(|x| {
58
+ if x.0 == old_expr.name {
59
+ (expression.name.as_ref().to_owned(), x.1)
60
+ } else {
61
+ x
62
+ }
63
+ })
64
+ .collect::<HashMap<_, _>>();
65
+
66
+ let columns = columns
67
+ .into_iter()
68
+ .map(|x| match x {
69
+ Some(x) if x == old_expr.name => Some(new_expr.name.as_ref().to_owned()),
70
+ x => x,
71
+ })
72
+ .collect::<Vec<_>>();
73
+
74
+ let group_by = group_by
75
+ .into_iter()
76
+ .map(|x| {
77
+ if x == old_expr.name {
78
+ new_expr.name.as_ref().to_owned()
79
+ } else {
80
+ x
81
+ }
82
+ })
83
+ .collect::<Vec<_>>();
84
+
85
+ let split_by = split_by
86
+ .into_iter()
87
+ .map(|x| {
88
+ if x == old_expr.name {
89
+ new_expr.name.as_ref().to_owned()
90
+ } else {
91
+ x
92
+ }
93
+ })
94
+ .collect::<Vec<_>>();
95
+
96
+ let sort = sort
97
+ .into_iter()
98
+ .map(|x| {
99
+ if x.0 == old_expr.name {
100
+ Sort(new_expr.name.as_ref().to_owned(), x.1)
101
+ } else {
102
+ x
103
+ }
104
+ })
105
+ .collect::<Vec<_>>();
106
+
107
+ // TODO expression editing can change type, which may invalidate filters
108
+ let filter = filter
109
+ .into_iter()
110
+ .map(|x| {
111
+ if x.column() == old_expr.name {
112
+ Filter::new(new_expr.name.as_ref(), x.op(), x.term().clone())
113
+ } else {
114
+ x
115
+ }
116
+ })
117
+ .collect::<Vec<_>>();
118
+
119
+ ViewConfigUpdate {
120
+ columns: Some(columns),
121
+ aggregates: Some(aggregates),
122
+ expressions: Some(expressions),
123
+ group_by: Some(group_by),
124
+ split_by: Some(split_by),
125
+ sort: Some(sort),
126
+ filter: Some(filter),
127
+ filter_op: None,
128
+ group_by_depth: None,
129
+ }
130
+ }
131
+ }