@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,340 @@
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::HashSet;
14
+
15
+ use itertools::Itertools;
16
+ use perspective_client::config::*;
17
+
18
+ use super::{HasRenderer, HasSession, IsInvalidDrop};
19
+ use crate::dragdrop::*;
20
+ use crate::renderer::*;
21
+ use crate::session::*;
22
+ use crate::*;
23
+
24
+ /// The possible states of a column (row) in the active columns list, including
25
+ /// the `Option<String>` label type.
26
+ #[derive(Clone, Debug, Eq, PartialEq)]
27
+ pub struct ActiveColumnState {
28
+ pub label: Label,
29
+ pub state: ActiveColumnStateData,
30
+ }
31
+
32
+ #[derive(Clone, Debug, Eq, PartialEq)]
33
+ pub enum ActiveColumnStateData {
34
+ Column(String),
35
+ Required,
36
+ DragOver,
37
+ Invalid,
38
+ }
39
+
40
+ impl From<&Option<String>> for ActiveColumnStateData {
41
+ fn from(value: &Option<String>) -> Self {
42
+ match value {
43
+ Some(x) => Self::Column(x.to_string()),
44
+ None => Self::Required,
45
+ }
46
+ }
47
+ }
48
+
49
+ impl ActiveColumnState {
50
+ pub fn get_name(&self) -> Option<&'_ str> {
51
+ match &self.state {
52
+ ActiveColumnStateData::Column(x) => Some(x.as_str()),
53
+ _ => None,
54
+ }
55
+ }
56
+ }
57
+
58
+ type Label = Option<String>;
59
+
60
+ /// An iterator for columns state.
61
+ ///
62
+ /// Encapsulates the logic of determining which columns go in the "Active" and
63
+ /// "Inactive" column sections of the `ColumnSelector` component, via the
64
+ /// iterator returning functions `active()`, `inactive()` and `expression()`.
65
+ pub struct ColumnsIteratorSet<'a> {
66
+ config: &'a ViewConfig,
67
+ session: &'a Session,
68
+ renderer: &'a Renderer,
69
+ metadata: MetadataRef<'a>,
70
+ is_dragover_column: Option<(usize, String)>,
71
+ named_columns: Vec<String>,
72
+ }
73
+
74
+ impl HasRenderer for ColumnsIteratorSet<'_> {
75
+ fn renderer(&self) -> &'_ Renderer {
76
+ self.renderer
77
+ }
78
+ }
79
+ impl HasSession for ColumnsIteratorSet<'_> {
80
+ fn session(&self) -> &'_ Session {
81
+ self.session
82
+ }
83
+ }
84
+
85
+ impl<'a> ColumnsIteratorSet<'a> {
86
+ pub fn new(
87
+ config: &'a ViewConfig,
88
+ session: &'a Session,
89
+ renderer: &'a Renderer,
90
+ dragdrop: &DragDrop,
91
+ ) -> ColumnsIteratorSet<'a> {
92
+ let is_dragover_column = dragdrop.is_dragover(DragTarget::Active);
93
+ let named_columns = renderer.metadata().names.clone().unwrap_or_default();
94
+ ColumnsIteratorSet {
95
+ config,
96
+ session,
97
+ renderer,
98
+ metadata: session.metadata(),
99
+ is_dragover_column,
100
+ named_columns,
101
+ }
102
+ }
103
+
104
+ /// Generate an iterator for active columns, which are represented as
105
+ /// `Option` for dragover and missing columns.
106
+ pub fn active(&'a self) -> impl Iterator<Item = ActiveColumnState> + 'a {
107
+ let min_cols = self
108
+ .renderer
109
+ .metadata()
110
+ .names
111
+ .as_ref()
112
+ .map_or(0, |x| x.len());
113
+
114
+ let last_col = self.config.columns.last().and_then(|x| x.as_ref());
115
+ let has_blank_tail = last_col.is_none()
116
+ || self.config.columns.len() < self.named_columns.len()
117
+ || self.config.columns.iter().filter(|x| x.is_some()).count()
118
+ == self
119
+ .session
120
+ .metadata()
121
+ .get_table_columns()
122
+ .map(|x| x.len())
123
+ .unwrap_or_default()
124
+ + self.config.expressions.len();
125
+
126
+ match &self.is_dragover_column {
127
+ Some((to_index, from_column)) => {
128
+ let is_to_swap = self.renderer.metadata().is_swap(*to_index);
129
+ let to_column = self.config.columns.get(*to_index);
130
+ let is_to_empty = to_column.map(|x| x.is_none()).unwrap_or_default();
131
+ let from_index = self
132
+ .config
133
+ .columns
134
+ .iter()
135
+ .position(|x| x.as_ref() == Some(from_column));
136
+
137
+ let is_from_required = from_index
138
+ .and_then(|x| self.renderer.metadata().min.map(|y| x < y))
139
+ .unwrap_or_default();
140
+
141
+ let is_from_swap = from_index
142
+ .map(|x| self.renderer.metadata().is_swap(x))
143
+ .unwrap_or_default();
144
+
145
+ let is_swap_invalid = self.is_invalid_columns_column(from_column, *to_index);
146
+ let is_dragover_after_last = *to_index == self.config.columns.len();
147
+ if is_swap_invalid {
148
+ let all_columns = self.config.columns.iter().map(|x| x.into());
149
+ let before_cols = all_columns
150
+ .clone()
151
+ .pad_using(min_cols, |_| ActiveColumnStateData::Required)
152
+ .take(*to_index);
153
+
154
+ let after_cols = all_columns.skip(*to_index + 1);
155
+ self.to_active_column_state(Box::new(
156
+ before_cols
157
+ .chain(std::iter::once(ActiveColumnStateData::Invalid))
158
+ .chain(after_cols),
159
+ ))
160
+ } else if is_to_swap || is_from_required {
161
+ let all_columns = self.config.columns.iter().filter_map(move |x| match x {
162
+ Some(x) if x == from_column => {
163
+ if is_to_empty && !is_from_swap {
164
+ None
165
+ } else {
166
+ Some(to_column.unwrap_or(&None).into())
167
+ }
168
+ },
169
+ x => Some(x.into()),
170
+ });
171
+
172
+ let before_cols = all_columns
173
+ .clone()
174
+ .pad_using(min_cols, |_| ActiveColumnStateData::Required)
175
+ .take(*to_index);
176
+
177
+ let after_cols = all_columns.skip(*to_index + 1);
178
+ self.to_active_column_state(Box::new(
179
+ before_cols
180
+ .chain(std::iter::once(ActiveColumnStateData::DragOver))
181
+ .chain(after_cols),
182
+ ))
183
+ } else if !is_from_swap && from_index.is_some() && is_dragover_after_last {
184
+ let iter = self.config.columns.iter().map(|x| x.into());
185
+ self.to_active_column_state(Box::new(
186
+ iter.chain(std::iter::once(ActiveColumnStateData::Invalid)),
187
+ ))
188
+ } else {
189
+ let to_offset = match to_column {
190
+ Some(Some(_)) => *to_index,
191
+ _ => *to_index + 1,
192
+ };
193
+
194
+ let all_columns = self.config.columns.iter().filter_map(move |x| match x {
195
+ Some(x) if x == from_column => {
196
+ if !is_from_swap {
197
+ // this is invalid
198
+ None
199
+ } else {
200
+ Some(ActiveColumnStateData::Required)
201
+ }
202
+ },
203
+ x => Some(x.into()),
204
+ });
205
+
206
+ let before_cols = all_columns
207
+ .clone()
208
+ .pad_using(min_cols, |_| ActiveColumnStateData::Required)
209
+ .take(*to_index);
210
+
211
+ let tail = if !is_from_swap && from_index.is_some() && !has_blank_tail {
212
+ Some(ActiveColumnStateData::Required)
213
+ } else {
214
+ None
215
+ };
216
+
217
+ let after_cols = all_columns.skip(to_offset).chain(tail);
218
+ self.to_active_column_state(Box::new(
219
+ before_cols
220
+ .chain(std::iter::once(ActiveColumnStateData::DragOver))
221
+ .chain(after_cols),
222
+ ))
223
+ }
224
+ },
225
+ _ => {
226
+ let iter = self.config.columns.iter().map(|x| x.into());
227
+ self.to_active_column_state(if has_blank_tail {
228
+ Box::new(iter)
229
+ } else {
230
+ Box::new(iter.chain(std::iter::once(ActiveColumnStateData::Required)))
231
+ })
232
+ },
233
+ }
234
+ }
235
+
236
+ fn to_active_column_state(
237
+ &'a self,
238
+ iter: Box<dyn Iterator<Item = ActiveColumnStateData> + 'a>,
239
+ ) -> impl Iterator<Item = ActiveColumnState> + 'a {
240
+ iter.pad_using(self.named_columns.len(), |_| {
241
+ ActiveColumnStateData::Required
242
+ })
243
+ .enumerate()
244
+ .map(move |(idx, state)| {
245
+ let label = self.named_columns.get(idx).cloned();
246
+ ActiveColumnState { state, label }
247
+ })
248
+ }
249
+
250
+ /// Generate an iterator for inactive expressions.
251
+ pub fn expression(&'a self) -> impl Iterator<Item = OrderedColumn<'a>> {
252
+ self.order_columns(self.metadata.get_expression_columns())
253
+ }
254
+
255
+ /// Generate an iterator for inactive columns, which also shows the columns
256
+ /// in sorted order by type, then name.
257
+ pub fn inactive(&'a self) -> impl Iterator<Item = OrderedColumn<'a>> {
258
+ self.order_columns(self.metadata.get_table_columns().into_iter().flatten())
259
+ }
260
+
261
+ fn order_columns(
262
+ &'a self,
263
+ values: impl Iterator<Item = &'a String>,
264
+ ) -> impl Iterator<Item = OrderedColumn<'a>> {
265
+ let is_drag_active = maybe! {
266
+ let dragover_col = self.is_dragover_column.as_ref();
267
+ let cols = &self.config.columns;
268
+ let (_, drag_name) = dragover_col?;
269
+ let is_drag_active = cols.iter().flatten().any(|x| x == drag_name);
270
+ Some(is_drag_active)
271
+ };
272
+
273
+ let col_set = self.config.columns.iter().collect::<HashSet<_>>();
274
+ let mut filtered = values
275
+ .filter_map(move |name| self.to_ordered_column(name, is_drag_active, &col_set))
276
+ .collect::<Vec<_>>();
277
+
278
+ filtered.sort();
279
+ filtered.into_iter()
280
+ }
281
+
282
+ /// Convert a column `name` into an `OrderedColumn` based on whether it is
283
+ /// active or in a drag state where an immediate drop would make it active.
284
+ fn to_ordered_column(
285
+ &'a self,
286
+ name: &'a str,
287
+ is_drag_active: Option<bool>,
288
+ col_set: &HashSet<&Option<String>>,
289
+ ) -> Option<OrderedColumn<'a>> {
290
+ let dragover_col = self.is_dragover_column.as_ref();
291
+ let cols = &self.config.columns;
292
+ let is_active = col_set.contains(&Some(name.to_string())); // cols.iter().flatten().any(|x| x == name);
293
+ let is_swap_over = maybe! {
294
+ let (drop_index, _) = dragover_col?;
295
+ let is_swap = self.renderer.metadata().is_swap(*drop_index);
296
+ let is_over = cols.get(*drop_index)?.as_ref()? == name;
297
+ Some(is_swap && is_over && !is_drag_active?)
298
+ };
299
+
300
+ if !is_active || is_swap_over.unwrap_or_default() {
301
+ let col_type = self.session.metadata().get_column_table_type(name)?;
302
+ let is_visible = dragover_col.is_none_or(|(_, x)| x != name);
303
+ Some(OrderedColumn {
304
+ is_visible,
305
+ name,
306
+ col_type,
307
+ })
308
+ } else {
309
+ None
310
+ }
311
+ }
312
+ }
313
+
314
+ pub struct OrderedColumn<'a> {
315
+ pub is_visible: bool,
316
+ pub name: &'a str,
317
+ col_type: ColumnType,
318
+ }
319
+
320
+ impl<'a> PartialEq for OrderedColumn<'a> {
321
+ fn eq(&self, rhs: &OrderedColumn<'a>) -> bool {
322
+ self.col_type == rhs.col_type && self.name == rhs.name
323
+ }
324
+ }
325
+
326
+ impl Eq for OrderedColumn<'_> {}
327
+
328
+ impl<'a> PartialOrd for OrderedColumn<'a> {
329
+ fn partial_cmp(&self, rhs: &OrderedColumn<'a>) -> Option<std::cmp::Ordering> {
330
+ Some(self.cmp(rhs))
331
+ }
332
+ }
333
+
334
+ impl<'a> Ord for OrderedColumn<'a> {
335
+ fn cmp(&self, rhs: &OrderedColumn<'a>) -> std::cmp::Ordering {
336
+ self.col_type
337
+ .cmp(&rhs.col_type)
338
+ .then(self.name.cmp(rhs.name))
339
+ }
340
+ }
@@ -0,0 +1,157 @@
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::HashSet;
14
+
15
+ use futures::join;
16
+ use itertools::Itertools;
17
+ use perspective_client::ViewWindow;
18
+ use perspective_js::utils::ApiResult;
19
+ use wasm_bindgen::JsCast;
20
+ use wasm_bindgen_futures::JsFuture;
21
+
22
+ use super::export_app;
23
+ use super::export_method::*;
24
+ use super::get_viewer_config::*;
25
+ use super::structural::*;
26
+ use crate::config::*;
27
+ use crate::js::JsPerspectiveViewerPlugin;
28
+ use crate::utils::*;
29
+
30
+ fn tag_name_to_package(plugin: &JsPerspectiveViewerPlugin) -> String {
31
+ let tag_name = plugin.unchecked_ref::<web_sys::HtmlElement>().tag_name();
32
+ let tag_parts = tag_name.split('-').take(3).map(|x| x.to_lowercase());
33
+ Itertools::intersperse(tag_parts, "-".to_owned()).collect::<String>()
34
+ }
35
+
36
+ /// A model trait for Copy/Export UI task behavior,
37
+ ///
38
+ /// Export functionality, for downloads and copy-to-clipboard, are mostly shared
39
+ /// behavior, but require access to a few state objects depending on which
40
+ /// format is desired. The `CopyExportModel` groups this functionality in a
41
+ /// shared location, rather than distributing in the various state objects
42
+ /// that are relevent per-format.
43
+ pub trait CopyExportModel:
44
+ HasSession + HasRenderer + HasPresentation + GetViewerConfigModel
45
+ {
46
+ async fn html_as_jsvalue(&self) -> ApiResult<web_sys::Blob> {
47
+ let view_config = self.get_viewer_config();
48
+ let session = self.session().clone();
49
+ let plugins = self
50
+ .renderer()
51
+ .get_all_plugins()
52
+ .iter()
53
+ .map(tag_name_to_package)
54
+ .collect::<HashSet<String>>()
55
+ .into_iter()
56
+ .collect::<Vec<_>>();
57
+
58
+ let (arrow, config) = join!(session.arrow_as_vec(true, None), view_config);
59
+ let arrow = arrow?;
60
+ let mut config = config?;
61
+ config.settings = false;
62
+ let js_config = serde_json::to_string(&config)?;
63
+ let html = export_app::render(&base64::encode(arrow), &js_config, &plugins);
64
+ js_sys::JsString::from(html.trim()).as_blob()
65
+ }
66
+
67
+ /// Create a blob of this plugin's `.png` rendering by calling the
68
+ /// `Plugin::render` method dynamically (as it may not exist e.g. for
69
+ /// datagrid).
70
+ ///
71
+ /// # Errors
72
+ ///
73
+ /// It is assumed that `Plugin::render` exists on the plugin's Custom
74
+ /// Element.
75
+ async fn png_as_jsvalue(&self) -> ApiResult<web_sys::Blob> {
76
+ let renderer = self.renderer().clone();
77
+ let plugin = renderer.get_active_plugin()?;
78
+ let render = js_sys::Reflect::get(&plugin, js_intern::js_intern!("render"))?;
79
+ let render_fun = render.unchecked_into::<js_sys::Function>();
80
+ let png = render_fun.call0(&plugin)?;
81
+ let result = JsFuture::from(png.unchecked_into::<js_sys::Promise>())
82
+ .await?
83
+ .unchecked_into();
84
+ Ok(result)
85
+ }
86
+
87
+ async fn txt_as_jsvalue(&self, viewport: Option<ViewWindow>) -> ApiResult<web_sys::Blob> {
88
+ let renderer = self.renderer().clone();
89
+ let plugin = renderer.get_active_plugin()?;
90
+ let render = js_sys::Reflect::get(&plugin, js_intern::js_intern!("render"))?;
91
+ let render_fun = render.unchecked_into::<js_sys::Function>();
92
+ let txt = render_fun.call1(&plugin, &serde_wasm_bindgen::to_value(&viewport)?)?;
93
+ let result = JsFuture::from(txt.unchecked_into::<js_sys::Promise>())
94
+ .await?
95
+ .unchecked_into();
96
+ Ok(result)
97
+ }
98
+
99
+ /// Generate a result `Blob` for all types of `ExportMethod`.
100
+ async fn export_method_to_jsvalue(&self, method: ExportMethod) -> ApiResult<web_sys::Blob> {
101
+ let viewport = self.renderer().get_selection();
102
+
103
+ match method {
104
+ ExportMethod::Csv => self.session().csv_as_jsvalue(false, None).await?.as_blob(),
105
+ ExportMethod::CsvSelected => self
106
+ .session()
107
+ .csv_as_jsvalue(false, viewport)
108
+ .await?
109
+ .as_blob(),
110
+ ExportMethod::CsvAll => self.session().csv_as_jsvalue(true, None).await?.as_blob(),
111
+ ExportMethod::Json => self.session().json_as_jsvalue(false, None).await?.as_blob(),
112
+ ExportMethod::JsonSelected => self
113
+ .session()
114
+ .json_as_jsvalue(false, viewport)
115
+ .await?
116
+ .as_blob(),
117
+ ExportMethod::JsonAll => self.session().json_as_jsvalue(true, None).await?.as_blob(),
118
+ ExportMethod::Ndjson => self
119
+ .session()
120
+ .ndjson_as_jsvalue(false, None)
121
+ .await?
122
+ .as_blob(),
123
+ ExportMethod::NdjsonSelected => self
124
+ .session()
125
+ .ndjson_as_jsvalue(false, viewport)
126
+ .await?
127
+ .as_blob(),
128
+ ExportMethod::NdjsonAll => self
129
+ .session()
130
+ .ndjson_as_jsvalue(true, None)
131
+ .await?
132
+ .as_blob(),
133
+ ExportMethod::Arrow => self
134
+ .session()
135
+ .arrow_as_jsvalue(false, None)
136
+ .await?
137
+ .as_blob(),
138
+ ExportMethod::ArrowSelected => self
139
+ .session()
140
+ .arrow_as_jsvalue(false, viewport)
141
+ .await?
142
+ .as_blob(),
143
+ ExportMethod::ArrowAll => self.session().arrow_as_jsvalue(true, None).await?.as_blob(),
144
+ ExportMethod::Html => self.html_as_jsvalue().await,
145
+ ExportMethod::Plugin if self.renderer().is_chart() => self.png_as_jsvalue().await,
146
+ ExportMethod::Plugin => self.txt_as_jsvalue(viewport).await,
147
+ ExportMethod::JsonConfig => self
148
+ .get_viewer_config()
149
+ .await?
150
+ .encode(&Some(ViewerConfigEncoding::JSONString))?
151
+ .dyn_into::<js_sys::JsString>()?
152
+ .as_blob(),
153
+ }
154
+ }
155
+ }
156
+
157
+ impl<T: HasRenderer + HasSession + HasPresentation> CopyExportModel for T {}
@@ -0,0 +1,59 @@
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 itertools::Itertools;
14
+
15
+ use super::{HasPresentation, HasRenderer, HasSession, UpdateAndRender};
16
+ use crate::config::{Expression, ViewConfigUpdate};
17
+ use crate::utils::ApiFuture;
18
+
19
+ pub trait CreateColumn: HasSession + HasPresentation + HasRenderer + UpdateAndRender {
20
+ fn clone_column(&self, name: &str, in_place: bool, open_settings: bool) -> ApiFuture<()> {
21
+ // 1. Create a new expression.
22
+ let expr_name = self.session().metadata().make_new_column_name(Some(name));
23
+ let expr = Expression::new(Some(&expr_name), &format!("\"{name}\""));
24
+ let view_config = self.session().get_view_config();
25
+ let mut serde_exprs = view_config.expressions.clone();
26
+ serde_exprs.retain(|name, _expr| name != &expr_name);
27
+ serde_exprs.insert(&expr);
28
+
29
+ // 2. Replace this column in the view configuration.
30
+ let mut cols = view_config.columns.clone();
31
+ if in_place {
32
+ let (idx, _val) = cols
33
+ .iter()
34
+ .find_position(|c| c.as_ref().map(|s| s == name).unwrap_or_default())
35
+ .unwrap_or_else(|| {
36
+ web_sys::console::error_1(
37
+ &format!("Couldn't find {name} in view config!").into(),
38
+ );
39
+ panic!();
40
+ });
41
+ cols[idx] = Some(expr_name.clone());
42
+ }
43
+
44
+ // 3. Ensure that the new column is opened
45
+ if open_settings {
46
+ self.presentation()
47
+ .set_open_column_settings(Some(expr_name));
48
+ }
49
+
50
+ // 4. Update
51
+ drop(view_config);
52
+ self.update_and_render(ViewConfigUpdate {
53
+ expressions: Some(serde_exprs),
54
+ columns: Some(cols),
55
+ ..Default::default()
56
+ })
57
+ }
58
+ }
59
+ impl<T: HasPresentation + HasSession + HasRenderer> CreateColumn for T {}
@@ -0,0 +1,95 @@
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::{Expression, ViewConfigUpdate};
14
+
15
+ use super::UpdateAndRender;
16
+ use super::structural::*;
17
+ use crate::components::column_settings_sidebar::ColumnSettingsTab;
18
+ use crate::components::viewer::ColumnLocator;
19
+ use crate::presentation::{OpenColumnSettings, Presentation};
20
+ use crate::renderer::Renderer;
21
+ use crate::session::Session;
22
+ use crate::*;
23
+
24
+ #[derive(PartialEq)]
25
+ pub struct ExpressionUpdater {
26
+ presentation: Presentation,
27
+ renderer: Renderer,
28
+ session: Session,
29
+ }
30
+ derive_model!(Presentation, Renderer, Session for ExpressionUpdater);
31
+
32
+ pub trait EditExpression: HasPresentation + HasRenderer + HasSession + UpdateAndRender {
33
+ fn get_expression_updater(&self) -> ExpressionUpdater {
34
+ ExpressionUpdater {
35
+ presentation: self.presentation().clone(),
36
+ renderer: self.renderer().clone(),
37
+ session: self.session().clone(),
38
+ }
39
+ }
40
+
41
+ /// Spawns a future which will update the expression.
42
+ fn update_expr(&self, old_name: String, new_expr: Expression<'static>) {
43
+ let this = self.get_expression_updater();
44
+ ApiFuture::spawn(async move {
45
+ let update = this
46
+ .session
47
+ .create_replace_expression_update(&old_name, &new_expr)
48
+ .await;
49
+
50
+ this.presentation
51
+ .set_open_column_settings(Some(OpenColumnSettings {
52
+ locator: Some(ColumnLocator::Expression(new_expr.name.to_string())),
53
+ tab: Some(ColumnSettingsTab::Attributes),
54
+ }));
55
+
56
+ this.update_and_render(update)?.await?;
57
+ Ok(())
58
+ });
59
+ }
60
+
61
+ /// Saves a new expression. Spawns a future.
62
+ fn save_expr(&self, expr: Expression) -> ApiResult<()> {
63
+ let task = {
64
+ let mut serde_exprs = self.session().get_view_config().expressions.clone();
65
+ serde_exprs.insert(&expr);
66
+ self.presentation()
67
+ .set_open_column_settings(Some(OpenColumnSettings {
68
+ locator: Some(ColumnLocator::Expression(expr.name.clone().into())),
69
+ tab: Some(ColumnSettingsTab::Attributes),
70
+ }));
71
+ self.update_and_render(ViewConfigUpdate {
72
+ expressions: Some(serde_exprs),
73
+ ..Default::default()
74
+ })
75
+ }?;
76
+
77
+ ApiFuture::spawn(task);
78
+ Ok(())
79
+ }
80
+
81
+ fn delete_expr(&self, expr_name: &str) -> ApiResult<()> {
82
+ let mut serde_exprs = self.session().get_view_config().expressions.clone();
83
+ serde_exprs.remove(expr_name);
84
+ let config = ViewConfigUpdate {
85
+ expressions: Some(serde_exprs),
86
+ ..ViewConfigUpdate::default()
87
+ };
88
+
89
+ let task = self.update_and_render(config)?;
90
+ ApiFuture::spawn(task);
91
+ Ok(())
92
+ }
93
+ }
94
+
95
+ impl<T: HasRenderer + HasSession + HasPresentation + UpdateAndRender> EditExpression for T {}