@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.
- package/dist/cdn/perspective-viewer.js +2 -2
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -0
- package/dist/css/themes.css +1 -1
- package/dist/esm/extensions.d.ts +32 -1
- package/dist/esm/perspective-viewer.d.ts +1 -0
- package/dist/esm/perspective-viewer.inline.js +2 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +2 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/ts-rs/GroupRollupMode.d.ts +1 -0
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +2 -0
- package/dist/wasm/perspective-viewer.d.ts +14 -14
- package/dist/wasm/perspective-viewer.js +88 -80
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +14 -14
- package/package.json +3 -2
- package/src/less/column-selector.less +2 -2
- package/src/less/config-selector.less +66 -4
- package/src/rust/components/column_selector/config_selector.rs +102 -29
- package/src/rust/components/column_selector/pivot_column.rs +12 -7
- package/src/rust/components/column_selector.rs +27 -17
- package/src/rust/components/containers/dragdrop_list.rs +27 -6
- package/src/rust/components/containers/scroll_panel.rs +8 -1
- package/src/rust/components/containers/select.rs +3 -3
- package/src/rust/components/containers/split_panel.rs +2 -2
- package/src/rust/components/plugin_selector.rs +15 -5
- package/src/rust/components/status_indicator.rs +3 -0
- package/src/rust/js/plugin.rs +19 -0
- package/src/rust/model/intersection_observer.rs +3 -1
- package/src/rust/renderer/registry.rs +8 -1
- package/src/rust/session/column_defaults_update.rs +18 -0
- package/src/rust/session/replace_expression_update.rs +1 -0
- package/src/themes/botanical.less +142 -0
- package/src/themes/themes.less +2 -1
- package/src/ts/extensions.ts +73 -2
- package/src/ts/perspective-viewer.ts +1 -0
- package/src/ts/ts-rs/GroupRollupMode.ts +3 -0
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -1
- package/tsconfig.json +1 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-d729f682ba5c19df}/inline3.js +0 -0
- /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::
|
|
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
|
-
|
|
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 =
|
|
441
|
-
|
|
442
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
-
<
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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 =
|
|
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
|
|
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()
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
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=
|
|
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
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|