@perspective-dev/viewer 4.2.0 → 4.3.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 (45) 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 -0
  4. package/dist/css/themes.css +1 -1
  5. package/dist/esm/extensions.d.ts +32 -1
  6. package/dist/esm/perspective-viewer.d.ts +1 -0
  7. package/dist/esm/perspective-viewer.inline.js +2 -2
  8. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  9. package/dist/esm/perspective-viewer.js +2 -2
  10. package/dist/esm/perspective-viewer.js.map +4 -4
  11. package/dist/esm/ts-rs/GroupRollupMode.d.ts +1 -0
  12. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +2 -0
  13. package/dist/wasm/perspective-viewer.d.ts +14 -14
  14. package/dist/wasm/perspective-viewer.js +88 -80
  15. package/dist/wasm/perspective-viewer.wasm +0 -0
  16. package/dist/wasm/perspective-viewer.wasm.d.ts +14 -14
  17. package/package.json +3 -2
  18. package/src/less/column-selector.less +2 -2
  19. package/src/less/config-selector.less +66 -4
  20. package/src/rust/components/column_selector/config_selector.rs +102 -29
  21. package/src/rust/components/column_selector/pivot_column.rs +12 -7
  22. package/src/rust/components/column_selector.rs +27 -17
  23. package/src/rust/components/containers/dragdrop_list.rs +27 -6
  24. package/src/rust/components/containers/scroll_panel.rs +8 -1
  25. package/src/rust/components/containers/select.rs +3 -3
  26. package/src/rust/components/containers/split_panel.rs +2 -2
  27. package/src/rust/components/plugin_selector.rs +15 -5
  28. package/src/rust/components/status_indicator.rs +3 -0
  29. package/src/rust/js/plugin.rs +19 -0
  30. package/src/rust/model/intersection_observer.rs +3 -1
  31. package/src/rust/renderer/registry.rs +8 -1
  32. package/src/rust/session/column_defaults_update.rs +18 -0
  33. package/src/rust/session/replace_expression_update.rs +1 -0
  34. package/src/themes/botanical.less +142 -0
  35. package/src/themes/themes.less +2 -1
  36. package/src/ts/extensions.ts +73 -2
  37. package/src/ts/perspective-viewer.ts +1 -0
  38. package/src/ts/ts-rs/GroupRollupMode.ts +3 -0
  39. package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -1
  40. package/tsconfig.json +1 -0
  41. /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline0.js +0 -0
  42. /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline1.js +0 -0
  43. /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline2.js +0 -0
  44. /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline3.js +0 -0
  45. /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline4.js +0 -0
@@ -30,6 +30,44 @@
30
30
  }
31
31
  }
32
32
 
33
+ #top_panel.group-rollup-mode-total {
34
+ #group_by {
35
+ width: 100%;
36
+ // height: 26px;
37
+ .pivot-column {
38
+ .pivot-column-total {
39
+ min-height: 24px;
40
+ margin-bottom: 4px;
41
+ &:before {
42
+ background-color: var(--plugin--background);
43
+ }
44
+ }
45
+
46
+ .column_name {
47
+ color: var(--inactive--color);
48
+ }
49
+
50
+ .type-icon {
51
+ background-color: var(--inactive--color);
52
+ }
53
+
54
+ &:hover .pivot-column-border {
55
+ border-color: var(--inactive--color, #ababab);
56
+ }
57
+
58
+ // input {
59
+ // background-color: var(--plugin--background);
60
+ // pointer-events: none;
61
+ // border: 1px solid var(--inactive--color);
62
+ // color: var(--inactive--color) !important;
63
+ // // &:placeholder {
64
+
65
+ // // }
66
+ // }
67
+ }
68
+ }
69
+ }
70
+
33
71
  #top_panel {
34
72
  display: flex;
35
73
  flex-direction: column;
@@ -270,6 +308,30 @@
270
308
  display: inline-block;
271
309
  }
272
310
 
311
+ .pivot_controls {
312
+ display: flex;
313
+ justify-content: flex-end;
314
+ height: 15px;
315
+ margin-bottom: -24px;
316
+ margin-right: 28px;
317
+ margin-top: 9px;
318
+ select:hover {
319
+ color: var(--icon--color, inherit);
320
+ }
321
+ }
322
+
323
+ .group_rollup_wrapper {
324
+ width: 48px;
325
+ margin-bottom: -30px;
326
+ flex: 0 1 auto;
327
+ color: var(--inactive--color);
328
+ padding-top: 15px;
329
+ font-size: 9px;
330
+ select {
331
+ font-size: 9px !important;
332
+ }
333
+ }
334
+
273
335
  #transpose_button {
274
336
  cursor: pointer;
275
337
  flex-grow: 0;
@@ -278,12 +340,12 @@
278
340
  user-select: none;
279
341
  padding: 0;
280
342
  align-self: center;
281
- margin-bottom: -23px;
282
- margin-top: 11.5px;
283
- align-self: flex-end;
343
+ // margin-bottom: -23px;
344
+ // margin-top: 11.5px;
345
+ // align-self: flex-end;
284
346
  z-index: 1;
285
347
  min-height: 0px;
286
- margin-right: 30px;
348
+ // margin-right: 30px;
287
349
 
288
350
  &:hover:before {
289
351
  color: var(--icon--color, inherit);
@@ -23,6 +23,7 @@ use super::filter_column::*;
23
23
  use super::pivot_column::*;
24
24
  use super::sort_column::*;
25
25
  use crate::components::containers::dragdrop_list::*;
26
+ use crate::components::containers::select::{Select, SelectItem};
26
27
  use crate::components::style::LocalStyle;
27
28
  use crate::custom_elements::{ColumnDropDownElement, FilterDropDownElement};
28
29
  use crate::dragdrop::*;
@@ -32,7 +33,7 @@ use crate::session::*;
32
33
  use crate::utils::*;
33
34
  use crate::{PerspectiveProperties, css};
34
35
 
35
- #[derive(Properties, PerspectiveProperties!)]
36
+ #[derive(Clone, Properties, PerspectiveProperties!)]
36
37
  pub struct ConfigSelectorProps {
37
38
  pub onselect: Callback<()>,
38
39
 
@@ -63,6 +64,7 @@ pub enum ConfigSelectorMsg {
63
64
  TransposePivots,
64
65
  ViewCreated,
65
66
  New(DragTarget, InPlaceColumn),
67
+ UpdateGroupRollupMode(GroupRollupMode),
66
68
  }
67
69
 
68
70
  #[derive(Clone)]
@@ -135,11 +137,9 @@ impl Component for ConfigSelector {
135
137
  ctx.props().onselect.emit(());
136
138
  false
137
139
  },
138
- ConfigSelectorMsg::Close(index, DragTarget::GroupBy) => {
139
- let mut group_by = ctx.props().session.get_view_config().group_by.clone();
140
- group_by.remove(index);
140
+ ConfigSelectorMsg::UpdateGroupRollupMode(mode) => {
141
141
  let config = ViewConfigUpdate {
142
- group_by: Some(group_by),
142
+ group_rollup_mode: Some(mode),
143
143
  ..ViewConfigUpdate::default()
144
144
  };
145
145
 
@@ -148,9 +148,45 @@ impl Component for ConfigSelector {
148
148
  .map(ApiFuture::spawn)
149
149
  .unwrap_or_log();
150
150
 
151
- ctx.props().onselect.emit(());
152
151
  false
153
152
  },
153
+ ConfigSelectorMsg::Close(index, DragTarget::GroupBy) => {
154
+ if ctx.props().session.get_view_config().group_rollup_mode == GroupRollupMode::Total
155
+ {
156
+ let requirements = ctx.props().renderer.metadata();
157
+
158
+ let rollup_features = ctx
159
+ .props()
160
+ .session
161
+ .metadata()
162
+ .get_features()
163
+ .map(|x| x.get_group_rollup_modes())
164
+ .unwrap();
165
+
166
+ let group_rollups = requirements.get_group_rollups(&rollup_features);
167
+
168
+ ctx.link()
169
+ .send_message(ConfigSelectorMsg::UpdateGroupRollupMode(
170
+ group_rollups.first().cloned().unwrap(),
171
+ ));
172
+ false
173
+ } else {
174
+ let mut group_by = ctx.props().session.get_view_config().group_by.clone();
175
+ group_by.remove(index);
176
+ let config = ViewConfigUpdate {
177
+ group_by: Some(group_by),
178
+ ..ViewConfigUpdate::default()
179
+ };
180
+
181
+ ctx.props()
182
+ .update_and_render(config)
183
+ .map(ApiFuture::spawn)
184
+ .unwrap_or_log();
185
+
186
+ ctx.props().onselect.emit(());
187
+ false
188
+ }
189
+ },
154
190
  ConfigSelectorMsg::Close(index, DragTarget::SplitBy) => {
155
191
  let mut split_by = ctx.props().session.get_view_config().split_by.clone();
156
192
  split_by.remove(index);
@@ -227,6 +263,7 @@ impl Component for ConfigSelector {
227
263
  ctx.props().onselect.emit(());
228
264
  false
229
265
  },
266
+
230
267
  ConfigSelectorMsg::SetFilterValue(index, input) => {
231
268
  let mut filter = ctx.props().session.get_view_config().filter.clone();
232
269
 
@@ -437,11 +474,15 @@ impl Component for ConfigSelector {
437
474
  let config = session.get_view_config();
438
475
  let transpose = ctx.link().callback(|_| ConfigSelectorMsg::TransposePivots);
439
476
  let column_dropdown = self.column_dropdown.clone();
440
- let class = if dragdrop.get_drag_column().is_some() {
441
- "dragdrop-highlight"
442
- } else {
443
- ""
444
- };
477
+ let mut class = classes!();
478
+
479
+ if dragdrop.get_drag_column().is_some() {
480
+ class.push("dragdrop-highlight");
481
+ }
482
+
483
+ if config.group_rollup_mode == GroupRollupMode::Total {
484
+ class.push("group-rollup-mode-total");
485
+ }
445
486
 
446
487
  let dragend = Callback::from({
447
488
  let dragdrop = dragdrop.clone();
@@ -450,21 +491,52 @@ impl Component for ConfigSelector {
450
491
 
451
492
  let metadata = session.metadata();
452
493
  let features = metadata.get_features().unwrap();
494
+ let requirements = renderer.metadata();
495
+ let on_group_rollup_mode = ctx
496
+ .link()
497
+ .callback(ConfigSelectorMsg::UpdateGroupRollupMode);
498
+
499
+ let rollup_features = ctx
500
+ .props()
501
+ .session
502
+ .metadata()
503
+ .get_features()
504
+ .map(|x| x.get_group_rollup_modes())
505
+ .unwrap();
506
+
507
+ let group_rollups = requirements.get_group_rollups(&rollup_features);
453
508
 
454
509
  html! {
455
510
  <div slot="top_panel" id="top_panel" {class} ondragend={dragend}>
456
511
  <LocalStyle href={css!("config-selector")} />
457
- if !config.group_by.is_empty() && config.split_by.is_empty() {
458
- <span
459
- id="transpose_button"
460
- class="rrow centered"
461
- title="Transpose Pivots"
462
- onmousedown={transpose.clone()}
463
- />
464
- }
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(
518
+ group_rollups
519
+ .iter()
520
+ .map(|x| SelectItem::Option(*x))
521
+ .collect(),
522
+ )}
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>
465
536
  if features.group_by {
466
537
  <GroupBySelector
467
538
  name="group_by"
539
+ disabled={config.group_rollup_mode == GroupRollupMode::Total}
468
540
  parent={ctx.link().clone()}
469
541
  column_dropdown={column_dropdown.clone()}
470
542
  exclude={config.group_by.iter().cloned().collect::<HashSet<_>>()}
@@ -477,7 +549,7 @@ impl Component for ConfigSelector {
477
549
  action={DragTarget::GroupBy}
478
550
  column={group_by.clone()}
479
551
  {dragdrop}
480
- {session}
552
+ opt_session={session}
481
553
  >
482
554
  </PivotColumn>
483
555
  }
@@ -486,12 +558,14 @@ impl Component for ConfigSelector {
486
558
  }
487
559
  if features.split_by {
488
560
  if !config.split_by.is_empty() {
489
- <span
490
- id="transpose_button"
491
- class="rrow centered"
492
- title="Transpose Pivots"
493
- onmousedown={transpose}
494
- />
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>
495
569
  }
496
570
  <SplitBySelector
497
571
  name="split_by"
@@ -506,9 +580,8 @@ impl Component for ConfigSelector {
506
580
  <PivotColumn
507
581
  action={ DragTarget::SplitBy }
508
582
  column={ split_by.clone() }
509
-
510
- {dragdrop}
511
- {session}>
583
+ {dragdrop}
584
+ opt_session={session}>
512
585
  </PivotColumn>
513
586
  }
514
587
  }) }
@@ -26,11 +26,15 @@ pub struct PivotColumnProps {
26
26
  /// Column name.
27
27
  pub column: String,
28
28
 
29
+ #[prop_or_default]
30
+ pub column_type: Option<ColumnType>,
31
+
29
32
  /// The drag starte of this column, if applicable.
30
33
  pub action: DragTarget,
31
34
 
32
35
  // State
33
- pub session: Session,
36
+ #[prop_or_default]
37
+ pub opt_session: Option<Session>,
34
38
  pub dragdrop: DragDrop,
35
39
  }
36
40
 
@@ -74,12 +78,13 @@ impl Component for PivotColumn {
74
78
  move |_event| dragdrop.notify_drag_end()
75
79
  });
76
80
 
77
- let col_type = ctx
78
- .props()
79
- .session
80
- .metadata()
81
- .get_column_table_type(&ctx.props().column)
82
- .unwrap_or(ColumnType::Integer);
81
+ let col_type = ctx.props().column_type.unwrap_or_else(|| {
82
+ ctx.props()
83
+ .opt_session
84
+ .as_ref()
85
+ .and_then(|x| x.metadata().get_column_table_type(&ctx.props().column))
86
+ .unwrap_or(ColumnType::Integer)
87
+ });
83
88
 
84
89
  html! {
85
90
  <div
@@ -28,6 +28,7 @@ use std::rc::Rc;
28
28
  pub use empty_column::*;
29
29
  pub use invalid_column::*;
30
30
  use perspective_js::utils::ApiFuture;
31
+ pub use pivot_column::*;
31
32
  use web_sys::*;
32
33
  use yew::prelude::*;
33
34
 
@@ -77,6 +78,7 @@ pub enum ColumnSelectorMsg {
77
78
  TableLoaded,
78
79
  ViewCreated,
79
80
  HoverActiveIndex(Option<usize>),
81
+ SetWidth(f64),
80
82
  Drag(DragEffect),
81
83
  DragEnd,
82
84
  Drop((String, DragTarget, DragEffect, usize)),
@@ -91,6 +93,7 @@ pub struct ColumnSelector {
91
93
  named_row_count: usize,
92
94
  drag_container: DragDropContainer,
93
95
  column_dropdown: ColumnDropDownElement,
96
+ viewport_width: f64,
94
97
  on_reset: Rc<PubSub<()>>,
95
98
  }
96
99
 
@@ -147,6 +150,7 @@ impl Component for ColumnSelector {
147
150
  Self {
148
151
  _subscriptions: [table_sub, view_sub, drop_sub, drag_sub, dragend_sub],
149
152
  named_row_count,
153
+ viewport_width: 0f64,
150
154
  drag_container,
151
155
  column_dropdown,
152
156
  on_reset: Default::default(),
@@ -157,6 +161,10 @@ impl Component for ColumnSelector {
157
161
  match msg {
158
162
  Drag(DragEffect::Move(DragTarget::Active)) => false,
159
163
  Drag(_) | DragEnd | TableLoaded => true,
164
+ SetWidth(w) => {
165
+ self.viewport_width = w;
166
+ false
167
+ },
160
168
  ViewCreated => {
161
169
  let named = maybe! {
162
170
  let plugin =
@@ -355,11 +363,7 @@ impl Component for ColumnSelector {
355
363
  })
356
364
  .collect();
357
365
 
358
- let size = if !inactive_children.is_empty() {
359
- 56.0
360
- } else {
361
- 28.0
362
- };
366
+ let size = 28.0;
363
367
 
364
368
  let add_column = if ctx
365
369
  .props()
@@ -389,8 +393,8 @@ impl Component for ColumnSelector {
389
393
  inactive_children.insert(0, add_column);
390
394
  }
391
395
 
392
- let selected_columns = html! {
393
- <div id="selected-columns">
396
+ let mut selected_columns = vec![html! {
397
+ <div id="selected-columns" key="__active_columns__">
394
398
  <ScrollPanel
395
399
  id="active-columns"
396
400
  class={active_classes}
@@ -398,13 +402,27 @@ impl Component for ColumnSelector {
398
402
  dragenter={&self.drag_container.dragenter}
399
403
  dragleave={&self.drag_container.dragleave}
400
404
  viewport_ref={&self.drag_container.noderef}
405
+ initial_width={self.viewport_width}
406
+ on_auto_width={ctx.link().callback(ColumnSelectorMsg::SetWidth)}
401
407
  drop={ondrop}
402
408
  on_resize={&ctx.props().on_resize}
403
409
  on_dimensions_reset={&self.on_reset}
404
410
  children={std::iter::once(config_selector).chain(active_columns).collect::<Vec<_>>()}
405
411
  />
406
412
  </div>
407
- };
413
+ }];
414
+
415
+ if !inactive_children.is_empty() {
416
+ selected_columns.push(html! {
417
+ <ScrollPanel
418
+ id="sub-columns"
419
+ key="__sub_columns__"
420
+ on_resize={&ctx.props().on_resize}
421
+ on_dimensions_reset={&self.on_reset}
422
+ children={inactive_children}
423
+ />
424
+ })
425
+ }
408
426
 
409
427
  html! {
410
428
  <>
@@ -415,15 +433,7 @@ impl Component for ColumnSelector {
415
433
  skip_empty=true
416
434
  orientation={Orientation::Vertical}
417
435
  >
418
- { selected_columns }
419
- if !inactive_children.is_empty() {
420
- <ScrollPanel
421
- id="sub-columns"
422
- on_resize={&ctx.props().on_resize}
423
- on_dimensions_reset={&self.on_reset}
424
- children={inactive_children}
425
- />
426
- }
436
+ { for selected_columns }
427
437
  </SplitPanel>
428
438
  </>
429
439
  }
@@ -14,11 +14,13 @@ use std::collections::HashSet;
14
14
  use std::marker::PhantomData;
15
15
 
16
16
  use derivative::Derivative;
17
+ use perspective_client::proto::ColumnType;
17
18
  use web_sys::*;
18
19
  use yew::html::Scope;
19
20
  use yew::prelude::*;
20
21
 
21
22
  use crate::components::column_selector::{EmptyColumn, InPlaceColumn, InvalidColumn};
23
+ use crate::components::type_icon::TypeIcon;
22
24
  use crate::custom_elements::ColumnDropDownElement;
23
25
  use crate::dragdrop::*;
24
26
  use crate::utils::DragTarget;
@@ -32,12 +34,16 @@ where
32
34
  <U as Component>::Properties: DragDropListItemProps,
33
35
  {
34
36
  pub parent: Scope<T>,
37
+
35
38
  pub dragdrop: DragDrop,
36
39
  pub name: &'static str,
37
40
  pub column_dropdown: ColumnDropDownElement,
38
41
  pub exclude: HashSet<String>,
39
42
  pub children: ChildrenWithProps<U>,
40
43
 
44
+ #[prop_or_default]
45
+ pub disabled: bool,
46
+
41
47
  #[prop_or_default]
42
48
  pub is_dragover: Option<(
43
49
  usize,
@@ -59,6 +65,7 @@ where
59
65
  && self.children == other.children
60
66
  && self.allow_duplicates == other.allow_duplicates
61
67
  && self.is_dragover == other.is_dragover
68
+ && self.disabled == other.disabled
62
69
  }
63
70
  }
64
71
 
@@ -283,20 +290,34 @@ where
283
290
  let column_dropdown = ctx.props().column_dropdown.clone();
284
291
  let exclude = ctx.props().exclude.clone();
285
292
  let on_select = ctx.props().parent.callback(V::create);
293
+ let class = classes!("rrow");
294
+ let is_enabled = true;
295
+
286
296
  html! {
287
- <div ref={&self.elem} class="rrow">
297
+ <div ref={&self.elem} {class}>
288
298
  <div
289
299
  id={ctx.props().name}
290
- ondragover={dragover}
291
- ondragenter={drag_container.dragenter}
292
- ondragleave={drag_container.dragleave}
300
+ ondragover={is_enabled.then_some(dragover)}
301
+ ondragenter={is_enabled.then_some(drag_container.dragenter)}
302
+ ondragleave={is_enabled.then_some(drag_container.dragleave)}
293
303
  ref={drag_container.noderef}
294
- ondrop={drop}
304
+ ondrop={is_enabled.then_some(drop)}
295
305
  >
296
306
  <div class="psp-text-field">
297
307
  <ul class="psp-text-field__input" for={ctx.props().name}>
298
308
  { columns_html }
299
- if ctx.props().is_dragover.is_none() | (!invalid_drag && valid_duplicate_drag) {
309
+ if ctx.props().disabled && ctx.props().is_dragover.is_none() {
310
+ <div class="pivot-column">
311
+ <div class="pivot-column-border pivot-column-total">
312
+ <TypeIcon ty={ColumnType::Integer} />
313
+ <span class="column_name">{ "TOTAL" }</span>
314
+ </div>
315
+ <span
316
+ class="toggle-mode is_column_active"
317
+ onmousedown={ctx.props().parent.callback(move |_| V::close(0))}
318
+ />
319
+ </div>
320
+ } else if ctx.props().is_dragover.is_none() | (!invalid_drag && valid_duplicate_drag) {
300
321
  <EmptyColumn {column_dropdown} {exclude} {on_select} />
301
322
  } else if invalid_drag {
302
323
  <InvalidColumn />
@@ -34,6 +34,9 @@ pub struct ScrollPanelProps {
34
34
  #[prop_or_default]
35
35
  pub viewport_ref: Option<NodeRef>,
36
36
 
37
+ #[prop_or_default]
38
+ pub initial_width: Option<f64>,
39
+
37
40
  #[prop_or_default]
38
41
  pub class: Classes,
39
42
 
@@ -52,6 +55,9 @@ pub struct ScrollPanelProps {
52
55
  #[prop_or_default]
53
56
  pub on_resize: Option<Rc<PubSub<()>>>,
54
57
 
58
+ #[prop_or_default]
59
+ pub on_auto_width: Callback<f64>,
60
+
55
61
  #[prop_or_default]
56
62
  pub on_dimensions_reset: Option<Rc<PubSub<()>>>,
57
63
 
@@ -125,7 +131,7 @@ impl Component for ScrollPanel {
125
131
  Self {
126
132
  viewport_ref: Default::default(),
127
133
  viewport_height: 0f64,
128
- viewport_width: 0f64,
134
+ viewport_width: ctx.props().initial_width.unwrap_or_default(),
129
135
  content_window: None,
130
136
  needs_rerender: true,
131
137
  total_height,
@@ -150,6 +156,7 @@ impl Component for ScrollPanel {
150
156
 
151
157
  self.viewport_height = rect.height() - 8.0;
152
158
  self.viewport_width = self.viewport_width.max(rect.width() - 6.0);
159
+ ctx.props().on_auto_width.emit(self.viewport_width);
153
160
  re_render
154
161
  },
155
162
  ScrollPanelMsg::CalculateWindowContent => self.calculate_window_content(ctx),
@@ -220,9 +220,9 @@ where
220
220
  };
221
221
 
222
222
  let value = if ctx.props().is_autosize {
223
- self.selected.to_string()
223
+ Some(self.selected.to_string())
224
224
  } else {
225
- "".to_owned()
225
+ None
226
226
  };
227
227
 
228
228
  html! {
@@ -230,7 +230,7 @@ where
230
230
  <label>
231
231
  { ctx.props().label.as_ref().map(|x| x.to_string()).unwrap_or_default() }
232
232
  </label>
233
- <div class={wrapper_class} data-value={value.clone()}>{ select }</div>
233
+ <div class={wrapper_class} data-value={value}>{ select }</div>
234
234
  } else {
235
235
  <div class={wrapper_class} data-value={value}>{ select }</div>
236
236
  }
@@ -201,11 +201,11 @@ impl Component for SplitPanel {
201
201
  let count = iter.len();
202
202
  let contents = html! {
203
203
  <>
204
- <LocalStyle key=0 href={css!("containers/split-panel")} />
204
+ <LocalStyle href={css!("containers/split-panel")} />
205
205
  for (i, x) in iter {
206
206
  if i == 0 {
207
207
  if count == 1 {
208
- <key={i}>
208
+ <key=0>
209
209
  {x}
210
210
  </>
211
211
  } else {
@@ -83,11 +83,21 @@ impl Component for PluginSelector {
83
83
  let metadata =
84
84
  renderer.get_next_plugin_metadata(&PluginUpdate::Update(plugin_name));
85
85
 
86
- let mut update = ViewConfigUpdate::default();
87
- session.set_update_column_defaults(
88
- &mut update,
89
- metadata.as_ref().unwrap_or(&*renderer.metadata()),
90
- );
86
+ let prev_metadata = renderer.metadata();
87
+ let requirements = metadata.as_ref().unwrap_or(&*prev_metadata);
88
+ let rollup_features = session
89
+ .metadata()
90
+ .get_features()
91
+ .map(|x| x.get_group_rollup_modes())
92
+ .unwrap();
93
+
94
+ let group_rollups = requirements.get_group_rollups(&rollup_features);
95
+ let mut update = ViewConfigUpdate {
96
+ group_rollup_mode: group_rollups.first().cloned(),
97
+ ..ViewConfigUpdate::default()
98
+ };
99
+
100
+ session.set_update_column_defaults(&mut update, requirements);
91
101
 
92
102
  if let Ok(task) = ctx.props().update_and_render(update) {
93
103
  ApiFuture::spawn(task);
@@ -164,6 +164,9 @@ impl Reducible for StatusIconState {
164
164
  StatusIconStateAction::Increment | StatusIconStateAction::Decrement,
165
165
  ) => StatusIconState::Loading,
166
166
  (_, StatusIconStateAction::Increment) => Self::Updating(1),
167
+ (StatusIconState::Errored(x, y, z), _) => {
168
+ StatusIconState::Errored(x.clone(), y.clone(), z)
169
+ },
167
170
  (_, StatusIconStateAction::Decrement) => StatusIconState::Normal,
168
171
  };
169
172