@perspective-dev/viewer 4.0.1 → 4.1.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 (183) 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/dracula.css +1 -1
  4. package/dist/css/gruvbox-dark.css +1 -1
  5. package/dist/css/gruvbox.css +1 -1
  6. package/dist/css/icons.css +1 -1
  7. package/dist/css/monokai.css +1 -1
  8. package/dist/css/pro-dark.css +1 -1
  9. package/dist/css/pro.css +1 -1
  10. package/dist/css/solarized-dark.css +1 -1
  11. package/dist/css/solarized.css +1 -1
  12. package/dist/css/themes.css +1 -1
  13. package/dist/css/vaporwave.css +1 -1
  14. package/dist/esm/extensions.d.ts +23 -2
  15. package/dist/esm/perspective-viewer.d.ts +2 -7
  16. package/dist/esm/perspective-viewer.inline.js +2 -2
  17. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  18. package/dist/esm/perspective-viewer.js +2 -2
  19. package/dist/esm/perspective-viewer.js.map +4 -4
  20. package/dist/esm/plugin.d.ts +1 -1
  21. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +1 -0
  22. package/dist/wasm/perspective-viewer.d.ts +218 -46
  23. package/dist/wasm/perspective-viewer.js +1250 -761
  24. package/dist/wasm/perspective-viewer.wasm +0 -0
  25. package/dist/wasm/perspective-viewer.wasm.d.ts +38 -19
  26. package/package.json +1 -1
  27. package/src/less/containers/scroll-panel.less +0 -1
  28. package/src/less/plugin-selector.less +15 -5
  29. package/src/less/status-bar.less +75 -27
  30. package/src/less/viewer.less +140 -58
  31. package/src/rust/components/column_dropdown.rs +21 -21
  32. package/src/rust/components/column_selector/active_column.rs +131 -120
  33. package/src/rust/components/column_selector/add_expression_button.rs +5 -0
  34. package/src/rust/components/column_selector/aggregate_selector.rs +8 -4
  35. package/src/rust/components/column_selector/config_selector.rs +170 -161
  36. package/src/rust/components/column_selector/empty_column.rs +16 -11
  37. package/src/rust/components/column_selector/{expression_toolbar.rs → expr_edit_button.rs} +7 -0
  38. package/src/rust/components/column_selector/filter_column.rs +195 -194
  39. package/src/rust/components/column_selector/inactive_column.rs +82 -67
  40. package/src/rust/components/column_selector/pivot_column.rs +16 -11
  41. package/src/rust/components/column_selector/sort_column.rs +9 -7
  42. package/src/rust/components/column_selector.rs +42 -37
  43. package/src/rust/components/column_settings_sidebar/save_settings.rs +3 -1
  44. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +58 -0
  45. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +6 -6
  46. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +2 -94
  47. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +111 -0
  48. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +3 -3
  49. package/src/rust/components/column_settings_sidebar/style_tab.rs +23 -83
  50. package/src/rust/components/{column_settings_sidebar/sidebar.rs → column_settings_sidebar.rs} +198 -171
  51. package/src/rust/components/containers/dragdrop_list.rs +20 -20
  52. package/src/rust/components/containers/dropdown_menu.rs +4 -6
  53. package/src/rust/components/containers/mod.rs +1 -4
  54. package/src/rust/components/containers/scroll_panel.rs +80 -80
  55. package/src/rust/components/containers/scroll_panel_item.rs +36 -36
  56. package/src/rust/components/containers/select.rs +46 -44
  57. package/src/rust/components/containers/sidebar.rs +3 -19
  58. package/src/rust/components/{column_settings_sidebar/style_tab/symbol/symbol_config.rs → containers/sidebar_close_button.rs} +15 -9
  59. package/src/rust/components/containers/split_panel.rs +212 -200
  60. package/src/rust/components/containers/tab_list.rs +11 -11
  61. package/src/rust/components/copy_dropdown.rs +22 -25
  62. package/src/rust/components/datetime_column_style/custom.rs +19 -19
  63. package/src/rust/components/datetime_column_style/simple.rs +13 -14
  64. package/src/rust/components/datetime_column_style.rs +75 -76
  65. package/src/rust/components/editable_header.rs +18 -14
  66. package/src/rust/components/empty_row.rs +5 -5
  67. package/src/rust/components/export_dropdown.rs +42 -42
  68. package/src/rust/components/expression_editor.rs +25 -19
  69. package/src/rust/components/filter_dropdown.rs +22 -22
  70. package/src/rust/components/font_loader.rs +11 -9
  71. package/src/rust/components/form/code_editor.rs +106 -105
  72. package/src/rust/components/form/color_range_selector.rs +14 -12
  73. package/src/rust/components/form/color_selector.rs +3 -1
  74. package/src/rust/components/form/debug.rs +95 -94
  75. package/src/rust/components/form/highlight.rs +5 -3
  76. package/src/rust/components/form/mod.rs +3 -2
  77. package/src/rust/components/form/optional_field.rs +2 -2
  78. package/src/rust/components/form/{select_field.rs → select_enum_field.rs} +1 -46
  79. package/src/rust/components/form/select_value_field.rs +64 -0
  80. package/src/rust/components/function_dropdown.rs +21 -21
  81. package/src/rust/components/main_panel.rs +219 -0
  82. package/src/rust/components/mod.rs +6 -6
  83. package/src/rust/components/modal.rs +42 -42
  84. package/src/rust/components/number_column_style.rs +34 -88
  85. package/src/rust/components/plugin_selector.rs +22 -25
  86. package/src/rust/components/render_warning.rs +9 -6
  87. package/src/rust/components/settings_panel.rs +82 -0
  88. package/src/rust/components/status_bar.rs +250 -146
  89. package/src/rust/components/status_bar_counter.rs +26 -119
  90. package/src/rust/components/status_indicator.rs +95 -79
  91. package/src/rust/components/string_column_style.rs +45 -45
  92. package/src/rust/components/style/style_provider.rs +1 -15
  93. package/src/rust/components/style_controls/number_string_format/digits_section.rs +1 -1
  94. package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
  95. package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
  96. package/src/rust/components/style_controls/number_string_format.rs +45 -46
  97. package/src/rust/components/type_icon.rs +14 -11
  98. package/src/rust/components/viewer.rs +241 -384
  99. package/src/rust/config/columns_config.rs +2 -2
  100. package/src/rust/config/datetime_column_style.rs +1 -6
  101. package/src/rust/config/mod.rs +1 -0
  102. package/src/rust/config/number_column_style.rs +0 -6
  103. package/src/rust/config/number_string_format.rs +27 -4
  104. package/src/rust/config/viewer_config.rs +27 -167
  105. package/src/rust/custom_elements/copy_dropdown.rs +14 -6
  106. package/src/rust/custom_elements/export_dropdown.rs +15 -7
  107. package/src/rust/custom_elements/filter_dropdown.rs +4 -4
  108. package/src/rust/custom_elements/mod.rs +3 -0
  109. package/src/rust/custom_elements/viewer.rs +353 -161
  110. package/src/rust/custom_events.rs +55 -32
  111. package/src/rust/dragdrop.rs +4 -24
  112. package/src/rust/exprtk/cursor.rs +10 -1
  113. package/src/rust/exprtk/mod.rs +2 -0
  114. package/src/rust/exprtk/tokenize.rs +20 -3
  115. package/src/rust/js/clipboard.rs +2 -2
  116. package/src/rust/js/mimetype.rs +2 -7
  117. package/src/rust/js/mod.rs +0 -1
  118. package/src/rust/js/plugin.rs +7 -0
  119. package/src/rust/lib.rs +18 -5
  120. package/src/rust/model/column_locator.rs +82 -0
  121. package/src/rust/model/columns_iter_set.rs +1 -0
  122. package/src/rust/model/copy_export.rs +50 -14
  123. package/src/rust/model/edit_expression.rs +2 -5
  124. package/src/rust/model/eject.rs +41 -0
  125. package/src/rust/model/get_viewer_config.rs +4 -28
  126. package/src/rust/model/intersection_observer.rs +20 -8
  127. package/src/rust/model/mod.rs +11 -4
  128. package/src/rust/model/plugin_column_styles.rs +0 -31
  129. package/src/rust/model/reset_all.rs +38 -0
  130. package/src/rust/model/resize_observer.rs +34 -7
  131. package/src/rust/model/restore_and_render.rs +12 -7
  132. package/src/rust/{utils/scope.rs → model/send_plugin_config.rs} +32 -35
  133. package/src/rust/model/structural.rs +194 -23
  134. package/src/rust/model/update_and_render.rs +14 -4
  135. package/src/rust/{model/create_col.rs → presentation/column_locator.rs} +73 -42
  136. package/src/rust/{utils/wasm_abi.rs → presentation/sheets.rs} +54 -40
  137. package/src/rust/presentation.rs +60 -119
  138. package/src/rust/renderer/activate.rs +20 -5
  139. package/src/rust/renderer/limits.rs +0 -149
  140. package/src/rust/renderer/render_timer.rs +1 -1
  141. package/src/rust/renderer.rs +34 -18
  142. package/src/rust/root.rs +50 -0
  143. package/src/rust/session/column_defaults_update.rs +4 -4
  144. package/src/rust/session/drag_drop_update.rs +1 -1
  145. package/src/rust/session/metadata.rs +3 -17
  146. package/src/rust/session/replace_expression_update.rs +1 -2
  147. package/src/rust/session.rs +162 -82
  148. package/src/rust/utils/browser/blob.rs +16 -2
  149. package/src/rust/utils/browser/download.rs +1 -0
  150. package/src/rust/{components/column_settings_sidebar/mod.rs → utils/browser/dragdrop.rs} +14 -5
  151. package/src/rust/utils/browser/mod.rs +8 -4
  152. package/src/rust/utils/browser/selection.rs +5 -0
  153. package/src/rust/utils/custom_element.rs +28 -13
  154. package/src/rust/utils/datetime.rs +5 -0
  155. package/src/rust/utils/debounce.rs +7 -1
  156. package/src/rust/utils/hooks/use_async_callback.rs +7 -17
  157. package/src/rust/utils/mod.rs +28 -40
  158. package/src/rust/utils/number_format.rs +6 -5
  159. package/src/rust/utils/pubsub.rs +15 -10
  160. package/src/rust/utils/weak_scope.rs +11 -1
  161. package/src/svg/bookmark-icon.svg +4 -0
  162. package/src/svg/drag-handle copy.svg +10 -0
  163. package/src/svg/drawer-tab-hover.svg +5 -7
  164. package/src/svg/drawer-tab-invert-hover.svg +4 -8
  165. package/src/svg/drawer-tab-invert.svg +4 -7
  166. package/src/svg/drawer-tab.svg +4 -6
  167. package/src/svg/status_ok.svg +24 -24
  168. package/src/ts/extensions.ts +51 -3
  169. package/src/ts/perspective-viewer.ts +2 -14
  170. package/src/ts/plugin.ts +1 -1
  171. package/src/ts/ts-rs/ViewerConfigUpdate.ts +1 -1
  172. package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +0 -177
  173. package/src/rust/components/containers/tests/mod.rs +0 -11
  174. package/src/rust/components/containers/tests/split_panel.rs +0 -91
  175. package/src/rust/js/testing.rs +0 -149
  176. package/src/rust/utils/tee.rs +0 -88
  177. /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline0.js +0 -0
  178. /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline1.js +0 -0
  179. /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline2.js +0 -0
  180. /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline3.js +0 -0
  181. /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline4.js +0 -0
  182. /package/src/rust/components/{style_controls.rs → style_controls/mod.rs} +0 -0
  183. /package/src/rust/{components/containers → config}/kvpair.rs +0 -0
@@ -9,77 +9,69 @@
9
9
  // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
+ mod attributes_tab;
13
+
14
+ mod save_settings;
15
+ mod style_tab;
12
16
 
13
- use std::fmt::Display;
14
17
  use std::rc::Rc;
15
18
 
16
19
  use derivative::Derivative;
17
20
  use itertools::Itertools;
18
21
  use perspective_client::config::{ColumnType, Expression};
19
22
  use perspective_client::utils::PerspectiveResultExt;
20
- use yew::{Callback, Component, Html, Properties, html};
23
+ use yew::{Callback, Component, Html, Properties, html, props};
21
24
 
22
- use super::attributes_tab::AttributesTabProps;
23
- use super::style_tab::StyleTabProps;
25
+ use self::attributes_tab::AttributesTabProps;
26
+ use self::style_tab::StyleTabProps;
24
27
  use crate::components::column_settings_sidebar::attributes_tab::AttributesTab;
25
28
  use crate::components::column_settings_sidebar::save_settings::SaveSettingsProps;
26
29
  use crate::components::column_settings_sidebar::style_tab::StyleTab;
27
30
  use crate::components::containers::sidebar::Sidebar;
28
- use crate::components::containers::tab_list::{Tab, TabList};
31
+ use crate::components::containers::tab_list::TabList;
29
32
  use crate::components::editable_header::EditableHeaderProps;
30
33
  use crate::components::expression_editor::ExpressionEditorProps;
31
34
  use crate::components::style::LocalStyle;
32
35
  use crate::components::type_icon::TypeIconType;
33
- use crate::components::viewer::ColumnLocator;
34
36
  use crate::custom_events::CustomEvents;
35
37
  use crate::model::*;
36
- use crate::presentation::Presentation;
38
+ use crate::presentation::{ColumnLocator, ColumnSettingsTab, Presentation};
37
39
  use crate::renderer::Renderer;
38
40
  use crate::session::Session;
39
- use crate::utils::{AddListener, Subscription};
40
- use crate::{css, derive_model};
41
-
42
- #[derive(Debug, Default, Clone, Copy, PartialEq)]
43
- pub enum ColumnSettingsTab {
44
- #[default]
45
- Attributes,
46
- Style,
47
- }
48
- impl Tab for ColumnSettingsTab {}
49
- impl Display for ColumnSettingsTab {
50
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51
- f.write_fmt(format_args!("{self:?}"))
52
- }
53
- }
41
+ use crate::utils::*;
42
+ use crate::*;
54
43
 
55
- #[derive(Clone, Properties, Derivative)]
44
+ #[derive(Clone, Derivative, Properties, PerspectiveProperties!)]
56
45
  #[derivative(Debug)]
57
- pub struct ColumnSettingsProps {
58
- #[derivative(Debug = "ignore")]
59
- pub session: Session,
46
+ pub struct ColumnSettingsPanelProps {
47
+ pub selected_column: ColumnLocator,
48
+ pub selected_tab: Option<ColumnSettingsTab>,
49
+ pub on_close: Callback<()>,
50
+ pub width_override: Option<i32>,
51
+ pub on_select_tab: Callback<ColumnSettingsTab>,
52
+
53
+ // State
60
54
  #[derivative(Debug = "ignore")]
61
- pub renderer: Renderer,
55
+ pub custom_events: CustomEvents,
56
+
62
57
  #[derivative(Debug = "ignore")]
63
58
  pub presentation: Presentation,
59
+
64
60
  #[derivative(Debug = "ignore")]
65
- pub custom_events: CustomEvents,
61
+ pub renderer: Renderer,
66
62
 
67
- pub selected_column: ColumnLocator,
68
- pub on_close: Callback<()>,
69
- pub width_override: Option<i32>,
70
- pub is_active: bool,
63
+ #[derivative(Debug = "ignore")]
64
+ pub session: Session,
71
65
  }
72
66
 
73
- derive_model!(Session, Renderer, Presentation for ColumnSettingsProps);
74
-
75
- impl PartialEq for ColumnSettingsProps {
67
+ impl PartialEq for ColumnSettingsPanelProps {
76
68
  fn eq(&self, other: &Self) -> bool {
77
- self.selected_column == other.selected_column && self.is_active == other.is_active
69
+ self.selected_column == other.selected_column && self.selected_tab == other.selected_tab
78
70
  }
79
71
  }
80
72
 
81
73
  #[derive(Debug)]
82
- pub enum ColumnSettingsMsg {
74
+ pub enum ColumnSettingsPanelMsg {
83
75
  SetExprValue(Rc<String>),
84
76
  SetExprValid(bool),
85
77
  SetHeaderValue(Option<String>),
@@ -91,105 +83,38 @@ pub enum ColumnSettingsMsg {
91
83
  SessionUpdated(bool),
92
84
  }
93
85
 
94
- #[derive(Default, Derivative)]
86
+ #[derive(Derivative)]
95
87
  #[derivative(Debug)]
96
- pub struct ColumnSettingsSidebar {
97
- initial_expr_value: Rc<String>,
98
- expr_value: Rc<String>,
88
+ pub struct ColumnSettingsPanel {
89
+ column_name: String,
99
90
  expr_valid: bool,
100
- initial_header_value: Option<String>,
101
- header_value: Option<String>,
91
+ expr_value: Rc<String>,
102
92
  header_valid: bool,
103
- selected_tab: ColumnSettingsTab,
104
- selected_tab_idx: usize,
105
- save_enabled: bool,
106
- save_count: u8,
107
- reset_enabled: bool,
108
- reset_count: u8,
109
- column_name: String,
93
+ header_value: Option<String>,
94
+ initial_expr_value: Rc<String>,
95
+ initial_header_value: Option<String>,
110
96
  maybe_ty: Option<ColumnType>,
111
- tabs: Vec<ColumnSettingsTab>,
112
-
113
97
  on_input: Callback<Rc<String>>,
114
98
  on_save: Callback<()>,
115
99
  on_validate: Callback<bool>,
100
+ reset_count: u8,
101
+ reset_enabled: bool,
102
+ save_count: u8,
103
+ save_enabled: bool,
104
+ tabs: Vec<ColumnSettingsTab>,
116
105
 
117
106
  #[derivative(Debug = "ignore")]
118
- session_sub: Option<Subscription>,
119
- }
120
-
121
- impl ColumnSettingsSidebar {
122
- fn save_enabled_effect(&mut self) {
123
- let changed = self.expr_value != self.initial_expr_value
124
- || self.header_value != self.initial_header_value;
125
- let valid = self.expr_valid && self.header_valid;
126
- self.save_enabled = changed && valid;
127
- }
128
-
129
- fn initialize(&mut self, ctx: &yew::prelude::Context<Self>) {
130
- let column_name = ctx
131
- .props()
132
- .selected_column
133
- .name_or_default(&ctx.props().session);
134
- let initial_expr_value = ctx
135
- .props()
136
- .session
137
- .metadata()
138
- .get_expression_by_alias(&column_name)
139
- .unwrap_or_default();
140
- let initial_expr_value = Rc::new(initial_expr_value);
141
- let initial_header_value =
142
- (*initial_expr_value != column_name).then_some(column_name.clone());
143
- let maybe_ty = ctx.props().selected_column.view_type(ctx.props().session());
144
-
145
- let tabs = {
146
- let mut tabs = vec![];
147
- let is_new_expr = ctx.props().selected_column.is_new_expr();
148
- let show_styles = !is_new_expr
149
- && ctx
150
- .props()
151
- .can_render_column_styles(&column_name)
152
- .unwrap_or_default();
153
-
154
- if !is_new_expr && show_styles {
155
- tabs.push(ColumnSettingsTab::Style);
156
- }
157
-
158
- if ctx.props().selected_column.is_expr() {
159
- tabs.push(ColumnSettingsTab::Attributes);
160
- }
161
- tabs
162
- };
163
-
164
- let on_input = ctx.link().callback(ColumnSettingsMsg::SetExprValue);
165
- let on_save = ctx.link().callback(ColumnSettingsMsg::OnSaveAttributes);
166
- let on_validate = ctx.link().callback(ColumnSettingsMsg::SetExprValid);
167
- *self = Self {
168
- column_name,
169
- expr_value: initial_expr_value.clone(),
170
- initial_expr_value,
171
- header_value: initial_header_value.clone(),
172
- initial_header_value,
173
- maybe_ty,
174
- tabs,
175
- header_valid: true,
176
- on_input,
177
- on_save,
178
- on_validate,
179
- session_sub: self.session_sub.take(),
180
- ..*self
181
- }
182
- }
107
+ _session_sub: Option<Subscription>,
183
108
  }
184
109
 
185
- impl Component for ColumnSettingsSidebar {
186
- type Message = ColumnSettingsMsg;
187
- type Properties = ColumnSettingsProps;
110
+ impl Component for ColumnSettingsPanel {
111
+ type Message = ColumnSettingsPanelMsg;
112
+ type Properties = ColumnSettingsPanelProps;
188
113
 
189
114
  fn create(ctx: &yew::prelude::Context<Self>) -> Self {
190
115
  let session_cb = ctx
191
116
  .link()
192
- .callback(|(is_update, _)| ColumnSettingsMsg::SessionUpdated(is_update));
117
+ .callback(|(is_update, _)| ColumnSettingsPanelMsg::SessionUpdated(is_update));
193
118
 
194
119
  let session_sub = ctx
195
120
  .props()
@@ -198,24 +123,32 @@ impl Component for ColumnSettingsSidebar {
198
123
  .add_listener(session_cb);
199
124
 
200
125
  let mut this = Self {
201
- session_sub: Some(session_sub),
202
- ..Default::default()
126
+ _session_sub: Some(session_sub),
127
+ initial_expr_value: Rc::default(),
128
+ expr_value: Rc::default(),
129
+ expr_valid: false,
130
+ initial_header_value: None,
131
+ header_value: None,
132
+ header_valid: false,
133
+ save_enabled: false,
134
+ save_count: 0,
135
+ reset_enabled: false,
136
+ reset_count: 0,
137
+ column_name: "".to_owned(),
138
+ maybe_ty: None,
139
+ tabs: vec![],
140
+ on_input: Callback::default(),
141
+ on_save: Callback::default(),
142
+ on_validate: Callback::default(),
203
143
  };
144
+
204
145
  this.initialize(ctx);
205
146
  this
206
147
  }
207
148
 
208
149
  fn changed(&mut self, ctx: &yew::prelude::Context<Self>, old_props: &Self::Properties) -> bool {
209
150
  if ctx.props() != old_props {
210
- let selected_tab = self.selected_tab;
211
151
  self.initialize(ctx);
212
- self.selected_tab = selected_tab;
213
- self.selected_tab_idx = self
214
- .tabs
215
- .iter()
216
- .find_position(|tab| **tab == selected_tab)
217
- .map(|(idx, _val)| idx)
218
- .unwrap_or_default();
219
152
  true
220
153
  } else {
221
154
  false
@@ -223,8 +156,8 @@ impl Component for ColumnSettingsSidebar {
223
156
  }
224
157
 
225
158
  fn update(&mut self, ctx: &yew::prelude::Context<Self>, msg: Self::Message) -> bool {
226
- match msg {
227
- ColumnSettingsMsg::SetExprValue(val) => {
159
+ let result = match msg {
160
+ ColumnSettingsPanelMsg::SetExprValue(val) => {
228
161
  if self.expr_value != val {
229
162
  self.expr_value = val;
230
163
  self.reset_enabled = true;
@@ -233,12 +166,12 @@ impl Component for ColumnSettingsSidebar {
233
166
  false
234
167
  }
235
168
  },
236
- ColumnSettingsMsg::SetExprValid(val) => {
169
+ ColumnSettingsPanelMsg::SetExprValid(val) => {
237
170
  self.expr_valid = val;
238
171
  self.save_enabled_effect();
239
172
  true
240
173
  },
241
- ColumnSettingsMsg::SetHeaderValue(val) => {
174
+ ColumnSettingsPanelMsg::SetHeaderValue(val) => {
242
175
  if self.header_value != val {
243
176
  self.header_value = val;
244
177
  self.reset_enabled = true;
@@ -247,18 +180,17 @@ impl Component for ColumnSettingsSidebar {
247
180
  false
248
181
  }
249
182
  },
250
- ColumnSettingsMsg::SetHeaderValid(val) => {
183
+ ColumnSettingsPanelMsg::SetHeaderValid(val) => {
251
184
  self.header_valid = val;
252
185
  self.save_enabled_effect();
253
186
  true
254
187
  },
255
- ColumnSettingsMsg::SetSelectedTab((idx, val)) => {
256
- let rerender = self.selected_tab != val || self.selected_tab_idx != idx;
257
- self.selected_tab = val;
258
- self.selected_tab_idx = idx;
188
+ ColumnSettingsPanelMsg::SetSelectedTab((_, val)) => {
189
+ let rerender = ctx.props().selected_tab != Some(val);
190
+ ctx.props().on_select_tab.emit(val);
259
191
  rerender
260
192
  },
261
- ColumnSettingsMsg::OnResetAttributes(()) => {
193
+ ColumnSettingsPanelMsg::OnResetAttributes(()) => {
262
194
  self.header_value.clone_from(&self.initial_header_value);
263
195
  self.expr_value.clone_from(&self.initial_expr_value);
264
196
  self.save_enabled = false;
@@ -266,11 +198,12 @@ impl Component for ColumnSettingsSidebar {
266
198
  self.reset_count += 1;
267
199
  true
268
200
  },
269
- ColumnSettingsMsg::OnSaveAttributes(()) => {
201
+ ColumnSettingsPanelMsg::OnSaveAttributes(()) => {
270
202
  let new_expr = Expression::new(
271
203
  self.header_value.clone().map(|s| s.into()),
272
204
  (*(self.expr_value)).clone().into(),
273
205
  );
206
+
274
207
  match &ctx.props().selected_column {
275
208
  ColumnLocator::Table(_) => {
276
209
  tracing::error!("Tried to save non-expression column!")
@@ -292,7 +225,7 @@ impl Component for ColumnSettingsSidebar {
292
225
  self.save_count += 1;
293
226
  true
294
227
  },
295
- ColumnSettingsMsg::OnDelete(()) => {
228
+ ColumnSettingsPanelMsg::OnDelete(()) => {
296
229
  if ctx.props().selected_column.is_saved_expr() {
297
230
  ctx.props().delete_expr(&self.column_name).unwrap_or_log();
298
231
  }
@@ -300,7 +233,7 @@ impl Component for ColumnSettingsSidebar {
300
233
  ctx.props().on_close.emit(());
301
234
  true
302
235
  },
303
- ColumnSettingsMsg::SessionUpdated(is_update) => {
236
+ ColumnSettingsPanelMsg::SessionUpdated(is_update) => {
304
237
  if !is_update {
305
238
  self.initialize(ctx);
306
239
  true
@@ -308,48 +241,62 @@ impl Component for ColumnSettingsSidebar {
308
241
  false
309
242
  }
310
243
  },
311
- }
244
+ };
245
+
246
+ result
312
247
  }
313
248
 
314
249
  fn view(&self, ctx: &yew::prelude::Context<Self>) -> Html {
315
- let header_props = EditableHeaderProps {
250
+ let header_props = props!(EditableHeaderProps {
251
+ initial_value: self.initial_header_value.clone(),
252
+ placeholder: self.expr_value.clone(),
253
+ reset_count: self.reset_count,
254
+ editable: ctx.props().selected_column.is_expr()
255
+ && matches!(
256
+ ctx.props().selected_tab,
257
+ Some(ColumnSettingsTab::Attributes)
258
+ ),
316
259
  icon_type: self
317
260
  .maybe_ty
318
261
  .map(|ty| ty.into())
319
262
  .or(Some(TypeIconType::Expr)),
320
263
  on_change: ctx.link().batch_callback(|(value, valid)| {
321
264
  vec![
322
- ColumnSettingsMsg::SetHeaderValue(value),
323
- ColumnSettingsMsg::SetHeaderValid(valid),
265
+ ColumnSettingsPanelMsg::SetHeaderValue(value),
266
+ ColumnSettingsPanelMsg::SetHeaderValid(valid),
324
267
  ]
325
268
  }),
326
- editable: ctx.props().selected_column.is_expr()
327
- && matches!(self.selected_tab, ColumnSettingsTab::Attributes),
328
- initial_value: self.initial_header_value.clone(),
329
- placeholder: self.expr_value.clone(),
330
- session: ctx.props().session.clone(),
331
- reset_count: self.reset_count,
332
- };
269
+ session: &ctx.props().session
270
+ });
333
271
 
334
- let expr_editor = ExpressionEditorProps {
335
- session: ctx.props().session.clone(),
272
+ let expr_editor = props!(ExpressionEditorProps {
336
273
  on_input: self.on_input.clone(),
337
274
  on_save: self.on_save.clone(),
338
275
  on_validate: self.on_validate.clone(),
339
276
  alias: ctx.props().selected_column.name().cloned(),
340
277
  disabled: !ctx.props().selected_column.is_expr(),
341
278
  reset_count: self.reset_count,
342
- };
279
+ session: &ctx.props().session
280
+ });
281
+
282
+ let disable_delete = ctx
283
+ .props()
284
+ .session
285
+ .is_locator_active(&ctx.props().selected_column);
343
286
 
344
287
  let save_section = SaveSettingsProps {
345
288
  save_enabled: self.save_enabled,
346
289
  reset_enabled: self.reset_enabled,
347
290
  is_save: ctx.props().selected_column.name().is_some(),
348
- on_reset: ctx.link().callback(ColumnSettingsMsg::OnResetAttributes),
349
- on_save: ctx.link().callback(ColumnSettingsMsg::OnSaveAttributes),
350
- on_delete: ctx.link().callback(ColumnSettingsMsg::OnDelete),
291
+ on_reset: ctx
292
+ .link()
293
+ .callback(ColumnSettingsPanelMsg::OnResetAttributes),
294
+ on_save: ctx
295
+ .link()
296
+ .callback(ColumnSettingsPanelMsg::OnSaveAttributes),
297
+ on_delete: ctx.link().callback(ColumnSettingsPanelMsg::OnDelete),
351
298
  show_danger_zone: ctx.props().selected_column.is_saved_expr(),
352
- disable_delete: ctx.props().is_active,
299
+ disable_delete,
353
300
  };
354
301
 
355
302
  let attrs_tab = AttributesTabProps {
@@ -357,21 +304,28 @@ impl Component for ColumnSettingsSidebar {
357
304
  save_section,
358
305
  };
359
306
 
360
- let style_tab = StyleTabProps {
361
- custom_events: ctx.props().custom_events.clone(),
362
- session: ctx.props().session.clone(),
363
- renderer: ctx.props().renderer.clone(),
364
- presentation: ctx.props().presentation.clone(),
307
+ let style_tab = props!(StyleTabProps {
365
308
  ty: self.maybe_ty,
366
309
  column_name: self.column_name.clone(),
367
310
  group_by_depth: ctx.props().session.get_view_config().group_by.len() as u32,
368
- };
311
+ custom_events: ctx.props().custom_events(),
312
+ presentation: ctx.props().presentation(),
313
+ renderer: ctx.props().renderer(),
314
+ session: ctx.props().session()
315
+ });
369
316
 
370
317
  let tab_children = self.tabs.iter().map(|tab| match tab {
371
318
  ColumnSettingsTab::Attributes => html! { <AttributesTab ..attrs_tab.clone() /> },
372
319
  ColumnSettingsTab::Style => html! { <StyleTab ..style_tab.clone() /> },
373
320
  });
374
321
 
322
+ let selected_tab_idx = self
323
+ .tabs
324
+ .iter()
325
+ .find_position(|tab| Some(**tab) == ctx.props().selected_tab)
326
+ .map(|(idx, _val)| idx)
327
+ .unwrap_or_default();
328
+
375
329
  html! {
376
330
  <>
377
331
  <LocalStyle href={css!("column-settings-panel")} />
@@ -379,13 +333,13 @@ impl Component for ColumnSettingsSidebar {
379
333
  on_close={ctx.props().on_close.clone()}
380
334
  id_prefix="column_settings"
381
335
  width_override={ctx.props().width_override}
382
- selected_tab={self.selected_tab_idx}
336
+ selected_tab={selected_tab_idx}
383
337
  {header_props}
384
338
  >
385
339
  <TabList<ColumnSettingsTab>
386
340
  tabs={self.tabs.clone()}
387
- on_tab_change={ctx.link().callback(ColumnSettingsMsg::SetSelectedTab)}
388
- selected_tab={self.selected_tab_idx}
341
+ on_tab_change={ctx.link().callback(ColumnSettingsPanelMsg::SetSelectedTab)}
342
+ selected_tab={selected_tab_idx}
389
343
  >
390
344
  { for tab_children }
391
345
  </TabList<ColumnSettingsTab>>
@@ -394,3 +348,76 @@ impl Component for ColumnSettingsSidebar {
394
348
  }
395
349
  }
396
350
  }
351
+
352
+ impl ColumnSettingsPanel {
353
+ fn save_enabled_effect(&mut self) {
354
+ let changed = self.expr_value != self.initial_expr_value
355
+ || self.header_value != self.initial_header_value;
356
+ let valid = self.expr_valid && self.header_valid;
357
+ self.save_enabled = changed && valid;
358
+ }
359
+
360
+ fn initialize(&mut self, ctx: &yew::prelude::Context<Self>) {
361
+ let column_name = ctx
362
+ .props()
363
+ .session
364
+ .locator_name_or_default(&ctx.props().selected_column);
365
+
366
+ let initial_expr_value = ctx
367
+ .props()
368
+ .session
369
+ .metadata()
370
+ .get_expression_by_alias(&column_name)
371
+ .unwrap_or_default();
372
+
373
+ let initial_expr_value = Rc::new(initial_expr_value);
374
+ let initial_header_value =
375
+ (*initial_expr_value != column_name).then_some(column_name.clone());
376
+
377
+ let maybe_ty = ctx
378
+ .props()
379
+ .session()
380
+ .locator_view_type(&ctx.props().selected_column);
381
+
382
+ let tabs = {
383
+ let mut tabs = vec![];
384
+ let is_new_expr = ctx.props().selected_column.is_new_expr();
385
+ let show_styles = !is_new_expr
386
+ && ctx
387
+ .props()
388
+ .can_render_column_styles(&column_name)
389
+ .unwrap_or_default();
390
+
391
+ if !is_new_expr && show_styles {
392
+ tabs.push(ColumnSettingsTab::Style);
393
+ }
394
+
395
+ if ctx.props().selected_column.is_expr() {
396
+ tabs.push(ColumnSettingsTab::Attributes);
397
+ }
398
+ tabs
399
+ };
400
+
401
+ let on_input = ctx.link().callback(ColumnSettingsPanelMsg::SetExprValue);
402
+ let on_save = ctx
403
+ .link()
404
+ .callback(ColumnSettingsPanelMsg::OnSaveAttributes);
405
+
406
+ let on_validate = ctx.link().callback(ColumnSettingsPanelMsg::SetExprValid);
407
+ *self = Self {
408
+ column_name,
409
+ expr_value: initial_expr_value.clone(),
410
+ initial_expr_value,
411
+ header_value: initial_header_value.clone(),
412
+ initial_header_value,
413
+ maybe_ty,
414
+ tabs,
415
+ header_valid: true,
416
+ on_input,
417
+ on_save,
418
+ on_validate,
419
+ _session_sub: self._session_sub.take(),
420
+ ..*self
421
+ }
422
+ }
423
+ }
@@ -21,21 +21,7 @@ use yew::prelude::*;
21
21
  use crate::components::column_selector::{EmptyColumn, InPlaceColumn, InvalidColumn};
22
22
  use crate::custom_elements::ColumnDropDownElement;
23
23
  use crate::dragdrop::*;
24
-
25
- /// Must be implemented by `Properties` of children of `DragDropList`, returning
26
- /// the value a DragDropItem represents.
27
- pub trait DragDropListItemProps: Properties {
28
- type Item: Clone + PartialEq;
29
- fn get_item(&self) -> Self::Item;
30
- }
31
-
32
- pub trait DragContext<T> {
33
- fn close(index: usize) -> T;
34
- fn dragleave() -> T;
35
- fn dragenter(index: usize) -> T;
36
- fn create(col: InPlaceColumn) -> T;
37
- fn is_self_move(effect: DragTarget) -> bool;
38
- }
24
+ use crate::utils::DragTarget;
39
25
 
40
26
  #[derive(Properties, Derivative)]
41
27
  #[derivative(Clone(bound = ""))]
@@ -227,11 +213,10 @@ where
227
213
  .position(|x| x.1.1.as_ref().unwrap().props.get_item() == *column);
228
214
 
229
215
  valid_duplicate_drag = is_duplicate.is_some() && !ctx.props().allow_duplicates;
230
- if let Some(duplicate) = is_duplicate
231
- && !is_append
232
- && (!ctx.props().allow_duplicates || is_self_move)
233
- {
234
- columns.remove(duplicate);
216
+ if let Some(duplicate) = is_duplicate {
217
+ if !is_append && (!ctx.props().allow_duplicates || is_self_move) {
218
+ columns.remove(duplicate);
219
+ }
235
220
  }
236
221
 
237
222
  // If inserting into the middle of the list, use
@@ -323,3 +308,18 @@ where
323
308
  }
324
309
  }
325
310
  }
311
+
312
+ /// Must be implemented by `Properties` of children of `DragDropList`, returning
313
+ /// the value a DragDropItem represents.
314
+ pub trait DragDropListItemProps: Properties {
315
+ type Item: Clone + PartialEq;
316
+ fn get_item(&self) -> Self::Item;
317
+ }
318
+
319
+ pub trait DragContext<T> {
320
+ fn close(index: usize) -> T;
321
+ fn dragleave() -> T;
322
+ fn dragenter(index: usize) -> T;
323
+ fn create(col: InPlaceColumn) -> T;
324
+ fn is_self_move(effect: DragTarget) -> bool;
325
+ }
@@ -20,10 +20,6 @@ use super::select::SelectItem;
20
20
  use crate::components::style::LocalStyle;
21
21
  use crate::*;
22
22
 
23
- pub type DropDownMenuItem<T> = SelectItem<T>;
24
-
25
- pub type DropDownMenuMsg = ();
26
-
27
23
  #[derive(Properties, PartialEq)]
28
24
  pub struct DropDownMenuProps<T>
29
25
  where
@@ -44,7 +40,7 @@ impl<T> Component for DropDownMenu<T>
44
40
  where
45
41
  T: Into<Html> + Clone + PartialEq + 'static,
46
42
  {
47
- type Message = DropDownMenuMsg;
43
+ type Message = ();
48
44
  type Properties = DropDownMenuProps<T>;
49
45
 
50
46
  fn create(_ctx: &Context<Self>) -> Self {
@@ -76,7 +72,7 @@ where
76
72
  DropDownMenuItem::OptGroup(name, xs) => {
77
73
  html! {
78
74
  <>
79
- <span class="dropdown-group-label">{ name }</span>
75
+ <span class="dropdown-group-label">{ name.as_ref() }</span>
80
76
  <div class="dropdown-group-container">
81
77
  { xs.iter().map(|x| {
82
78
  let click = ctx.props().callback.reform({
@@ -102,3 +98,5 @@ where
102
98
  html! { <><LocalStyle href={css!("containers/dropdown-menu")} />{ body }</> }
103
99
  }
104
100
  }
101
+
102
+ pub type DropDownMenuItem<T> = SelectItem<T>;
@@ -15,14 +15,11 @@
15
15
 
16
16
  pub mod dragdrop_list;
17
17
  pub mod dropdown_menu;
18
- pub mod kvpair;
19
18
  pub mod scroll_panel;
20
19
  pub mod scroll_panel_item;
21
20
  pub mod select;
22
21
  pub mod sidebar;
22
+ pub mod sidebar_close_button;
23
23
  pub mod split_panel;
24
24
  pub mod tab_list;
25
25
  pub mod trap_door_panel;
26
-
27
- #[cfg(test)]
28
- mod tests;