@perspective-dev/viewer 5.3.0 → 5.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 (265) hide show
  1. package/dist/cdn/perspective-viewer.js +8 -8
  2. package/dist/cdn/perspective-viewer.js.map +3 -3
  3. package/dist/css/blueprint.css +1 -0
  4. package/dist/css/botanical.css +1 -1
  5. package/dist/css/dracula.css +1 -1
  6. package/dist/css/eggplant.css +1 -0
  7. package/dist/css/gruvbox-dark.css +1 -1
  8. package/dist/css/gruvbox.css +1 -1
  9. package/dist/css/icons.css +1 -1
  10. package/dist/css/intl/ar.css +1 -0
  11. package/dist/css/intl/de.css +1 -1
  12. package/dist/css/intl/es.css +1 -1
  13. package/dist/css/intl/fr.css +1 -1
  14. package/dist/css/intl/ja.css +1 -1
  15. package/dist/css/intl/pt.css +1 -1
  16. package/dist/css/intl/zh.css +1 -1
  17. package/dist/css/intl.css +1 -1
  18. package/dist/css/ledger.css +1 -0
  19. package/dist/css/monokai.css +1 -1
  20. package/dist/css/nord.css +1 -0
  21. package/dist/css/phosphor.css +1 -1
  22. package/dist/css/pro-dark.css +1 -1
  23. package/dist/css/pro.css +1 -1
  24. package/dist/css/solarized-dark.css +1 -1
  25. package/dist/css/solarized.css +1 -1
  26. package/dist/css/themes.css +1 -1
  27. package/dist/css/vaporwave.css +1 -1
  28. package/dist/css/velvet.css +1 -0
  29. package/dist/docs/perspective-docs.json +1 -1
  30. package/dist/esm/column-format.d.ts +16 -3
  31. package/dist/esm/extensions.d.ts +0 -5
  32. package/dist/esm/perspective-viewer.inline.js +7 -7
  33. package/dist/esm/perspective-viewer.inline.js.map +3 -3
  34. package/dist/esm/perspective-viewer.js +8 -8
  35. package/dist/esm/perspective-viewer.js.map +3 -3
  36. package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +1 -1
  37. package/dist/wasm/perspective-viewer.d.ts +62 -73
  38. package/dist/wasm/perspective-viewer.js +230 -238
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +18 -28
  41. package/package.json +7 -7
  42. package/src/css/_context_menu.css +1 -1
  43. package/src/css/_dropdown_menu.css +1 -1
  44. package/src/css/_viewer_bundle.css +7 -8
  45. package/src/css/column-dropdown.css +0 -3
  46. package/src/css/column-selector.css +8 -5
  47. package/src/css/column-settings-panel.css +0 -206
  48. package/src/css/column-style.css +95 -0
  49. package/src/css/config-selector.css +18 -10
  50. package/src/css/filter-dropdown.css +5 -5
  51. package/src/css/form/debug.css +28 -4
  52. package/src/css/function-dropdown.css +5 -5
  53. package/src/css/panel-tab.css +23 -0
  54. package/src/css/plugin-selector.css +6 -5
  55. package/src/css/render-warning.css +1 -1
  56. package/src/css/status-bar.css +52 -21
  57. package/src/css/type-icon.css +1 -3
  58. package/src/css/{containers → ui/containers}/context-menu.css +22 -16
  59. package/src/css/ui/containers/dropdown-menu-items.css +66 -0
  60. package/src/css/{containers → ui/containers}/dropdown-menu.css +8 -53
  61. package/src/css/{containers → ui/containers}/tabs.css +13 -3
  62. package/src/css/{dom → ui/dom}/select.css +19 -8
  63. package/src/css/viewer.css +32 -31
  64. package/src/rust/agent/tools.rs +5 -2
  65. package/src/rust/components/chat_panel.rs +1 -1
  66. package/src/rust/components/{form/code_editor.rs → code_editor.rs} +4 -2
  67. package/src/rust/components/column_dropdown.rs +2 -2
  68. package/src/rust/components/column_selector/active_column.rs +15 -9
  69. package/src/rust/components/column_selector/aggregate_selector.rs +1 -1
  70. package/src/rust/components/column_selector/config_selector.rs +2 -2
  71. package/src/rust/components/column_selector/filter_column.rs +8 -5
  72. package/src/rust/components/column_selector/inactive_column.rs +4 -2
  73. package/src/rust/components/column_selector/pivot_column.rs +4 -3
  74. package/src/rust/components/column_selector/sort_column.rs +7 -4
  75. package/src/rust/components/column_selector.rs +3 -3
  76. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +1 -1
  77. package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +15 -17
  78. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +1 -1
  79. package/src/rust/components/column_settings_sidebar/style_tab.rs +296 -238
  80. package/src/rust/components/column_settings_sidebar.rs +3 -4
  81. package/src/rust/components/copy_dropdown.rs +1 -1
  82. package/src/rust/components/datetime_column_style/custom.rs +1 -3
  83. package/src/rust/components/datetime_column_style/simple.rs +16 -6
  84. package/src/rust/components/datetime_column_style.rs +51 -12
  85. package/src/rust/components/{form/debug.rs → debug_panel.rs} +5 -5
  86. package/src/rust/components/{containers/dragdrop_list.rs → dragdrop_list.rs} +2 -10
  87. package/src/rust/components/export_dropdown.rs +1 -1
  88. package/src/rust/components/expression_editor.rs +1 -1
  89. package/src/rust/components/filter_dropdown.rs +2 -2
  90. package/src/rust/components/function_dropdown.rs +2 -2
  91. package/src/rust/components/main_panel/frame_theme.rs +3 -59
  92. package/src/rust/components/main_panel/reconcile.rs +9 -4
  93. package/src/rust/components/main_panel/render.rs +62 -11
  94. package/src/rust/components/main_panel/update.rs +39 -10
  95. package/src/rust/components/main_panel.rs +26 -2
  96. package/src/rust/components/mod.rs +5 -7
  97. package/src/rust/components/new_panel_menu.rs +97 -0
  98. package/src/rust/components/number_series_style.rs +2 -3
  99. package/src/rust/components/panel_menu.rs +61 -87
  100. package/src/rust/components/panel_tab.rs +100 -43
  101. package/src/rust/components/plugin_tab.rs +125 -87
  102. package/src/rust/components/render_warning.rs +2 -2
  103. package/src/rust/components/{status_bar_counter.rs → rows_counter.rs} +10 -10
  104. package/src/rust/components/settings_panel.rs +3 -2
  105. package/src/rust/components/status_bar.rs +113 -20
  106. package/src/rust/components/status_indicator.rs +5 -14
  107. package/src/rust/components/string_column_style.rs +1 -2
  108. package/src/rust/components/{style/mod.rs → style.rs} +32 -15
  109. package/src/rust/components/style_controls/number_string_format/digits_section.rs +25 -15
  110. package/src/rust/components/style_controls/number_string_format/misc_section.rs +7 -3
  111. package/src/rust/components/style_controls/number_string_format/style_section.rs +2 -1
  112. package/src/rust/components/style_controls/number_string_format/types.rs +24 -0
  113. package/src/rust/components/style_controls/number_string_format.rs +37 -14
  114. package/src/rust/components/viewer/msg.rs +43 -30
  115. package/src/rust/components/viewer/panels.rs +50 -19
  116. package/src/rust/components/viewer/render.rs +15 -13
  117. package/src/rust/components/viewer/settings.rs +137 -68
  118. package/src/rust/components/viewer/snapshots.rs +5 -10
  119. package/src/rust/components/viewer/wiring.rs +1 -21
  120. package/src/rust/components/viewer.rs +15 -10
  121. package/src/rust/components/window_editor.rs +8 -9
  122. package/src/rust/config/column_config_schema.rs +358 -52
  123. package/src/rust/config/datetime_column_style.rs +4 -21
  124. package/src/rust/config/mod.rs +0 -2
  125. package/src/rust/config/number_string_format.rs +211 -18
  126. package/src/rust/config/workspace_config.rs +2 -1
  127. package/src/rust/custom_elements/debug_plugin.rs +1 -10
  128. package/src/rust/custom_elements/mod.rs +0 -3
  129. package/src/rust/custom_elements/viewer.rs +0 -18
  130. package/src/rust/js/plugin.rs +0 -86
  131. package/src/rust/lib.rs +12 -15
  132. package/src/rust/presentation/column_locator.rs +3 -7
  133. package/src/rust/presentation.rs +85 -38
  134. package/src/rust/queries/hosted_tables.rs +38 -0
  135. package/src/rust/queries/mod.rs +2 -0
  136. package/src/rust/queries/palette_set.rs +1 -1
  137. package/src/rust/queries/plugin_column_styles.rs +2 -2
  138. package/src/rust/renderer/activate.rs +1 -3
  139. package/src/rust/renderer/dispatch.rs +117 -30
  140. package/src/rust/renderer/limits.rs +24 -5
  141. package/src/rust/renderer/plugin_config.rs +56 -8
  142. package/src/rust/renderer/props.rs +2 -1
  143. package/src/rust/renderer.rs +14 -27
  144. package/src/rust/session/props.rs +4 -3
  145. package/src/rust/session/view_subscription.rs +19 -6
  146. package/src/rust/session.rs +38 -70
  147. package/src/rust/tasks/create_panel.rs +1 -1
  148. package/src/rust/tasks/dismiss_render_warning.rs +1 -1
  149. package/src/rust/tasks/eject.rs +1 -0
  150. package/src/rust/tasks/pipeline.rs +0 -60
  151. package/src/rust/tasks/presize_panels.rs +24 -1
  152. package/src/rust/tasks/restore_and_render.rs +0 -17
  153. package/src/rust/tasks/send_column_config.rs +1 -1
  154. package/src/rust/tasks/send_plugin_config.rs +1 -1
  155. package/src/rust/tasks/set_edit_mode.rs +1 -1
  156. package/src/rust/ui/containers/control_group.rs +113 -0
  157. package/src/rust/{components → ui}/containers/dropdown_menu.rs +5 -2
  158. package/src/rust/{components → ui}/containers/mod.rs +1 -4
  159. package/src/rust/{components → ui}/containers/scroll_panel.rs +0 -22
  160. package/src/rust/{components → ui}/containers/scroll_panel_item.rs +0 -13
  161. package/src/rust/{components → ui}/containers/select.rs +8 -8
  162. package/src/rust/{components → ui}/containers/sidebar.rs +5 -32
  163. package/src/rust/{components → ui}/containers/split_panel.rs +8 -80
  164. package/src/rust/{components → ui}/containers/tab_list.rs +15 -9
  165. package/src/rust/{components → ui}/context_menu.rs +8 -13
  166. package/src/rust/{presentation/drag_helpers.rs → ui/dragdrop.rs} +26 -31
  167. package/src/rust/{components → ui}/font_loader.rs +0 -26
  168. package/src/rust/{components → ui}/form/color_selector.rs +4 -2
  169. package/src/rust/ui/form/intl_label.rs +81 -0
  170. package/src/rust/{components → ui}/form/mirrored_textarea.rs +0 -53
  171. package/src/rust/{components → ui}/form/mod.rs +1 -10
  172. package/src/rust/{components → ui}/form/multi_stop_gradient_selector.rs +4 -5
  173. package/src/rust/{components → ui}/form/named_value_picker.rs +1 -6
  174. package/src/rust/{components → ui}/form/number_field.rs +1 -1
  175. package/src/rust/{components → ui}/form/number_range_field.rs +1 -1
  176. package/src/rust/{components → ui}/form/optional_field.rs +3 -1
  177. package/src/rust/{components → ui}/form/palette_selector.rs +4 -5
  178. package/src/rust/{components → ui}/form/select_enum_field.rs +2 -2
  179. package/src/rust/{components → ui}/form/select_value_field.rs +2 -2
  180. package/src/rust/ui/mod.rs +56 -0
  181. package/src/rust/ui/modal.rs +61 -0
  182. package/src/rust/{components → ui}/portal.rs +174 -79
  183. package/src/rust/{components/style/style_provider.rs → ui/style.rs} +4 -34
  184. package/src/rust/utils/completion.rs +0 -6
  185. package/src/rust/{config/css_scale.rs → utils/css.rs} +38 -35
  186. package/src/rust/utils/mod.rs +2 -0
  187. package/src/rust/workspace.rs +35 -0
  188. package/src/svg/boolean-type.svg +3 -2
  189. package/src/svg/checkbox-checked-icon.svg +4 -7
  190. package/src/svg/checkbox-hover.svg +3 -3
  191. package/src/svg/checkbox-off.svg +2 -3
  192. package/src/svg/checkbox-on.svg +3 -3
  193. package/src/svg/checkbox-unchecked-icon.svg +3 -3
  194. package/src/svg/datagrid-select-column.svg +8 -15
  195. package/src/svg/datagrid-select-region.svg +8 -15
  196. package/src/svg/datagrid-select-row-tree.svg +7 -12
  197. package/src/svg/datagrid-select-row.svg +8 -13
  198. package/src/svg/date-type.svg +4 -23
  199. package/src/svg/drawer-tab-hover.svg +4 -6
  200. package/src/svg/drawer-tab-invert-hover.svg +5 -5
  201. package/src/svg/drawer-tab-invert.svg +3 -5
  202. package/src/svg/drawer-tab.svg +5 -5
  203. package/src/svg/mega-menu-icons-candlestick.svg +5 -37
  204. package/src/svg/mega-menu-icons-ohlc.svg +4 -39
  205. package/src/svg/mega-menu-icons-sunburst.svg +4 -38
  206. package/src/svg/mega-menu-icons-treemap.svg +3 -43
  207. package/src/svg/mega-menu-icons-y-scatter.svg +12 -72
  208. package/src/svg/new-panel-icon.svg +4 -0
  209. package/src/svg/number-type.svg +3 -3
  210. package/src/svg/radio-hover.svg +3 -3
  211. package/src/svg/radio-off.svg +3 -3
  212. package/src/svg/radio-on.svg +3 -3
  213. package/src/svg/status_ok.svg +3 -26
  214. package/src/svg/string-type.svg +4 -8
  215. package/src/svg/theme-icon.svg +5 -5
  216. package/src/themes/blueprint.css +133 -0
  217. package/src/themes/botanical.css +3 -52
  218. package/src/themes/defaults.css +3 -144
  219. package/src/themes/dracula.css +1 -71
  220. package/src/themes/eggplant.css +131 -0
  221. package/src/themes/gruvbox-dark.css +2 -79
  222. package/src/themes/gruvbox.css +2 -40
  223. package/src/themes/icons.css +2 -10
  224. package/src/themes/intl/ar.css +185 -0
  225. package/src/themes/intl/de.css +65 -33
  226. package/src/themes/intl/es.css +60 -28
  227. package/src/themes/intl/fr.css +60 -28
  228. package/src/themes/intl/ja.css +62 -30
  229. package/src/themes/intl/pt.css +58 -26
  230. package/src/themes/intl/zh.css +68 -36
  231. package/src/themes/intl.css +42 -7
  232. package/src/themes/ledger.css +137 -0
  233. package/src/themes/monokai.css +1 -64
  234. package/src/themes/nord.css +131 -0
  235. package/src/themes/phosphor.css +1 -61
  236. package/src/themes/pro-dark.css +1 -52
  237. package/src/themes/pro.css +98 -0
  238. package/src/themes/solarized-dark.css +1 -46
  239. package/src/themes/solarized.css +1 -24
  240. package/src/themes/themes.css +10 -5
  241. package/src/themes/vaporwave.css +1 -57
  242. package/src/themes/velvet.css +132 -0
  243. package/src/ts/column-format.ts +52 -2
  244. package/src/ts/extensions.ts +0 -13
  245. package/src/ts/ts-rs/ViewOnUpdateResp.ts +1 -1
  246. package/src/css/plugin-settings-panel.css +0 -99
  247. package/src/rust/components/modal.rs +0 -177
  248. package/src/rust/custom_elements/copy_dropdown.rs +0 -219
  249. package/src/rust/custom_elements/export_dropdown.rs +0 -216
  250. package/src/rust/custom_elements/modal.rs +0 -299
  251. package/src/svg/dropdown-selector-light.svg +0 -3
  252. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline0.js +0 -0
  253. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline1.js +0 -0
  254. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline2.js +0 -0
  255. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline3.js +0 -0
  256. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline4.js +0 -0
  257. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline5.js +0 -0
  258. /package/src/css/{containers → ui/containers}/scroll-panel.css +0 -0
  259. /package/src/css/{containers → ui/containers}/split-panel.css +0 -0
  260. /package/src/css/{dom → ui/dom}/checkbox.css +0 -0
  261. /package/src/css/{dom → ui/dom}/scrollbar.css +0 -0
  262. /package/src/css/{form → ui/form}/mirrored-textarea.css +0 -0
  263. /package/src/rust/components/{form → code_editor}/highlight.rs +0 -0
  264. /package/src/rust/{components → ui}/containers/sidebar_close_button.rs +0 -0
  265. /package/src/rust/{components → ui}/form/number_input.rs +0 -0
@@ -14,12 +14,12 @@ mod agg_depth_selector;
14
14
  pub(crate) mod primitive_field;
15
15
  mod symbol;
16
16
 
17
- use std::collections::HashMap;
17
+ use std::collections::{BTreeMap, HashMap};
18
18
  use std::rc::Rc;
19
19
 
20
20
  use itertools::Itertools;
21
21
  use perspective_client::config::ColumnType;
22
- use yew::{Html, Properties, function_component, html};
22
+ use yew::{Callback, Html, Properties, function_component, html};
23
23
 
24
24
  use self::agg_depth_selector::*;
25
25
  use self::primitive_field::{
@@ -31,15 +31,16 @@ use crate::components::number_series_style::NumberSeriesStyle;
31
31
  use crate::components::string_column_style::StringColumnStyle;
32
32
  use crate::components::style_controls::CustomNumberFormat;
33
33
  use crate::config::{
34
- ControlSpec, CssKind, CustomNumberFormatConfig, DatetimeColumnStyleConfig,
35
- NumberSeriesStyleConfig, StringColumnStyleConfig,
34
+ ColumnConfigFieldUpdate, ControlSpec, CustomNumberFormatConfig, DatetimeColumnStyleConfig,
35
+ NumberFormatDefaults, NumberSeriesStyleConfig, StringColumnStyleConfig,
36
36
  };
37
37
  use crate::presentation::Presentation;
38
38
  use crate::queries::{fetch_column_abs_max, get_column_config_schema, named_values};
39
39
  use crate::renderer::Renderer;
40
40
  use crate::session::Session;
41
41
  use crate::tasks::send_column_config;
42
- use crate::utils::PtrEqRc;
42
+ use crate::ui::ControlGroup;
43
+ use crate::utils::{CssKind, NamedValue, PtrEqRc};
43
44
  use crate::workspace::Workspace;
44
45
 
45
46
  #[derive(Clone, PartialEq, Properties)]
@@ -133,241 +134,27 @@ pub fn StyleTab(props: &StyleTabProps) -> Html {
133
134
  })
134
135
  };
135
136
 
136
- fn deser_sub<T: serde::de::DeserializeOwned>(
137
- raw: &Option<serde_json::Map<String, serde_json::Value>>,
138
- ) -> Option<T> {
139
- raw.as_ref()
140
- .and_then(|m| serde_json::from_value::<T>(serde_json::Value::Object(m.clone())).ok())
141
- }
137
+ let on_group_toggle = {
138
+ let presentation = props.presentation.clone();
139
+ yew::Callback::from(move |(key, open): (String, bool)| {
140
+ presentation.set_control_group_collapsed(&key, !open);
141
+ })
142
+ };
143
+
144
+ let ctx = FieldRenderCtx {
145
+ props,
146
+ raw_config: &raw_config,
147
+ on_change: &on_change,
148
+ on_group_toggle: &on_group_toggle,
149
+ on_pin: &on_pin,
150
+ named_colors: &named_colors,
151
+ named_palettes: &named_palettes,
152
+ named_gradients: &named_gradients,
153
+ restored: &restored,
154
+ };
142
155
 
143
156
  let components = schema
144
- .map(|schema| {
145
- schema
146
- .fields
147
- .into_iter()
148
- .filter_map(|spec| {
149
- let keys: Vec<String> = spec
150
- .serialized_keys()
151
- .into_iter()
152
- .map(|s| s.to_string())
153
- .collect();
154
- let component = match spec {
155
- ControlSpec::AggregateDepth => {
156
- let aggregate_depth = raw_config
157
- .as_ref()
158
- .and_then(|m| m.get("aggregate_depth"))
159
- .and_then(|v| v.as_u64())
160
- .unwrap_or(0)
161
- as u32;
162
- html! {
163
- <AggregateDepthSelector
164
- group_by_depth={props.group_by_depth}
165
- on_change={on_change.clone()}
166
- column_name={props.column_name.to_owned()}
167
- value={aggregate_depth}
168
- keys={keys.clone()}
169
- />
170
- }
171
- },
172
- ControlSpec::NumberSeriesStyle {
173
- default: default_config,
174
- } => {
175
- let config: Option<NumberSeriesStyleConfig> = deser_sub(&raw_config);
176
- html! {
177
- <NumberSeriesStyle
178
- {config}
179
- {default_config}
180
- on_change={on_change.clone()}
181
- keys={keys.clone()}
182
- />
183
- }
184
- },
185
- ControlSpec::DatetimeFormat => {
186
- let config: Option<DatetimeColumnStyleConfig> = deser_sub(&raw_config);
187
- let enable_time_config = props.ty.unwrap() == ColumnType::Datetime;
188
- html! {
189
- <DatetimeColumnStyle
190
- {enable_time_config}
191
- {config}
192
- on_change={on_change.clone()}
193
- keys={keys.clone()}
194
- />
195
- }
196
- },
197
- ControlSpec::StringFormat => {
198
- let config: Option<StringColumnStyleConfig> = deser_sub(&raw_config);
199
- html! {
200
- <StringColumnStyle
201
- {config}
202
- on_change={on_change.clone()}
203
- keys={keys.clone()}
204
- />
205
- }
206
- },
207
- ControlSpec::Symbols {
208
- default: default_config,
209
- } => {
210
- let restored_config: HashMap<String, String> = raw_config
211
- .as_ref()
212
- .and_then(|m| m.get("symbols"))
213
- .and_then(|v| serde_json::from_value(v.clone()).ok())
214
- .unwrap_or_default();
215
-
216
- html! {
217
- <SymbolStyle
218
- {default_config}
219
- restored_config={Some(restored_config)}
220
- on_change={on_change.clone()}
221
- column_name={props.column_name.clone()}
222
- selected_theme={props.selected_theme.clone()}
223
- session={props.session.clone()}
224
- keys={keys.clone()}
225
- />
226
- }
227
- },
228
- ControlSpec::NumberFormat => {
229
- let restored_config: CustomNumberFormatConfig = raw_config
230
- .as_ref()
231
- .and_then(|m| m.get("number_format"))
232
- .and_then(|v| serde_json::from_value(v.clone()).ok())
233
- .unwrap_or_default();
234
-
235
- html! {
236
- <CustomNumberFormat
237
- {restored_config}
238
- on_change={on_change.clone()}
239
- view_type={props.ty.unwrap()}
240
- column_name={props.column_name.clone()}
241
- keys={keys.clone()}
242
- />
243
- }
244
- },
245
- ControlSpec::Enum {
246
- key,
247
- variants,
248
- default,
249
- } => {
250
- let current = raw_config
251
- .as_ref()
252
- .and_then(|m| m.get(&key))
253
- .and_then(|v| v.as_str().map(|s| s.to_string()));
254
-
255
- html! {
256
- <EnumField
257
- field_key={key}
258
- {variants}
259
- {default}
260
- {current}
261
- on_change={on_change.clone()}
262
- />
263
- }
264
- },
265
- ControlSpec::Bool { key, default } => {
266
- let current = raw_config
267
- .as_ref()
268
- .and_then(|m| m.get(&key))
269
- .and_then(|v| v.as_bool());
270
- html! {
271
- <BoolField
272
- field_key={key}
273
- {default}
274
- {current}
275
- on_change={on_change.clone()}
276
- />
277
- }
278
- },
279
- ControlSpec::Color { key, default } => {
280
- let current = raw_config
281
- .as_ref()
282
- .and_then(|m| m.get(&key))
283
- .and_then(|v| v.as_str().map(|s| s.to_string()));
284
- html! {
285
- <ColorField
286
- field_key={key}
287
- {default}
288
- {current}
289
- named={named_colors.clone()}
290
- restored={restored.clone()}
291
- on_pin={on_pin.clone()}
292
- on_change={on_change.clone()}
293
- />
294
- }
295
- },
296
- ControlSpec::Palette { key, default, max } => {
297
- let current = raw_config
298
- .as_ref()
299
- .and_then(|m| m.get(&key))
300
- .and_then(|v| v.as_str().map(|s| s.to_string()));
301
- html! {
302
- <PaletteField
303
- field_key={key}
304
- {default}
305
- {max}
306
- {current}
307
- named={named_palettes.clone()}
308
- restored={restored.clone()}
309
- on_pin={on_pin.clone()}
310
- on_change={on_change.clone()}
311
- />
312
- }
313
- },
314
- ControlSpec::GradientStops {
315
- key,
316
- default,
317
- discrete,
318
- } => {
319
- let current = raw_config
320
- .as_ref()
321
- .and_then(|m| m.get(&key))
322
- .and_then(|v| v.as_str().map(|s| s.to_string()));
323
- html! {
324
- <GradientStopsField
325
- field_key={key}
326
- {default}
327
- {discrete}
328
- {current}
329
- named={named_gradients.clone()}
330
- restored={restored.clone()}
331
- on_pin={on_pin.clone()}
332
- on_change={on_change.clone()}
333
- />
334
- }
335
- },
336
- ControlSpec::Number {
337
- key,
338
- default,
339
- min,
340
- max,
341
- step,
342
- include,
343
- } => {
344
- let current = raw_config
345
- .as_ref()
346
- .and_then(|m| m.get(&key))
347
- .and_then(|v| v.as_f64());
348
- html! {
349
- <NumberFieldPrimitive
350
- field_key={key}
351
- {default}
352
- {current}
353
- {min}
354
- {max}
355
- {step}
356
- {include}
357
- on_change={on_change.clone()}
358
- />
359
- }
360
- },
361
- ControlSpec::String { .. } => {
362
- return None;
363
- },
364
- };
365
-
366
- let key = format!("{}::{}", props.column_name, keys.join("+"));
367
- Some(html! { <fieldset class="style-control" {key}>{ component }</fieldset> })
368
- })
369
- .collect_vec()
370
- })
157
+ .map(|schema| render_specs(schema.fields, &ctx))
371
158
  .unwrap_or_else(|error| {
372
159
  tracing::error!("{}", error);
373
160
  vec![]
@@ -379,3 +166,274 @@ pub fn StyleTab(props: &StyleTabProps) -> Html {
379
166
  </div>
380
167
  }
381
168
  }
169
+
170
+ fn deser_sub<T: serde::de::DeserializeOwned>(
171
+ raw: &Option<serde_json::Map<String, serde_json::Value>>,
172
+ ) -> Option<T> {
173
+ raw.as_ref()
174
+ .and_then(|m| serde_json::from_value::<T>(serde_json::Value::Object(m.clone())).ok())
175
+ }
176
+
177
+ struct FieldRenderCtx<'a> {
178
+ props: &'a StyleTabProps,
179
+ raw_config: &'a Option<serde_json::Map<String, serde_json::Value>>,
180
+ on_change: &'a Callback<ColumnConfigFieldUpdate>,
181
+ on_group_toggle: &'a Callback<(String, bool)>,
182
+ on_pin: &'a Callback<(CssKind, String)>,
183
+ named_colors: &'a Rc<Vec<NamedValue>>,
184
+ named_palettes: &'a Rc<Vec<NamedValue>>,
185
+ named_gradients: &'a Rc<Vec<NamedValue>>,
186
+ restored: &'a Rc<BTreeMap<String, String>>,
187
+ }
188
+
189
+ fn render_specs(specs: Vec<ControlSpec>, ctx: &FieldRenderCtx) -> Vec<Html> {
190
+ specs
191
+ .into_iter()
192
+ .filter_map(|spec| match spec {
193
+ ControlSpec::Group { key, fields } => {
194
+ let children = render_specs(fields, ctx);
195
+ (!children.is_empty()).then(|| {
196
+ let open = !ctx.props.presentation.is_control_group_collapsed(&key);
197
+
198
+ html! {
199
+ <ControlGroup
200
+ key={format!("{}::group::{}", ctx.props.column_name, key)}
201
+ group_key={key.clone()}
202
+ {open}
203
+ on_toggle={ctx.on_group_toggle.clone()}
204
+ >
205
+ { children }
206
+ </ControlGroup>
207
+ }
208
+ })
209
+ },
210
+ spec => {
211
+ let keys: Vec<String> = spec
212
+ .serialized_keys()
213
+ .into_iter()
214
+ .map(|s| s.to_string())
215
+ .collect();
216
+
217
+ let component = render_leaf(spec, &keys, ctx)?;
218
+ let key = format!("{}::{}", ctx.props.column_name, keys.join("+"));
219
+ Some(html! { <fieldset class="style-control" {key}>{ component }</fieldset> })
220
+ },
221
+ })
222
+ .collect_vec()
223
+ }
224
+
225
+ fn render_leaf(spec: ControlSpec, keys: &[String], ctx: &FieldRenderCtx) -> Option<Html> {
226
+ let props = ctx.props;
227
+ let raw_config = ctx.raw_config;
228
+ let on_change = ctx.on_change;
229
+ let component = match spec {
230
+ ControlSpec::AggregateDepth => {
231
+ let aggregate_depth = raw_config
232
+ .as_ref()
233
+ .and_then(|m| m.get("aggregate_depth"))
234
+ .and_then(|v| v.as_u64())
235
+ .unwrap_or(0) as u32;
236
+ html! {
237
+ <AggregateDepthSelector
238
+ group_by_depth={props.group_by_depth}
239
+ on_change={on_change.clone()}
240
+ column_name={props.column_name.to_owned()}
241
+ value={aggregate_depth}
242
+ keys={keys.to_vec()}
243
+ />
244
+ }
245
+ },
246
+ ControlSpec::NumberSeriesStyle {
247
+ default: default_config,
248
+ } => {
249
+ let config: Option<NumberSeriesStyleConfig> = deser_sub(raw_config);
250
+ html! {
251
+ <NumberSeriesStyle
252
+ {config}
253
+ {default_config}
254
+ on_change={on_change.clone()}
255
+ keys={keys.to_vec()}
256
+ />
257
+ }
258
+ },
259
+ ControlSpec::DatetimeFormat { default } => {
260
+ let config: Option<DatetimeColumnStyleConfig> = deser_sub(raw_config);
261
+ let enable_time_config = props.ty.unwrap() == ColumnType::Datetime;
262
+ let default_format = Rc::new(default.unwrap_or_default());
263
+ html! {
264
+ <DatetimeColumnStyle
265
+ {enable_time_config}
266
+ {config}
267
+ {default_format}
268
+ on_change={on_change.clone()}
269
+ keys={keys.to_vec()}
270
+ />
271
+ }
272
+ },
273
+ ControlSpec::StringFormat => {
274
+ let config: Option<StringColumnStyleConfig> = deser_sub(raw_config);
275
+ html! {
276
+ <StringColumnStyle {config} on_change={on_change.clone()} keys={keys.to_vec()} />
277
+ }
278
+ },
279
+ ControlSpec::Symbols {
280
+ default: default_config,
281
+ } => {
282
+ let restored_config: HashMap<String, String> = raw_config
283
+ .as_ref()
284
+ .and_then(|m| m.get("symbols"))
285
+ .and_then(|v| serde_json::from_value(v.clone()).ok())
286
+ .unwrap_or_default();
287
+
288
+ html! {
289
+ <SymbolStyle
290
+ {default_config}
291
+ restored_config={Some(restored_config)}
292
+ on_change={on_change.clone()}
293
+ column_name={props.column_name.clone()}
294
+ selected_theme={props.selected_theme.clone()}
295
+ session={props.session.clone()}
296
+ keys={keys.to_vec()}
297
+ />
298
+ }
299
+ },
300
+ ControlSpec::NumberFormat { default } => {
301
+ let restored_config: CustomNumberFormatConfig = raw_config
302
+ .as_ref()
303
+ .and_then(|m| m.get("number_format"))
304
+ .and_then(|v| serde_json::from_value(v.clone()).ok())
305
+ .unwrap_or_default();
306
+
307
+ let view_type = props.ty.unwrap();
308
+ let defaults = Rc::new(NumberFormatDefaults::resolve(
309
+ default.as_ref(),
310
+ view_type == ColumnType::Float,
311
+ ));
312
+
313
+ html! {
314
+ <CustomNumberFormat
315
+ {restored_config}
316
+ {defaults}
317
+ on_change={on_change.clone()}
318
+ {view_type}
319
+ column_name={props.column_name.clone()}
320
+ keys={keys.to_vec()}
321
+ />
322
+ }
323
+ },
324
+ ControlSpec::Enum {
325
+ key,
326
+ variants,
327
+ default,
328
+ } => {
329
+ let current = raw_config
330
+ .as_ref()
331
+ .and_then(|m| m.get(&key))
332
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
333
+
334
+ html! {
335
+ <EnumField
336
+ field_key={key}
337
+ {variants}
338
+ {default}
339
+ {current}
340
+ on_change={on_change.clone()}
341
+ />
342
+ }
343
+ },
344
+ ControlSpec::Bool { key, default } => {
345
+ let current = raw_config
346
+ .as_ref()
347
+ .and_then(|m| m.get(&key))
348
+ .and_then(|v| v.as_bool());
349
+ html! { <BoolField field_key={key} {default} {current} on_change={on_change.clone()} /> }
350
+ },
351
+ ControlSpec::Color { key, default } => {
352
+ let current = raw_config
353
+ .as_ref()
354
+ .and_then(|m| m.get(&key))
355
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
356
+ html! {
357
+ <ColorField
358
+ field_key={key}
359
+ {default}
360
+ {current}
361
+ named={ctx.named_colors.clone()}
362
+ restored={ctx.restored.clone()}
363
+ on_pin={ctx.on_pin.clone()}
364
+ on_change={on_change.clone()}
365
+ />
366
+ }
367
+ },
368
+ ControlSpec::Palette { key, default, max } => {
369
+ let current = raw_config
370
+ .as_ref()
371
+ .and_then(|m| m.get(&key))
372
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
373
+ html! {
374
+ <PaletteField
375
+ field_key={key}
376
+ {default}
377
+ {max}
378
+ {current}
379
+ named={ctx.named_palettes.clone()}
380
+ restored={ctx.restored.clone()}
381
+ on_pin={ctx.on_pin.clone()}
382
+ on_change={on_change.clone()}
383
+ />
384
+ }
385
+ },
386
+ ControlSpec::GradientStops {
387
+ key,
388
+ default,
389
+ discrete,
390
+ } => {
391
+ let current = raw_config
392
+ .as_ref()
393
+ .and_then(|m| m.get(&key))
394
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
395
+ html! {
396
+ <GradientStopsField
397
+ field_key={key}
398
+ {default}
399
+ {discrete}
400
+ {current}
401
+ named={ctx.named_gradients.clone()}
402
+ restored={ctx.restored.clone()}
403
+ on_pin={ctx.on_pin.clone()}
404
+ on_change={on_change.clone()}
405
+ />
406
+ }
407
+ },
408
+ ControlSpec::Number {
409
+ key,
410
+ default,
411
+ min,
412
+ max,
413
+ step,
414
+ include,
415
+ } => {
416
+ let current = raw_config
417
+ .as_ref()
418
+ .and_then(|m| m.get(&key))
419
+ .and_then(|v| v.as_f64());
420
+ html! {
421
+ <NumberFieldPrimitive
422
+ field_key={key}
423
+ {default}
424
+ {current}
425
+ {min}
426
+ {max}
427
+ {step}
428
+ {include}
429
+ on_change={on_change.clone()}
430
+ />
431
+ }
432
+ },
433
+ ControlSpec::String { .. } | ControlSpec::Group { .. } => {
434
+ return None;
435
+ },
436
+ };
437
+
438
+ Some(component)
439
+ }
@@ -29,9 +29,7 @@ use crate::components::column_settings_sidebar::attributes_tab::AttributesTab;
29
29
  use crate::components::column_settings_sidebar::save_settings::SaveSettingsProps;
30
30
  use crate::components::column_settings_sidebar::style_tab::StyleTab;
31
31
  use crate::components::column_settings_sidebar::window_tab::{WindowTab, WindowTabProps};
32
- use crate::components::containers::sidebar::Sidebar;
33
- use crate::components::containers::tab_list::TabList;
34
- use crate::components::editable_header::EditableHeaderProps;
32
+ use crate::components::editable_header::{EditableHeader, EditableHeaderProps};
35
33
  use crate::components::expression_editor::ExpressionEditorProps;
36
34
  use crate::components::type_icon::TypeIconType;
37
35
  use crate::components::window_editor::WindowEditorProps;
@@ -41,6 +39,7 @@ use crate::session::{Session, SessionMetadataRc};
41
39
  use crate::tasks::{
42
40
  delete_expr, delete_window, save_expr, save_window, update_expr, update_window,
43
41
  };
42
+ use crate::ui::{Sidebar, TabList};
44
43
  use crate::utils::PtrEqRc;
45
44
  use crate::workspace::Workspace;
46
45
 
@@ -519,7 +518,7 @@ impl Component for ColumnSettingsPanel {
519
518
  is_pinned={ctx.props().is_pinned}
520
519
  on_toggle_pin={Some(ctx.props().on_toggle_pin.clone())}
521
520
  selected_tab={selected_tab_idx}
522
- {header_props}
521
+ header={html! { <EditableHeader ..header_props /> }}
523
522
  >
524
523
  <TabList<ColumnSettingsTab>
525
524
  tabs={self.tabs.clone()}
@@ -14,9 +14,9 @@ use std::rc::Rc;
14
14
 
15
15
  use yew::prelude::*;
16
16
 
17
- use super::containers::dropdown_menu::*;
18
17
  use crate::config::*;
19
18
  use crate::renderer::*;
19
+ use crate::ui::{DropDownMenu, DropDownMenuItem};
20
20
 
21
21
  type CopyDropDownMenuItem = DropDownMenuItem<ExportFile>;
22
22
 
@@ -14,10 +14,8 @@ use std::rc::Rc;
14
14
 
15
15
  use yew::prelude::*;
16
16
 
17
- use crate::components::form::number_field::NumberField;
18
- use crate::components::form::select_value_field::SelectValueField;
19
- use crate::components::modal::{ModalLink, SetModalLink};
20
17
  use crate::config::*;
18
+ use crate::ui::{ModalLink, NumberField, SelectValueField, SetModalLink};
21
19
  use crate::utils::WeakScope;
22
20
 
23
21
  #[derive(Properties)]
@@ -12,9 +12,8 @@
12
12
 
13
13
  use yew::prelude::*;
14
14
 
15
- use crate::components::form::select_enum_field::SelectEnumField;
16
- use crate::components::modal::{ModalLink, SetModalLink};
17
15
  use crate::config::*;
16
+ use crate::ui::{ModalLink, SelectEnumField, SetModalLink};
18
17
  use crate::utils::WeakScope;
19
18
 
20
19
  #[derive(Properties)]
@@ -22,6 +21,13 @@ pub struct DatetimeStyleSimpleProps {
22
21
  pub enable_time_config: bool,
23
22
  pub config: SimpleDatetimeStyleConfig,
24
23
 
24
+ /// The plugin-declared default preset for each style select.
25
+ #[prop_or(SimpleDatetimeFormat::Short)]
26
+ pub date_style_default: SimpleDatetimeFormat,
27
+
28
+ #[prop_or(SimpleDatetimeFormat::Medium)]
29
+ pub time_style_default: SimpleDatetimeFormat,
30
+
25
31
  #[prop_or_default]
26
32
  pub on_change: Callback<SimpleDatetimeStyleConfig>,
27
33
 
@@ -37,7 +43,10 @@ impl ModalLink<DatetimeStyleSimple> for DatetimeStyleSimpleProps {
37
43
 
38
44
  impl PartialEq for DatetimeStyleSimpleProps {
39
45
  fn eq(&self, other: &Self) -> bool {
40
- self.enable_time_config == other.enable_time_config && self.config == other.config
46
+ self.enable_time_config == other.enable_time_config
47
+ && self.config == other.config
48
+ && self.date_style_default == other.date_style_default
49
+ && self.time_style_default == other.time_style_default
41
50
  }
42
51
  }
43
52
 
@@ -69,12 +78,12 @@ impl Component for DatetimeStyleSimple {
69
78
  fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
70
79
  match msg {
71
80
  DatetimeStyleSimpleMsg::DateStyleChanged(format) => {
72
- self.config.date_style = format.unwrap_or_default();
81
+ self.config.date_style = format.unwrap_or(ctx.props().date_style_default);
73
82
  self.dispatch_config(ctx);
74
83
  true
75
84
  },
76
85
  DatetimeStyleSimpleMsg::TimeStyleChanged(format) => {
77
- self.config.time_style = format.unwrap_or_default();
86
+ self.config.time_style = format.unwrap_or(ctx.props().time_style_default);
78
87
  self.dispatch_config(ctx);
79
88
  true
80
89
  },
@@ -99,13 +108,14 @@ impl Component for DatetimeStyleSimple {
99
108
  label="date-style"
100
109
  on_change={ctx.link().callback(DatetimeStyleSimpleMsg::DateStyleChanged)}
101
110
  current_value={self.config.date_style}
111
+ default_value={ctx.props().date_style_default}
102
112
  />
103
113
  if ctx.props().enable_time_config {
104
114
  <SelectEnumField<SimpleDatetimeFormat>
105
115
  label="time-style"
106
116
  on_change={ctx.link().callback(DatetimeStyleSimpleMsg::TimeStyleChanged)}
107
117
  current_value={self.config.time_style}
108
- default_value={SimpleDatetimeFormat::Medium}
118
+ default_value={ctx.props().time_style_default}
109
119
  />
110
120
  }
111
121
  </>