@perspective-dev/viewer 4.4.1 → 4.5.1

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 (227) hide show
  1. package/dist/cdn/perspective-viewer.js +1 -2
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/intl/de.css +1 -1
  9. package/dist/css/intl/es.css +1 -1
  10. package/dist/css/intl/fr.css +1 -1
  11. package/dist/css/intl/ja.css +1 -1
  12. package/dist/css/intl/pt.css +1 -1
  13. package/dist/css/intl/zh.css +1 -1
  14. package/dist/css/intl.css +1 -1
  15. package/dist/css/monokai.css +1 -1
  16. package/dist/css/phosphor.css +1 -1
  17. package/dist/css/pro-dark.css +1 -1
  18. package/dist/css/pro.css +1 -1
  19. package/dist/css/solarized-dark.css +1 -1
  20. package/dist/css/solarized.css +1 -1
  21. package/dist/css/themes.css +1 -1
  22. package/dist/css/vaporwave.css +1 -1
  23. package/dist/esm/bootstrap.d.ts +2 -1
  24. package/dist/esm/column-format.d.ts +51 -0
  25. package/dist/esm/extensions.d.ts +2 -0
  26. package/dist/esm/perspective-viewer.d.ts +3 -1
  27. package/dist/esm/perspective-viewer.inline.js +1 -2
  28. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  29. package/dist/esm/perspective-viewer.js +1 -2
  30. package/dist/esm/perspective-viewer.js.map +4 -4
  31. package/dist/esm/perspective-viewer.worker.d.ts +2 -0
  32. package/dist/esm/plugin.d.ts +16 -72
  33. package/dist/esm/ts-rs/ColumnSelectMode.d.ts +1 -0
  34. package/dist/esm/ts-rs/PluginStaticConfig.d.ts +77 -0
  35. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -3
  36. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -4
  37. package/dist/wasm/perspective-viewer.d.ts +77 -18
  38. package/dist/wasm/perspective-viewer.js +302 -148
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +20 -15
  41. package/package.json +24 -2
  42. package/src/css/column-selector.css +3 -2
  43. package/src/css/column-settings-panel.css +44 -9
  44. package/src/css/column-style.css +35 -2
  45. package/src/css/containers/scroll-panel.css +2 -1
  46. package/src/css/containers/tabs.css +8 -52
  47. package/src/css/dom/checkbox.css +2 -6
  48. package/src/css/form/code-editor.css +1 -0
  49. package/src/css/form/debug.css +3 -10
  50. package/src/css/plugin-selector.css +33 -0
  51. package/src/css/plugin-settings-panel.css +99 -0
  52. package/src/css/viewer.css +143 -3
  53. package/src/rust/components/column_dropdown.rs +3 -1
  54. package/src/rust/components/column_selector/active_column.rs +16 -19
  55. package/src/rust/components/column_selector/config_selector.rs +20 -20
  56. package/src/rust/components/column_selector/filter_column.rs +14 -14
  57. package/src/rust/components/column_selector/inactive_column.rs +10 -15
  58. package/src/rust/components/column_selector/pivot_column.rs +7 -7
  59. package/src/rust/components/column_selector/sort_column.rs +7 -7
  60. package/src/rust/components/column_selector.rs +55 -37
  61. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +15 -7
  62. package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +395 -0
  63. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +15 -6
  64. package/src/rust/components/column_settings_sidebar/style_tab.rs +267 -136
  65. package/src/rust/components/column_settings_sidebar.rs +44 -49
  66. package/src/rust/components/containers/dragdrop_list.rs +32 -5
  67. package/src/rust/components/containers/mod.rs +0 -1
  68. package/src/rust/components/containers/scroll_panel.rs +21 -7
  69. package/src/rust/components/containers/sidebar.rs +8 -6
  70. package/src/rust/components/containers/split_panel.rs +3 -3
  71. package/src/rust/components/containers/tab_list.rs +3 -9
  72. package/src/rust/components/copy_dropdown.rs +2 -3
  73. package/src/rust/components/datetime_column_style.rs +19 -81
  74. package/src/rust/components/editable_header.rs +17 -3
  75. package/src/rust/components/export_dropdown.rs +2 -3
  76. package/src/rust/components/expression_editor.rs +29 -17
  77. package/src/rust/components/filter_dropdown.rs +2 -1
  78. package/src/rust/components/form/color_range_selector.rs +14 -7
  79. package/src/rust/components/form/debug.rs +47 -37
  80. package/src/rust/components/main_panel.rs +24 -65
  81. package/src/rust/components/mod.rs +2 -1
  82. package/src/rust/components/number_series_style.rs +161 -0
  83. package/src/rust/components/plugin_tab.rs +221 -0
  84. package/src/rust/components/settings_panel.rs +181 -59
  85. package/src/rust/components/status_bar.rs +141 -174
  86. package/src/rust/components/status_indicator.rs +15 -22
  87. package/src/rust/components/string_column_style.rs +20 -82
  88. package/src/rust/components/style_controls/number_string_format.rs +14 -30
  89. package/src/rust/components/viewer.rs +169 -132
  90. package/src/rust/config/column_config_schema.rs +195 -0
  91. package/src/rust/config/columns_config.rs +4 -97
  92. package/src/rust/config/datetime_column_style.rs +0 -5
  93. package/src/rust/config/mod.rs +8 -2
  94. package/src/rust/config/number_series_style.rs +79 -0
  95. package/src/rust/config/plugin_static_config.rs +144 -0
  96. package/src/rust/config/string_column_style.rs +0 -5
  97. package/src/rust/config/viewer_config.rs +5 -6
  98. package/src/rust/custom_elements/copy_dropdown.rs +30 -18
  99. package/src/rust/custom_elements/debug_plugin.rs +1 -3
  100. package/src/rust/custom_elements/export_dropdown.rs +26 -18
  101. package/src/rust/custom_elements/viewer.rs +62 -73
  102. package/src/rust/custom_events.rs +181 -224
  103. package/src/rust/js/plugin.rs +45 -117
  104. package/src/rust/lib.rs +34 -5
  105. package/src/rust/presentation/drag_helpers.rs +206 -0
  106. package/src/rust/presentation/props.rs +8 -0
  107. package/src/rust/presentation.rs +256 -41
  108. package/src/rust/{tasks → queries}/column_locator.rs +17 -73
  109. package/src/rust/queries/column_values.rs +59 -0
  110. package/src/rust/{tasks → queries}/columns_iter_set.rs +11 -18
  111. package/src/rust/queries/exports.rs +96 -0
  112. package/src/rust/queries/fetch_column_stats.rs +94 -0
  113. package/src/rust/queries/get_viewer_config.rs +54 -0
  114. package/src/rust/queries/mod.rs +44 -0
  115. package/src/rust/queries/plugin_column_styles.rs +101 -0
  116. package/src/rust/{engines.rs → queries/validate_expression.rs} +26 -15
  117. package/src/rust/renderer/activate.rs +1 -0
  118. package/src/rust/renderer/limits.rs +9 -4
  119. package/src/rust/renderer/plugin_store.rs +12 -0
  120. package/src/rust/renderer/props.rs +28 -3
  121. package/src/rust/renderer/registry.rs +40 -15
  122. package/src/rust/renderer.rs +703 -60
  123. package/src/rust/session/column_defaults_update.rs +20 -28
  124. package/src/rust/session/drag_drop_update.rs +10 -10
  125. package/src/rust/session/metadata.rs +31 -16
  126. package/src/rust/session/props.rs +15 -6
  127. package/src/rust/session/view_subscription.rs +10 -0
  128. package/src/rust/session.rs +109 -147
  129. package/src/rust/tasks/copy_export.rs +178 -158
  130. package/src/rust/tasks/{structural.rs → dismiss_render_warning.rs} +20 -40
  131. package/src/rust/tasks/edit_expression.rs +68 -88
  132. package/src/rust/tasks/eject.rs +25 -22
  133. package/src/rust/tasks/intersection_observer.rs +8 -21
  134. package/src/rust/tasks/mod.rs +19 -21
  135. package/src/rust/tasks/reset_all.rs +98 -0
  136. package/src/rust/tasks/resize_observer.rs +11 -33
  137. package/src/rust/tasks/restore_and_render.rs +128 -90
  138. package/src/rust/tasks/{get_viewer_config.rs → send_column_config.rs} +39 -35
  139. package/src/rust/tasks/send_plugin_config.rs +33 -33
  140. package/src/rust/tasks/update_and_render.rs +75 -49
  141. package/src/rust/{components/containers/trap_door_panel.rs → tasks/update_theme.rs} +34 -33
  142. package/src/rust/tasks/validate_expression.rs +61 -0
  143. package/src/rust/utils/browser/selection.rs +4 -4
  144. package/src/rust/utils/mod.rs +0 -63
  145. package/src/svg/checkbox-checked-icon.svg +1 -1
  146. package/src/svg/checkbox-unchecked-icon.svg +1 -1
  147. package/src/svg/mega-menu-icons-density.svg +23 -0
  148. package/src/svg/mega-menu-icons-map-density.svg +24 -0
  149. package/src/svg/mega-menu-icons-map-line.svg +19 -0
  150. package/src/themes/botanical.css +27 -53
  151. package/src/themes/defaults.css +24 -36
  152. package/src/themes/dracula.css +36 -54
  153. package/src/themes/gruvbox-dark.css +39 -59
  154. package/src/themes/gruvbox.css +16 -28
  155. package/src/themes/icons.css +5 -0
  156. package/src/themes/intl/de.css +43 -6
  157. package/src/themes/intl/es.css +43 -6
  158. package/src/themes/intl/fr.css +43 -6
  159. package/src/themes/intl/ja.css +43 -6
  160. package/src/themes/intl/pt.css +43 -6
  161. package/src/themes/intl/zh.css +43 -6
  162. package/src/themes/intl.css +38 -4
  163. package/src/themes/monokai.css +45 -61
  164. package/src/themes/phosphor.css +20 -29
  165. package/src/themes/pro-dark.css +25 -34
  166. package/src/themes/solarized-dark.css +21 -36
  167. package/src/themes/solarized.css +13 -23
  168. package/src/themes/vaporwave.css +40 -74
  169. package/src/ts/bootstrap.ts +14 -3
  170. package/src/ts/column-format.ts +162 -0
  171. package/src/ts/extensions.ts +4 -0
  172. package/src/ts/perspective-viewer.ts +9 -1
  173. package/src/{rust/components/column_settings_sidebar/style_tab/stub.rs → ts/perspective-viewer.worker.ts} +2 -22
  174. package/src/ts/plugin.ts +25 -101
  175. package/src/ts/ts-rs/{FormatUnit.ts → ColumnSelectMode.ts} +1 -1
  176. package/src/ts/ts-rs/PluginStaticConfig.ts +78 -0
  177. package/src/ts/ts-rs/ViewerConfig.ts +1 -2
  178. package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -3
  179. package/dist/esm/ts-rs/ColumnConfigValues.d.ts +0 -31
  180. package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +0 -1
  181. package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +0 -15
  182. package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +0 -18
  183. package/dist/esm/ts-rs/DatetimeColorMode.d.ts +0 -1
  184. package/dist/esm/ts-rs/DatetimeFormatType.d.ts +0 -6
  185. package/dist/esm/ts-rs/FormatMode.d.ts +0 -1
  186. package/dist/esm/ts-rs/FormatUnit.d.ts +0 -1
  187. package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +0 -1
  188. package/dist/esm/ts-rs/NumberForegroundMode.d.ts +0 -1
  189. package/dist/esm/ts-rs/PluginConfig.d.ts +0 -2
  190. package/dist/esm/ts-rs/RoundingMode.d.ts +0 -1
  191. package/dist/esm/ts-rs/RoundingPriority.d.ts +0 -1
  192. package/dist/esm/ts-rs/SignDisplay.d.ts +0 -1
  193. package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +0 -1
  194. package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +0 -6
  195. package/dist/esm/ts-rs/StringColorMode.d.ts +0 -1
  196. package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +0 -1
  197. package/dist/esm/ts-rs/UseGrouping.d.ts +0 -1
  198. package/src/rust/components/number_column_style.rs +0 -491
  199. package/src/rust/config/number_column_style.rs +0 -136
  200. package/src/rust/dragdrop.rs +0 -481
  201. package/src/rust/tasks/plugin_column_styles.rs +0 -98
  202. package/src/ts/ts-rs/ColumnConfigValues.ts +0 -14
  203. package/src/ts/ts-rs/CustomDatetimeFormat.ts +0 -3
  204. package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +0 -5
  205. package/src/ts/ts-rs/CustomNumberFormatConfig.ts +0 -8
  206. package/src/ts/ts-rs/DatetimeColorMode.ts +0 -3
  207. package/src/ts/ts-rs/DatetimeFormatType.ts +0 -8
  208. package/src/ts/ts-rs/FormatMode.ts +0 -3
  209. package/src/ts/ts-rs/NumberBackgroundMode.ts +0 -3
  210. package/src/ts/ts-rs/NumberForegroundMode.ts +0 -3
  211. package/src/ts/ts-rs/PluginConfig.ts +0 -4
  212. package/src/ts/ts-rs/RoundingMode.ts +0 -3
  213. package/src/ts/ts-rs/RoundingPriority.ts +0 -3
  214. package/src/ts/ts-rs/SignDisplay.ts +0 -3
  215. package/src/ts/ts-rs/SimpleDatetimeFormat.ts +0 -3
  216. package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +0 -4
  217. package/src/ts/ts-rs/StringColorMode.ts +0 -3
  218. package/src/ts/ts-rs/TrailingZeroDisplay.ts +0 -3
  219. package/src/ts/ts-rs/UseGrouping.ts +0 -3
  220. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline0.js +0 -0
  221. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline1.js +0 -0
  222. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline2.js +0 -0
  223. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline3.js +0 -0
  224. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline4.js +0 -0
  225. /package/src/rust/{tasks → config}/export_method.rs +0 -0
  226. /package/src/rust/{tasks → queries}/export_app.rs +0 -0
  227. /package/src/rust/{tasks → queries}/is_invalid_drop.rs +0 -0
@@ -10,105 +10,12 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- use std::collections::HashMap;
13
+ //! Auxiliary types used by `ColumnConfigSchema`'s composite control
14
+ //! variants. Per-column persisted state itself is opaque
15
+ //! `serde_json::Map<String, serde_json::Value>`; see
16
+ //! [`crate::presentation::ColumnConfigMap`].
14
17
 
15
18
  use serde::{Deserialize, Serialize};
16
- use ts_rs::TS;
17
-
18
- use super::{
19
- CustomNumberFormatConfig, DatetimeColumnStyleConfig, DatetimeColumnStyleDefaultConfig,
20
- NumberColumnStyleConfig, NumberColumnStyleDefaultConfig, StringColumnStyleConfig,
21
- StringColumnStyleDefaultConfig,
22
- };
23
-
24
- fn is_zero(x: &u32) -> bool {
25
- x == &0
26
- }
27
-
28
- /// The value de/serialized and stored in the viewer config.
29
- /// Also passed to the plugin via `plugin.save()`.
30
- #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, TS)]
31
- pub struct ColumnConfigValues {
32
- #[serde(default)]
33
- #[serde(skip_serializing_if = "HashMap::is_empty")]
34
- pub symbols: HashMap<String, String>,
35
-
36
- #[serde(flatten)]
37
- pub datagrid_number_style: NumberColumnStyleConfig,
38
-
39
- #[serde(flatten)]
40
- pub datagrid_string_style: StringColumnStyleConfig,
41
-
42
- #[serde(flatten)]
43
- pub datagrid_datetime_style: DatetimeColumnStyleConfig,
44
-
45
- #[serde(default)]
46
- #[serde(skip_serializing_if = "Option::is_none")]
47
- pub number_format: Option<CustomNumberFormatConfig>,
48
-
49
- #[serde(default)]
50
- #[serde(skip_serializing_if = "is_zero")]
51
- pub aggregate_depth: u32,
52
- }
53
-
54
- #[derive(Debug)]
55
- pub enum ColumnConfigValueUpdate {
56
- DatagridNumberStyle(Option<NumberColumnStyleConfig>),
57
- DatagridStringStyle(Option<StringColumnStyleConfig>),
58
- DatagridDatetimeStyle(Option<DatetimeColumnStyleConfig>),
59
- Symbols(Option<HashMap<String, String>>),
60
- CustomNumberStringFormat(Option<CustomNumberFormatConfig>),
61
- AggregateDepth(u32),
62
- }
63
-
64
- impl ColumnConfigValues {
65
- pub fn update(self, update: ColumnConfigValueUpdate) -> Self {
66
- match update {
67
- ColumnConfigValueUpdate::DatagridNumberStyle(update) => Self {
68
- datagrid_number_style: update.unwrap_or_default(),
69
- ..self
70
- },
71
- ColumnConfigValueUpdate::DatagridStringStyle(update) => Self {
72
- datagrid_string_style: update.unwrap_or_default(),
73
- ..self
74
- },
75
- ColumnConfigValueUpdate::DatagridDatetimeStyle(update) => Self {
76
- datagrid_datetime_style: update.unwrap_or_default(),
77
- ..self
78
- },
79
- ColumnConfigValueUpdate::Symbols(update) => Self {
80
- symbols: update.unwrap_or_default(),
81
- ..self
82
- },
83
- ColumnConfigValueUpdate::CustomNumberStringFormat(update) => Self {
84
- number_format: update.filter(|x| x != &CustomNumberFormatConfig::default()),
85
- ..self
86
- },
87
- ColumnConfigValueUpdate::AggregateDepth(aggregate_depth) => Self {
88
- aggregate_depth,
89
- ..self
90
- },
91
- }
92
- }
93
-
94
- pub fn is_empty(&self) -> bool {
95
- self == &Self::default()
96
- }
97
- }
98
-
99
- /// The controls returned by plugin.column_style_controls.
100
- ///
101
- /// This is a way to fill out default values for the given controls.
102
- /// If a control is not given, it will not be rendered. I would like to
103
- /// eventually show these as inactive values.
104
- #[derive(Serialize, Deserialize, PartialEq, Debug, Default)]
105
- pub struct ColumnStyleOpts {
106
- pub datagrid_number_style: Option<NumberColumnStyleDefaultConfig>,
107
- pub datagrid_string_style: Option<StringColumnStyleDefaultConfig>,
108
- pub datagrid_datetime_style: Option<DatetimeColumnStyleDefaultConfig>,
109
- pub symbols: Option<KeyValueOpts>,
110
- pub number_string_format: Option<bool>,
111
- }
112
19
 
113
20
  #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
114
21
  #[serde(rename_all = "snake_case")]
@@ -92,8 +92,3 @@ impl Default for DatetimeColumnStyleConfig {
92
92
  }
93
93
  }
94
94
  }
95
-
96
- #[derive(Clone, Default, Deserialize, Eq, PartialEq, Serialize, Debug)]
97
- pub struct DatetimeColumnStyleDefaultConfig {
98
- pub color: String,
99
- }
@@ -13,19 +13,25 @@
13
13
  //! A collection of (de-)serializable structs which capture the application
14
14
  //! state, suitable for persistence, history, etc. features.
15
15
 
16
+ mod column_config_schema;
16
17
  mod columns_config;
17
18
  mod datetime_column_style;
19
+ mod export_method;
18
20
  mod kvpair;
19
- mod number_column_style;
21
+ mod number_series_style;
20
22
  mod number_string_format;
23
+ mod plugin_static_config;
21
24
  mod string_column_style;
22
25
  pub mod view_config;
23
26
  mod viewer_config;
24
27
 
28
+ pub use column_config_schema::*;
25
29
  pub use columns_config::*;
26
30
  pub use datetime_column_style::*;
27
- pub use number_column_style::*;
31
+ pub use export_method::*;
32
+ pub use number_series_style::*;
28
33
  pub use number_string_format::*;
34
+ pub use plugin_static_config::*;
29
35
  pub use string_column_style::*;
30
36
  pub use view_config::*;
31
37
  pub use viewer_config::*;
@@ -0,0 +1,79 @@
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 serde::{Deserialize, Serialize};
14
+ use strum::{Display, EnumIter};
15
+ use ts_rs::TS;
16
+
17
+ /// Render glyph for a numeric aggregate in the Y Bar plugin. Serialized as
18
+ /// a lowercase string to match the plugin's runtime lookup (which does a
19
+ /// case-insensitive `chart_type` match against the same literal set).
20
+ #[derive(
21
+ Clone, Copy, Debug, Default, Deserialize, Display, EnumIter, Eq, PartialEq, Serialize, TS,
22
+ )]
23
+ pub enum ChartType {
24
+ #[default]
25
+ #[serde(rename = "bar")]
26
+ Bar,
27
+
28
+ #[serde(rename = "line")]
29
+ Line,
30
+
31
+ #[serde(rename = "scatter")]
32
+ Scatter,
33
+
34
+ #[serde(rename = "area")]
35
+ Area,
36
+ }
37
+
38
+ impl ChartType {
39
+ pub fn is_default(&self) -> bool {
40
+ *self == Self::Bar
41
+ }
42
+
43
+ /// Glyphs for which `stack` is a meaningful option. Line/Scatter never
44
+ /// stack; Bar/Area stack by default but can be opted out per column.
45
+ pub fn supports_stack(&self) -> bool {
46
+ matches!(self, Self::Bar | Self::Area)
47
+ }
48
+ }
49
+
50
+ /// Per-column render-style config for numeric aggregates in series charts
51
+ /// (currently Y Bar). Stored flat in the column's
52
+ /// `serde_json::Map<String, serde_json::Value>`, so the JSON shape at the
53
+ /// viewer boundary is `{ "chart_type": "line", "stack": false }`.
54
+ ///
55
+ /// Default `Bar` + `None` stack serializes as an empty object so plugins
56
+ /// that never touch these fields don't pay any JSON overhead.
57
+ #[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, TS)]
58
+ pub struct NumberSeriesStyleConfig {
59
+ #[serde(default)]
60
+ #[serde(skip_serializing_if = "ChartType::is_default")]
61
+ pub chart_type: ChartType,
62
+
63
+ /// Stack override. `None` means "use the glyph default"
64
+ /// (Bar/Area stack, Line/Scatter don't). `Some(false)` on a Bar/Area
65
+ /// forces non-stacking.
66
+ #[serde(default)]
67
+ #[serde(skip_serializing_if = "Option::is_none")]
68
+ pub stack: Option<bool>,
69
+ }
70
+
71
+ /// Defaults-only shape carried by `ControlSpec::NumberSeriesStyle`. The
72
+ /// presence of this control in a plugin's `column_config_schema` is the
73
+ /// signal for the sidebar to render the chart-type picker.
74
+ #[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq)]
75
+ pub struct NumberSeriesStyleDefaultConfig {
76
+ pub chart_type: ChartType,
77
+ #[serde(default)]
78
+ pub stack: Option<bool>,
79
+ }
@@ -0,0 +1,144 @@
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::GroupRollupMode;
14
+ use serde::Deserialize;
15
+ use ts_rs::TS;
16
+
17
+ #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, TS)]
18
+ #[serde(rename_all = "camelCase")]
19
+ pub enum ColumnSelectMode {
20
+ #[default]
21
+ Toggle,
22
+ Select,
23
+ }
24
+
25
+ impl ColumnSelectMode {
26
+ pub fn css(&self) -> yew::Classes {
27
+ match self {
28
+ Self::Toggle => yew::classes!("toggle-mode", "is_column_active"),
29
+ Self::Select => yew::classes!("select-mode", "is_column_active"),
30
+ }
31
+ }
32
+ }
33
+
34
+ /// Static, immutable configuration for a plugin.
35
+ ///
36
+ /// Returned once per plugin from `get_static_config()` at registration
37
+ /// time and cached in [`crate::renderer::PluginRecord`]. Consumers
38
+ /// (renderer, session, queries, components) read these fields off the
39
+ /// renderer's active-plugin metadata rather than calling back into JS.
40
+ ///
41
+ /// `<perspective-viewer>` reads this exactly once per plugin (at
42
+ /// `registerPlugin` time) and caches it for the lifetime of the
43
+ /// application. The result must be stable; do not mutate any field
44
+ /// after registration.
45
+ #[derive(Clone, Debug, Default, Deserialize, PartialEq, TS)]
46
+ pub struct PluginStaticConfig {
47
+ /// The unique key for this plugin. Used as the `plugin` field in a
48
+ /// `ViewerConfig` and as the display name key in the
49
+ /// `<perspective-viewer>` UI.
50
+ pub name: String,
51
+
52
+ /// Category in the plugin picker menu.
53
+ #[serde(default)]
54
+ #[ts(as = "Option<_>")]
55
+ #[ts(optional)]
56
+ pub category: Option<String>,
57
+
58
+ /// Soft limit on the number of columns the plugin will render.
59
+ /// Triggers the "Rendering N of M" warning when the view exceeds
60
+ /// this value (until dismissed).
61
+ #[serde(default)]
62
+ #[ts(as = "Option<_>")]
63
+ #[ts(optional)]
64
+ pub max_columns: Option<usize>,
65
+
66
+ /// Soft limit on the number of cells (rows × columns) the plugin
67
+ /// will render. Triggers the "Rendering N of M" warning when the view
68
+ /// exceeds this value (until dismissed).
69
+ #[serde(default)]
70
+ #[ts(as = "Option<_>")]
71
+ #[ts(optional)]
72
+ pub max_cells: Option<usize>,
73
+
74
+ /// Column add/remove behavior. `"select"` exclusively selects the
75
+ /// added column, removing other columns. `"toggle"` toggles the
76
+ /// column on or off based on its current state, leaving other
77
+ /// columns alone.
78
+ #[serde(default)]
79
+ #[ts(as = "Option<_>")]
80
+ #[ts(optional)]
81
+ pub select_mode: ColumnSelectMode,
82
+
83
+ /// Minimum number of columns the plugin requires to render. Mostly
84
+ /// affects drag/drop and column-remove button behavior. `undefined`
85
+ /// is treated identically to `1`.
86
+ #[serde(default)]
87
+ #[ts(as = "Option<_>")]
88
+ #[ts(optional)]
89
+ pub min_config_columns: Option<usize>,
90
+
91
+ /// Named column slots. Named columns have replace/swap behavior in
92
+ /// drag/drop rather than insert. The length must be at least
93
+ /// `min_config_columns`.
94
+ #[serde(default)]
95
+ #[ts(as = "Option<_>")]
96
+ #[ts(optional)]
97
+ pub config_column_names: Vec<String>,
98
+
99
+ /// Group-rollup modes the plugin accepts, in preference order.
100
+ /// The first entry that matches a feature flag becomes the default.
101
+ #[serde(default)]
102
+ #[ts(as = "Option<_>")]
103
+ #[ts(optional)]
104
+ pub group_rollup_modes: Option<Vec<GroupRollupMode>>,
105
+
106
+ /// Plugin load priority. Higher numbers win; ties resolve in
107
+ /// registration order. The highest-priority plugin is loaded by
108
+ /// default unless `restore({ plugin })` overrides it.
109
+ #[serde(default)]
110
+ #[ts(as = "Option<_>")]
111
+ #[ts(optional)]
112
+ pub priority: Option<i32>,
113
+
114
+ /// Whether this plugin opts into per-column style controls in the
115
+ /// settings sidebar. When `true`, the StyleTab is shown for active
116
+ /// columns and the plugin's `column_config_schema` is queried for
117
+ /// the per-column field set. When `false` or omitted, no StyleTab
118
+ /// is shown.
119
+ #[serde(default)]
120
+ #[ts(as = "Option<_>")]
121
+ #[ts(optional)]
122
+ pub can_render_column_styles: bool,
123
+ }
124
+
125
+ impl PluginStaticConfig {
126
+ /// `true` if dropping a column at `index` should swap with the
127
+ /// column already there rather than insert. Only the named slots
128
+ /// (`config_column_names[..len()-1]`) participate in swap behaviour;
129
+ /// the trailing unnamed tail inserts.
130
+ pub fn is_swap(&self, index: usize) -> bool {
131
+ !self.config_column_names.is_empty() && index < self.config_column_names.len() - 1
132
+ }
133
+
134
+ pub fn get_group_rollups(&self, rollup_features: &[GroupRollupMode]) -> Vec<GroupRollupMode> {
135
+ self.group_rollup_modes
136
+ .clone()
137
+ .map(|x| {
138
+ x.into_iter()
139
+ .filter(|y| rollup_features.is_empty() || rollup_features.contains(y))
140
+ .collect()
141
+ })
142
+ .unwrap_or_default()
143
+ }
144
+ }
@@ -133,8 +133,3 @@ pub struct StringColumnStyleConfig {
133
133
  #[serde(default)]
134
134
  pub color: Option<String>,
135
135
  }
136
-
137
- #[derive(Debug, Clone, Default, Deserialize, Eq, PartialEq, Serialize)]
138
- pub struct StringColumnStyleDefaultConfig {
139
- pub color: String,
140
- }
@@ -10,7 +10,6 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- use std::collections::HashMap;
14
13
  use std::ops::Deref;
15
14
  use std::sync::LazyLock;
16
15
 
@@ -21,8 +20,7 @@ use serde_json::Value;
21
20
  use ts_rs::TS;
22
21
  use wasm_bindgen::prelude::*;
23
22
 
24
- use super::ColumnConfigValues;
25
- use crate::presentation::ColumnConfigMap;
23
+ use crate::renderer::ColumnConfigMap;
26
24
 
27
25
  /// The state of an entire `custom_elements::PerspectiveViewerElement` component
28
26
  /// and its `Plugin`.
@@ -32,7 +30,7 @@ pub struct ViewerConfig<V: TS = String> {
32
30
  pub version: V,
33
31
  pub columns_config: ColumnConfigMap,
34
32
  pub plugin: String,
35
- pub plugin_config: Value,
33
+ pub plugin_config: serde_json::Map<String, Value>,
36
34
  pub settings: bool,
37
35
  pub table: Option<String>,
38
36
  pub theme: Option<String>,
@@ -106,7 +104,7 @@ pub struct ViewerConfigUpdate {
106
104
  #[serde(default)]
107
105
  #[ts(as = "Option<_>")]
108
106
  #[ts(optional)]
109
- pub plugin_config: Option<PluginConfig>,
107
+ pub plugin_config: PluginConfigUpdate,
110
108
 
111
109
  #[serde(default)]
112
110
  #[ts(as = "Option<_>")]
@@ -162,7 +160,8 @@ pub type ThemeUpdate = OptionalUpdate<String>;
162
160
  pub type TitleUpdate = OptionalUpdate<String>;
163
161
  pub type TableUpdate = OptionalUpdate<String>;
164
162
  pub type VersionUpdate = OptionalUpdate<String>;
165
- pub type ColumnConfigUpdate = OptionalUpdate<HashMap<String, ColumnConfigValues>>;
163
+ pub type ColumnConfigUpdate = OptionalUpdate<ColumnConfigMap>;
164
+ pub type PluginConfigUpdate = OptionalUpdate<serde_json::Map<String, Value>>;
166
165
 
167
166
  /// Handles `{}` when included as a field with `#[serde(default)]`.
168
167
  impl<T: Clone> Default for OptionalUpdate<T> {
@@ -23,8 +23,11 @@ use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::copy_dropdown::CopyDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
25
  use crate::components::style::StyleProvider;
26
+ use crate::config::*;
26
27
  use crate::js::*;
28
+ use crate::presentation::Presentation;
27
29
  use crate::renderer::*;
30
+ use crate::session::Session;
28
31
  use crate::tasks::*;
29
32
  use crate::utils::*;
30
33
  use crate::*;
@@ -130,57 +133,66 @@ impl CopyDropDownMenuElement {
130
133
  }
131
134
 
132
135
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
133
- self.set_config_model(parent)
136
+ self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
134
137
  }
135
138
 
136
139
  pub fn connected_callback(&self) {}
137
140
  }
138
141
 
139
142
  impl CopyDropDownMenuElement {
140
- pub fn new_from_model<A>(model: &A) -> Self
141
- where
142
- A: GetViewerConfigModel + StateProvider,
143
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
144
- {
143
+ pub fn new_from_model(
144
+ session: &Session,
145
+ renderer: &Renderer,
146
+ presentation: &Presentation,
147
+ ) -> Self {
145
148
  let dropdown = global::document()
146
149
  .create_element("perspective-copy-menu")
147
150
  .unwrap()
148
151
  .unchecked_into::<HtmlElement>();
149
152
 
150
153
  let elem = Self::new(dropdown);
151
- elem.set_config_model(model);
154
+ elem.set_config_model(session, renderer, presentation);
152
155
  elem
153
156
  }
154
157
 
155
- pub fn set_config_model<A>(&self, model: &A)
156
- where
157
- A: GetViewerConfigModel + StateProvider,
158
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
159
- {
158
+ pub fn set_config_model(
159
+ &self,
160
+ session: &Session,
161
+ renderer: &Renderer,
162
+ presentation: &Presentation,
163
+ ) {
160
164
  let callback = Callback::from({
161
- let model = model.clone_state();
165
+ let session = session.clone();
166
+ let renderer = renderer.clone();
167
+ let presentation = presentation.clone();
162
168
  let target = self.target.clone();
163
169
  let root = self.root.clone();
164
170
  move |x: ExportFile| {
165
- let model = model.clone();
171
+ let session = session.clone();
172
+ let renderer = renderer.clone();
173
+ let presentation = presentation.clone();
166
174
  let target = target.clone();
167
175
  let root = root.clone();
168
176
  spawn_local(async move {
169
177
  let mime = x.method.mimetype(x.is_chart);
170
- let task = model.export_method_to_blob(x.method);
178
+ let task = export_method_to_blob(&session, &renderer, &presentation, x.method);
171
179
  let result = copy_to_clipboard(task, mime).await;
172
- crate::maybe_log!({
180
+ let r = (|| -> ApiResult<()> {
173
181
  result?;
174
182
  *target.borrow_mut() = None;
175
183
  if let Some(root) = root.borrow().as_ref() {
176
184
  root.send_message(CopyDropDownWrapperMsg::Close);
177
185
  }
178
- })
186
+ Ok(())
187
+ })();
188
+ if let Err(e) = r {
189
+ web_sys::console::warn_1(&e.into());
190
+ }
179
191
  })
180
192
  }
181
193
  });
182
194
 
183
- let renderer = model.renderer().clone();
195
+ let renderer = renderer.clone();
184
196
  let init = ShadowRootInit::new(ShadowRootMode::Open);
185
197
  let shadow_root = self
186
198
  .elem
@@ -93,9 +93,7 @@ impl PerspectiveDebugPluginElement {
93
93
  ApiFuture::default()
94
94
  }
95
95
 
96
- pub fn restyle(&self) -> ApiFuture<()> {
97
- ApiFuture::default()
98
- }
96
+ pub fn restyle(&self) {}
99
97
 
100
98
  pub fn save(&self) -> ApiResult<JsValue> {
101
99
  Ok(JsValue::null())
@@ -23,6 +23,8 @@ use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::export_dropdown::ExportDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
25
  use crate::components::style::StyleProvider;
26
+ use crate::config::*;
27
+ use crate::presentation::Presentation;
26
28
  use crate::renderer::*;
27
29
  use crate::session::*;
28
30
  use crate::tasks::*;
@@ -132,43 +134,49 @@ impl ExportDropDownMenuElement {
132
134
  }
133
135
 
134
136
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
135
- self.set_config_model(parent)
137
+ self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
136
138
  }
137
139
 
138
140
  pub fn connected_callback(&self) {}
139
141
  }
140
142
 
141
143
  impl ExportDropDownMenuElement {
142
- pub fn new_from_model<A>(model: &A) -> Self
143
- where
144
- A: GetViewerConfigModel + StateProvider,
145
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
146
- {
144
+ pub fn new_from_model(
145
+ session: &Session,
146
+ renderer: &Renderer,
147
+ presentation: &Presentation,
148
+ ) -> Self {
147
149
  let dropdown = global::document()
148
150
  .create_element("perspective-export-menu")
149
151
  .unwrap()
150
152
  .unchecked_into::<HtmlElement>();
151
153
 
152
154
  let elem = Self::new(dropdown);
153
- elem.set_config_model(model);
155
+ elem.set_config_model(session, renderer, presentation);
154
156
  elem
155
157
  }
156
158
 
157
- fn set_config_model<A>(&self, model: &A)
158
- where
159
- A: GetViewerConfigModel + StateProvider,
160
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
161
- {
159
+ fn set_config_model(
160
+ &self,
161
+ session: &Session,
162
+ renderer: &Renderer,
163
+ presentation: &Presentation,
164
+ ) {
162
165
  let callback = Callback::from({
163
- let model = model.clone_state();
166
+ let session = session.clone();
167
+ let renderer = renderer.clone();
168
+ let presentation = presentation.clone();
164
169
  let target = self.target.clone();
165
170
  let root = self.root.clone();
166
171
  move |x: ExportFile| {
167
172
  if !x.name.is_empty() {
168
- clone!(target, root, model);
173
+ clone!(target, root, session, renderer, presentation);
169
174
  spawn_local(async move {
170
- let val = model.export_method_to_blob(x.method).await.unwrap();
171
- let is_chart = model.renderer().is_chart();
175
+ let val =
176
+ export_method_to_blob(&session, &renderer, &presentation, x.method)
177
+ .await
178
+ .unwrap();
179
+ let is_chart = renderer.is_chart();
172
180
  download(&x.as_filename(is_chart), &val).unwrap();
173
181
  *target.borrow_mut() = None;
174
182
  if let Some(root) = root.borrow().as_ref() {
@@ -179,8 +187,8 @@ impl ExportDropDownMenuElement {
179
187
  }
180
188
  });
181
189
 
182
- let renderer = model.renderer().clone();
183
- let session = model.session().clone();
190
+ let renderer = renderer.clone();
191
+ let session = session.clone();
184
192
  let init = ShadowRootInit::new(ShadowRootMode::Open);
185
193
  let shadow_root = self
186
194
  .elem