@perspective-dev/viewer 4.3.0 → 4.4.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 (227) hide show
  1. package/dist/cdn/perspective-viewer.js +2 -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/pro-dark.css +1 -1
  17. package/dist/css/pro.css +1 -1
  18. package/dist/css/solarized-dark.css +1 -1
  19. package/dist/css/solarized.css +1 -1
  20. package/dist/css/themes.css +1 -1
  21. package/dist/css/vaporwave.css +1 -1
  22. package/dist/esm/perspective-viewer.inline.js +2 -2
  23. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  24. package/dist/esm/perspective-viewer.js +2 -2
  25. package/dist/esm/perspective-viewer.js.map +4 -4
  26. package/dist/wasm/perspective-viewer.d.ts +57 -53
  27. package/dist/wasm/perspective-viewer.js +190 -165
  28. package/dist/wasm/perspective-viewer.wasm +0 -0
  29. package/dist/wasm/perspective-viewer.wasm.d.ts +17 -18
  30. package/package.json +7 -5
  31. package/src/{less/aggregate-selector.less → css/aggregate-selector.css} +23 -20
  32. package/src/css/column-dropdown.css +109 -0
  33. package/src/{less/column-selector.less → css/column-selector.css} +160 -158
  34. package/src/{less/column-settings-panel.less → css/column-settings-panel.css} +69 -59
  35. package/src/{less/column-style.less → css/column-style.css} +52 -66
  36. package/src/{less/column-symbol-attributes.less → css/column-symbol-attributes.css} +15 -14
  37. package/src/{less/config-selector.less → css/config-selector.css} +151 -135
  38. package/src/{less/containers/dropdown-menu.less → css/containers/dropdown-menu.css} +20 -19
  39. package/src/{less/containers/pairs-list.less → css/containers/pairs-list.css} +13 -12
  40. package/src/{themes/variables.less → css/containers/scroll-panel.css} +25 -22
  41. package/src/{less/containers/split-panel.less → css/containers/split-panel.css} +15 -14
  42. package/src/{less/containers/tabs.less → css/containers/tabs.css} +17 -19
  43. package/src/css/dom/checkbox.css +102 -0
  44. package/src/css/dom/scrollbar.css +35 -0
  45. package/src/{less/dom/select.less → css/dom/select.css} +17 -18
  46. package/src/{less/empty-column.less → css/empty-column.css} +19 -18
  47. package/src/{less/expression-editor.less → css/expression-editor.css} +19 -18
  48. package/src/{less/filter-dropdown.less → css/filter-dropdown.css} +12 -11
  49. package/src/{less/filter-item.less → css/filter-item.css} +16 -15
  50. package/src/{less/form/code-editor.less → css/form/code-editor.css} +26 -30
  51. package/src/{less/form/debug.less → css/form/debug.css} +19 -18
  52. package/src/{less/function-dropdown.less → css/function-dropdown.css} +12 -11
  53. package/src/css/plugin-selector.css +261 -0
  54. package/src/{less/render-warning.less → css/render-warning.css} +18 -17
  55. package/src/{less/status-bar.less → css/status-bar.css} +156 -144
  56. package/src/css/type-icon.css +116 -0
  57. package/src/{less/viewer.less → css/viewer.css} +112 -146
  58. package/src/rust/components/column_dropdown.rs +229 -119
  59. package/src/rust/components/column_selector/active_column.rs +81 -62
  60. package/src/rust/components/column_selector/add_expression_button.rs +1 -0
  61. package/src/rust/components/column_selector/aggregate_selector.rs +25 -15
  62. package/src/rust/components/column_selector/config_selector.rs +315 -199
  63. package/src/rust/components/column_selector/empty_column.rs +2 -2
  64. package/src/rust/components/column_selector/expr_edit_button.rs +8 -2
  65. package/src/rust/components/column_selector/filter_column.rs +37 -26
  66. package/src/rust/components/column_selector/inactive_column.rs +41 -29
  67. package/src/rust/components/column_selector/invalid_column.rs +7 -18
  68. package/src/rust/components/column_selector/pivot_column.rs +11 -5
  69. package/src/rust/components/column_selector/sort_column.rs +23 -13
  70. package/src/rust/components/column_selector.rs +163 -84
  71. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +1 -1
  72. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +3 -2
  73. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +3 -2
  74. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +2 -3
  75. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +7 -1
  76. package/src/rust/components/column_settings_sidebar/style_tab.rs +153 -112
  77. package/src/rust/components/column_settings_sidebar.rs +91 -53
  78. package/src/rust/components/containers/dragdrop_list.rs +2 -1
  79. package/src/rust/components/containers/sidebar_close_button.rs +1 -1
  80. package/src/rust/components/containers/split_panel.rs +1 -0
  81. package/src/rust/components/containers/tab_list.rs +1 -1
  82. package/src/rust/components/copy_dropdown.rs +7 -28
  83. package/src/rust/components/datetime_column_style/custom.rs +2 -2
  84. package/src/rust/components/datetime_column_style/simple.rs +2 -2
  85. package/src/rust/components/datetime_column_style.rs +4 -2
  86. package/src/rust/components/editable_header.rs +7 -4
  87. package/src/rust/components/empty_row.rs +1 -1
  88. package/src/rust/components/export_dropdown.rs +4 -30
  89. package/src/rust/components/expression_editor.rs +19 -10
  90. package/src/rust/components/filter_dropdown.rs +246 -102
  91. package/src/rust/components/font_loader.rs +11 -28
  92. package/src/rust/components/form/code_editor.rs +17 -2
  93. package/src/rust/components/form/color_range_selector.rs +19 -6
  94. package/src/rust/components/form/debug.rs +30 -13
  95. package/src/rust/components/function_dropdown.rs +186 -113
  96. package/src/rust/components/main_panel.rs +71 -89
  97. package/src/rust/components/mod.rs +1 -1
  98. package/src/rust/components/modal.rs +7 -1
  99. package/src/rust/components/number_column_style.rs +22 -7
  100. package/src/rust/components/plugin_selector.rs +34 -102
  101. package/src/rust/components/portal.rs +274 -0
  102. package/src/rust/components/render_warning.rs +72 -123
  103. package/src/rust/components/settings_panel.rs +115 -11
  104. package/src/rust/components/status_bar.rs +222 -98
  105. package/src/rust/components/status_bar_counter.rs +8 -20
  106. package/src/rust/components/status_indicator.rs +64 -114
  107. package/src/rust/components/string_column_style.rs +2 -2
  108. package/src/rust/components/style/style_cache.rs +5 -1
  109. package/src/rust/components/viewer.rs +391 -39
  110. package/src/rust/custom_elements/copy_dropdown.rs +102 -21
  111. package/src/rust/custom_elements/export_dropdown.rs +102 -20
  112. package/src/rust/custom_elements/mod.rs +0 -7
  113. package/src/rust/custom_elements/modal.rs +7 -103
  114. package/src/rust/custom_elements/viewer.rs +99 -35
  115. package/src/rust/custom_events.rs +23 -2
  116. package/src/rust/dragdrop.rs +149 -10
  117. package/src/{less/containers/scroll-panel.less → rust/engines.rs} +15 -13
  118. package/src/rust/js/plugin.rs +1 -1
  119. package/src/rust/lib.rs +5 -4
  120. package/src/rust/presentation/props.rs +39 -0
  121. package/src/rust/presentation/sheets.rs +3 -3
  122. package/src/rust/presentation.rs +44 -8
  123. package/src/rust/renderer/limits.rs +32 -3
  124. package/src/{less/dom/scrollbar.less → rust/renderer/props.rs} +18 -19
  125. package/src/rust/renderer.rs +83 -9
  126. package/src/rust/session/column_defaults_update.rs +1 -1
  127. package/src/rust/session/metadata.rs +23 -2
  128. package/src/rust/session/props.rs +178 -0
  129. package/src/rust/session.rs +124 -117
  130. package/src/rust/tasks/column_locator.rs +133 -0
  131. package/src/rust/{model → tasks}/columns_iter_set.rs +14 -23
  132. package/src/rust/{model → tasks}/edit_expression.rs +34 -10
  133. package/src/rust/{model → tasks}/eject.rs +2 -2
  134. package/src/rust/{model → tasks}/get_viewer_config.rs +0 -11
  135. package/src/rust/{model → tasks}/intersection_observer.rs +19 -3
  136. package/src/{less/containers/radio-list.less → rust/tasks/is_invalid_drop.rs} +21 -14
  137. package/src/rust/tasks/mod.rs +52 -0
  138. package/src/rust/{model → tasks}/plugin_column_styles.rs +69 -46
  139. package/src/rust/{model → tasks}/resize_observer.rs +39 -6
  140. package/src/rust/{model → tasks}/send_plugin_config.rs +1 -1
  141. package/src/rust/tasks/structural.rs +53 -0
  142. package/src/rust/utils/mod.rs +4 -0
  143. package/src/rust/utils/modal_position.rs +110 -0
  144. package/src/rust/utils/ptr_eq_rc.rs +74 -0
  145. package/src/rust/utils/pubsub.rs +11 -1
  146. package/src/svg/bg-pattern.png +0 -0
  147. package/src/svg/close-icon.svg +1 -1
  148. package/src/svg/expression.svg +1 -1
  149. package/src/svg/mega-menu-icons-candlestick.svg +1 -1
  150. package/src/svg/mega-menu-icons-datagrid.svg +1 -2
  151. package/src/svg/mega-menu-icons-heatmap.svg +1 -1
  152. package/src/svg/mega-menu-icons-map-scatter.svg +1 -1
  153. package/src/svg/mega-menu-icons-ohlc.svg +1 -1
  154. package/src/svg/mega-menu-icons-sunburst.svg +1 -1
  155. package/src/svg/mega-menu-icons-treemap.svg +1 -1
  156. package/src/svg/mega-menu-icons-x-bar.svg +1 -1
  157. package/src/svg/mega-menu-icons-x-y-line.svg +1 -1
  158. package/src/svg/mega-menu-icons-x-y-scatter.svg +1 -1
  159. package/src/svg/mega-menu-icons-y-area.svg +1 -1
  160. package/src/svg/mega-menu-icons-y-bar.svg +1 -1
  161. package/src/svg/mega-menu-icons-y-line.svg +1 -1
  162. package/src/svg/mega-menu-icons-y-scatter.svg +1 -1
  163. package/src/svg/radio-hover.svg +1 -1
  164. package/src/svg/radio-off.svg +1 -1
  165. package/src/svg/radio-on.svg +1 -1
  166. package/src/themes/botanical.css +157 -0
  167. package/src/themes/defaults.css +139 -0
  168. package/src/themes/dracula.css +233 -0
  169. package/src/themes/gruvbox-dark.css +255 -0
  170. package/src/themes/gruvbox.css +134 -0
  171. package/src/themes/icons.css +124 -0
  172. package/src/themes/intl/de.css +102 -0
  173. package/src/themes/intl/es.css +102 -0
  174. package/src/themes/intl/fr.css +102 -0
  175. package/src/themes/intl/ja.css +102 -0
  176. package/src/themes/intl/pt.css +102 -0
  177. package/src/themes/intl/zh.css +102 -0
  178. package/src/themes/intl.css +102 -0
  179. package/src/themes/monokai.css +233 -0
  180. package/src/themes/pro-dark.css +158 -0
  181. package/src/themes/{themes.less → pro.css} +17 -21
  182. package/src/themes/solarized-dark.css +135 -0
  183. package/src/themes/solarized.css +95 -0
  184. package/src/themes/themes.css +22 -0
  185. package/src/themes/vaporwave.css +256 -0
  186. package/dist/css/variables.css +0 -0
  187. package/src/less/column-dropdown.less +0 -95
  188. package/src/less/dom/checkbox.less +0 -100
  189. package/src/less/plugin-selector.less +0 -183
  190. package/src/less/type-icon.less +0 -68
  191. package/src/rust/components/error_message.rs +0 -56
  192. package/src/rust/custom_elements/column_dropdown.rs +0 -123
  193. package/src/rust/custom_elements/filter_dropdown.rs +0 -179
  194. package/src/rust/custom_elements/function_dropdown.rs +0 -115
  195. package/src/rust/model/column_locator.rs +0 -82
  196. package/src/rust/model/is_invalid_drop.rs +0 -36
  197. package/src/rust/model/mod.rs +0 -100
  198. package/src/rust/model/reset_all.rs +0 -38
  199. package/src/rust/model/structural.rs +0 -244
  200. package/src/themes/botanical.less +0 -142
  201. package/src/themes/dracula.less +0 -101
  202. package/src/themes/gruvbox-dark.less +0 -116
  203. package/src/themes/gruvbox.less +0 -152
  204. package/src/themes/icons.less +0 -130
  205. package/src/themes/intl/de.less +0 -102
  206. package/src/themes/intl/es.less +0 -102
  207. package/src/themes/intl/fr.less +0 -102
  208. package/src/themes/intl/ja.less +0 -102
  209. package/src/themes/intl/pt.less +0 -102
  210. package/src/themes/intl/zh.less +0 -102
  211. package/src/themes/intl.less +0 -102
  212. package/src/themes/monokai.less +0 -107
  213. package/src/themes/pro-dark.less +0 -147
  214. package/src/themes/pro.less +0 -186
  215. package/src/themes/solarized-dark.less +0 -78
  216. package/src/themes/solarized.less +0 -102
  217. package/src/themes/vaporwave.less +0 -145
  218. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline0.js +0 -0
  219. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline1.js +0 -0
  220. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline2.js +0 -0
  221. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline3.js +0 -0
  222. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline4.js +0 -0
  223. /package/src/rust/{model → tasks}/copy_export.rs +0 -0
  224. /package/src/rust/{model → tasks}/export_app.rs +0 -0
  225. /package/src/rust/{model → tasks}/export_method.rs +0 -0
  226. /package/src/rust/{model → tasks}/restore_and_render.rs +0 -0
  227. /package/src/rust/{model → tasks}/update_and_render.rs +0 -0
@@ -13,8 +13,7 @@
13
13
  use std::collections::HashSet;
14
14
  use std::rc::Rc;
15
15
 
16
- use perspective_client::config::*;
17
- use perspective_client::utils::PerspectiveResultExt;
16
+ use perspective_client::config::{ViewConfig, *};
18
17
  use perspective_js::utils::ApiFuture;
19
18
  use yew::prelude::*;
20
19
 
@@ -22,24 +21,38 @@ use super::InPlaceColumn;
22
21
  use super::filter_column::*;
23
22
  use super::pivot_column::*;
24
23
  use super::sort_column::*;
24
+ use crate::components::column_dropdown::{ColumnDropDownElement, ColumnDropDownPortal};
25
25
  use crate::components::containers::dragdrop_list::*;
26
26
  use crate::components::containers::select::{Select, SelectItem};
27
+ use crate::components::filter_dropdown::{FilterDropDownElement, FilterDropDownPortal};
27
28
  use crate::components::style::LocalStyle;
28
- use crate::custom_elements::{ColumnDropDownElement, FilterDropDownElement};
29
+ use crate::css;
29
30
  use crate::dragdrop::*;
30
- use crate::model::*;
31
31
  use crate::renderer::*;
32
+ use crate::session::drag_drop_update::*;
32
33
  use crate::session::*;
33
34
  use crate::utils::*;
34
- use crate::{PerspectiveProperties, css};
35
35
 
36
- #[derive(Clone, Properties, PerspectiveProperties!)]
36
+ #[derive(Clone, Properties)]
37
37
  pub struct ConfigSelectorProps {
38
38
  pub onselect: Callback<()>,
39
39
 
40
40
  #[prop_or_default]
41
41
  pub ondragenter: Callback<()>,
42
42
 
43
+ /// Current view config threaded as a value prop so that config changes
44
+ /// (group_by, sort, filter, etc.) trigger re-renders via normal prop
45
+ /// diffing rather than a PubSub `view_created` subscription.
46
+ pub view_config: PtrEqRc<ViewConfig>,
47
+ /// Column currently being dragged — threaded to show `dragdrop-highlight`
48
+ /// without subscribing to `dragstart_received`/`dragend_received`.
49
+ pub drag_column: Option<String>,
50
+ /// Session metadata snapshot — threaded from `SessionProps`.
51
+ pub metadata: SessionMetadataRc,
52
+
53
+ /// Selected theme name, threaded for PortalModal consumers.
54
+ pub selected_theme: Option<String>,
55
+
43
56
  // State
44
57
  pub session: Session,
45
58
  pub renderer: Renderer,
@@ -47,22 +60,22 @@ pub struct ConfigSelectorProps {
47
60
  }
48
61
 
49
62
  impl PartialEq for ConfigSelectorProps {
50
- fn eq(&self, _other: &Self) -> bool {
51
- false
63
+ fn eq(&self, other: &Self) -> bool {
64
+ self.view_config == other.view_config
65
+ && self.drag_column == other.drag_column
66
+ && self.metadata == other.metadata
67
+ && self.selected_theme == other.selected_theme
52
68
  }
53
69
  }
54
70
 
55
71
  #[derive(Debug)]
56
72
  pub enum ConfigSelectorMsg {
57
- DragStart,
58
- DragEnd,
59
73
  DragOver(usize, DragTarget),
60
74
  DragLeave(DragTarget),
61
75
  Drop(String, DragTarget, DragEffect, usize),
62
76
  Close(usize, DragTarget),
63
77
  SetFilterValue(usize, String),
64
78
  TransposePivots,
65
- ViewCreated,
66
79
  New(DragTarget, InPlaceColumn),
67
80
  UpdateGroupRollupMode(GroupRollupMode),
68
81
  }
@@ -71,7 +84,7 @@ pub enum ConfigSelectorMsg {
71
84
  pub struct ConfigSelector {
72
85
  filter_dropdown: FilterDropDownElement,
73
86
  column_dropdown: ColumnDropDownElement,
74
- _subscriptions: [Rc<Subscription>; 4],
87
+ _subscriptions: [Rc<Subscription>; 1],
75
88
  }
76
89
 
77
90
  impl Component for ConfigSelector {
@@ -79,12 +92,6 @@ impl Component for ConfigSelector {
79
92
  type Properties = ConfigSelectorProps;
80
93
 
81
94
  fn create(ctx: &Context<Self>) -> Self {
82
- let cb = ctx.link().callback(|_| ConfigSelectorMsg::DragStart);
83
- let drag_sub = Rc::new(ctx.props().dragdrop.dragstart_received.add_listener(cb));
84
-
85
- let cb = ctx.link().callback(|_| ConfigSelectorMsg::DragEnd);
86
- let dragend_sub = Rc::new(ctx.props().dragdrop.dragend_received.add_listener(cb));
87
-
88
95
  let cb = ctx
89
96
  .link()
90
97
  .callback(|x: (String, DragTarget, DragEffect, usize)| {
@@ -92,12 +99,9 @@ impl Component for ConfigSelector {
92
99
  });
93
100
  let drop_sub = Rc::new(ctx.props().dragdrop.drop_received.add_listener(cb));
94
101
 
95
- let cb = ctx.link().callback(|_| ConfigSelectorMsg::ViewCreated);
96
- let view_sub = Rc::new(ctx.props().session.view_created.add_listener(cb));
97
-
98
102
  let filter_dropdown = FilterDropDownElement::new(ctx.props().session.clone());
99
103
  let column_dropdown = ColumnDropDownElement::new(ctx.props().session.clone());
100
- let _subscriptions = [drop_sub, view_sub, drag_sub, dragend_sub];
104
+ let _subscriptions = [drop_sub];
101
105
  Self {
102
106
  filter_dropdown,
103
107
  column_dropdown,
@@ -107,8 +111,6 @@ impl Component for ConfigSelector {
107
111
 
108
112
  fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
109
113
  match msg {
110
- ConfigSelectorMsg::DragStart | ConfigSelectorMsg::ViewCreated => true,
111
- ConfigSelectorMsg::DragEnd => true,
112
114
  ConfigSelectorMsg::DragOver(index, action) => {
113
115
  let should_render = ctx.props().dragdrop.notify_drag_enter(action, index);
114
116
  if should_render {
@@ -121,7 +123,7 @@ impl Component for ConfigSelector {
121
123
  true
122
124
  },
123
125
  ConfigSelectorMsg::Close(index, DragTarget::Sort) => {
124
- let mut sort = ctx.props().session.get_view_config().sort.clone();
126
+ let mut sort = ctx.props().view_config.sort.clone();
125
127
  sort.remove(index);
126
128
  let sort = Some(sort);
127
129
  let config = ViewConfigUpdate {
@@ -129,10 +131,16 @@ impl Component for ConfigSelector {
129
131
  ..ViewConfigUpdate::default()
130
132
  };
131
133
 
132
- ctx.props()
133
- .update_and_render(config)
134
- .map(ApiFuture::spawn)
135
- .unwrap_or_log();
134
+ {
135
+ let session = ctx.props().session.clone();
136
+ let renderer = ctx.props().renderer.clone();
137
+ if session.update_view_config(config).is_ok() {
138
+ ApiFuture::spawn(async move {
139
+ renderer.apply_pending_plugin()?;
140
+ renderer.draw(session.validate().await?.create_view()).await
141
+ });
142
+ }
143
+ }
136
144
 
137
145
  ctx.props().onselect.emit(());
138
146
  false
@@ -143,22 +151,26 @@ impl Component for ConfigSelector {
143
151
  ..ViewConfigUpdate::default()
144
152
  };
145
153
 
146
- ctx.props()
147
- .update_and_render(config)
148
- .map(ApiFuture::spawn)
149
- .unwrap_or_log();
154
+ {
155
+ let session = ctx.props().session.clone();
156
+ let renderer = ctx.props().renderer.clone();
157
+ if session.update_view_config(config).is_ok() {
158
+ ApiFuture::spawn(async move {
159
+ renderer.apply_pending_plugin()?;
160
+ renderer.draw(session.validate().await?.create_view()).await
161
+ });
162
+ }
163
+ }
150
164
 
151
165
  false
152
166
  },
153
167
  ConfigSelectorMsg::Close(index, DragTarget::GroupBy) => {
154
- if ctx.props().session.get_view_config().group_rollup_mode == GroupRollupMode::Total
155
- {
168
+ if ctx.props().view_config.group_rollup_mode == GroupRollupMode::Total {
156
169
  let requirements = ctx.props().renderer.metadata();
157
170
 
158
171
  let rollup_features = ctx
159
172
  .props()
160
- .session
161
- .metadata()
173
+ .metadata
162
174
  .get_features()
163
175
  .map(|x| x.get_group_rollup_modes())
164
176
  .unwrap();
@@ -171,51 +183,69 @@ impl Component for ConfigSelector {
171
183
  ));
172
184
  false
173
185
  } else {
174
- let mut group_by = ctx.props().session.get_view_config().group_by.clone();
186
+ let mut group_by = ctx.props().view_config.group_by.clone();
175
187
  group_by.remove(index);
176
188
  let config = ViewConfigUpdate {
177
189
  group_by: Some(group_by),
178
190
  ..ViewConfigUpdate::default()
179
191
  };
180
192
 
181
- ctx.props()
182
- .update_and_render(config)
183
- .map(ApiFuture::spawn)
184
- .unwrap_or_log();
193
+ {
194
+ let session = ctx.props().session.clone();
195
+ let renderer = ctx.props().renderer.clone();
196
+ if session.update_view_config(config).is_ok() {
197
+ ApiFuture::spawn(async move {
198
+ renderer.apply_pending_plugin()?;
199
+ renderer.draw(session.validate().await?.create_view()).await
200
+ });
201
+ }
202
+ }
185
203
 
186
204
  ctx.props().onselect.emit(());
187
205
  false
188
206
  }
189
207
  },
190
208
  ConfigSelectorMsg::Close(index, DragTarget::SplitBy) => {
191
- let mut split_by = ctx.props().session.get_view_config().split_by.clone();
209
+ let mut split_by = ctx.props().view_config.split_by.clone();
192
210
  split_by.remove(index);
193
211
  let config = ViewConfigUpdate {
194
212
  split_by: Some(split_by),
195
213
  ..ViewConfigUpdate::default()
196
214
  };
197
215
 
198
- ctx.props()
199
- .update_and_render(config)
200
- .map(ApiFuture::spawn)
201
- .unwrap_or_log();
216
+ {
217
+ let session = ctx.props().session.clone();
218
+ let renderer = ctx.props().renderer.clone();
219
+ if session.update_view_config(config).is_ok() {
220
+ ApiFuture::spawn(async move {
221
+ renderer.apply_pending_plugin()?;
222
+ renderer.draw(session.validate().await?.create_view()).await
223
+ });
224
+ }
225
+ }
202
226
 
203
227
  ctx.props().onselect.emit(());
204
228
  false
205
229
  },
206
230
  ConfigSelectorMsg::Close(index, DragTarget::Filter) => {
207
231
  self.filter_dropdown.hide().unwrap();
208
- let mut filter = ctx.props().session.get_view_config().filter.clone();
232
+ let mut filter = ctx.props().view_config.filter.clone();
209
233
  filter.remove(index);
210
234
  let config = ViewConfigUpdate {
211
235
  filter: Some(filter),
212
236
  ..ViewConfigUpdate::default()
213
237
  };
214
238
 
215
- ctx.props()
216
- .update_and_render(config)
217
- .map(ApiFuture::spawn)
218
- .unwrap_or_log();
239
+ {
240
+ let session = ctx.props().session.clone();
241
+ let renderer = ctx.props().renderer.clone();
242
+ if session.update_view_config(config).is_ok() {
243
+ ApiFuture::spawn(async move {
244
+ renderer.apply_pending_plugin()?;
245
+ renderer.draw(session.validate().await?.create_view()).await
246
+ });
247
+ }
248
+ }
219
249
 
220
250
  ctx.props().onselect.emit(());
221
251
  false
@@ -224,18 +254,31 @@ impl Component for ConfigSelector {
224
254
  ConfigSelectorMsg::Drop(column, action, effect, index)
225
255
  if action != DragTarget::Active =>
226
256
  {
227
- let update = ctx.props().session.create_drag_drop_update(
257
+ let col_type = ctx
258
+ .props()
259
+ .metadata
260
+ .get_column_table_type(column.as_str())
261
+ .unwrap();
262
+ let update = ctx.props().view_config.create_drag_drop_update(
228
263
  column,
264
+ col_type,
229
265
  index,
230
266
  action,
231
267
  effect,
232
268
  &ctx.props().renderer.metadata(),
269
+ ctx.props().metadata.get_features().unwrap(),
233
270
  );
234
271
 
235
- ctx.props()
236
- .update_and_render(update)
237
- .map(ApiFuture::spawn)
238
- .unwrap_or_log();
272
+ {
273
+ let session = ctx.props().session.clone();
274
+ let renderer = ctx.props().renderer.clone();
275
+ if session.update_view_config(update).is_ok() {
276
+ ApiFuture::spawn(async move {
277
+ renderer.apply_pending_plugin()?;
278
+ renderer.draw(session.validate().await?.create_view()).await
279
+ });
280
+ }
281
+ }
239
282
 
240
283
  ctx.props().onselect.emit(());
241
284
  false
@@ -247,7 +290,7 @@ impl Component for ConfigSelector {
247
290
  },
248
291
  ConfigSelectorMsg::Drop(..) => false,
249
292
  ConfigSelectorMsg::TransposePivots => {
250
- let mut view_config = ctx.props().session.get_view_config().clone();
293
+ let mut view_config = (*ctx.props().view_config).clone();
251
294
  std::mem::swap(&mut view_config.group_by, &mut view_config.split_by);
252
295
 
253
296
  let update = ViewConfigUpdate {
@@ -256,16 +299,22 @@ impl Component for ConfigSelector {
256
299
  ..ViewConfigUpdate::default()
257
300
  };
258
301
 
259
- ctx.props()
260
- .update_and_render(update)
261
- .map(ApiFuture::spawn)
262
- .unwrap_or_log();
302
+ {
303
+ let session = ctx.props().session.clone();
304
+ let renderer = ctx.props().renderer.clone();
305
+ if session.update_view_config(update).is_ok() {
306
+ ApiFuture::spawn(async move {
307
+ renderer.apply_pending_plugin()?;
308
+ renderer.draw(session.validate().await?.create_view()).await
309
+ });
310
+ }
311
+ }
263
312
  ctx.props().onselect.emit(());
264
313
  false
265
314
  },
266
315
 
267
316
  ConfigSelectorMsg::SetFilterValue(index, input) => {
268
- let mut filter = ctx.props().session.get_view_config().filter.clone();
317
+ let mut filter = ctx.props().view_config.filter.clone();
269
318
 
270
319
  // TODO Can't special case these - need to make this part of the
271
320
  // Features API.
@@ -295,47 +344,65 @@ impl Component for ConfigSelector {
295
344
  }
296
345
  };
297
346
 
298
- ctx.props()
299
- .update_and_render(update)
300
- .map(ApiFuture::spawn)
301
- .unwrap_or_log();
347
+ {
348
+ let session = ctx.props().session.clone();
349
+ let renderer = ctx.props().renderer.clone();
350
+ if session.update_view_config(update).is_ok() {
351
+ ApiFuture::spawn(async move {
352
+ renderer.apply_pending_plugin()?;
353
+ renderer.draw(session.validate().await?.create_view()).await
354
+ });
355
+ }
356
+ }
302
357
 
303
358
  false
304
359
  },
305
360
  ConfigSelectorMsg::New(DragTarget::GroupBy, InPlaceColumn::Column(col)) => {
306
- let mut view_config = ctx.props().session.get_view_config().clone();
361
+ let mut view_config = (*ctx.props().view_config).clone();
307
362
  view_config.group_by.push(col);
308
363
  let update = ViewConfigUpdate {
309
364
  group_by: Some(view_config.group_by),
310
365
  ..ViewConfigUpdate::default()
311
366
  };
312
367
 
313
- ctx.props()
314
- .update_and_render(update)
315
- .map(ApiFuture::spawn)
316
- .unwrap_or_log();
368
+ {
369
+ let session = ctx.props().session.clone();
370
+ let renderer = ctx.props().renderer.clone();
371
+ if session.update_view_config(update).is_ok() {
372
+ ApiFuture::spawn(async move {
373
+ renderer.apply_pending_plugin()?;
374
+ renderer.draw(session.validate().await?.create_view()).await
375
+ });
376
+ }
377
+ }
317
378
 
318
379
  ctx.props().onselect.emit(());
319
380
  false
320
381
  },
321
382
  ConfigSelectorMsg::New(DragTarget::SplitBy, InPlaceColumn::Column(col)) => {
322
- let mut view_config = ctx.props().session.get_view_config().clone();
383
+ let mut view_config = (*ctx.props().view_config).clone();
323
384
  view_config.split_by.push(col);
324
385
  let update = ViewConfigUpdate {
325
386
  split_by: Some(view_config.split_by),
326
387
  ..ViewConfigUpdate::default()
327
388
  };
328
389
 
329
- ctx.props()
330
- .update_and_render(update)
331
- .map(ApiFuture::spawn)
332
- .unwrap_or_log();
390
+ {
391
+ let session = ctx.props().session.clone();
392
+ let renderer = ctx.props().renderer.clone();
393
+ if session.update_view_config(update).is_ok() {
394
+ ApiFuture::spawn(async move {
395
+ renderer.apply_pending_plugin()?;
396
+ renderer.draw(session.validate().await?.create_view()).await
397
+ });
398
+ }
399
+ }
333
400
 
334
401
  ctx.props().onselect.emit(());
335
402
  false
336
403
  },
337
404
  ConfigSelectorMsg::New(DragTarget::Filter, InPlaceColumn::Column(column)) => {
338
- let mut view_config = ctx.props().session.get_view_config().clone();
405
+ let mut view_config = (*ctx.props().view_config).clone();
339
406
  let op = ctx.props().default_op(column.as_str()).unwrap_or_default();
340
407
  view_config.filter.push(Filter::new(
341
408
  &column,
@@ -348,32 +415,44 @@ impl Component for ConfigSelector {
348
415
  ..ViewConfigUpdate::default()
349
416
  };
350
417
 
351
- ctx.props()
352
- .update_and_render(update)
353
- .map(ApiFuture::spawn)
354
- .unwrap_or_log();
418
+ {
419
+ let session = ctx.props().session.clone();
420
+ let renderer = ctx.props().renderer.clone();
421
+ if session.update_view_config(update).is_ok() {
422
+ ApiFuture::spawn(async move {
423
+ renderer.apply_pending_plugin()?;
424
+ renderer.draw(session.validate().await?.create_view()).await
425
+ });
426
+ }
427
+ }
355
428
 
356
429
  ctx.props().onselect.emit(());
357
430
  false
358
431
  },
359
432
  ConfigSelectorMsg::New(DragTarget::Sort, InPlaceColumn::Column(col)) => {
360
- let mut view_config = ctx.props().session.get_view_config().clone();
433
+ let mut view_config = (*ctx.props().view_config).clone();
361
434
  view_config.sort.push(Sort(col, SortDir::Asc));
362
435
  let update = ViewConfigUpdate {
363
436
  sort: Some(view_config.sort),
364
437
  ..ViewConfigUpdate::default()
365
438
  };
366
439
 
367
- ctx.props()
368
- .update_and_render(update)
369
- .map(ApiFuture::spawn)
370
- .unwrap_or_log();
440
+ {
441
+ let session = ctx.props().session.clone();
442
+ let renderer = ctx.props().renderer.clone();
443
+ if session.update_view_config(update).is_ok() {
444
+ ApiFuture::spawn(async move {
445
+ renderer.apply_pending_plugin()?;
446
+ renderer.draw(session.validate().await?.create_view()).await
447
+ });
448
+ }
449
+ }
371
450
 
372
451
  ctx.props().onselect.emit(());
373
452
  false
374
453
  },
375
454
  ConfigSelectorMsg::New(DragTarget::GroupBy, InPlaceColumn::Expression(col)) => {
376
- let mut view_config = ctx.props().session.get_view_config().clone();
455
+ let mut view_config = (*ctx.props().view_config).clone();
377
456
  view_config.group_by.push(col.name.as_ref().to_owned());
378
457
  view_config.expressions.insert(&col);
379
458
  let update = ViewConfigUpdate {
@@ -382,16 +461,22 @@ impl Component for ConfigSelector {
382
461
  ..ViewConfigUpdate::default()
383
462
  };
384
463
 
385
- ctx.props()
386
- .update_and_render(update)
387
- .map(ApiFuture::spawn)
388
- .unwrap_or_log();
464
+ {
465
+ let session = ctx.props().session.clone();
466
+ let renderer = ctx.props().renderer.clone();
467
+ if session.update_view_config(update).is_ok() {
468
+ ApiFuture::spawn(async move {
469
+ renderer.apply_pending_plugin()?;
470
+ renderer.draw(session.validate().await?.create_view()).await
471
+ });
472
+ }
473
+ }
389
474
 
390
475
  ctx.props().onselect.emit(());
391
476
  false
392
477
  },
393
478
  ConfigSelectorMsg::New(DragTarget::SplitBy, InPlaceColumn::Expression(col)) => {
394
- let mut view_config = ctx.props().session.get_view_config().clone();
479
+ let mut view_config = (*ctx.props().view_config).clone();
395
480
  view_config.split_by.push(col.name.as_ref().to_owned());
396
481
  view_config.expressions.insert(&col);
397
482
  let update = ViewConfigUpdate {
@@ -400,16 +485,22 @@ impl Component for ConfigSelector {
400
485
  ..ViewConfigUpdate::default()
401
486
  };
402
487
 
403
- ctx.props()
404
- .update_and_render(update)
405
- .map(ApiFuture::spawn)
406
- .unwrap_or_log();
488
+ {
489
+ let session = ctx.props().session.clone();
490
+ let renderer = ctx.props().renderer.clone();
491
+ if session.update_view_config(update).is_ok() {
492
+ ApiFuture::spawn(async move {
493
+ renderer.apply_pending_plugin()?;
494
+ renderer.draw(session.validate().await?.create_view()).await
495
+ });
496
+ }
497
+ }
407
498
 
408
499
  ctx.props().onselect.emit(());
409
500
  false
410
501
  },
411
502
  ConfigSelectorMsg::New(DragTarget::Filter, InPlaceColumn::Expression(col)) => {
412
- let mut view_config = ctx.props().session.get_view_config().clone();
503
+ let mut view_config = (*ctx.props().view_config).clone();
413
504
  let column = col.name.as_ref();
414
505
  view_config.filter.push(Filter::new(
415
506
  column,
@@ -426,16 +517,22 @@ impl Component for ConfigSelector {
426
517
  ..ViewConfigUpdate::default()
427
518
  };
428
519
 
429
- ctx.props()
430
- .update_and_render(update)
431
- .map(ApiFuture::spawn)
432
- .unwrap_or_log();
520
+ {
521
+ let session = ctx.props().session.clone();
522
+ let renderer = ctx.props().renderer.clone();
523
+ if session.update_view_config(update).is_ok() {
524
+ ApiFuture::spawn(async move {
525
+ renderer.apply_pending_plugin()?;
526
+ renderer.draw(session.validate().await?.create_view()).await
527
+ });
528
+ }
529
+ }
433
530
 
434
531
  ctx.props().onselect.emit(());
435
532
  false
436
533
  },
437
534
  ConfigSelectorMsg::New(DragTarget::Sort, InPlaceColumn::Expression(col)) => {
438
- let mut view_config = ctx.props().session.get_view_config().clone();
535
+ let mut view_config = (*ctx.props().view_config).clone();
439
536
  view_config
440
537
  .sort
441
538
  .push(Sort(col.name.as_ref().to_owned(), SortDir::Asc));
@@ -446,10 +543,16 @@ impl Component for ConfigSelector {
446
543
  ..ViewConfigUpdate::default()
447
544
  };
448
545
 
449
- ctx.props()
450
- .update_and_render(update)
451
- .map(ApiFuture::spawn)
452
- .unwrap_or_log();
546
+ {
547
+ let session = ctx.props().session.clone();
548
+ let renderer = ctx.props().renderer.clone();
549
+ if session.update_view_config(update).is_ok() {
550
+ ApiFuture::spawn(async move {
551
+ renderer.apply_pending_plugin()?;
552
+ renderer.draw(session.validate().await?.create_view()).await
553
+ });
554
+ }
555
+ }
453
556
 
454
557
  ctx.props().onselect.emit(());
455
558
  false
@@ -471,12 +574,12 @@ impl Component for ConfigSelector {
471
574
  session,
472
575
  ..
473
576
  } = ctx.props();
474
- let config = session.get_view_config();
577
+ let config = &ctx.props().view_config;
475
578
  let transpose = ctx.link().callback(|_| ConfigSelectorMsg::TransposePivots);
476
579
  let column_dropdown = self.column_dropdown.clone();
477
580
  let mut class = classes!();
478
581
 
479
- if dragdrop.get_drag_column().is_some() {
582
+ if ctx.props().drag_column.is_some() {
480
583
  class.push("dragdrop-highlight");
481
584
  }
482
585
 
@@ -489,17 +592,14 @@ impl Component for ConfigSelector {
489
592
  move |_event| dragdrop.notify_drag_end()
490
593
  });
491
594
 
492
- let metadata = session.metadata();
595
+ let metadata = &ctx.props().metadata;
493
596
  let features = metadata.get_features().unwrap();
494
597
  let requirements = renderer.metadata();
495
598
  let on_group_rollup_mode = ctx
496
599
  .link()
497
600
  .callback(ConfigSelectorMsg::UpdateGroupRollupMode);
498
601
 
499
- let rollup_features = ctx
500
- .props()
501
- .session
502
- .metadata()
602
+ let rollup_features = metadata
503
603
  .get_features()
504
604
  .map(|x| x.get_group_rollup_modes())
505
605
  .unwrap();
@@ -507,124 +607,130 @@ impl Component for ConfigSelector {
507
607
  let group_rollups = requirements.get_group_rollups(&rollup_features);
508
608
 
509
609
  html! {
510
- <div slot="top_panel" id="top_panel" {class} ondragend={dragend}>
511
- <LocalStyle href={css!("config-selector")} />
512
- <div class="pivot_controls">
513
- if group_rollups.len() > 1 {
514
- <Select<GroupRollupMode>
515
- id="group_rollup_mode_selector"
516
- wrapper_class="group_rollup_wrapper"
517
- values={Rc::new(
610
+ <>
611
+ <div slot="top_panel" id="top_panel" {class} ondragend={dragend}>
612
+ <LocalStyle href={css!("config-selector")} />
613
+ <div class="pivot_controls">
614
+ if group_rollups.len() > 1 {
615
+ <Select<GroupRollupMode>
616
+ id="group_rollup_mode_selector"
617
+ wrapper_class="group_rollup_wrapper"
618
+ is_autosize=true
619
+ values={Rc::new(
518
620
  group_rollups
519
621
  .iter()
520
622
  .map(|x| SelectItem::Option(*x))
521
623
  .collect(),
522
624
  )}
523
- selected={config.group_rollup_mode}
524
- on_select={on_group_rollup_mode}
525
- />
526
- }
527
- if !config.group_by.is_empty() && config.split_by.is_empty() {
528
- <span
529
- id="transpose_button"
530
- class="rrow centered"
531
- title="Transpose Pivots"
532
- onmousedown={transpose.clone()}
533
- />
534
- }
535
- </div>
536
- if features.group_by {
537
- <GroupBySelector
538
- name="group_by"
539
- disabled={config.group_rollup_mode == GroupRollupMode::Total}
540
- parent={ctx.link().clone()}
541
- column_dropdown={column_dropdown.clone()}
542
- exclude={config.group_by.iter().cloned().collect::<HashSet<_>>()}
543
- is_dragover={ctx.props().dragdrop.is_dragover(DragTarget::GroupBy)}
544
- {dragdrop}
545
- >
546
- { for config.group_by.iter().map(|group_by| {
625
+ selected={config.group_rollup_mode}
626
+ on_select={on_group_rollup_mode}
627
+ />
628
+ }
629
+ if !config.group_by.is_empty() && config.split_by.is_empty() {
630
+ <span
631
+ id="transpose_button"
632
+ class="rrow centered"
633
+ title="Transpose Pivots"
634
+ onmousedown={transpose.clone()}
635
+ />
636
+ }
637
+ </div>
638
+ if features.group_by {
639
+ <GroupBySelector
640
+ name="group_by"
641
+ disabled={config.group_rollup_mode == GroupRollupMode::Total}
642
+ parent={ctx.link().clone()}
643
+ column_dropdown={column_dropdown.clone()}
644
+ exclude={config.group_by.iter().cloned().collect::<HashSet<_>>()}
645
+ is_dragover={ctx.props().dragdrop.is_dragover(DragTarget::GroupBy)}
646
+ {dragdrop}
647
+ >
648
+ { for config.group_by.iter().map(|group_by| {
547
649
  html_nested! {
548
650
  <PivotColumn
549
651
  action={DragTarget::GroupBy}
550
652
  column={group_by.clone()}
653
+ metadata={metadata.clone()}
551
654
  {dragdrop}
552
655
  opt_session={session}
553
656
  >
554
657
  </PivotColumn>
555
658
  }
556
659
  }) }
557
- </GroupBySelector>
558
- }
559
- if features.split_by {
560
- if !config.split_by.is_empty() {
561
- <div class="pivot_controls">
562
- <span
563
- id="transpose_button"
564
- class="rrow centered"
565
- title="Transpose Pivots"
566
- onmousedown={transpose}
567
- />
568
- </div>
660
+ </GroupBySelector>
569
661
  }
570
- <SplitBySelector
571
- name="split_by"
572
- parent={ctx.link().clone()}
573
- column_dropdown={column_dropdown.clone()}
574
- exclude={config.split_by.iter().cloned().collect::<HashSet<_>>()}
575
- is_dragover={dragdrop.is_dragover(DragTarget::SplitBy)}
576
- {dragdrop}
577
- >
578
- { for config.split_by.iter().map(|split_by| {
662
+ if features.split_by {
663
+ if !config.split_by.is_empty() {
664
+ <div class="pivot_controls">
665
+ <span
666
+ id="transpose_button"
667
+ class="rrow centered"
668
+ title="Transpose Pivots"
669
+ onmousedown={transpose}
670
+ />
671
+ </div>
672
+ }
673
+ <SplitBySelector
674
+ name="split_by"
675
+ parent={ctx.link().clone()}
676
+ column_dropdown={column_dropdown.clone()}
677
+ exclude={config.split_by.iter().cloned().collect::<HashSet<_>>()}
678
+ is_dragover={dragdrop.is_dragover(DragTarget::SplitBy)}
679
+ {dragdrop}
680
+ >
681
+ { for config.split_by.iter().map(|split_by| {
579
682
  html_nested! {
580
683
  <PivotColumn
581
684
  action={ DragTarget::SplitBy }
582
685
  column={ split_by.clone() }
686
+ metadata={metadata.clone()}
583
687
  {dragdrop}
584
688
  opt_session={session}>
585
689
  </PivotColumn>
586
690
  }
587
691
  }) }
588
- </SplitBySelector>
589
- }
590
- if features.sort {
591
- <SortSelector
592
- name="sort"
593
- allow_duplicates=true
594
- parent={ctx.link().clone()}
595
- column_dropdown={column_dropdown.clone()}
596
- exclude={config.sort.iter().map(|x| x.0.clone()).collect::<HashSet<_>>()}
597
- is_dragover={dragdrop.is_dragover(DragTarget::Sort).map(|(index, name)| {
692
+ </SplitBySelector>
693
+ }
694
+ if features.sort {
695
+ <SortSelector
696
+ name="sort"
697
+ allow_duplicates=true
698
+ parent={ctx.link().clone()}
699
+ column_dropdown={column_dropdown.clone()}
700
+ exclude={config.sort.iter().map(|x| x.0.clone()).collect::<HashSet<_>>()}
701
+ is_dragover={dragdrop.is_dragover(DragTarget::Sort).map(|(index, name)| {
598
702
  (index, Sort(name, SortDir::Asc))
599
703
  })}
600
- {dragdrop}
601
- >
602
- { for config.sort.iter().enumerate().map(|(idx, sort)| {
704
+ {dragdrop}
705
+ >
706
+ { for config.sort.iter().enumerate().map(|(idx, sort)| {
603
707
  html_nested! {
604
708
  <SortColumn
605
709
  idx={ idx }
606
710
  sort={ sort.clone() }
711
+ view_config={config.clone()}
712
+ metadata={metadata.clone()}
607
713
  {dragdrop}
608
714
  {renderer}
609
715
  {session}>
610
716
  </SortColumn>
611
717
  }
612
718
  }) }
613
- </SortSelector>
614
- }
615
- if !features.filter_ops.is_empty() {
616
- <FilterSelector
617
- name="filter"
618
- allow_duplicates=true
619
- parent={ctx.link().clone()}
620
- {column_dropdown}
621
- exclude={config.filter.iter().map(|x| x.column().to_string()).collect::<HashSet<_>>()}
622
- is_dragover={dragdrop.is_dragover(DragTarget::Filter).map(|(index, name)| {
719
+ </SortSelector>
720
+ }
721
+ if !features.filter_ops.is_empty() {
722
+ <FilterSelector
723
+ name="filter"
724
+ allow_duplicates=true
725
+ parent={ctx.link().clone()}
726
+ {column_dropdown}
727
+ exclude={config.filter.iter().map(|x| x.column().to_string()).collect::<HashSet<_>>()}
728
+ is_dragover={dragdrop.is_dragover(DragTarget::Filter).map(|(index, name)| {
623
729
  (index, Filter::new(&name, "", FilterTerm::Scalar(Scalar::Null)))
624
730
  })}
625
- {dragdrop}
626
- >
627
- { for config.filter.iter().enumerate().map(|(idx, filter)| {
731
+ {dragdrop}
732
+ >
733
+ { for config.filter.iter().enumerate().map(|(idx, filter)| {
628
734
  let filter_keydown = ctx.link()
629
735
  .callback(move |txt| ConfigSelectorMsg::SetFilterValue(idx, txt));
630
736
 
@@ -634,24 +740,34 @@ impl Component for ConfigSelector {
634
740
  filter_dropdown={ &self.filter_dropdown }
635
741
  filter={ filter.clone() }
636
742
  on_keydown={ filter_keydown }
743
+ view_config={config.clone()}
744
+ metadata={metadata.clone()}
637
745
  {dragdrop}
638
746
  {renderer}
639
747
  {session}>
640
748
  </FilterColumn>
641
749
  }
642
750
  }) }
643
- </FilterSelector>
644
- }
645
- </div>
751
+ </FilterSelector>
752
+ }
753
+ </div>
754
+ <ColumnDropDownPortal
755
+ element={self.column_dropdown.clone()}
756
+ theme={ctx.props().selected_theme.clone().unwrap_or_default()}
757
+ />
758
+ <FilterDropDownPortal
759
+ element={self.filter_dropdown.clone()}
760
+ theme={ctx.props().selected_theme.clone().unwrap_or_default()}
761
+ />
762
+ </>
646
763
  }
647
764
  }
648
765
  }
649
766
 
650
767
  impl ConfigSelectorProps {
651
768
  fn default_op(&self, column: &str) -> Option<String> {
652
- let metadata = self.session.metadata();
653
- let features = metadata.get_features()?;
654
- let col_type = metadata.get_column_table_type(column)?;
769
+ let features = self.metadata.get_features()?;
770
+ let col_type = self.metadata.get_column_table_type(column)?;
655
771
  let first = features.default_op(col_type)?;
656
772
  Some(first.to_string())
657
773
  }